Wanted items timeline

main
Bob Mottram 2021-08-09 19:41:05 +01:00
parent 641963dc05
commit cbb55581e1
56 changed files with 681 additions and 40 deletions

267
daemon.py
View File

@ -157,6 +157,7 @@ from webapp_confirm import htmlConfirmRemoveSharedItem
from webapp_confirm import htmlConfirmUnblock
from webapp_person_options import htmlPersonOptions
from webapp_timeline import htmlShares
from webapp_timeline import htmlWanted
from webapp_timeline import htmlInbox
from webapp_timeline import htmlBookmarks
from webapp_timeline import htmlInboxDMs
@ -3401,6 +3402,73 @@ class PubServer(BaseHTTPRequestHandler):
cookie, callingDomain)
self.server.POSTbusy = False
def _removeWanted(self, callingDomain: str, cookie: str,
authorized: bool, path: str,
baseDir: str, httpPrefix: str,
domain: str, domainFull: str,
onionDomain: str, i2pDomain: str,
debug: bool) -> None:
"""Removes a wanted item
"""
usersPath = path.split('/rmwanted')[0]
originPathStr = httpPrefix + '://' + domainFull + usersPath
length = int(self.headers['Content-length'])
try:
removeShareConfirmParams = \
self.rfile.read(length).decode('utf-8')
except SocketError as e:
if e.errno == errno.ECONNRESET:
print('WARN: POST removeShareConfirmParams ' +
'connection was reset')
else:
print('WARN: POST removeShareConfirmParams socket error')
self.send_response(400)
self.end_headers()
self.server.POSTbusy = False
return
except ValueError as e:
print('ERROR: POST removeShareConfirmParams rfile.read failed, ' +
str(e))
self.send_response(400)
self.end_headers()
self.server.POSTbusy = False
return
if '&submitYes=' in removeShareConfirmParams and authorized:
removeShareConfirmParams = \
removeShareConfirmParams.replace('+', ' ').strip()
removeShareConfirmParams = \
urllib.parse.unquote_plus(removeShareConfirmParams)
shareActor = removeShareConfirmParams.split('actor=')[1]
if '&' in shareActor:
shareActor = shareActor.split('&')[0]
adminNickname = getConfigParam(baseDir, 'admin')
adminActor = \
httpPrefix + '://' + domainFull + '/users' + adminNickname
actor = originPathStr
actorNickname = getNicknameFromActor(actor)
if actor == shareActor or actor == adminActor or \
isModerator(baseDir, actorNickname):
itemID = removeShareConfirmParams.split('itemID=')[1]
if '&' in itemID:
itemID = itemID.split('&')[0]
shareNickname = getNicknameFromActor(shareActor)
if shareNickname:
shareDomain, sharePort = getDomainFromActor(shareActor)
removeSharedItem(baseDir,
shareNickname, shareDomain, itemID,
httpPrefix, domainFull, 'wanted')
if callingDomain.endswith('.onion') and onionDomain:
originPathStr = 'http://' + onionDomain + usersPath
elif (callingDomain.endswith('.i2p') and i2pDomain):
originPathStr = 'http://' + i2pDomain + usersPath
self._redirect_headers(originPathStr + '/tlwanted',
cookie, callingDomain)
self.server.POSTbusy = False
def _removePost(self, callingDomain: str, cookie: str,
authorized: bool, path: str,
baseDir: str, httpPrefix: str,
@ -9099,6 +9167,87 @@ class PubServer(BaseHTTPRequestHandler):
self.server.GETbusy = False
return True
def _showWantedTimeline(self, authorized: bool,
callingDomain: str, path: str,
baseDir: str, httpPrefix: str,
domain: str, domainFull: str, port: int,
onionDomain: str, i2pDomain: str,
GETstartTime, GETtimings: {},
proxyType: str, cookie: str,
debug: str) -> bool:
"""Shows the wanted timeline
"""
if '/users/' in path:
if authorized:
if self._requestHTTP():
nickname = path.replace('/users/', '')
nickname = nickname.replace('/tlwanted', '')
pageNumber = 1
if '?page=' in nickname:
pageNumber = nickname.split('?page=')[1]
nickname = nickname.split('?page=')[0]
if pageNumber.isdigit():
pageNumber = int(pageNumber)
else:
pageNumber = 1
accessKeys = self.server.accessKeys
if self.server.keyShortcuts.get(nickname):
accessKeys = \
self.server.keyShortcuts[nickname]
msg = \
htmlWanted(self.server.cssCache,
self.server.defaultTimeline,
self.server.recentPostsCache,
self.server.maxRecentPosts,
self.server.translate,
pageNumber, maxPostsInFeed,
self.server.session,
baseDir,
self.server.cachedWebfingers,
self.server.personCache,
nickname,
domain,
port,
self.server.allowDeletion,
httpPrefix,
self.server.projectVersion,
self.server.YTReplacementDomain,
self.server.showPublishedDateOnly,
self.server.newswire,
self.server.positiveVoting,
self.server.showPublishAsIcon,
self.server.fullWidthTimelineButtonHeader,
self.server.iconsAsButtons,
self.server.rssIconAtTop,
self.server.publishButtonAtTop,
authorized, self.server.themeName,
self.server.peertubeInstances,
self.server.allowLocalNetworkAccess,
self.server.textModeBanner,
accessKeys,
self.server.systemLanguage,
self.server.maxLikeCount,
self.server.sharedItemsFederatedDomains)
msg = msg.encode('utf-8')
msglen = len(msg)
self._set_headers('text/html', msglen,
cookie, callingDomain)
self._write(msg)
self._benchmarkGETtimings(GETstartTime, GETtimings,
'show blogs 2 done',
'show wanted 2')
self.server.GETbusy = False
return True
# not the shares timeline
if debug:
print('DEBUG: GET access to wanted timeline is unauthorized')
self.send_response(405)
self.end_headers()
self.server.GETbusy = False
return True
def _showBookmarksTimeline(self, authorized: bool,
callingDomain: str, path: str,
baseDir: str, httpPrefix: str,
@ -10447,7 +10596,7 @@ class PubServer(BaseHTTPRequestHandler):
newPostEnd = ('newpost', 'newblog', 'newunlisted',
'newfollowers', 'newdm', 'newreminder',
'newreport', 'newquestion',
'newshare')
'newshare', 'newwanted')
for postType in newPostEnd:
if path.endswith('/' + postType):
isNewPostEndpoint = True
@ -11387,6 +11536,40 @@ class PubServer(BaseHTTPRequestHandler):
'htmlShowShare')
return
# after selecting a wanted item from the left column then show it
if htmlGET and '?showwanted=' in self.path and '/users/' in self.path:
itemID = self.path.split('?showwanted=')[1]
usersPath = self.path.split('?showwanted=')[0]
nickname = usersPath.replace('/users/', '')
itemID = urllib.parse.unquote_plus(itemID.strip())
msg = \
htmlShowShare(self.server.baseDir,
self.server.domain, nickname,
self.server.httpPrefix, self.server.domainFull,
itemID, self.server.translate,
self.server.sharedItemsFederatedDomains,
self.server.defaultTimeline,
self.server.themeName, 'wanted')
if not msg:
if callingDomain.endswith('.onion') and \
self.server.onionDomain:
actor = 'http://' + self.server.onionDomain + usersPath
elif (callingDomain.endswith('.i2p') and
self.server.i2pDomain):
actor = 'http://' + self.server.i2pDomain + usersPath
self._redirect_headers(actor + '/tlwanted',
cookie, callingDomain)
return
msg = msg.encode('utf-8')
msglen = len(msg)
self._set_headers('text/html', msglen,
cookie, callingDomain)
self._write(msg)
self._benchmarkGETtimings(GETstartTime, GETtimings,
'blog post 2 done',
'htmlShowWanted')
return
# remove a shared item
if htmlGET and '?rmshare=' in self.path:
itemID = self.path.split('?rmshare=')[1]
@ -11420,6 +11603,39 @@ class PubServer(BaseHTTPRequestHandler):
'remove shared item')
return
# remove a wanted item
if htmlGET and '?rmwanted=' in self.path:
itemID = self.path.split('?rmwanted=')[1]
itemID = urllib.parse.unquote_plus(itemID.strip())
usersPath = self.path.split('?rmwanted=')[0]
actor = \
self.server.httpPrefix + '://' + \
self.server.domainFull + usersPath
msg = htmlConfirmRemoveSharedItem(self.server.cssCache,
self.server.translate,
self.server.baseDir,
actor, itemID,
callingDomain, 'wanted')
if not msg:
if callingDomain.endswith('.onion') and \
self.server.onionDomain:
actor = 'http://' + self.server.onionDomain + usersPath
elif (callingDomain.endswith('.i2p') and
self.server.i2pDomain):
actor = 'http://' + self.server.i2pDomain + usersPath
self._redirect_headers(actor + '/tlwanted',
cookie, callingDomain)
return
msg = msg.encode('utf-8')
msglen = len(msg)
self._set_headers('text/html', msglen,
cookie, callingDomain)
self._write(msg)
self._benchmarkGETtimings(GETstartTime, GETtimings,
'blog post 2 done',
'remove shared item')
return
self._benchmarkGETtimings(GETstartTime, GETtimings,
'blog post 2 done',
'remove shared item done')
@ -12996,6 +13212,22 @@ class PubServer(BaseHTTPRequestHandler):
cookie, self.server.debug):
return
# get the wanted items timeline for a given person
if self.path.endswith('/tlwanted') or '/tlwanted?page=' in self.path:
if self._showWantedTimeline(authorized,
callingDomain, self.path,
self.server.baseDir,
self.server.httpPrefix,
self.server.domain,
self.server.domainFull,
self.server.port,
self.server.onionDomain,
self.server.i2pDomain,
GETstartTime, GETtimings,
self.server.proxyType,
cookie, self.server.debug):
return
self._benchmarkGETtimings(GETstartTime, GETtimings,
'show blogs 2 done',
'show shares 2 done')
@ -13955,7 +14187,7 @@ class PubServer(BaseHTTPRequestHandler):
if self._postToOutbox(messageJson, __version__, nickname):
return 1
return -1
elif postType == 'newshare':
elif postType == 'newshare' or postType == 'newwanted':
if not fields.get('itemQty'):
print(postType + ' no itemQty')
return -1
@ -13997,7 +14229,12 @@ class PubServer(BaseHTTPRequestHandler):
getPriceFromString(fields['itemPrice'])
if fields['itemCurrency']:
itemCurrency = fields['itemCurrency']
print('Adding shared item')
if postType == 'newshare':
print('Adding shared item')
sharesFileType = 'shares'
else:
print('Adding wanted item')
sharesFileType = 'wanted'
addShare(self.server.baseDir,
self.server.httpPrefix,
nickname,
@ -14012,7 +14249,7 @@ class PubServer(BaseHTTPRequestHandler):
self.server.debug,
city, itemPrice, itemCurrency,
self.server.systemLanguage,
self.server.translate, 'shares')
self.server.translate, sharesFileType)
if filename:
if os.path.isfile(filename):
os.remove(filename)
@ -14540,6 +14777,19 @@ class PubServer(BaseHTTPRequestHandler):
self.server.debug)
return
# removes a wanted item
if self.path.endswith('/rmwanted'):
self._removeWanted(callingDomain, cookie,
authorized, self.path,
self.server.baseDir,
self.server.httpPrefix,
self.server.domain,
self.server.domainFull,
self.server.onionDomain,
self.server.i2pDomain,
self.server.debug)
return
self._benchmarkPOSTtimings(POSTstartTime, POSTtimings, 8)
# removes a post
@ -14717,8 +14967,8 @@ class PubServer(BaseHTTPRequestHandler):
# receive different types of post created by htmlNewPost
postTypes = ("newpost", "newblog", "newunlisted", "newfollowers",
"newdm", "newreport", "newshare", "newquestion",
"editblogpost", "newreminder")
"newdm", "newreport", "newshare", "newwanted",
"newquestion", "editblogpost", "newreminder")
for currPostType in postTypes:
if not authorized:
if self.server.debug:
@ -14728,6 +14978,8 @@ class PubServer(BaseHTTPRequestHandler):
postRedirect = self.server.defaultTimeline
if currPostType == 'newshare':
postRedirect = 'shares'
elif currPostType == 'newwanted':
postRedirect = 'wanted'
pageNumber = \
self._receiveNewPost(currPostType, self.path,
@ -15233,8 +15485,9 @@ def runDaemon(maxLikeCount: int,
'menuOutbox': 's',
'menuBookmarks': 'q',
'menuShares': 'h',
'menuWanted': 'w',
'menuBlogs': 'b',
'menuNewswire': 'w',
'menuNewswire': 'u',
'menuLinks': 'l',
'menuMedia': 'm',
'menuModeration': 'o',

View File

@ -279,6 +279,21 @@ function notifications {
fi
fi
# send notifications for new wanted items to XMPP/email users
epicyonWantedFile="$epicyonDir/.newWanted"
if [ -f "$epicyonWantedFile" ]; then
if ! grep -q "##sent##" "$epicyonWantedFile"; then
epicyonWantedMessage=$(notification_translate_text 'Wanted')
epicyonWantedFileContent=$(echo "$epicyonWantedMessage")" "$(cat "$epicyonWantedFile")
if [[ "$epicyonWantedFileContent" == *':'* ]]; then
epicyonWantedMessage="Epicyon: $epicyonWantedFileContent"
fi
sendNotification "$USERNAME" "Epicyon" "$epicyonWantedMessage"
echo "##sent##" > "$epicyonWantedFile"
chown ${PROJECT_NAME}:${PROJECT_NAME} "$epicyonWantedFile"
fi
fi
# send notifications for follow requests to XMPP/email users
epicyonFollowFile="$epicyonDir/followrequests.txt"
epicyonFollowNotificationsFile="$epicyonDir/follownotifications.txt"

View File

@ -253,7 +253,7 @@ def _getshareTypeFromDfcId(dfcUri: str, dfcIds: {}) -> str:
def _indicateNewShareAvailable(baseDir: str, httpPrefix: str,
nickname: str, domain: str,
domainFull: str) -> None:
domainFull: str, sharesFileType: str) -> None:
"""Indicate to each account that a new share is available
"""
for subdir, dirs, files in os.walk(baseDir + '/accounts'):
@ -261,7 +261,10 @@ def _indicateNewShareAvailable(baseDir: str, httpPrefix: str,
if not isAccountDir(handle):
continue
accountDir = baseDir + '/accounts/' + handle
newShareFile = accountDir + '/.newShare'
if sharesFileType == 'shares':
newShareFile = accountDir + '/.newShare'
else:
newShareFile = accountDir + '/.newWanted'
if os.path.isfile(newShareFile):
continue
accountNickname = handle.split('@')[0]
@ -272,8 +275,12 @@ def _indicateNewShareAvailable(baseDir: str, httpPrefix: str,
continue
try:
with open(newShareFile, 'w+') as fp:
fp.write(httpPrefix + '://' + domainFull +
'/users/' + accountNickname + '/tlshares')
if sharesFileType == 'shares':
fp.write(httpPrefix + '://' + domainFull +
'/users/' + accountNickname + '/tlshares')
else:
fp.write(httpPrefix + '://' + domainFull +
'/users/' + accountNickname + '/tlwanted')
except BaseException:
pass
break
@ -363,7 +370,8 @@ def addShare(baseDir: str,
saveJson(sharesJson, sharesFilename)
_indicateNewShareAvailable(baseDir, httpPrefix,
nickname, domain, domainFull)
nickname, domain, domainFull,
sharesFileType)
def expireShares(baseDir: str) -> None:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

View File

@ -461,5 +461,15 @@
"Shares Catalog": "كتالوج الأسهم",
"tool": "أداة",
"clothes": "ملابس",
"medical": "طبي"
"medical": "طبي",
"Wanted": "مطلوب",
"Describe something wanted": "وصف شيء مطلوب",
"Enter the details for your wanted item below.": "أدخل تفاصيل العنصر المطلوب أدناه.",
"Name of the wanted item": "اسم العنصر المطلوب",
"Description of the item wanted": "وصف العنصر المطلوب",
"Type of wanted item. eg. hat": "نوع الشيء المطلوب. على سبيل المثال قبعة",
"Category of wanted item. eg. clothes": "فئة العنصر المطلوب. على سبيل المثال ملابس",
"City or location of the wanted item": "مدينة أو موقع العنصر المطلوب",
"Maximum Price": "السعر الأقصى",
"Create a new wanted item": "قم بإنشاء عنصر مطلوب جديد"
}

View File

@ -461,5 +461,15 @@
"Shares Catalog": "Catàleg d'accions",
"tool": "eina",
"clothes": "roba",
"medical": "mèdic"
"medical": "mèdic",
"Wanted": "Volia",
"Describe something wanted": "Descriviu alguna cosa que volgués",
"Enter the details for your wanted item below.": "Introduïu els detalls de l'article que voleu a continuació.",
"Name of the wanted item": "Nom de l'element desitjat",
"Description of the item wanted": "Descripció de l'element desitjat",
"Type of wanted item. eg. hat": "Tipus d'article desitjat. per exemple. barret",
"Category of wanted item. eg. clothes": "Categoria de l'article desitjat. per exemple. roba",
"City or location of the wanted item": "Ciutat o ubicació de larticle desitjat",
"Maximum Price": "Preu màxim",
"Create a new wanted item": "Creeu un element desitjat"
}

View File

@ -461,5 +461,15 @@
"Shares Catalog": "Catalog Cyfranddaliadau",
"tool": "hofferyn",
"clothes": "ddillad",
"medical": "meddygol"
"medical": "meddygol",
"Wanted": "Am",
"Describe something wanted": "Disgrifio rhywbeth ei eisiau",
"Enter the details for your wanted item below.": "Rhowch y manylion ar gyfer eich eitem eisiau isod.",
"Name of the wanted item": "Enw'r eitem sydd ei eisiau",
"Description of the item wanted": "Disgrifiad o'r eitem eisiau",
"Type of wanted item. eg. hat": "Math o eitem eisiau. ee. het",
"Category of wanted item. eg. clothes": "Categori yr eitem sydd ei eisiau. ee. dillad",
"City or location of the wanted item": "Dinas neu leoliad yr eitem sydd ei eisiau",
"Maximum Price": "Uchafswm Pris",
"Create a new wanted item": "Creu eitem newydd ei heisiau"
}

View File

@ -461,5 +461,15 @@
"Shares Catalog": "Aktienkatalog",
"tool": "werkzeug",
"clothes": "kleidung",
"medical": "medizinisch"
"medical": "medizinisch",
"Wanted": "Gesucht",
"Describe something wanted": "Beschreibe etwas gewünscht",
"Enter the details for your wanted item below.": "Geben Sie unten die Details zu Ihrem gewünschten Artikel ein.",
"Name of the wanted item": "Name des gesuchten Artikels",
"Description of the item wanted": "Beschreibung des gesuchten Artikels",
"Type of wanted item. eg. hat": "Art des gesuchten Artikels. z.B. Hut",
"Category of wanted item. eg. clothes": "Kategorie des gesuchten Artikels. z.B. Kleidung",
"City or location of the wanted item": "Stadt oder Ort des gesuchten Artikels",
"Maximum Price": "Höchstpreis",
"Create a new wanted item": "Erstelle einen neuen gesuchten Artikel"
}

