Functions for shares catalog endpoints

merge-requests/30/head
Bob Mottram 2021-07-24 23:08:11 +01:00
parent 723e6e7a5e
commit 5d5dab6d2f
25 changed files with 262 additions and 46 deletions

View File

@ -13631,6 +13631,10 @@ class PubServer(BaseHTTPRequestHandler):
return -1
if not fields.get('itemType'):
return -1
if not fields.get('itemPrice'):
return -1
if not fields.get('itemCurrency'):
return -1
if not fields.get('category'):
return -1
if not fields.get('location'):
@ -13652,6 +13656,13 @@ class PubServer(BaseHTTPRequestHandler):
if fields['itemQty']:
if fields['itemQty'].isdigit():
itemQty = int(fields['itemQty'])
itemPrice = "0"
if fields['itemPrice']:
if fields['itemPrice'].isdigit():
itemPrice = fields['itemPrice']
itemCurrency = "EUR"
if fields['itemCurrency']:
itemCurrency = fields['itemCurrency']
addShare(self.server.baseDir,
self.server.httpPrefix,
nickname,
@ -13664,7 +13675,7 @@ class PubServer(BaseHTTPRequestHandler):
fields['location'],
durationStr,
self.server.debug,
city,
city, itemPrice, itemCurrency,
self.server.systemLanguage,
self.server.translate)
if filename:

View File

@ -561,6 +561,12 @@ parser.add_argument('--itemImage', dest='itemImage', type=str,
parser.add_argument('--itemQty', dest='itemQty', type=int,
default=1,
help='Quantity of items being shared')
parser.add_argument('--itemPrice', dest='itemPrice', type=str,
default="0",
help='Total price of items being shared')
parser.add_argument('--itemCurrency', dest='itemCurrency', type=str,
default="EUR",
help='Currency of items being shared')
parser.add_argument('--itemType', dest='itemType', type=str,
default=None,
help='Type of item being shared')
@ -1290,7 +1296,8 @@ if args.itemName:
args.location,
args.duration,
cachedWebfingers, personCache,
debug, __version__)
debug, __version__,
args.itemPrice, args.itemCurrency)
for i in range(10):
# TODO detect send success/fail
time.sleep(1)
@ -2330,7 +2337,7 @@ if args.testdata:
"img/shares1.png",
1, "tool",
"mechanical",
"City",
"City", "0", "GBP",
"2 months",
debug, city, args.language, {})
addShare(baseDir,
@ -2340,7 +2347,7 @@ if args.testdata:
"img/shares2.png",
1, "hat",
"clothing",
"City",
"City", "0", "GBP",
"3 months",
debug, city, args.language, {})

165
shares.py
View File

