Wanted items timeline
267
daemon.py
|
@ -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',
|
||||
|
|
|
@ -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"
|
||||
|
|
18
shares.py
|
@ -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:
|
||||
|
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.5 KiB |
After Width: | Height: | Size: 8.1 KiB |
After Width: | Height: | Size: 8.1 KiB |
After Width: | Height: | Size: 8.1 KiB |
After Width: | Height: | Size: 6.0 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.8 KiB |
After Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.8 KiB |
After Width: | Height: | Size: 6.4 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.7 KiB |
After Width: | Height: | Size: 6.6 KiB |
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.7 KiB |
After Width: | Height: | Size: 6.8 KiB |
After Width: | Height: | Size: 6.6 KiB |
After Width: | Height: | Size: 6.8 KiB |
After Width: | Height: | Size: 6.9 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.8 KiB |
After Width: | Height: | Size: 6.6 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 5.8 KiB |
After Width: | Height: | Size: 6.8 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 6.6 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 5.7 KiB |
After Width: | Height: | Size: 6.8 KiB |
|
@ -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": "قم بإنشاء عنصر مطلوب جديد"
|
||||
}
|
||||
|
|
|
@ -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 l’article desitjat",
|
||||
"Maximum Price": "Preu màxim",
|
||||
"Create a new wanted item": "Creeu un element desitjat"
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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é"
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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": "एक नई वांछित वस्तु बनाएँ"
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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": "新しい欲しいアイテムを作成する"
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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": "Создать новый требуемый предмет"
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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": "创建一个新的通缉物品"
|
||||
}
|
||||
|
|
|
@ -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 = \
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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 = {}
|
||||
|
|
|
@ -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,
|
||||
|
|