View File

@ -461,5 +461,15 @@
"Shares Catalog": "Shares Catalog",
"tool": "tool",
"clothes": "clothes",
"medical": "medical"
"medical": "medical",
"Wanted": "Wanted",
"Describe something wanted": "Describe something wanted",
"Enter the details for your wanted item below.": "Enter the details for your wanted item below.",
"Name of the wanted item": "Name of the wanted item",
"Description of the item wanted": "Description of the item wanted",
"Type of wanted item. eg. hat": "Type of wanted item. eg. hat",
"Category of wanted item. eg. clothes": "Category of wanted item. eg. clothes",
"City or location of the wanted item": "City or location of the wanted item",
"Maximum Price": "Maximum Price",
"Create a new wanted item": "Create a new wanted item"
}

View File

@ -461,5 +461,15 @@
"Shares Catalog": "Catálogo de acciones",
"tool": "herramienta",
"clothes": "ropa",
"medical": "médica"
"medical": "médica",
"Wanted": "Buscada",
"Describe something wanted": "Describe algo quería",
"Enter the details for your wanted item below.": "Ingrese los detalles de su artículo deseado a continuación.",
"Name of the wanted item": "Nombre del artículo buscado",
"Description of the item wanted": "Descripción del artículo deseado",
"Type of wanted item. eg. hat": "Tipo de artículo deseado. p.ej. sombrero",
"Category of wanted item. eg. clothes": "Categoría de artículo buscado. p.ej. ropa",
"City or location of the wanted item": "Ciudad o ubicación del artículo buscado",
"Maximum Price": "Precio Máximo",
"Create a new wanted item": "Crea un nuevo artículo buscado"
}