@ -9,6 +9,7 @@ __module_group__ = "Timeline"
import os
import time
import datetime
from webfinger import webfingerHandle
from auth import createBasicAuthHeader
from posts import getPersonBox
@ -180,6 +181,7 @@ def addShare(baseDir: str,
displayName: str, summary: str, imageFilename: str,
itemQty: int, itemType: str, itemCategory: str, location: str,
duration: str, debug: bool, city: str,
price: str, currency: str,
systemLanguage: str, translate: {}) -> None:
"""Adds a new share
"""
@ -241,7 +243,9 @@ def addShare(baseDir: str,
"category": itemCategory,
"location": location,
"published": published,
"expire": durationSec
"expire": durationSec,
"price": "0",
"currency": ""
}
saveJson(sharesJson, sharesFilename)
@ -283,25 +287,27 @@ def _expireSharesForAccount(baseDir: str, nickname: str, domain: str) -> None:
handleDomain = removeDomainPort(domain)
handle = nickname + '@' + handleDomain
sharesFilename = baseDir + '/accounts/' + handle + '/shares.json'
if os.path.isfile(sharesFilename):
sharesJson = loadJson(sharesFilename)
if sharesJson:
currTime = int(time.time())
deleteItemID = []
for itemID, item in sharesJson.items():
if currTime > item['expire']:
deleteItemID.append(itemID)
if deleteItemID:
for itemID in deleteItemID:
del sharesJson[itemID]
# remove any associated images
itemIDfile = \
baseDir + '/sharefiles/' + nickname + '/' + itemID
formats = getImageExtensions()
for ext in formats:
if os.path.isfile(itemIDfile + '.' + ext):
os.remove(itemIDfile + '.' + ext)
saveJson(sharesJson, sharesFilename)
if not os.path.isfile(sharesFilename):
return
sharesJson = loadJson(sharesFilename)
if not sharesJson:
return
currTime = int(time.time())
deleteItemID = []
for itemID, item in sharesJson.items():
if currTime > item['expire']:
deleteItemID.append(itemID)
if not deleteItemID:
return
for itemID in deleteItemID:
del sharesJson[itemID]
# remove any associated images
itemIDfile = baseDir + '/sharefiles/' + nickname + '/' + itemID
formats = getImageExtensions()
for ext in formats:
if os.path.isfile(itemIDfile + '.' + ext):
os.remove(itemIDfile + '.' + ext)
saveJson(sharesJson, sharesFilename)
def getSharesFeedForPerson(baseDir: str,
@ -410,7 +416,8 @@ def sendShareViaServer(baseDir, session,
itemQty: int, itemType: str, itemCategory: str,
location: str, duration: str,
cachedWebfingers: {}, personCache: {},
debug: bool, projectVersion: str) -> {}:
debug: bool, projectVersion: str,
itemPrice: str, itemCurrency: str) -> {}:
"""Creates an item share via c2s
"""
if not session:
@ -438,6 +445,8 @@ def sendShareViaServer(baseDir, session,
"category": itemCategory,
"location": location,
"duration": duration,
"itemPrice": itemPrice,
"itemCurrency": itemCurrency,
'to': [toUrl],
'cc': [ccUrl]
},
@ -663,7 +672,10 @@ def outboxShareUpload(baseDir: str, httpPrefix: str,
messageJson['object']['itemCategory'],
messageJson['object']['location'],
messageJson['object']['duration'],
debug, city, systemLanguage, translate)
debug, city,
messageJson['object']['itemPrice'],
messageJson['object']['itemCurrency'],
systemLanguage, translate)
if debug:
print('DEBUG: shared item received via c2s')
@ -695,3 +707,112 @@ def outboxUndoShareUpload(baseDir: str, httpPrefix: str,
messageJson['object']['displayName'])
if debug:
print('DEBUG: shared item removed via c2s')
def sharesCatalogAccountEndpoint(baseDir: str, httpPrefix: str,
nickname: str, domain: str,
domainFull: str,
path: str) -> {}:
"""Returns the endpoint for the shares catalog of a particular account
"""
dfcUrl = \
"http://static.datafoodconsortium.org/ontologies/DFC_FullModel.owl#"
owner = httpPrefix + '://' + domainFull + '/users/' + nickname
dfcInstanceId = owner + '/catalog'
endpoint = {
"@context": {
"DFC": dfcUrl,
"@base": "http://maPlateformeNationale"
},
"@id": dfcInstanceId,
"@type": "DFC:Entreprise",
"DFC:supplies": []
}
sharesFilename = acctDir(baseDir, nickname, domain) + '/shares.json'
if not os.path.isfile(sharesFilename):
return endpoint
sharesJson = loadJson(sharesFilename)
if not sharesJson:
return endpoint
for itemID, item in sharesJson.items():
if not item.get('dfcId'):
continue
expireDate = datetime.datetime.fromtimestamp(item['durationSec'])
expireDateStr = expireDate.strftime("%Y-%m-%dT%H:%M:%SZ")
catalogItem = {
"@id": item['dfcId'],
"DFC:offeredThrough": owner,
"DFC:startDate": item['published'],
"DFC:expiryDate": expireDateStr,
"DFC:quantity": item['itemQty'],
"DFC:totalTheoriticalStock": item['itemQty'],
"DFC:price": "0",
"DFC:Image": item['imageUrl'],
"DFC:description": item['displayName'] + ': ' + item['summary']
}
endpoint['DFC:supplies'].append(catalogItem)
return endpoint
def sharesCatalogEndpoint(baseDir: str, httpPrefix: str,
domainFull: str,
path: str) -> {}:
"""Returns the endpoint for the shares catalog for the instance
"""
dfcUrl = \
"http://static.datafoodconsortium.org/ontologies/DFC_FullModel.owl#"
dfcInstanceId = httpPrefix + '://' + domainFull + '/catalog'
endpoint = {
"@context": {
"DFC": dfcUrl,
"@base": "http://maPlateformeNationale"
},
"@id": dfcInstanceId,
"@type": "DFC:Entreprise",
"DFC:supplies": []
}
for subdir, dirs, files in os.walk(baseDir + '/accounts'):
for acct in dirs:
if not isAccountDir(acct):
continue
nickname = acct.split('@')[0]
domain = acct.split('@')[1]
owner = httpPrefix + '://' + domainFull + '/users/' + nickname
sharesFilename = \
acctDir(baseDir, nickname, domain) + '/shares.json'
if not os.path.isfile(sharesFilename):
continue
sharesJson = loadJson(sharesFilename)
if not sharesJson:
continue
for itemID, item in sharesJson.items():
if not item.get('dfcId'):
continue
expireDate = \
datetime.datetime.fromtimestamp(item['durationSec'])
expireDateStr = expireDate.strftime("%Y-%m-%dT%H:%M:%SZ")
description = item['displayName'] + ': ' + item['summary']
catalogItem = {
"@id": item['dfcId'],
"DFC:offeredThrough": owner,
"DFC:startDate": item['published'],
"DFC:expiryDate": expireDateStr,
"DFC:quantity": item['itemQty'],
"DFC:totalTheoriticalStock": item['itemQty'],
"DFC:price": "0",
"DFC:Image": item['imageUrl'],
"DFC:description": description
}
endpoint['DFC:supplies'].append(catalogItem)
return endpoint

