diff --git a/daemon.py b/daemon.py
index e9811f752..128414500 100644
--- a/daemon.py
+++ b/daemon.py
@@ -10202,6 +10202,7 @@ class PubServer(BaseHTTPRequestHandler):
path.endswith('/followers') or \
path.endswith('/skills') or \
path.endswith('/roles') or \
+ path.endswith('/wanted') or \
path.endswith('/shares'):
divertToLoginScreen = False
@@ -14577,6 +14578,7 @@ class PubServer(BaseHTTPRequestHandler):
self.path = self.path.replace('/tlblogs/', '/tlblogs')
self.path = self.path.replace('/inbox/', '/inbox')
self.path = self.path.replace('/shares/', '/shares')
+ self.path = self.path.replace('/wanted/', '/wanted')
self.path = self.path.replace('/sharedInbox/', '/sharedInbox')
if self.path == '/inbox':
@@ -15021,7 +15023,9 @@ class PubServer(BaseHTTPRequestHandler):
self._benchmarkPOSTtimings(POSTstartTime, POSTtimings, 15)
- if self.path.endswith('/outbox') or self.path.endswith('/shares'):
+ if self.path.endswith('/outbox') or \
+ self.path.endswith('/wanted') or \
+ self.path.endswith('/shares'):
if usersInPath:
if authorized:
self.outboxAuthenticated = True
@@ -15038,6 +15042,7 @@ class PubServer(BaseHTTPRequestHandler):
# check that the post is to an expected path
if not (self.path.endswith('/outbox') or
self.path.endswith('/inbox') or
+ self.path.endswith('/wanted') or
self.path.endswith('/shares') or
self.path.endswith('/moderationaction') or
self.path == '/sharedInbox'):
diff --git a/shares.py b/shares.py
index ed0b9ff44..af9a88b38 100644
--- a/shares.py
+++ b/shares.py
@@ -737,6 +737,220 @@ def sendUndoShareViaServer(baseDir: str, session,
return undoShareJson
+def sendWantedViaServer(baseDir, session,
+ fromNickname: str, password: str,
+ fromDomain: str, fromPort: int,
+ httpPrefix: str, displayName: str,
+ summary: str, imageFilename: str,
+ itemQty: float, itemType: str, itemCategory: str,
+ location: str, duration: str,
+ cachedWebfingers: {}, personCache: {},
+ debug: bool, projectVersion: str,
+ itemMaxPrice: str, itemCurrency: str) -> {}:
+ """Creates a wanted item via c2s
+ """
+ if not session:
+ print('WARN: No session for sendWantedViaServer')
+ return 6
+
+ # convert $4.23 to 4.23 USD
+ newItemMaxPrice, newItemCurrency = getPriceFromString(itemMaxPrice)
+ if newItemMaxPrice != itemMaxPrice:
+ itemMaxPrice = newItemMaxPrice
+ if not itemCurrency:
+ if newItemCurrency != itemCurrency:
+ itemCurrency = newItemCurrency
+
+ fromDomainFull = getFullDomain(fromDomain, fromPort)
+
+ toUrl = 'https://www.w3.org/ns/activitystreams#Public'
+ ccUrl = httpPrefix + '://' + fromDomainFull + \
+ '/users/' + fromNickname + '/followers'
+
+ actor = httpPrefix + '://' + fromDomainFull + '/users/' + fromNickname
+ newShareJson = {
+ "@context": "https://www.w3.org/ns/activitystreams",
+ 'type': 'Add',
+ 'actor': actor,
+ 'target': actor + '/wanted',
+ 'object': {
+ "type": "Offer",
+ "displayName": displayName,
+ "summary": summary,
+ "itemQty": float(itemQty),
+ "itemType": itemType,
+ "category": itemCategory,
+ "location": location,
+ "duration": duration,
+ "itemPrice": itemMaxPrice,
+ "itemCurrency": itemCurrency,
+ 'to': [toUrl],
+ 'cc': [ccUrl]
+ },
+ 'to': [toUrl],
+ 'cc': [ccUrl]
+ }
+
+ handle = httpPrefix + '://' + fromDomainFull + '/@' + fromNickname
+
+ # lookup the inbox for the To handle
+ wfRequest = \
+ webfingerHandle(session, handle, httpPrefix,
+ cachedWebfingers,
+ fromDomain, projectVersion, debug, False)
+ if not wfRequest:
+ if debug:
+ print('DEBUG: share webfinger failed for ' + handle)
+ return 1
+ if not isinstance(wfRequest, dict):
+ print('WARN: wanted webfinger for ' + handle +
+ ' did not return a dict. ' + str(wfRequest))
+ return 1
+
+ postToBox = 'outbox'
+
+ # get the actor inbox for the To handle
+ (inboxUrl, pubKeyId, pubKey,
+ fromPersonId, sharedInbox,
+ avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
+ personCache, projectVersion,
+ httpPrefix, fromNickname,
+ fromDomain, postToBox,
+ 83653)
+
+ if not inboxUrl:
+ if debug:
+ print('DEBUG: wanted no ' + postToBox +
+ ' was found for ' + handle)
+ return 3
+ if not fromPersonId:
+ if debug:
+ print('DEBUG: wanted no actor was found for ' + handle)
+ return 4
+
+ authHeader = createBasicAuthHeader(fromNickname, password)
+
+ if imageFilename:
+ headers = {
+ 'host': fromDomain,
+ 'Authorization': authHeader
+ }
+ postResult = \
+ postImage(session, imageFilename, [],
+ inboxUrl.replace('/' + postToBox, '/wanted'),
+ headers)
+
+ headers = {
+ 'host': fromDomain,
+ 'Content-type': 'application/json',
+ 'Authorization': authHeader
+ }
+ postResult = \
+ postJson(httpPrefix, fromDomainFull,
+ session, newShareJson, [], inboxUrl, headers, 30, True)
+ if not postResult:
+ if debug:
+ print('DEBUG: POST wanted failed for c2s to ' + inboxUrl)
+# return 5
+
+ if debug:
+ print('DEBUG: c2s POST wanted item success')
+
+ return newShareJson
+
+
+def sendUndoWantedViaServer(baseDir: str, session,
+ fromNickname: str, password: str,
+ fromDomain: str, fromPort: int,
+ httpPrefix: str, displayName: str,
+ cachedWebfingers: {}, personCache: {},
+ debug: bool, projectVersion: str) -> {}:
+ """Undoes a wanted item via c2s
+ """
+ if not session:
+ print('WARN: No session for sendUndoWantedViaServer')
+ return 6
+
+ fromDomainFull = getFullDomain(fromDomain, fromPort)
+
+ toUrl = 'https://www.w3.org/ns/activitystreams#Public'
+ ccUrl = httpPrefix + '://' + fromDomainFull + \
+ '/users/' + fromNickname + '/followers'
+
+ actor = httpPrefix + '://' + fromDomainFull + '/users/' + fromNickname
+ undoShareJson = {
+ "@context": "https://www.w3.org/ns/activitystreams",
+ 'type': 'Remove',
+ 'actor': actor,
+ 'target': actor + '/wanted',
+ 'object': {
+ "type": "Offer",
+ "displayName": displayName,
+ 'to': [toUrl],
+ 'cc': [ccUrl]
+ },
+ 'to': [toUrl],
+ 'cc': [ccUrl]
+ }
+
+ handle = httpPrefix + '://' + fromDomainFull + '/@' + fromNickname
+
+ # lookup the inbox for the To handle
+ wfRequest = \
+ webfingerHandle(session, handle, httpPrefix, cachedWebfingers,
+ fromDomain, projectVersion, debug, False)
+ if not wfRequest:
+ if debug:
+ print('DEBUG: unwant webfinger failed for ' + handle)
+ return 1
+ if not isinstance(wfRequest, dict):
+ print('WARN: unwant webfinger for ' + handle +
+ ' did not return a dict. ' + str(wfRequest))
+ return 1
+
+ postToBox = 'outbox'
+
+ # get the actor inbox for the To handle
+ (inboxUrl, pubKeyId, pubKey,
+ fromPersonId, sharedInbox,
+ avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
+ personCache, projectVersion,
+ httpPrefix, fromNickname,
+ fromDomain, postToBox,
+ 12663)
+
+ if not inboxUrl:
+ if debug:
+ print('DEBUG: unwant no ' + postToBox +
+ ' was found for ' + handle)
+ return 3
+ if not fromPersonId:
+ if debug:
+ print('DEBUG: unwant no actor was found for ' + handle)
+ return 4
+
+ authHeader = createBasicAuthHeader(fromNickname, password)
+
+ headers = {
+ 'host': fromDomain,
+ 'Content-type': 'application/json',
+ 'Authorization': authHeader
+ }
+ postResult = \
+ postJson(httpPrefix, fromDomainFull,
+ session, undoShareJson, [], inboxUrl,
+ headers, 30, True)
+ if not postResult:
+ if debug:
+ print('DEBUG: POST unwant failed for c2s to ' + inboxUrl)
+# return 5
+
+ if debug:
+ print('DEBUG: c2s POST unwant success')
+
+ return undoShareJson
+
+
def getSharedItemsCatalogViaServer(baseDir, session,
nickname: str, password: str,
domain: str, port: int,
diff --git a/webapp_column_left.py b/webapp_column_left.py
index 20b763824..5d67fff7a 100644
--- a/webapp_column_left.py
+++ b/webapp_column_left.py
@@ -404,7 +404,7 @@ def htmlEditLinks(cssCache: {}, translate: {}, baseDir: str, path: str,
if '/users/' not in path:
return ''
path = path.replace('/inbox', '').replace('/outbox', '')
- path = path.replace('/shares', '')
+ path = path.replace('/shares', '').replace('/wanted', '')
nickname = getNicknameFromActor(path)
if not nickname:
diff --git a/webapp_column_right.py b/webapp_column_right.py
index 60ea44614..b296027ee 100644
--- a/webapp_column_right.py
+++ b/webapp_column_right.py
@@ -525,7 +525,7 @@ def htmlEditNewswire(cssCache: {}, translate: {}, baseDir: str, path: str,
if '/users/' not in path:
return ''
path = path.replace('/inbox', '').replace('/outbox', '')
- path = path.replace('/shares', '')
+ path = path.replace('/shares', '').replace('/wanted', '')
nickname = getNicknameFromActor(path)
if not nickname:
diff --git a/webapp_profile.py b/webapp_profile.py
index f68156ecc..be7a68158 100644
--- a/webapp_profile.py
+++ b/webapp_profile.py
@@ -521,6 +521,7 @@ def htmlProfile(rssIconAtTop: bool,
rolesButton = 'button'
skillsButton = 'button'
sharesButton = 'button'
+ wantedButton = 'button'
if selected == 'posts':
postsButton = 'buttonselected'
elif selected == 'following':
@@ -533,6 +534,8 @@ def htmlProfile(rssIconAtTop: bool,
skillsButton = 'buttonselected'
elif selected == 'shares':
sharesButton = 'buttonselected'
+ elif selected == 'wanted':
+ wantedButton = 'buttonselected'
loginButton = ''
followApprovalsSection = ''
@@ -802,6 +805,10 @@ def htmlProfile(rssIconAtTop: bool,
' ' + \
''
+ profileStr += \
+ ' ' + \
+ ''
profileStr += logoutStr + editProfileStr
profileStr += ' '
profileStr += ''
@@ -1820,7 +1827,7 @@ def htmlEditProfile(cssCache: {}, translate: {}, baseDir: str, path: str,
"""Shows the edit profile screen
"""
path = path.replace('/inbox', '').replace('/outbox', '')
- path = path.replace('/shares', '')
+ path = path.replace('/shares', '').replace('/wanted', '')
nickname = getNicknameFromActor(path)
if not nickname:
return ''