View File

@ -461,5 +461,15 @@
"Shares Catalog": "Actions Catalogue",
"tool": "outil",
"clothes": "vêtements",
"medical": "médicale"
"medical": "médicale",
"Wanted": "Recherchée",
"Describe something wanted": "Décrire quelque chose voulu",
"Enter the details for your wanted item below.": "Entrez les détails de votre article recherché ci-dessous.",
"Name of the wanted item": "Nom de l'article recherché",
"Description of the item wanted": "Description de l'article recherché",
"Type of wanted item. eg. hat": "Type d'article recherché. par exemple. chapeau",
"Category of wanted item. eg. clothes": "Catégorie de l'article recherché. par exemple. vêtements",
"City or location of the wanted item": "Ville ou lieu de l'article recherché",
"Maximum Price": "Prix maximum",
"Create a new wanted item": "Créer un nouvel article recherché"
}

View File

@ -461,5 +461,15 @@
"Shares Catalog": "Scaireanna Catalóg",
"tool": "uirlis",
"clothes": "éadaí",
"medical": "scrúdú dochtúra"
"medical": "scrúdú dochtúra",
"Wanted": "Theastaigh",
"Describe something wanted": "Déan cur síos ar rud éigin a theastaíonn",
"Enter the details for your wanted item below.": "Iontráil sonraí do mhír atá uait.",
"Name of the wanted item": "Ainm an earra a theastaigh",
"Description of the item wanted": "Tuairisc ar an mír a theastaigh",
"Type of wanted item. eg. hat": "Cineál earra a theastaigh. m.sh. hata",
"Category of wanted item. eg. clothes": "Catagóir an earra a theastaigh. m.sh. éadaí",
"City or location of the wanted item": "Cathair nó suíomh an earra a theastaigh",
"Maximum Price": "Uasphraghas",
"Create a new wanted item": "Cruthaigh mír nua a theastaigh"
}

