mirror of https://gitlab.com/bashrc2/epicyon
Functions for shares catalog endpoints
parent
723e6e7a5e
commit
5d5dab6d2f
13
daemon.py
13
daemon.py
|
@ -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:
|
||||
|
|
13
epicyon.py
13
epicyon.py
|
@ -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
165
shares.py
|
@ -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
|
||||
|
|
4
tests.py
4
tests.py
|
@ -3272,7 +3272,9 @@ def _testFunctions():
|
|||
'E2EEremoveDevice',
|
||||
'setOrganizationScheme',
|
||||
'fill_headers',
|
||||
'_nothing'
|
||||
'_nothing',
|
||||
'sharesCatalogEndpoint',
|
||||
'sharesCatalogAccountEndpoint'
|
||||
]
|
||||
excludeImports = [
|
||||
'link',
|
||||
|
|
|
@ -454,5 +454,7 @@
|
|||
"Languages": "اللغات",
|
||||
"Translated": "تترجم",
|
||||
"Quantity": "كمية",
|
||||
"food": "غذاء"
|
||||
"food": "غذاء",
|
||||
"Price": "السعر",
|
||||
"Currency": "عملة"
|
||||
}
|
||||
|
|
|
@ -454,5 +454,7 @@
|
|||
"Languages": "Idiomes",
|
||||
"Translated": "Traduït",
|
||||
"Quantity": "Quantitat",
|
||||
"food": "menjar"
|
||||
"food": "menjar",
|
||||
"Price": "Preu",
|
||||
"Currency": "Moneda"
|
||||
}
|
||||
|
|
|
@ -454,5 +454,7 @@
|
|||
"Languages": "Ieithoedd",
|
||||
"Translated": "Chyfieithwyd",
|
||||
"Quantity": "Symiau",
|
||||
"food": "bwyd"
|
||||
"food": "bwyd",
|
||||
"Price": "Prisia",
|
||||
"Currency": "Harian"
|
||||
}
|
||||
|
|
|
@ -454,5 +454,7 @@
|
|||
"Languages": "Sprachen",
|
||||
"Translated": "Übersetzt",
|
||||
"Quantity": "Menge",
|
||||
"food": "lebensmittel"
|
||||
"food": "lebensmittel",
|
||||
"Price": "Preis",
|
||||
"Currency": "Währung"
|
||||
}
|
||||
|
|
|
@ -454,5 +454,7 @@
|
|||
"Languages": "Languages",
|
||||
"Translated": "Translated",
|
||||
"Quantity": "Quantity",
|
||||
"food": "food"
|
||||
"food": "food",
|
||||
"Price": "Price",
|
||||
"Currency": "Currency"
|
||||
}
|
||||
|
|
|
@ -454,5 +454,7 @@
|
|||
"Languages": "Idiomas",
|
||||
"Translated": "Traducida",
|
||||
"Quantity": "Cantidad",
|
||||
"food": "comida"
|
||||
"food": "comida",
|
||||
"Price": "Precio",
|
||||
"Currency": "Divisa"
|
||||
}
|
||||
|
|
|
@ -454,5 +454,7 @@
|
|||
"Languages": "Langues",
|
||||
"Translated": "Traduite",
|
||||
"Quantity": "Quantité",
|
||||
"food": "aliments"
|
||||
"food": "aliments",
|
||||
"Price": "Prix",
|
||||
"Currency": "Devise"
|
||||
}
|
||||
|
|
|
@ -454,5 +454,7 @@
|
|||
"Languages": "Teangacha",
|
||||
"Translated": "Aistrithe",
|
||||
"Quantity": "Cainníocht",
|
||||
"food": "bia"
|
||||
"food": "bia",
|
||||
"Price": "Praghas a chur ar",
|
||||
"Currency": "Airgeadra"
|
||||
}
|
||||
|
|
|
@ -454,5 +454,7 @@
|
|||
"Languages": "बोली",
|
||||
"Translated": "अनुवाद",
|
||||
"Quantity": "मात्रा",
|
||||
"food": "खाना"
|
||||
"food": "खाना",
|
||||
"Price": "कीमत",
|
||||
"Currency": "मुद्रा"
|
||||
}
|
||||
|
|
|
@ -454,5 +454,7 @@
|
|||
"Languages": "Le lingue",
|
||||
"Translated": "Tradotto",
|
||||
"Quantity": "Quantità",
|
||||
"food": "cibo"
|
||||
"food": "cibo",
|
||||
"Price": "Prezzo",
|
||||
"Currency": "Moneta"
|
||||
}
|
||||
|
|
|
@ -454,5 +454,7 @@
|
|||
"Languages": "言語",
|
||||
"Translated": "翻訳",
|
||||
"Quantity": "量",
|
||||
"food": "食物"
|
||||
"food": "食物",
|
||||
"Price": "価格",
|
||||
"Currency": "通貨"
|
||||
}
|
||||
|
|
|
@ -454,5 +454,7 @@
|
|||
"Languages": "Ziman",
|
||||
"Translated": "Wergerandin",
|
||||
"Quantity": "Jimarî",
|
||||
"food": "xûrek"
|
||||
"food": "xûrek",
|
||||
"Price": "Biha",
|
||||
"Currency": "Diravcins"
|
||||
}
|
||||
|
|
|
@ -450,5 +450,7 @@
|
|||
"Languages": "Languages",
|
||||
"Translated": "Translated",
|
||||
"Quantity": "Quantity",
|
||||
"food": "food"
|
||||
"food": "food",
|
||||
"Price": "Price",
|
||||
"Currency": "Currency"
|
||||
}
|
||||
|
|
|
@ -454,5 +454,7 @@
|
|||
"Languages": "Línguas",
|
||||
"Translated": "Traduzida",
|
||||
"Quantity": "Quantidade",
|
||||
"food": "comida"
|
||||
"food": "comida",
|
||||
"Price": "Preço",
|
||||
"Currency": "Moeda"
|
||||
}
|
||||
|
|
|
@ -454,5 +454,7 @@
|
|||
"Languages": "Языки",
|
||||
"Translated": "Перевод",
|
||||
"Quantity": "Количество",
|
||||
"food": "еда"
|
||||
"food": "еда",
|
||||
"Price": "Цена",
|
||||
"Currency": "Валюта"
|
||||
}
|
||||
|
|
|
@ -454,5 +454,7 @@
|
|||
"Languages": "Lugha",
|
||||
"Translated": "Ilitafsiriwa",
|
||||
"Quantity": "Wingi",
|
||||
"food": "chakula"
|
||||
"food": "chakula",
|
||||
"Price": "Bei",
|
||||
"Currency": "Fedha"
|
||||
}
|
||||
|
|
|
@ -454,5 +454,7 @@
|
|||
"Languages": "语言",
|
||||
"Translated": "翻译",
|
||||
"Quantity": "数量",
|
||||
"food": "食物"
|
||||
"food": "食物",
|
||||
"Price": "价钱",
|
||||
"Currency": "货币"
|
||||
}
|
||||
|
|
|
@ -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':
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
"""
|
||||
|
|
Loading…
Reference in New Issue