View File

@ -3272,7 +3272,9 @@ def _testFunctions():
'E2EEremoveDevice',
'setOrganizationScheme',
'fill_headers',
'_nothing'
'_nothing',
'sharesCatalogEndpoint',
'sharesCatalogAccountEndpoint'
]
excludeImports = [
'link',

View File

@ -454,5 +454,7 @@
"Languages": "اللغات",
"Translated": "تترجم",
"Quantity": "كمية",
"food": "غذاء"
"food": "غذاء",
"Price": "السعر",
"Currency": "عملة"
}

View File

@ -454,5 +454,7 @@
"Languages": "Idiomes",
"Translated": "Traduït",
"Quantity": "Quantitat",
"food": "menjar"
"food": "menjar",
"Price": "Preu",
"Currency": "Moneda"
}

View File

@ -454,5 +454,7 @@
"Languages": "Ieithoedd",
"Translated": "Chyfieithwyd",
"Quantity": "Symiau",
"food": "bwyd"
"food": "bwyd",
"Price": "Prisia",
"Currency": "Harian"
}

View File

@ -454,5 +454,7 @@
"Languages": "Sprachen",
"Translated": "Übersetzt",
"Quantity": "Menge",
"food": "lebensmittel"
"food": "lebensmittel",
"Price": "Preis",
"Currency": "Währung"
}

View File

@ -454,5 +454,7 @@
"Languages": "Languages",
"Translated": "Translated",
"Quantity": "Quantity",
"food": "food"
"food": "food",
"Price": "Price",
"Currency": "Currency"
}

View File

@ -454,5 +454,7 @@
"Languages": "Idiomas",
"Translated": "Traducida",
"Quantity": "Cantidad",
"food": "comida"
"food": "comida",
"Price": "Precio",
"Currency": "Divisa"
}

View File

@ -454,5 +454,7 @@
"Languages": "Langues",
"Translated": "Traduite",
"Quantity": "Quantité",
"food": "aliments"
"food": "aliments",
"Price": "Prix",
"Currency": "Devise"
}

View File

@ -454,5 +454,7 @@
"Languages": "Teangacha",
"Translated": "Aistrithe",
"Quantity": "Cainníocht",
"food": "bia"
"food": "bia",
"Price": "Praghas a chur ar",
"Currency": "Airgeadra"
}

View File

@ -454,5 +454,7 @@
"Languages": "बोली",
"Translated": "अनुवाद",
"Quantity": "मात्रा",
"food": "खाना"
"food": "खाना",
"Price": "कीमत",
"Currency": "मुद्रा"
}

View File

@ -454,5 +454,7 @@
"Languages": "Le lingue",
"Translated": "Tradotto",
"Quantity": "Quantità",
"food": "cibo"
"food": "cibo",
"Price": "Prezzo",
"Currency": "Moneta"
}

View File

@ -454,5 +454,7 @@
"Languages": "言語",
"Translated": "翻訳",
"Quantity": "量",
"food": "食物"
"food": "食物",
"Price": "価格",
"Currency": "通貨"
}

View File

@ -454,5 +454,7 @@
"Languages": "Ziman",
"Translated": "Wergerandin",
"Quantity": "Jimarî",
"food": "xûrek"
"food": "xûrek",
"Price": "Biha",
"Currency": "Diravcins"
}

View File

@ -450,5 +450,7 @@
"Languages": "Languages",
"Translated": "Translated",
"Quantity": "Quantity",
"food": "food"
"food": "food",
"Price": "Price",
"Currency": "Currency"
}