View File

@ -461,5 +461,15 @@
"Shares Catalog": "शेयर कैटलॉग",
"tool": "साधन",
"clothes": "कपड़े",
"medical": "मेडिकल"
"medical": "मेडिकल",
"Wanted": "वांछित",
"Describe something wanted": "कुछ चाहते थे का वर्णन करें",
"Enter the details for your wanted item below.": "अपनी वांछित वस्तु का विवरण नीचे दर्ज करें।",
"Name of the wanted item": "वांछित वस्तु का नाम",
"Description of the item wanted": "वांछित वस्तु का विवरण",
"Type of wanted item. eg. hat": "वांछित वस्तु का प्रकार। उदाहरण के लिए टोपी",
"Category of wanted item. eg. clothes": "वांछित वस्तु की श्रेणी। उदाहरण के लिए कपड़े",
"City or location of the wanted item": "वांछित वस्तु का शहर या स्थान",
"Maximum Price": "अधिकतम मूल्य",
"Create a new wanted item": "एक नई वांछित वस्तु बनाएँ"
}

View File

@ -461,5 +461,15 @@
"Shares Catalog": "Condivide il catalogo",
"tool": "attrezzo",
"clothes": "abiti",
"medical": "medica"
"medical": "medica",
"Wanted": "Ricercata",
"Describe something wanted": "Descrivi qualcosa di ricercato",
"Enter the details for your wanted item below.": "Inserisci i dettagli per l'articolo desiderato di seguito.",
"Name of the wanted item": "Nome dell'articolo desiderato",
"Description of the item wanted": "Descrizione dell'articolo desiderato",
"Type of wanted item. eg. hat": "Tipo di articolo desiderato. per esempio. cappello",
"Category of wanted item. eg. clothes": "Categoria dell'oggetto ricercato. per esempio. Abiti",
"City or location of the wanted item": "Città o posizione dell'articolo desiderato",
"Maximum Price": "Prezzo massimo",
"Create a new wanted item": "Crea un nuovo oggetto ricercato"
}

View File

@ -461,5 +461,15 @@
"Shares Catalog": "カタログを共有します",
"tool": "道具",
"clothes": "服",
"medical": "医学"
"medical": "医学",
"Wanted": "欲しかった",
"Describe something wanted": "必要なものを説明してください",
"Enter the details for your wanted item below.": "必要なアイテムの詳細を以下に入力してください。",
"Name of the wanted item": "欲しいアイテムの名前",
"Description of the item wanted": "欲しいアイテムの説明",
"Type of wanted item. eg. hat": "欲しいアイテムの種類。 例えば。 帽子",
"Category of wanted item. eg. clothes": "欲しいアイテムのカテゴリー。 例えば。 服",
"City or location of the wanted item": "欲しいアイテムの都市または場所",
"Maximum Price": "最高価格",
"Create a new wanted item": "新しい欲しいアイテムを作成する"
}

View File

@ -461,5 +461,15 @@
"Shares Catalog": "Kataloga Shares",
"tool": "hacet",
"clothes": "lebas",
"medical": "pizişkî"
"medical": "pizişkî",
"Wanted": "Xwestin",
"Describe something wanted": "Tiştek xwestin diyar bikin",
"Enter the details for your wanted item below.": "Li jêr hûrguliyên tiştê ku we dixwest binivîsin.",
"Name of the wanted item": "Navê tiştê tê xwestin",
"Description of the item wanted": "Danasîna tiştê xwestî",
"Type of wanted item. eg. hat": "Tîpa tiştê xwestî. mînak. kûm",
"Category of wanted item. eg. clothes": "Kategoriya tiştê xwestî. mînak. cilan",
"City or location of the wanted item": "Bajar an cîhê tiştê xwestî",
"Maximum Price": "Maximum Price",
"Create a new wanted item": "Tiştek xwestî ya nû biafirînin"
}

View File

@ -457,5 +457,15 @@
"Shares Catalog": "Shares Catalog",
"tool": "tool",
"clothes": "clothes",
"medical": "medical"
"medical": "medical",
"Wanted": "Wanted",
"Describe something wanted": "Describe something wanted",
"Enter the details for your wanted item below.": "Enter the details for your wanted item below.",
"Name of the wanted item": "Name of the wanted item",
"Description of the item wanted": "Description of the item wanted",
"Type of wanted item. eg. hat": "Type of wanted item. eg. hat",
"Category of wanted item. eg. clothes": "Category of wanted item. eg. clothes",
"City or location of the wanted item": "City or location of the wanted item",
"Maximum Price": "Maximum Price",
"Create a new wanted item": "Create a new wanted item"
}

View File

@ -461,5 +461,15 @@
"Shares Catalog": "Catálogo de ações",
"tool": "ferramenta",
"clothes": "roupas",
"medical": "médica"
"medical": "médica",
"Wanted": "Procurada",
"Describe something wanted": "Descreva algo queria",
"Enter the details for your wanted item below.": "Insira os detalhes do item desejado abaixo.",
"Name of the wanted item": "Nome do item desejado",
"Description of the item wanted": "Descrição do item desejado",
"Type of wanted item. eg. hat": "Tipo de item desejado. por exemplo. chapéu",
"Category of wanted item. eg. clothes": "Categoria do item desejado. por exemplo. roupas",
"City or location of the wanted item": "Cidade ou localização do item desejado",
"Maximum Price": "Preço Máximo",
"Create a new wanted item": "Crie um novo item desejado"
}

View File

@ -461,5 +461,15 @@
"Shares Catalog": "Акции каталог",
"tool": "орудие труда",
"clothes": "одежда",
"medical": "медицинский"
"medical": "медицинский",
"Wanted": "В розыске",
"Describe something wanted": "Опишите что-то хотел",
"Enter the details for your wanted item below.": "Введите ниже сведения о желаемом товаре.",
"Name of the wanted item": "Название желаемого предмета",
"Description of the item wanted": "Описание разыскиваемого предмета",
"Type of wanted item. eg. hat": "Тип разыскиваемого предмета. например. шапка",
"Category of wanted item. eg. clothes": "Категория разыскиваемого предмета. например. одежда",
"City or location of the wanted item": "Город или местонахождение разыскиваемого предмета",
"Maximum Price": "Максимальная цена",
"Create a new wanted item": "Создать новый требуемый предмет"
}