View File

@ -454,5 +454,7 @@
"Languages": "Línguas",
"Translated": "Traduzida",
"Quantity": "Quantidade",
"food": "comida"
"food": "comida",
"Price": "Preço",
"Currency": "Moeda"
}

View File

@ -454,5 +454,7 @@
"Languages": "Языки",
"Translated": "Перевод",
"Quantity": "Количество",
"food": "еда"
"food": "еда",
"Price": "Цена",
"Currency": "Валюта"
}

View File

@ -454,5 +454,7 @@
"Languages": "Lugha",
"Translated": "Ilitafsiriwa",
"Quantity": "Wingi",
"food": "chakula"
"food": "chakula",
"Price": "Bei",
"Currency": "Fedha"
}

View File

@ -454,5 +454,7 @@
"Languages": "语言",
"Translated": "翻译",
"Quantity": "数量",
"food": "食物"
"food": "食物",
"Price": "价钱",
"Currency": "货币"
}

View File

@ -19,6 +19,7 @@ from webapp_utils import htmlHeaderWithExternalStyle
from webapp_utils import htmlFooter
from webapp_utils import editTextField
from webapp_utils import editNumberField
from webapp_utils import editCurrencyField
def _htmlFollowingDataList(baseDir: str, nickname: str,
@ -371,6 +372,13 @@ def htmlNewPost(cssCache: {}, mediaInstance: bool, translate: {},
cityOrLocStr = translate['City or location of the shared item']
extraFields += editTextField(cityOrLocStr + ':', 'location', '')
extraFields += '</div>\n'
extraFields += '<div class="container">\n'
extraFields += \
editCurrencyField(translate['Price'] + ':', 'itemPrice', '0.00')
extraFields += '<br>' + \
editTextField(translate['Currency'] + ':',
'itemCurrency', 'EUR')
extraFields += '</div>\n'
citationsStr = ''
if endpoint == 'newblog':

View File

@ -188,7 +188,16 @@ def htmlSearchSharedItems(cssCache: {}, translate: {},
':</b> ' + sharedItem['category'] + ' '
sharedItemsForm += \
'<b>' + translate['Location'] + \
':</b> ' + sharedItem['location'] + '</p>\n'
':</b> ' + sharedItem['location']
if sharedItem.get('itemPrice') and \
sharedItem.get('itemCurrency'):
if sharedItem['itemPrice'].isdigit():
if float(sharedItem['itemPrice']) > 0:
sharedItemsForm += \
' <b>' + translate['Price'] + \
':</b> ' + sharedItem['itemPrice'] + \
' ' + sharedItem['itemCurrency']
sharedItemsForm += '</p>\n'
contactActor = \
httpPrefix + '://' + domainFull + \
'/users/' + contactNickname

View File

@ -830,7 +830,14 @@ def htmlIndividualShare(actor: str, item: {}, translate: {},
profileStr += \
'<b>' + translate['Category'] + ':</b> ' + item['category'] + ' '
profileStr += \
'<b>' + translate['Location'] + ':</b> ' + item['location'] + '</p>\n'
'<b>' + translate['Location'] + ':</b> ' + item['location']
if item.get('itemPrice') and item.get('itemCurrency'):
if item['itemPrice'].isdigit():
if float(item['itemPrice']) > 0:
profileStr += ' ' + \
'<b>' + translate['Price'] + ':</b> ' + \
item['itemPrice'] + ' ' + item['itemCurrency']
profileStr += '</p>\n'
sharedesc = item['displayName']
if '<' not in sharedesc and '?' not in sharedesc:
if showContact:

View File

@ -1159,6 +1159,23 @@ def editNumberField(label: str, name: str, value: int = 1,
'min="' + str(minValue) + '" max="' + str(maxValue) + '" step="1">\n'
def editCurrencyField(label: str, name: str, value: str = "0.00",
placeholder: str = "0.00") -> str:
"""Returns html for editing a currency field
"""
if value is None:
value = '0.00'
placeholderStr = '0.00'
if placeholder:
if placeholder.isdigit():
placeholderStr = ' placeholder="' + str(placeholder) + '"'
return \
'<label class="labels">' + label + '</label><br>\n' + \
' <input type="text" name="' + name + '" value="' + \
str(value) + '"' + placeholderStr + ' ' + \
'" pattern="^\\d{1,3}(,\\d{3})*(\\.\\d+)?" data-type="currency">\n'
def editCheckBox(label: str, name: str, checked: bool = False) -> str:
"""Returns html for editing a checkbox field
"""