View File

@ -461,5 +461,15 @@
"Shares Catalog": "Inashiriki orodha",
"tool": "chombo",
"clothes": "nguo",
"medical": "matibabu"
"medical": "matibabu",
"Wanted": "Alitaka",
"Describe something wanted": "Eleza kitu kinachotaka",
"Enter the details for your wanted item below.": "Ingiza maelezo ya kitu unachotafuta hapa chini.",
"Name of the wanted item": "Jina la kitu kinachotafutwa",
"Description of the item wanted": "Maelezo ya bidhaa inayotakiwa",
"Type of wanted item. eg. hat": "Aina ya bidhaa inayotafutwa. km. kofia",
"Category of wanted item. eg. clothes": "Jamii ya bidhaa inayotafutwa. km. nguo",
"City or location of the wanted item": "Jiji au eneo la kitu kinachotafutwa",
"Maximum Price": "Bei ya juu",
"Create a new wanted item": "Unda kipengee kipya kinachotafutwa"
}

View File

@ -461,5 +461,15 @@
"Shares Catalog": "股票目录",
"tool": "工具",
"clothes": "衣服",
"medical": "医疗的"
"medical": "医疗的",
"Wanted": "通缉",
"Describe something wanted": "描述一些想要的东西",
"Enter the details for your wanted item below.": "在下方输入您想要的商品的详细信息。",
"Name of the wanted item": "通缉物品名称",
"Description of the item wanted": "所需物品的描述",
"Type of wanted item. eg. hat": "通缉物品的类型。 例如。 帽子",
"Category of wanted item. eg. clothes": "通缉物品类别。 例如。 衣服",
"City or location of the wanted item": "通缉物品的城市或位置",
"Maximum Price": "最高价格",
"Create a new wanted item": "创建一个新的通缉物品"
}

View File

@ -163,6 +163,13 @@ def _htmlNewPostDropDown(scopeIcon: str, scopeDescription: str,
'icons/scope_share.png"/><b>' + \
translate['Shares'] + '</b><br>' + \
translate['Describe a shared item'] + '</a></li>\n'
dropDownContent += \
'<li><a href="' + pathBase + \
'/newwanted" accesskey="' + accessKeys['menuWanted'] + '">' + \
'<img loading="lazy" alt="" title="" src="/' + \
'icons/scope_wanted.png"/><b>' + \
translate['Wanted'] + '</b><br>' + \
translate['Describe something wanted'] + '</a></li>\n'
dropDownContent += \
'<li><a href="' + pathBase + \
'/newquestion"><img loading="lazy" alt="" title="" src="/' + \
@ -198,7 +205,7 @@ def htmlNewPost(cssCache: {}, mediaInstance: bool, translate: {},
bannerFile, bannerFilename = \
getBannerFile(baseDir, nickname, domain, theme)
if not path.endswith('/newshare'):
if not path.endswith('/newshare') and not path.endswith('/newwanted'):
if not path.endswith('/newreport'):
if not inReplyTo or path.endswith('/newreminder'):
newPostText = '<h1>' + \
@ -251,10 +258,16 @@ def htmlNewPost(cssCache: {}, mediaInstance: bool, translate: {},
' <a href="/terms">' + \
translate['Terms of Service'] + '</a></p>\n'
else:
newPostText = \
'<h1>' + \
translate['Enter the details for your shared item below.'] + \
'</h1>\n'
if path.endswith('/newshare'):
newPostText = \
'<h1>' + \
translate['Enter the details for your shared item below.'] + \
'</h1>\n'
else:
newPostText = \
'<h1>' + \
translate['Enter the details for your wanted item below.'] + \
'</h1>\n'
if path.endswith('/newquestion'):
newPostText = \
@ -275,7 +288,7 @@ def htmlNewPost(cssCache: {}, mediaInstance: bool, translate: {},
path = path.split('?')[0]
pathBase = path.replace('/newreport', '').replace('/newpost', '')
pathBase = pathBase.replace('/newblog', '').replace('/newshare', '')
pathBase = pathBase.replace('/newunlisted', '')
pathBase = pathBase.replace('/newunlisted', '').replace('/newwanted', '')
pathBase = pathBase.replace('/newreminder', '')
pathBase = pathBase.replace('/newfollowers', '').replace('/newdm', '')
@ -414,6 +427,71 @@ def htmlNewPost(cssCache: {}, mediaInstance: bool, translate: {},
currName + '</option>\n'
extraFields += ' </select>\n'
extraFields += '</div>\n'
elif path.endswith('/newwanted'):
scopeIcon = 'scope_wanted.png'
scopeDescription = translate['Wanted']
placeholderSubject = translate['Name of the wanted item'] + '...'
placeholderMessage = \
translate['Description of the item wanted'] + '...'
endpoint = 'newwanted'
extraFields = '<div class="container">\n'
extraFields += \
editNumberField(translate['Quantity'],
'itemQty', 1, 1, 999999, 1)
extraFields += '<br>' + \
editTextField(translate['Type of wanted item. eg. hat'] + ':',
'itemType', '', '', True)
categoryTypes = getCategoryTypes(baseDir)
catStr = translate['Category of wanted item. eg. clothes']
extraFields += '<label class="labels">' + catStr + '</label><br>\n'
extraFields += ' <select id="themeDropdown" ' + \
'name="category" class="theme">\n'
for category in categoryTypes:
translatedCategory = "food"
if translate.get(category):
translatedCategory = translate[category]
extraFields += ' <option value="' + \
translatedCategory + '">' + \
translatedCategory + '</option>\n'
extraFields += ' </select><br>\n'
extraFields += \
editNumberField(translate['Duration of listing in days'],
'duration', 14, 1, 365, 1)
extraFields += '</div>\n'
extraFields += '<div class="container">\n'
cityOrLocStr = translate['City or location of the wanted item']
extraFields += editTextField(cityOrLocStr + ':', 'location', '')
extraFields += '</div>\n'
extraFields += '<div class="container">\n'
extraFields += \
editCurrencyField(translate['Maximum Price'] + ':',
'itemPrice', '0.00', '0.00', True)
extraFields += '<br>'
extraFields += \
'<label class="labels">' + translate['Currency'] + '</label><br>\n'
currencies = getCurrencies()
extraFields += ' <select id="themeDropdown" ' + \
'name="itemCurrency" class="theme">\n'
currencyList = []
for symbol, currName in currencies.items():
currencyList.append(currName + ' ' + symbol)
currencyList.sort()
defaultCurrency = getConfigParam(baseDir, 'defaultCurrency')
if not defaultCurrency:
defaultCurrency = "EUR"
for currName in currencyList:
if defaultCurrency not in currName:
extraFields += ' <option value="' + \
currName + '">' + currName + '</option>\n'
else:
extraFields += ' <option value="' + \
currName + '" selected="selected">' + \
currName + '</option>\n'
extraFields += ' </select>\n'
extraFields += '</div>\n'
citationsStr = ''
@ -444,6 +522,7 @@ def htmlNewPost(cssCache: {}, mediaInstance: bool, translate: {},
dateAndLocation = ''
if endpoint != 'newshare' and \
endpoint != 'newwanted' and \
endpoint != 'newreport' and \
endpoint != 'newquestion':
dateAndLocation = \

View File

@ -34,6 +34,7 @@ def headerButtonsTimeline(defaultTimeline: str,
minimal: bool,
sentButton: str,
sharesButtonStr: str,
wantedButtonStr: str,
bookmarksButtonStr: str,
eventsButtonStr: str,
moderationButtonStr: str,
@ -210,7 +211,8 @@ def headerButtonsTimeline(defaultTimeline: str,
# add other buttons
tlStr += \
sharesButtonStr + bookmarksButtonStr + eventsButtonStr + \
sharesButtonStr + wantedButtonStr + bookmarksButtonStr + \
eventsButtonStr + \
moderationButtonStr + happeningStr + newPostButtonStr
if not featuresHeader:

View File

@ -750,6 +750,8 @@ def htmlProfile(rssIconAtTop: bool,
htmlHideFromScreenReader('🛠') + ' ' + translate['Skills']
menuShares = \
htmlHideFromScreenReader('🤝') + ' ' + translate['Shares']
menuWanted = \
htmlHideFromScreenReader('') + ' ' + translate['Wanted']
menuLogout = \
htmlHideFromScreenReader('') + ' ' + translate['Logout']
navLinks = {
@ -760,6 +762,7 @@ def htmlProfile(rssIconAtTop: bool,
menuRoles: userPathStr + '/roles#timeline',
menuSkills: userPathStr + '/skills#timeline',
menuShares: userPathStr + '/shares#timeline',
menuWanted: userPathStr + '/wanted#timeline',
menuLogout: '/logout'
}
navAccessKeys = {}

View File

@ -145,6 +145,20 @@ def _htmlTimelineNewPost(manuallyApproveFollowers: bool,
'<a href="' + usersPath + '/newshare?nodropdown">' + \
'<button class="button"><span>' + \
translate['Post'] + '</span></button></a>'
elif boxName == 'tlwanted':
if not iconsAsButtons:
newPostButtonStr += \
'<a class="imageAnchor" href="' + usersPath + \
'/newwanted?nodropdown"><img loading="lazy" src="/' + \
'icons/newpost.png" title="' + \
translate['Create a new wanted item'] + '" alt="| ' + \
translate['Create a new wanted item'] + \
'" class="timelineicon"/></a>\n'
else:
newPostButtonStr += \
'<a href="' + usersPath + '/newwanted?nodropdown">' + \
'<button class="button"><span>' + \
translate['Post'] + '</span></button></a>'
else:
if not manuallyApproveFollowers:
if not iconsAsButtons:
@ -260,7 +274,8 @@ def _htmlTimelineModerationButtons(moderator: bool, boxName: str,
def _htmlTimelineKeyboard(moderator: bool, textModeBanner: str, usersPath: str,
nickname: str, newCalendarEvent: bool,
newDM: bool, newReply: bool, newShare: bool,
newDM: bool, newReply: bool,
newShare: bool, newWanted: bool,
followApprovals: bool,
accessKeys: {}, translate: {}) -> str:
"""Returns html for timeline keyboard navigation
@ -277,6 +292,9 @@ def _htmlTimelineKeyboard(moderator: bool, textModeBanner: str, usersPath: str,
sharesStr = translate['Shares']
if newShare:
sharesStr = '<strong>' + sharesStr + '</strong>'
wantedStr = translate['Wanted']
if newWanted:
wantedStr = '<strong>' + wantedStr + '</strong>'
menuProfile = \
htmlHideFromScreenReader('👤') + ' ' + \
translate['Switch to profile view']
@ -297,6 +315,8 @@ def _htmlTimelineKeyboard(moderator: bool, textModeBanner: str, usersPath: str,
htmlHideFromScreenReader('🔖') + ' ' + translate['Bookmarks']
menuShares = \
htmlHideFromScreenReader('🤝') + ' ' + sharesStr
menuWanted = \
htmlHideFromScreenReader('') + ' ' + wantedStr
menuBlogs = \
htmlHideFromScreenReader('📝') + ' ' + translate['Blogs']
menuNewswire = \
@ -318,6 +338,7 @@ def _htmlTimelineKeyboard(moderator: bool, textModeBanner: str, usersPath: str,
menuOutbox: usersPath + '/outbox#timelineposts',
menuBookmarks: usersPath + '/tlbookmarks#timelineposts',
menuShares: usersPath + '/tlshares#timelineposts',
menuWanted: usersPath + '/tlwanted#timelineposts',
menuBlogs: usersPath + '/tlblogs#timelineposts',
menuNewswire: usersPath + '/newswiremobile',
menuLinks: usersPath + '/linksmobile'
@ -446,6 +467,14 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
if boxName == 'tlshares':
os.remove(newShareFile)
# should the Wanted button be highlighted?
newWanted = False
newWantedFile = accountDir + '/.newWanted'
if os.path.isfile(newWantedFile):
newWanted = True
if boxName == 'tlwanted':
os.remove(newWantedFile)
# should the Moderation/reports button be highlighted?
newReport = False
newReportFile = accountDir + '/.newReport'
@ -497,6 +526,9 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
sharesButton = 'button'
if newShare:
sharesButton = 'buttonhighlighted'
wantedButton = 'button'
if newWanted:
wantedButton = 'buttonhighlighted'
moderationButton = 'button'
if newReport:
moderationButton = 'buttonhighlighted'
@ -528,6 +560,10 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
sharesButton = 'buttonselected'
if newShare:
sharesButton = 'buttonselectedhighlighted'
elif boxName == 'tlwanted':
wantedButton = 'buttonselected'
if newWanted:
wantedButton = 'buttonselectedhighlighted'
elif boxName == 'tlbookmarks' or boxName == 'bookmarks':
bookmarksButton = 'buttonselected'
@ -582,6 +618,12 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
htmlHighlightLabel(translate['Shares'], newShare) + \
'</span></button></a>'
wantedButtonStr = \
'<a href="' + usersPath + '/tlwanted"><button class="' + \
wantedButton + '"><span>' + \
htmlHighlightLabel(translate['Wanted'], newWanted) + \
'</span></button></a>'
bookmarksButtonStr = \
'<a href="' + usersPath + '/tlbookmarks"><button class="' + \
bookmarksButton + '"><span>' + translate['Bookmarks'] + \
@ -612,7 +654,8 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
# keyboard navigation
tlStr += \
_htmlTimelineKeyboard(moderator, textModeBanner, usersPath, nickname,
newCalendarEvent, newDM, newReply, newShare,
newCalendarEvent, newDM, newReply,
newShare, newWanted,
followApprovals, accessKeys, translate)
# banner and row of buttons
@ -634,7 +677,8 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
newsButton, inboxButton,
dmButton, newDM, repliesButton,
newReply, minimal, sentButton,
sharesButtonStr, bookmarksButtonStr,
sharesButtonStr, wantedButtonStr,
bookmarksButtonStr,
eventsButtonStr, moderationButtonStr,
newPostButtonStr, baseDir, nickname,
domain, timelineStartTime,
@ -676,7 +720,8 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
newsButton, inboxButton,
dmButton, newDM, repliesButton,
newReply, minimal, sentButton,
sharesButtonStr, bookmarksButtonStr,
sharesButtonStr, wantedButtonStr,
bookmarksButtonStr,
eventsButtonStr, moderationButtonStr,
newPostButtonStr, baseDir, nickname,
domain, timelineStartTime,
@ -711,6 +756,24 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
boxName,
enableTimingLog, timelineStartTime) +
htmlFooter())
elif boxName == 'tlwanted':
maxSharesPerAccount = itemsPerPage
return (tlStr +
_htmlSharesTimeline(translate, pageNumber, itemsPerPage,
baseDir, actor, nickname, domain, port,
maxSharesPerAccount, httpPrefix,
sharedItemsFederatedDomains, 'wanted') +
_htmlTimelineEnd(baseDir, nickname, domainFull,
httpPrefix, translate,
moderator, editor,
newswire, positiveVoting,
showPublishAsIcon,
rssIconAtTop, publishButtonAtTop,
authorized, theme,
defaultTimeline, accessKeys,
boxName,
enableTimingLog, timelineStartTime) +
htmlFooter())
_logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '7')
@ -1032,6 +1095,54 @@ def htmlShares(cssCache: {}, defaultTimeline: str,
sharedItemsFederatedDomains)
def htmlWanted(cssCache: {}, defaultTimeline: str,
recentPostsCache: {}, maxRecentPosts: int,
translate: {}, pageNumber: int, itemsPerPage: int,
session, baseDir: str,
cachedWebfingers: {}, personCache: {},
nickname: str, domain: str, port: int,
allowDeletion: bool,
httpPrefix: str, projectVersion: str,
YTReplacementDomain: str,
showPublishedDateOnly: bool,
newswire: {}, positiveVoting: bool,
showPublishAsIcon: bool,
fullWidthTimelineButtonHeader: bool,
iconsAsButtons: bool,
rssIconAtTop: bool,
publishButtonAtTop: bool,
authorized: bool, theme: str,
peertubeInstances: [],
allowLocalNetworkAccess: bool,
textModeBanner: str,
accessKeys: {}, systemLanguage: str,
maxLikeCount: int,
sharedItemsFederatedDomains: []) -> str:
"""Show the wanted timeline as html
"""
manuallyApproveFollowers = \
followerApprovalActive(baseDir, nickname, domain)
return htmlTimeline(cssCache, defaultTimeline,
recentPostsCache, maxRecentPosts,
translate, pageNumber,
itemsPerPage, session, baseDir,
cachedWebfingers, personCache,
nickname, domain, port, None,
'tlwanted', allowDeletion,
httpPrefix, projectVersion, manuallyApproveFollowers,
False, YTReplacementDomain,
showPublishedDateOnly,
newswire, False, False,
positiveVoting, showPublishAsIcon,
fullWidthTimelineButtonHeader,
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
authorized, None, theme, peertubeInstances,
allowLocalNetworkAccess, textModeBanner,
accessKeys, systemLanguage, maxLikeCount,
sharedItemsFederatedDomains)
def htmlInbox(cssCache: {}, defaultTimeline: str,
recentPostsCache: {}, maxRecentPosts: int,
translate: {}, pageNumber: int, itemsPerPage: int,