Merge branch 'main' of gitlab.com:bashrc2/epicyon
|
|
@ -3,6 +3,6 @@ image: debian:testing
|
||||||
test:
|
test:
|
||||||
script:
|
script:
|
||||||
- apt-get update
|
- apt-get update
|
||||||
- apt-get install -y python3-cryptography python3-dateutil python3-idna python3-numpy python3-pil.imagetk python3-requests python3-socks python3-setuptools python3-pyqrcode
|
- apt-get install -y python3-cryptography python3-dateutil python3-idna python3-numpy python3-pil.imagetk python3-requests python3-socks python3-setuptools python3-pyqrcode imagemagick gnupg
|
||||||
- python3 epicyon.py --tests
|
- python3 epicyon.py --tests
|
||||||
- python3 epicyon.py --testsnetwork
|
- python3 epicyon.py --testsnetwork
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ By submitting code, documentation or artwork you agree that it will be licensed
|
||||||
|
|
||||||
## Security Vulnerability Disclosure
|
## Security Vulnerability Disclosure
|
||||||
|
|
||||||
Create an issue on https://gitlab.com/bashrc2/epicyon/issues. If the vulnerability is especially sensitive then send an XMPP message to **bob@freedombone.net** or a Matrix message to **@bob:matrix.freedombone.net**.
|
Create an issue on https://gitlab.com/bashrc2/epicyon/issues. If the vulnerability is especially sensitive then send an XMPP message to **bob@libreserver.org** or a Matrix message to **@bob:matrix.libreserver.org**.
|
||||||
|
|
||||||
## Code of Conduct
|
## Code of Conduct
|
||||||
|
|
||||||
|
|
@ -14,7 +14,7 @@ The code of conduct can be found [here](code-of-conduct.md).
|
||||||
|
|
||||||
Submit to https://gitlab.com/bashrc2/epicyon/issues
|
Submit to https://gitlab.com/bashrc2/epicyon/issues
|
||||||
|
|
||||||
You can also post patches in the old-fashioned style via email to **bob@freedombone.net**. Include **[Epicyon]** in the subject line, otherwise it may be ignored.
|
You can also post patches in the old-fashioned style via email to **bob@libreserver.org**. Include **[Epicyon]** in the subject line, otherwise it may be ignored.
|
||||||
|
|
||||||
## Development Style
|
## Development Style
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -168,8 +168,6 @@ server {
|
||||||
location / {
|
location / {
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
client_max_body_size 31M;
|
client_max_body_size 31M;
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
|
||||||
proxy_set_header Connection "upgrade";
|
|
||||||
proxy_set_header Host $http_host;
|
proxy_set_header Host $http_host;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;
|
||||||
|
|
@ -185,10 +183,6 @@ server {
|
||||||
proxy_redirect off;
|
proxy_redirect off;
|
||||||
proxy_request_buffering off;
|
proxy_request_buffering off;
|
||||||
proxy_buffering off;
|
proxy_buffering off;
|
||||||
location ~ ^/accounts/(avatars|headers)/(.*).(png|jpg|gif|webp|svg) {
|
|
||||||
expires 1d;
|
|
||||||
proxy_pass http://localhost:7156;
|
|
||||||
}
|
|
||||||
proxy_pass http://localhost:7156;
|
proxy_pass http://localhost:7156;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "ActivityPub"
|
__module_group__ = "ActivityPub"
|
||||||
|
|
||||||
|
|
|
||||||
39
announce.py
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "ActivityPub"
|
__module_group__ = "ActivityPub"
|
||||||
|
|
||||||
|
|
@ -23,6 +23,7 @@ from utils import saveJson
|
||||||
from utils import undoAnnounceCollectionEntry
|
from utils import undoAnnounceCollectionEntry
|
||||||
from utils import updateAnnounceCollection
|
from utils import updateAnnounceCollection
|
||||||
from utils import localActorUrl
|
from utils import localActorUrl
|
||||||
|
from utils import replaceUsersWithAt
|
||||||
from posts import sendSignedJson
|
from posts import sendSignedJson
|
||||||
from posts import getPersonBox
|
from posts import getPersonBox
|
||||||
from session import postJson
|
from session import postJson
|
||||||
|
|
@ -121,7 +122,8 @@ def createAnnounce(session, baseDir: str, federationList: [],
|
||||||
clientToServer: bool,
|
clientToServer: bool,
|
||||||
sendThreads: [], postLog: [],
|
sendThreads: [], postLog: [],
|
||||||
personCache: {}, cachedWebfingers: {},
|
personCache: {}, cachedWebfingers: {},
|
||||||
debug: bool, projectVersion: str) -> {}:
|
debug: bool, projectVersion: str,
|
||||||
|
signingPrivateKeyPem: str) -> {}:
|
||||||
"""Creates an announce message
|
"""Creates an announce message
|
||||||
Typically toUrl will be https://www.w3.org/ns/activitystreams#Public
|
Typically toUrl will be https://www.w3.org/ns/activitystreams#Public
|
||||||
and ccUrl might be a specific person favorited or repeated and the
|
and ccUrl might be a specific person favorited or repeated and the
|
||||||
|
|
@ -178,7 +180,8 @@ def createAnnounce(session, baseDir: str, federationList: [],
|
||||||
announceNickname, announceDomain, announcePort, None,
|
announceNickname, announceDomain, announcePort, None,
|
||||||
httpPrefix, True, clientToServer, federationList,
|
httpPrefix, True, clientToServer, federationList,
|
||||||
sendThreads, postLog, cachedWebfingers, personCache,
|
sendThreads, postLog, cachedWebfingers, personCache,
|
||||||
debug, projectVersion, None, groupAccount)
|
debug, projectVersion, None, groupAccount,
|
||||||
|
signingPrivateKeyPem, 639633)
|
||||||
|
|
||||||
return newAnnounce
|
return newAnnounce
|
||||||
|
|
||||||
|
|
@ -188,7 +191,8 @@ def announcePublic(session, baseDir: str, federationList: [],
|
||||||
objectUrl: str, clientToServer: bool,
|
objectUrl: str, clientToServer: bool,
|
||||||
sendThreads: [], postLog: [],
|
sendThreads: [], postLog: [],
|
||||||
personCache: {}, cachedWebfingers: {},
|
personCache: {}, cachedWebfingers: {},
|
||||||
debug: bool, projectVersion: str) -> {}:
|
debug: bool, projectVersion: str,
|
||||||
|
signingPrivateKeyPem: str) -> {}:
|
||||||
"""Makes a public announcement
|
"""Makes a public announcement
|
||||||
"""
|
"""
|
||||||
fromDomain = getFullDomain(domain, port)
|
fromDomain = getFullDomain(domain, port)
|
||||||
|
|
@ -201,7 +205,8 @@ def announcePublic(session, baseDir: str, federationList: [],
|
||||||
objectUrl, True, clientToServer,
|
objectUrl, True, clientToServer,
|
||||||
sendThreads, postLog,
|
sendThreads, postLog,
|
||||||
personCache, cachedWebfingers,
|
personCache, cachedWebfingers,
|
||||||
debug, projectVersion)
|
debug, projectVersion,
|
||||||
|
signingPrivateKeyPem)
|
||||||
|
|
||||||
|
|
||||||
def sendAnnounceViaServer(baseDir: str, session,
|
def sendAnnounceViaServer(baseDir: str, session,
|
||||||
|
|
@ -209,7 +214,8 @@ def sendAnnounceViaServer(baseDir: str, session,
|
||||||
fromDomain: str, fromPort: int,
|
fromDomain: str, fromPort: int,
|
||||||
httpPrefix: str, repeatObjectUrl: str,
|
httpPrefix: str, repeatObjectUrl: str,
|
||||||
cachedWebfingers: {}, personCache: {},
|
cachedWebfingers: {}, personCache: {},
|
||||||
debug: bool, projectVersion: str) -> {}:
|
debug: bool, projectVersion: str,
|
||||||
|
signingPrivateKeyPem: str) -> {}:
|
||||||
"""Creates an announce message via c2s
|
"""Creates an announce message via c2s
|
||||||
"""
|
"""
|
||||||
if not session:
|
if not session:
|
||||||
|
|
@ -241,7 +247,8 @@ def sendAnnounceViaServer(baseDir: str, session,
|
||||||
# lookup the inbox for the To handle
|
# lookup the inbox for the To handle
|
||||||
wfRequest = webfingerHandle(session, handle, httpPrefix,
|
wfRequest = webfingerHandle(session, handle, httpPrefix,
|
||||||
cachedWebfingers,
|
cachedWebfingers,
|
||||||
fromDomain, projectVersion, debug, False)
|
fromDomain, projectVersion, debug, False,
|
||||||
|
signingPrivateKeyPem)
|
||||||
if not wfRequest:
|
if not wfRequest:
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: announce webfinger failed for ' + handle)
|
print('DEBUG: announce webfinger failed for ' + handle)
|
||||||
|
|
@ -254,9 +261,12 @@ def sendAnnounceViaServer(baseDir: str, session,
|
||||||
postToBox = 'outbox'
|
postToBox = 'outbox'
|
||||||
|
|
||||||
# get the actor inbox for the To handle
|
# get the actor inbox for the To handle
|
||||||
|
originDomain = fromDomain
|
||||||
(inboxUrl, pubKeyId, pubKey, fromPersonId,
|
(inboxUrl, pubKeyId, pubKey, fromPersonId,
|
||||||
sharedInbox, avatarUrl,
|
sharedInbox, avatarUrl,
|
||||||
displayName) = getPersonBox(baseDir, session, wfRequest,
|
displayName, _) = getPersonBox(signingPrivateKeyPem,
|
||||||
|
originDomain,
|
||||||
|
baseDir, session, wfRequest,
|
||||||
personCache,
|
personCache,
|
||||||
projectVersion, httpPrefix,
|
projectVersion, httpPrefix,
|
||||||
fromNickname, fromDomain,
|
fromNickname, fromDomain,
|
||||||
|
|
@ -297,7 +307,8 @@ def sendUndoAnnounceViaServer(baseDir: str, session,
|
||||||
domain: str, port: int,
|
domain: str, port: int,
|
||||||
httpPrefix: str, repeatObjectUrl: str,
|
httpPrefix: str, repeatObjectUrl: str,
|
||||||
cachedWebfingers: {}, personCache: {},
|
cachedWebfingers: {}, personCache: {},
|
||||||
debug: bool, projectVersion: str) -> {}:
|
debug: bool, projectVersion: str,
|
||||||
|
signingPrivateKeyPem: str) -> {}:
|
||||||
"""Undo an announce message via c2s
|
"""Undo an announce message via c2s
|
||||||
"""
|
"""
|
||||||
if not session:
|
if not session:
|
||||||
|
|
@ -307,7 +318,7 @@ def sendUndoAnnounceViaServer(baseDir: str, session,
|
||||||
domainFull = getFullDomain(domain, port)
|
domainFull = getFullDomain(domain, port)
|
||||||
|
|
||||||
actor = localActorUrl(httpPrefix, nickname, domainFull)
|
actor = localActorUrl(httpPrefix, nickname, domainFull)
|
||||||
handle = actor.replace('/users/', '/@')
|
handle = replaceUsersWithAt(actor)
|
||||||
|
|
||||||
statusNumber, published = getStatusNumber()
|
statusNumber, published = getStatusNumber()
|
||||||
unAnnounceJson = {
|
unAnnounceJson = {
|
||||||
|
|
@ -321,7 +332,8 @@ def sendUndoAnnounceViaServer(baseDir: str, session,
|
||||||
# lookup the inbox for the To handle
|
# lookup the inbox for the To handle
|
||||||
wfRequest = webfingerHandle(session, handle, httpPrefix,
|
wfRequest = webfingerHandle(session, handle, httpPrefix,
|
||||||
cachedWebfingers,
|
cachedWebfingers,
|
||||||
domain, projectVersion, debug, False)
|
domain, projectVersion, debug, False,
|
||||||
|
signingPrivateKeyPem)
|
||||||
if not wfRequest:
|
if not wfRequest:
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: undo announce webfinger failed for ' + handle)
|
print('DEBUG: undo announce webfinger failed for ' + handle)
|
||||||
|
|
@ -334,9 +346,12 @@ def sendUndoAnnounceViaServer(baseDir: str, session,
|
||||||
postToBox = 'outbox'
|
postToBox = 'outbox'
|
||||||
|
|
||||||
# get the actor inbox for the To handle
|
# get the actor inbox for the To handle
|
||||||
|
originDomain = domain
|
||||||
(inboxUrl, pubKeyId, pubKey, fromPersonId,
|
(inboxUrl, pubKeyId, pubKey, fromPersonId,
|
||||||
sharedInbox, avatarUrl,
|
sharedInbox, avatarUrl,
|
||||||
displayName) = getPersonBox(baseDir, session, wfRequest,
|
displayName, _) = getPersonBox(signingPrivateKeyPem,
|
||||||
|
originDomain,
|
||||||
|
baseDir, session, wfRequest,
|
||||||
personCache,
|
personCache,
|
||||||
projectVersion, httpPrefix,
|
projectVersion, httpPrefix,
|
||||||
nickname, domain,
|
nickname, domain,
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 182 KiB After Width: | Height: | Size: 141 KiB |
|
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 95 KiB |
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 73 KiB |
|
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 77 KiB After Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 63 KiB |
|
Before Width: | Height: | Size: 172 KiB After Width: | Height: | Size: 147 KiB |
|
Before Width: | Height: | Size: 87 KiB After Width: | Height: | Size: 78 KiB |
|
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 74 KiB |
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 184 KiB After Width: | Height: | Size: 166 KiB |
2
auth.py
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Security"
|
__module_group__ = "Security"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Profile Metadata"
|
__module_group__ = "Profile Metadata"
|
||||||
|
|
||||||
|
|
@ -82,7 +82,8 @@ def sendAvailabilityViaServer(baseDir: str, session,
|
||||||
httpPrefix: str,
|
httpPrefix: str,
|
||||||
status: str,
|
status: str,
|
||||||
cachedWebfingers: {}, personCache: {},
|
cachedWebfingers: {}, personCache: {},
|
||||||
debug: bool, projectVersion: str) -> {}:
|
debug: bool, projectVersion: str,
|
||||||
|
signingPrivateKeyPem: str) -> {}:
|
||||||
"""Sets the availability for a person via c2s
|
"""Sets the availability for a person via c2s
|
||||||
"""
|
"""
|
||||||
if not session:
|
if not session:
|
||||||
|
|
@ -107,7 +108,8 @@ def sendAvailabilityViaServer(baseDir: str, session,
|
||||||
# lookup the inbox for the To handle
|
# lookup the inbox for the To handle
|
||||||
wfRequest = webfingerHandle(session, handle, httpPrefix,
|
wfRequest = webfingerHandle(session, handle, httpPrefix,
|
||||||
cachedWebfingers,
|
cachedWebfingers,
|
||||||
domain, projectVersion, debug, False)
|
domain, projectVersion, debug, False,
|
||||||
|
signingPrivateKeyPem)
|
||||||
if not wfRequest:
|
if not wfRequest:
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: availability webfinger failed for ' + handle)
|
print('DEBUG: availability webfinger failed for ' + handle)
|
||||||
|
|
@ -120,9 +122,11 @@ def sendAvailabilityViaServer(baseDir: str, session,
|
||||||
postToBox = 'outbox'
|
postToBox = 'outbox'
|
||||||
|
|
||||||
# get the actor inbox for the To handle
|
# get the actor inbox for the To handle
|
||||||
(inboxUrl, pubKeyId, pubKey,
|
originDomain = domain
|
||||||
fromPersonId, sharedInbox,
|
(inboxUrl, pubKeyId, pubKey, fromPersonId, sharedInbox, avatarUrl,
|
||||||
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
displayName, _) = getPersonBox(signingPrivateKeyPem,
|
||||||
|
originDomain,
|
||||||
|
baseDir, session, wfRequest,
|
||||||
personCache, projectVersion,
|
personCache, projectVersion,
|
||||||
httpPrefix, nickname,
|
httpPrefix, nickname,
|
||||||
domain, postToBox, 57262)
|
domain, postToBox, 57262)
|
||||||
|
|
|
||||||
153
blocking.py
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Core"
|
__module_group__ = "Core"
|
||||||
|
|
||||||
|
|
@ -461,23 +461,35 @@ def mutePost(baseDir: str, nickname: str, domain: str, port: int,
|
||||||
debug: bool) -> None:
|
debug: bool) -> None:
|
||||||
""" Mutes the given post
|
""" Mutes the given post
|
||||||
"""
|
"""
|
||||||
|
print('mutePost: postId ' + postId)
|
||||||
postFilename = locatePost(baseDir, nickname, domain, postId)
|
postFilename = locatePost(baseDir, nickname, domain, postId)
|
||||||
if not postFilename:
|
if not postFilename:
|
||||||
|
print('mutePost: file not found ' + postId)
|
||||||
return
|
return
|
||||||
postJsonObject = loadJson(postFilename)
|
postJsonObject = loadJson(postFilename)
|
||||||
if not postJsonObject:
|
if not postJsonObject:
|
||||||
|
print('mutePost: object not loaded ' + postId)
|
||||||
return
|
return
|
||||||
|
print('mutePost: ' + str(postJsonObject))
|
||||||
|
|
||||||
|
postJsonObj = postJsonObject
|
||||||
|
alsoUpdatePostId = None
|
||||||
if hasObjectDict(postJsonObject):
|
if hasObjectDict(postJsonObject):
|
||||||
|
postJsonObj = postJsonObject['object']
|
||||||
|
else:
|
||||||
|
if postJsonObject.get('object'):
|
||||||
|
if isinstance(postJsonObject['object'], str):
|
||||||
|
alsoUpdatePostId = removeIdEnding(postJsonObject['object'])
|
||||||
|
|
||||||
domainFull = getFullDomain(domain, port)
|
domainFull = getFullDomain(domain, port)
|
||||||
actor = localActorUrl(httpPrefix, nickname, domainFull)
|
actor = localActorUrl(httpPrefix, nickname, domainFull)
|
||||||
|
|
||||||
if postJsonObject['object'].get('conversation'):
|
if postJsonObj.get('conversation'):
|
||||||
muteConversation(baseDir, nickname, domain,
|
muteConversation(baseDir, nickname, domain,
|
||||||
postJsonObject['object']['conversation'])
|
postJsonObj['conversation'])
|
||||||
|
|
||||||
# does this post have ignores on it from differenent actors?
|
# does this post have ignores on it from differenent actors?
|
||||||
if not postJsonObject['object'].get('ignores'):
|
if not postJsonObj.get('ignores'):
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: Adding initial mute to ' + postId)
|
print('DEBUG: Adding initial mute to ' + postId)
|
||||||
ignoresJson = {
|
ignoresJson = {
|
||||||
|
|
@ -490,11 +502,11 @@ def mutePost(baseDir: str, nickname: str, domain: str, port: int,
|
||||||
'actor': actor
|
'actor': actor
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
postJsonObject['object']['ignores'] = ignoresJson
|
postJsonObj['ignores'] = ignoresJson
|
||||||
else:
|
else:
|
||||||
if not postJsonObject['object']['ignores'].get('items'):
|
if not postJsonObj['ignores'].get('items'):
|
||||||
postJsonObject['object']['ignores']['items'] = []
|
postJsonObj['ignores']['items'] = []
|
||||||
itemsList = postJsonObject['object']['ignores']['items']
|
itemsList = postJsonObj['ignores']['items']
|
||||||
for ignoresItem in itemsList:
|
for ignoresItem in itemsList:
|
||||||
if ignoresItem.get('actor'):
|
if ignoresItem.get('actor'):
|
||||||
if ignoresItem['actor'] == actor:
|
if ignoresItem['actor'] == actor:
|
||||||
|
|
@ -505,8 +517,10 @@ def mutePost(baseDir: str, nickname: str, domain: str, port: int,
|
||||||
}
|
}
|
||||||
igIt = len(itemsList)
|
igIt = len(itemsList)
|
||||||
itemsList.append(newIgnore)
|
itemsList.append(newIgnore)
|
||||||
postJsonObject['object']['ignores']['totalItems'] = igIt
|
postJsonObj['ignores']['totalItems'] = igIt
|
||||||
saveJson(postJsonObject, postFilename)
|
postJsonObj['muted'] = True
|
||||||
|
if saveJson(postJsonObject, postFilename):
|
||||||
|
print('mutePost: saved ' + postFilename)
|
||||||
|
|
||||||
# remove cached post so that the muted version gets recreated
|
# remove cached post so that the muted version gets recreated
|
||||||
# without its content text and/or image
|
# without its content text and/or image
|
||||||
|
|
@ -514,7 +528,13 @@ def mutePost(baseDir: str, nickname: str, domain: str, port: int,
|
||||||
getCachedPostFilename(baseDir, nickname, domain, postJsonObject)
|
getCachedPostFilename(baseDir, nickname, domain, postJsonObject)
|
||||||
if cachedPostFilename:
|
if cachedPostFilename:
|
||||||
if os.path.isfile(cachedPostFilename):
|
if os.path.isfile(cachedPostFilename):
|
||||||
|
try:
|
||||||
os.remove(cachedPostFilename)
|
os.remove(cachedPostFilename)
|
||||||
|
print('MUTE: cached post removed ' + cachedPostFilename)
|
||||||
|
except BaseException:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
print('MUTE: cached post not found ' + cachedPostFilename)
|
||||||
|
|
||||||
with open(postFilename + '.muted', 'w+') as muteFile:
|
with open(postFilename + '.muted', 'w+') as muteFile:
|
||||||
muteFile.write('\n')
|
muteFile.write('\n')
|
||||||
|
|
@ -526,14 +546,39 @@ def mutePost(baseDir: str, nickname: str, domain: str, port: int,
|
||||||
removeIdEnding(postJsonObject['id']).replace('/', '#')
|
removeIdEnding(postJsonObject['id']).replace('/', '#')
|
||||||
if postId in recentPostsCache['index']:
|
if postId in recentPostsCache['index']:
|
||||||
print('MUTE: ' + postId + ' is in recent posts cache')
|
print('MUTE: ' + postId + ' is in recent posts cache')
|
||||||
if recentPostsCache['json'].get(postId):
|
if recentPostsCache.get('json'):
|
||||||
postJsonObject['muted'] = True
|
|
||||||
recentPostsCache['json'][postId] = json.dumps(postJsonObject)
|
recentPostsCache['json'][postId] = json.dumps(postJsonObject)
|
||||||
|
print('MUTE: ' + postId +
|
||||||
|
' marked as muted in recent posts memory cache')
|
||||||
if recentPostsCache.get('html'):
|
if recentPostsCache.get('html'):
|
||||||
if recentPostsCache['html'].get(postId):
|
if recentPostsCache['html'].get(postId):
|
||||||
del recentPostsCache['html'][postId]
|
del recentPostsCache['html'][postId]
|
||||||
print('MUTE: ' + postId +
|
print('MUTE: ' + postId + ' removed cached html')
|
||||||
' marked as muted in recent posts memory cache')
|
|
||||||
|
if alsoUpdatePostId:
|
||||||
|
postFilename = locatePost(baseDir, nickname, domain, alsoUpdatePostId)
|
||||||
|
if os.path.isfile(postFilename):
|
||||||
|
postJsonObj = loadJson(postFilename)
|
||||||
|
cachedPostFilename = \
|
||||||
|
getCachedPostFilename(baseDir, nickname, domain,
|
||||||
|
postJsonObj)
|
||||||
|
if cachedPostFilename:
|
||||||
|
if os.path.isfile(cachedPostFilename):
|
||||||
|
try:
|
||||||
|
os.remove(cachedPostFilename)
|
||||||
|
print('MUTE: cached referenced post removed ' +
|
||||||
|
cachedPostFilename)
|
||||||
|
except BaseException:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if recentPostsCache.get('json'):
|
||||||
|
if recentPostsCache['json'].get(alsoUpdatePostId):
|
||||||
|
del recentPostsCache['json'][alsoUpdatePostId]
|
||||||
|
print('MUTE: ' + alsoUpdatePostId + ' removed referenced json')
|
||||||
|
if recentPostsCache.get('html'):
|
||||||
|
if recentPostsCache['html'].get(alsoUpdatePostId):
|
||||||
|
del recentPostsCache['html'][alsoUpdatePostId]
|
||||||
|
print('MUTE: ' + alsoUpdatePostId + ' removed referenced html')
|
||||||
|
|
||||||
|
|
||||||
def unmutePost(baseDir: str, nickname: str, domain: str, port: int,
|
def unmutePost(baseDir: str, nickname: str, domain: str, port: int,
|
||||||
|
|
@ -550,22 +595,32 @@ def unmutePost(baseDir: str, nickname: str, domain: str, port: int,
|
||||||
|
|
||||||
muteFilename = postFilename + '.muted'
|
muteFilename = postFilename + '.muted'
|
||||||
if os.path.isfile(muteFilename):
|
if os.path.isfile(muteFilename):
|
||||||
|
try:
|
||||||
os.remove(muteFilename)
|
os.remove(muteFilename)
|
||||||
|
except BaseException:
|
||||||
|
pass
|
||||||
print('UNMUTE: ' + muteFilename + ' file removed')
|
print('UNMUTE: ' + muteFilename + ' file removed')
|
||||||
|
|
||||||
|
postJsonObj = postJsonObject
|
||||||
|
alsoUpdatePostId = None
|
||||||
if hasObjectDict(postJsonObject):
|
if hasObjectDict(postJsonObject):
|
||||||
if postJsonObject['object'].get('conversation'):
|
postJsonObj = postJsonObject['object']
|
||||||
unmuteConversation(baseDir, nickname, domain,
|
else:
|
||||||
postJsonObject['object']['conversation'])
|
if postJsonObject.get('object'):
|
||||||
|
if isinstance(postJsonObject['object'], str):
|
||||||
|
alsoUpdatePostId = removeIdEnding(postJsonObject['object'])
|
||||||
|
|
||||||
if postJsonObject['object'].get('ignores'):
|
if postJsonObj.get('conversation'):
|
||||||
|
unmuteConversation(baseDir, nickname, domain,
|
||||||
|
postJsonObj['conversation'])
|
||||||
|
|
||||||
|
if postJsonObj.get('ignores'):
|
||||||
domainFull = getFullDomain(domain, port)
|
domainFull = getFullDomain(domain, port)
|
||||||
actor = localActorUrl(httpPrefix, nickname, domainFull)
|
actor = localActorUrl(httpPrefix, nickname, domainFull)
|
||||||
totalItems = 0
|
totalItems = 0
|
||||||
if postJsonObject['object']['ignores'].get('totalItems'):
|
if postJsonObj['ignores'].get('totalItems'):
|
||||||
totalItems = \
|
totalItems = postJsonObj['ignores']['totalItems']
|
||||||
postJsonObject['object']['ignores']['totalItems']
|
itemsList = postJsonObj['ignores']['items']
|
||||||
itemsList = postJsonObject['object']['ignores']['items']
|
|
||||||
for ignoresItem in itemsList:
|
for ignoresItem in itemsList:
|
||||||
if ignoresItem.get('actor'):
|
if ignoresItem.get('actor'):
|
||||||
if ignoresItem['actor'] == actor:
|
if ignoresItem['actor'] == actor:
|
||||||
|
|
@ -576,10 +631,11 @@ def unmutePost(baseDir: str, nickname: str, domain: str, port: int,
|
||||||
if totalItems == 1:
|
if totalItems == 1:
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: mute was removed from post')
|
print('DEBUG: mute was removed from post')
|
||||||
del postJsonObject['object']['ignores']
|
del postJsonObj['ignores']
|
||||||
else:
|
else:
|
||||||
igItLen = len(postJsonObject['object']['ignores']['items'])
|
igItLen = len(postJsonObj['ignores']['items'])
|
||||||
postJsonObject['object']['ignores']['totalItems'] = igItLen
|
postJsonObj['ignores']['totalItems'] = igItLen
|
||||||
|
postJsonObj['muted'] = False
|
||||||
saveJson(postJsonObject, postFilename)
|
saveJson(postJsonObject, postFilename)
|
||||||
|
|
||||||
# remove cached post so that the muted version gets recreated
|
# remove cached post so that the muted version gets recreated
|
||||||
|
|
@ -588,7 +644,10 @@ def unmutePost(baseDir: str, nickname: str, domain: str, port: int,
|
||||||
getCachedPostFilename(baseDir, nickname, domain, postJsonObject)
|
getCachedPostFilename(baseDir, nickname, domain, postJsonObject)
|
||||||
if cachedPostFilename:
|
if cachedPostFilename:
|
||||||
if os.path.isfile(cachedPostFilename):
|
if os.path.isfile(cachedPostFilename):
|
||||||
|
try:
|
||||||
os.remove(cachedPostFilename)
|
os.remove(cachedPostFilename)
|
||||||
|
except BaseException:
|
||||||
|
pass
|
||||||
|
|
||||||
# if the post is in the recent posts cache then mark it as unmuted
|
# if the post is in the recent posts cache then mark it as unmuted
|
||||||
if recentPostsCache.get('index'):
|
if recentPostsCache.get('index'):
|
||||||
|
|
@ -596,14 +655,40 @@ def unmutePost(baseDir: str, nickname: str, domain: str, port: int,
|
||||||
removeIdEnding(postJsonObject['id']).replace('/', '#')
|
removeIdEnding(postJsonObject['id']).replace('/', '#')
|
||||||
if postId in recentPostsCache['index']:
|
if postId in recentPostsCache['index']:
|
||||||
print('UNMUTE: ' + postId + ' is in recent posts cache')
|
print('UNMUTE: ' + postId + ' is in recent posts cache')
|
||||||
if recentPostsCache['json'].get(postId):
|
if recentPostsCache.get('json'):
|
||||||
postJsonObject['muted'] = False
|
|
||||||
recentPostsCache['json'][postId] = json.dumps(postJsonObject)
|
recentPostsCache['json'][postId] = json.dumps(postJsonObject)
|
||||||
|
print('UNMUTE: ' + postId +
|
||||||
|
' marked as unmuted in recent posts cache')
|
||||||
if recentPostsCache.get('html'):
|
if recentPostsCache.get('html'):
|
||||||
if recentPostsCache['html'].get(postId):
|
if recentPostsCache['html'].get(postId):
|
||||||
del recentPostsCache['html'][postId]
|
del recentPostsCache['html'][postId]
|
||||||
print('UNMUTE: ' + postId +
|
print('UNMUTE: ' + postId + ' removed cached html')
|
||||||
' marked as unmuted in recent posts cache')
|
if alsoUpdatePostId:
|
||||||
|
postFilename = locatePost(baseDir, nickname, domain, alsoUpdatePostId)
|
||||||
|
if os.path.isfile(postFilename):
|
||||||
|
postJsonObj = loadJson(postFilename)
|
||||||
|
cachedPostFilename = \
|
||||||
|
getCachedPostFilename(baseDir, nickname, domain,
|
||||||
|
postJsonObj)
|
||||||
|
if cachedPostFilename:
|
||||||
|
if os.path.isfile(cachedPostFilename):
|
||||||
|
try:
|
||||||
|
os.remove(cachedPostFilename)
|
||||||
|
print('MUTE: cached referenced post removed ' +
|
||||||
|
cachedPostFilename)
|
||||||
|
except BaseException:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if recentPostsCache.get('json'):
|
||||||
|
if recentPostsCache['json'].get(alsoUpdatePostId):
|
||||||
|
del recentPostsCache['json'][alsoUpdatePostId]
|
||||||
|
print('UNMUTE: ' +
|
||||||
|
alsoUpdatePostId + ' removed referenced json')
|
||||||
|
if recentPostsCache.get('html'):
|
||||||
|
if recentPostsCache['html'].get(alsoUpdatePostId):
|
||||||
|
del recentPostsCache['html'][alsoUpdatePostId]
|
||||||
|
print('UNMUTE: ' +
|
||||||
|
alsoUpdatePostId + ' removed referenced html')
|
||||||
|
|
||||||
|
|
||||||
def outboxMute(baseDir: str, httpPrefix: str,
|
def outboxMute(baseDir: str, httpPrefix: str,
|
||||||
|
|
@ -740,7 +825,10 @@ def setBrochMode(baseDir: str, domainFull: str, enabled: bool) -> None:
|
||||||
if not enabled:
|
if not enabled:
|
||||||
# remove instance allow list
|
# remove instance allow list
|
||||||
if os.path.isfile(allowFilename):
|
if os.path.isfile(allowFilename):
|
||||||
|
try:
|
||||||
os.remove(allowFilename)
|
os.remove(allowFilename)
|
||||||
|
except BaseException:
|
||||||
|
pass
|
||||||
print('Broch mode turned off')
|
print('Broch mode turned off')
|
||||||
else:
|
else:
|
||||||
if os.path.isfile(allowFilename):
|
if os.path.isfile(allowFilename):
|
||||||
|
|
@ -799,11 +887,14 @@ def brochModeLapses(baseDir: str, lapseDays: int = 7) -> bool:
|
||||||
currTime = datetime.datetime.utcnow()
|
currTime = datetime.datetime.utcnow()
|
||||||
daysSinceBroch = (currTime - modifiedDate).days
|
daysSinceBroch = (currTime - modifiedDate).days
|
||||||
if daysSinceBroch >= lapseDays:
|
if daysSinceBroch >= lapseDays:
|
||||||
|
removed = False
|
||||||
try:
|
try:
|
||||||
os.remove(allowFilename)
|
os.remove(allowFilename)
|
||||||
|
removed = True
|
||||||
|
except BaseException:
|
||||||
|
pass
|
||||||
|
if removed:
|
||||||
setConfigParam(baseDir, "brochMode", False)
|
setConfigParam(baseDir, "brochMode", False)
|
||||||
print('Broch mode has elapsed')
|
print('Broch mode has elapsed')
|
||||||
return True
|
return True
|
||||||
except BaseException:
|
|
||||||
pass
|
|
||||||
return False
|
return False
|
||||||
|
|
|
||||||
2
blog.py
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "ActivityPub"
|
__module_group__ = "ActivityPub"
|
||||||
|
|
||||||
|
|
|
||||||
36
bookmarks.py
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Timeline"
|
__module_group__ = "Timeline"
|
||||||
|
|
||||||
|
|
@ -47,7 +47,10 @@ def undoBookmarksCollectionEntry(recentPostsCache: {},
|
||||||
domain, postJsonObject)
|
domain, postJsonObject)
|
||||||
if cachedPostFilename:
|
if cachedPostFilename:
|
||||||
if os.path.isfile(cachedPostFilename):
|
if os.path.isfile(cachedPostFilename):
|
||||||
|
try:
|
||||||
os.remove(cachedPostFilename)
|
os.remove(cachedPostFilename)
|
||||||
|
except BaseException:
|
||||||
|
pass
|
||||||
removePostFromCache(postJsonObject, recentPostsCache)
|
removePostFromCache(postJsonObject, recentPostsCache)
|
||||||
|
|
||||||
# remove from the index
|
# remove from the index
|
||||||
|
|
@ -152,7 +155,10 @@ def updateBookmarksCollection(recentPostsCache: {},
|
||||||
domain, postJsonObject)
|
domain, postJsonObject)
|
||||||
if cachedPostFilename:
|
if cachedPostFilename:
|
||||||
if os.path.isfile(cachedPostFilename):
|
if os.path.isfile(cachedPostFilename):
|
||||||
|
try:
|
||||||
os.remove(cachedPostFilename)
|
os.remove(cachedPostFilename)
|
||||||
|
except BaseException:
|
||||||
|
pass
|
||||||
removePostFromCache(postJsonObject, recentPostsCache)
|
removePostFromCache(postJsonObject, recentPostsCache)
|
||||||
|
|
||||||
if not postJsonObject.get('object'):
|
if not postJsonObject.get('object'):
|
||||||
|
|
@ -348,7 +354,8 @@ def sendBookmarkViaServer(baseDir: str, session,
|
||||||
domain: str, fromPort: int,
|
domain: str, fromPort: int,
|
||||||
httpPrefix: str, bookmarkUrl: str,
|
httpPrefix: str, bookmarkUrl: str,
|
||||||
cachedWebfingers: {}, personCache: {},
|
cachedWebfingers: {}, personCache: {},
|
||||||
debug: bool, projectVersion: str) -> {}:
|
debug: bool, projectVersion: str,
|
||||||
|
signingPrivateKeyPem: str) -> {}:
|
||||||
"""Creates a bookmark via c2s
|
"""Creates a bookmark via c2s
|
||||||
"""
|
"""
|
||||||
if not session:
|
if not session:
|
||||||
|
|
@ -377,7 +384,8 @@ def sendBookmarkViaServer(baseDir: str, session,
|
||||||
# lookup the inbox for the To handle
|
# lookup the inbox for the To handle
|
||||||
wfRequest = webfingerHandle(session, handle, httpPrefix,
|
wfRequest = webfingerHandle(session, handle, httpPrefix,
|
||||||
cachedWebfingers,
|
cachedWebfingers,
|
||||||
domain, projectVersion, debug, False)
|
domain, projectVersion, debug, False,
|
||||||
|
signingPrivateKeyPem)
|
||||||
if not wfRequest:
|
if not wfRequest:
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: bookmark webfinger failed for ' + handle)
|
print('DEBUG: bookmark webfinger failed for ' + handle)
|
||||||
|
|
@ -390,12 +398,15 @@ def sendBookmarkViaServer(baseDir: str, session,
|
||||||
postToBox = 'outbox'
|
postToBox = 'outbox'
|
||||||
|
|
||||||
# get the actor inbox for the To handle
|
# get the actor inbox for the To handle
|
||||||
(inboxUrl, pubKeyId, pubKey, fromPersonId, sharedInbox,
|
originDomain = domain
|
||||||
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
(inboxUrl, pubKeyId, pubKey, fromPersonId, sharedInbox, avatarUrl,
|
||||||
|
displayName, _) = getPersonBox(signingPrivateKeyPem,
|
||||||
|
originDomain,
|
||||||
|
baseDir, session, wfRequest,
|
||||||
personCache,
|
personCache,
|
||||||
projectVersion, httpPrefix,
|
projectVersion, httpPrefix,
|
||||||
nickname, domain,
|
nickname, domain,
|
||||||
postToBox, 52594)
|
postToBox, 58391)
|
||||||
|
|
||||||
if not inboxUrl:
|
if not inboxUrl:
|
||||||
if debug:
|
if debug:
|
||||||
|
|
@ -433,7 +444,8 @@ def sendUndoBookmarkViaServer(baseDir: str, session,
|
||||||
domain: str, fromPort: int,
|
domain: str, fromPort: int,
|
||||||
httpPrefix: str, bookmarkUrl: str,
|
httpPrefix: str, bookmarkUrl: str,
|
||||||
cachedWebfingers: {}, personCache: {},
|
cachedWebfingers: {}, personCache: {},
|
||||||
debug: bool, projectVersion: str) -> {}:
|
debug: bool, projectVersion: str,
|
||||||
|
signingPrivateKeyPem: str) -> {}:
|
||||||
"""Removes a bookmark via c2s
|
"""Removes a bookmark via c2s
|
||||||
"""
|
"""
|
||||||
if not session:
|
if not session:
|
||||||
|
|
@ -462,7 +474,8 @@ def sendUndoBookmarkViaServer(baseDir: str, session,
|
||||||
# lookup the inbox for the To handle
|
# lookup the inbox for the To handle
|
||||||
wfRequest = webfingerHandle(session, handle, httpPrefix,
|
wfRequest = webfingerHandle(session, handle, httpPrefix,
|
||||||
cachedWebfingers,
|
cachedWebfingers,
|
||||||
domain, projectVersion, debug, False)
|
domain, projectVersion, debug, False,
|
||||||
|
signingPrivateKeyPem)
|
||||||
if not wfRequest:
|
if not wfRequest:
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: unbookmark webfinger failed for ' + handle)
|
print('DEBUG: unbookmark webfinger failed for ' + handle)
|
||||||
|
|
@ -475,8 +488,11 @@ def sendUndoBookmarkViaServer(baseDir: str, session,
|
||||||
postToBox = 'outbox'
|
postToBox = 'outbox'
|
||||||
|
|
||||||
# get the actor inbox for the To handle
|
# get the actor inbox for the To handle
|
||||||
(inboxUrl, pubKeyId, pubKey, fromPersonId, sharedInbox,
|
originDomain = domain
|
||||||
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
(inboxUrl, pubKeyId, pubKey, fromPersonId, sharedInbox, avatarUrl,
|
||||||
|
displayName, _) = getPersonBox(signingPrivateKeyPem,
|
||||||
|
originDomain,
|
||||||
|
baseDir, session, wfRequest,
|
||||||
personCache,
|
personCache,
|
||||||
projectVersion, httpPrefix,
|
projectVersion, httpPrefix,
|
||||||
nickname, domain,
|
nickname, domain,
|
||||||
|
|
|
||||||
2
briar.py
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Profile Metadata"
|
__module_group__ = "Profile Metadata"
|
||||||
|
|
||||||
|
|
|
||||||
8
cache.py
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Core"
|
__module_group__ = "Core"
|
||||||
|
|
||||||
|
|
@ -139,7 +139,8 @@ def getWebfingerFromCache(handle: str, cachedWebfingers: {}) -> {}:
|
||||||
def getPersonPubKey(baseDir: str, session, personUrl: str,
|
def getPersonPubKey(baseDir: str, session, personUrl: str,
|
||||||
personCache: {}, debug: bool,
|
personCache: {}, debug: bool,
|
||||||
projectVersion: str, httpPrefix: str,
|
projectVersion: str, httpPrefix: str,
|
||||||
domain: str, onionDomain: str) -> str:
|
domain: str, onionDomain: str,
|
||||||
|
signingPrivateKeyPem: str) -> str:
|
||||||
if not personUrl:
|
if not personUrl:
|
||||||
return None
|
return None
|
||||||
personUrl = personUrl.replace('#main-key', '')
|
personUrl = personUrl.replace('#main-key', '')
|
||||||
|
|
@ -165,7 +166,8 @@ def getPersonPubKey(baseDir: str, session, personUrl: str,
|
||||||
'Accept': 'application/activity+json; profile="' + profileStr + '"'
|
'Accept': 'application/activity+json; profile="' + profileStr + '"'
|
||||||
}
|
}
|
||||||
personJson = \
|
personJson = \
|
||||||
getJson(session, personUrl, asHeader, None, debug,
|
getJson(signingPrivateKeyPem,
|
||||||
|
session, personUrl, asHeader, None, debug,
|
||||||
projectVersion, httpPrefix, personDomain)
|
projectVersion, httpPrefix, personDomain)
|
||||||
if not personJson:
|
if not personJson:
|
||||||
return None
|
return None
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ example.com {
|
||||||
header / X-Download-Options "noopen"
|
header / X-Download-Options "noopen"
|
||||||
header / X-Frame-Options "DENY"
|
header / X-Frame-Options "DENY"
|
||||||
header / X-Permitted-Cross-Domain-Policies "none"
|
header / X-Permitted-Cross-Domain-Policies "none"
|
||||||
header / X-Robots-Tag "noindex,nofollow,nosnippet,noarchive"
|
header / X-Robots-Tag "noindex"
|
||||||
header / X-XSS-Protection "1; mode=block"
|
header / X-XSS-Protection "1; mode=block"
|
||||||
|
|
||||||
proxy / http://localhost:7156 {
|
proxy / http://localhost:7156 {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "RSS Feeds"
|
__module_group__ = "RSS Feeds"
|
||||||
|
|
||||||
|
|
@ -93,7 +93,10 @@ def updateHashtagCategories(baseDir: str) -> None:
|
||||||
hashtagCategories = getHashtagCategories(baseDir)
|
hashtagCategories = getHashtagCategories(baseDir)
|
||||||
if not hashtagCategories:
|
if not hashtagCategories:
|
||||||
if os.path.isfile(categoryListFilename):
|
if os.path.isfile(categoryListFilename):
|
||||||
|
try:
|
||||||
os.remove(categoryListFilename)
|
os.remove(categoryListFilename)
|
||||||
|
except BaseException:
|
||||||
|
pass
|
||||||
return
|
return
|
||||||
|
|
||||||
categoryList = []
|
categoryList = []
|
||||||
|
|
|
||||||
2
city.py
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Metadata"
|
__module_group__ = "Metadata"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ If you're raising concerns about something or someone, there must be demonstrabl
|
||||||
|
|
||||||
This is not a big project and so there is no division of labor or special enforcement committee or bureaucratic process.
|
This is not a big project and so there is no division of labor or special enforcement committee or bureaucratic process.
|
||||||
|
|
||||||
Complaints should be either reported in the Matrix chat room **#epicyon:matrix.freedombone.net** or sent to bob@freedombone.net, preferably via XMPP/Conversations with OMEMO enabled but you can also use the same address for email correspondence.
|
Complaints should be either reported in the Matrix chat room **#epicyon:matrix.libreserver.org** or sent to bob@libreserver.org, preferably via XMPP/Conversations with OMEMO enabled but you can also use the same address for email correspondence.
|
||||||
|
|
||||||
## In case of violations
|
## In case of violations
|
||||||
|
|
||||||
|
|
@ -60,6 +60,5 @@ Violators of this code of conduct will:
|
||||||
|
|
||||||
* Be removed from any associated Matrix and/or XMPP chat rooms
|
* Be removed from any associated Matrix and/or XMPP chat rooms
|
||||||
* Will not have pending or future patches or pull requests merged
|
* Will not have pending or future patches or pull requests merged
|
||||||
* If they have a user account on *code.freedombone.net* it will be removed
|
|
||||||
|
|
||||||
This applies regardless of past levels of commitment or technical abilities.
|
This applies regardless of past levels of commitment or technical abilities.
|
||||||
|
|
|
||||||
19
content.py
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Core"
|
__module_group__ = "Core"
|
||||||
|
|
||||||
|
|
@ -11,6 +11,7 @@ import os
|
||||||
import email.parser
|
import email.parser
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
from shutil import copyfile
|
from shutil import copyfile
|
||||||
|
from utils import dangerousSVG
|
||||||
from utils import removeDomainPort
|
from utils import removeDomainPort
|
||||||
from utils import isValidLanguage
|
from utils import isValidLanguage
|
||||||
from utils import getImageExtensions
|
from utils import getImageExtensions
|
||||||
|
|
@ -938,9 +939,15 @@ def saveMediaInFormPOST(mediaBytes, debug: bool,
|
||||||
for ex in extensionTypes:
|
for ex in extensionTypes:
|
||||||
possibleOtherFormat = filenameBase + '.' + ex
|
possibleOtherFormat = filenameBase + '.' + ex
|
||||||
if os.path.isfile(possibleOtherFormat):
|
if os.path.isfile(possibleOtherFormat):
|
||||||
|
try:
|
||||||
os.remove(possibleOtherFormat)
|
os.remove(possibleOtherFormat)
|
||||||
|
except BaseException:
|
||||||
|
pass
|
||||||
if os.path.isfile(filenameBase):
|
if os.path.isfile(filenameBase):
|
||||||
|
try:
|
||||||
os.remove(filenameBase)
|
os.remove(filenameBase)
|
||||||
|
except BaseException:
|
||||||
|
pass
|
||||||
|
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: No media found within POST')
|
print('DEBUG: No media found within POST')
|
||||||
|
|
@ -1006,7 +1013,17 @@ def saveMediaInFormPOST(mediaBytes, debug: bool,
|
||||||
detectedExtension, '.' +
|
detectedExtension, '.' +
|
||||||
ex)
|
ex)
|
||||||
if os.path.isfile(possibleOtherFormat):
|
if os.path.isfile(possibleOtherFormat):
|
||||||
|
try:
|
||||||
os.remove(possibleOtherFormat)
|
os.remove(possibleOtherFormat)
|
||||||
|
except BaseException:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# don't allow scripts within svg files
|
||||||
|
if detectedExtension == 'svg':
|
||||||
|
svgStr = mediaBytes[startPos:]
|
||||||
|
svgStr = svgStr.decode()
|
||||||
|
if dangerousSVG(svgStr, False):
|
||||||
|
return None, None
|
||||||
|
|
||||||
with open(filename, 'wb') as fp:
|
with open(filename, 'wb') as fp:
|
||||||
fp.write(mediaBytes[startPos:])
|
fp.write(mediaBytes[startPos:])
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Security"
|
__module_group__ = "Security"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,14 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Timeline"
|
__module_group__ = "Timeline"
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from utils import hasObjectDict
|
from utils import hasObjectDict
|
||||||
from utils import acctDir
|
from utils import acctDir
|
||||||
|
from utils import removeIdEnding
|
||||||
|
|
||||||
|
|
||||||
def updateConversation(baseDir: str, nickname: str, domain: str,
|
def updateConversation(baseDir: str, nickname: str, domain: str,
|
||||||
|
|
@ -27,7 +28,7 @@ def updateConversation(baseDir: str, nickname: str, domain: str,
|
||||||
os.mkdir(conversationDir)
|
os.mkdir(conversationDir)
|
||||||
conversationId = postJsonObject['object']['conversation']
|
conversationId = postJsonObject['object']['conversation']
|
||||||
conversationId = conversationId.replace('/', '#')
|
conversationId = conversationId.replace('/', '#')
|
||||||
postId = postJsonObject['object']['id']
|
postId = removeIdEnding(postJsonObject['object']['id'])
|
||||||
conversationFilename = conversationDir + '/' + conversationId
|
conversationFilename = conversationDir + '/' + conversationId
|
||||||
if not os.path.isfile(conversationFilename):
|
if not os.path.isfile(conversationFilename):
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
2
cwtch.py
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Profile Metadata"
|
__module_group__ = "Profile Metadata"
|
||||||
|
|
||||||
|
|
|
||||||
12
delete.py
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "ActivityPub"
|
__module_group__ = "ActivityPub"
|
||||||
|
|
||||||
|
|
@ -30,7 +30,8 @@ def sendDeleteViaServer(baseDir: str, session,
|
||||||
fromDomain: str, fromPort: int,
|
fromDomain: str, fromPort: int,
|
||||||
httpPrefix: str, deleteObjectUrl: str,
|
httpPrefix: str, deleteObjectUrl: str,
|
||||||
cachedWebfingers: {}, personCache: {},
|
cachedWebfingers: {}, personCache: {},
|
||||||
debug: bool, projectVersion: str) -> {}:
|
debug: bool, projectVersion: str,
|
||||||
|
signingPrivateKeyPem: str) -> {}:
|
||||||
"""Creates a delete request message via c2s
|
"""Creates a delete request message via c2s
|
||||||
"""
|
"""
|
||||||
if not session:
|
if not session:
|
||||||
|
|
@ -57,7 +58,8 @@ def sendDeleteViaServer(baseDir: str, session,
|
||||||
# lookup the inbox for the To handle
|
# lookup the inbox for the To handle
|
||||||
wfRequest = \
|
wfRequest = \
|
||||||
webfingerHandle(session, handle, httpPrefix, cachedWebfingers,
|
webfingerHandle(session, handle, httpPrefix, cachedWebfingers,
|
||||||
fromDomain, projectVersion, debug, False)
|
fromDomain, projectVersion, debug, False,
|
||||||
|
signingPrivateKeyPem)
|
||||||
if not wfRequest:
|
if not wfRequest:
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: delete webfinger failed for ' + handle)
|
print('DEBUG: delete webfinger failed for ' + handle)
|
||||||
|
|
@ -70,9 +72,11 @@ def sendDeleteViaServer(baseDir: str, session,
|
||||||
postToBox = 'outbox'
|
postToBox = 'outbox'
|
||||||
|
|
||||||
# get the actor inbox for the To handle
|
# get the actor inbox for the To handle
|
||||||
|
originDomain = fromDomain
|
||||||
(inboxUrl, pubKeyId, pubKey,
|
(inboxUrl, pubKeyId, pubKey,
|
||||||
fromPersonId, sharedInbox, avatarUrl,
|
fromPersonId, sharedInbox, avatarUrl,
|
||||||
displayName) = getPersonBox(baseDir, session, wfRequest, personCache,
|
displayName, _) = getPersonBox(signingPrivateKeyPem, originDomain,
|
||||||
|
baseDir, session, wfRequest, personCache,
|
||||||
projectVersion, httpPrefix, fromNickname,
|
projectVersion, httpPrefix, fromNickname,
|
||||||
fromDomain, postToBox, 53036)
|
fromDomain, postToBox, 53036)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Client"
|
__module_group__ = "Client"
|
||||||
|
|
||||||
|
|
@ -418,7 +418,8 @@ def _desktopReplyToPost(session, postId: str,
|
||||||
debug: bool, subject: str,
|
debug: bool, subject: str,
|
||||||
screenreader: str, systemLanguage: str,
|
screenreader: str, systemLanguage: str,
|
||||||
espeak, conversationId: str,
|
espeak, conversationId: str,
|
||||||
lowBandwidth: bool) -> None:
|
lowBandwidth: bool,
|
||||||
|
signingPrivateKeyPem: str) -> None:
|
||||||
"""Use the desktop client to send a reply to the most recent post
|
"""Use the desktop client to send a reply to the most recent post
|
||||||
"""
|
"""
|
||||||
if '://' not in postId:
|
if '://' not in postId:
|
||||||
|
|
@ -463,7 +464,7 @@ def _desktopReplyToPost(session, postId: str,
|
||||||
city = 'London, England'
|
city = 'London, England'
|
||||||
sayStr = 'Sending reply'
|
sayStr = 'Sending reply'
|
||||||
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
|
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
|
||||||
if sendPostViaServer(__version__,
|
if sendPostViaServer(signingPrivateKeyPem, __version__,
|
||||||
baseDir, session, nickname, password,
|
baseDir, session, nickname, password,
|
||||||
domain, port,
|
domain, port,
|
||||||
toNickname, toDomain, toPort, ccUrl,
|
toNickname, toDomain, toPort, ccUrl,
|
||||||
|
|
@ -486,7 +487,8 @@ def _desktopNewPost(session,
|
||||||
cachedWebfingers: {}, personCache: {},
|
cachedWebfingers: {}, personCache: {},
|
||||||
debug: bool,
|
debug: bool,
|
||||||
screenreader: str, systemLanguage: str,
|
screenreader: str, systemLanguage: str,
|
||||||
espeak, lowBandwidth: bool) -> None:
|
espeak, lowBandwidth: bool,
|
||||||
|
signingPrivateKeyPem: str) -> None:
|
||||||
"""Use the desktop client to create a new post
|
"""Use the desktop client to create a new post
|
||||||
"""
|
"""
|
||||||
conversationId = None
|
conversationId = None
|
||||||
|
|
@ -527,7 +529,7 @@ def _desktopNewPost(session,
|
||||||
subject = None
|
subject = None
|
||||||
sayStr = 'Sending'
|
sayStr = 'Sending'
|
||||||
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
|
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
|
||||||
if sendPostViaServer(__version__,
|
if sendPostViaServer(signingPrivateKeyPem, __version__,
|
||||||
baseDir, session, nickname, password,
|
baseDir, session, nickname, password,
|
||||||
domain, port,
|
domain, port,
|
||||||
None, '#Public', port, ccUrl,
|
None, '#Public', port, ccUrl,
|
||||||
|
|
@ -661,7 +663,9 @@ def _readLocalBoxPost(session, nickname: str, domain: str,
|
||||||
systemLanguage: str,
|
systemLanguage: str,
|
||||||
screenreader: str, espeak,
|
screenreader: str, espeak,
|
||||||
translate: {}, yourActor: str,
|
translate: {}, yourActor: str,
|
||||||
domainFull: str, personCache: {}) -> {}:
|
domainFull: str, personCache: {},
|
||||||
|
signingPrivateKeyPem: str,
|
||||||
|
blockedCache: {}) -> {}:
|
||||||
"""Reads a post from the given timeline
|
"""Reads a post from the given timeline
|
||||||
Returns the post json
|
Returns the post json
|
||||||
"""
|
"""
|
||||||
|
|
@ -688,6 +692,7 @@ def _readLocalBoxPost(session, nickname: str, domain: str,
|
||||||
recentPostsCache = {}
|
recentPostsCache = {}
|
||||||
allowLocalNetworkAccess = False
|
allowLocalNetworkAccess = False
|
||||||
YTReplacementDomain = None
|
YTReplacementDomain = None
|
||||||
|
twitterReplacementDomain = None
|
||||||
postJsonObject2 = \
|
postJsonObject2 = \
|
||||||
downloadAnnounce(session, baseDir,
|
downloadAnnounce(session, baseDir,
|
||||||
httpPrefix,
|
httpPrefix,
|
||||||
|
|
@ -695,10 +700,13 @@ def _readLocalBoxPost(session, nickname: str, domain: str,
|
||||||
postJsonObject,
|
postJsonObject,
|
||||||
__version__, translate,
|
__version__, translate,
|
||||||
YTReplacementDomain,
|
YTReplacementDomain,
|
||||||
|
twitterReplacementDomain,
|
||||||
allowLocalNetworkAccess,
|
allowLocalNetworkAccess,
|
||||||
recentPostsCache, False,
|
recentPostsCache, False,
|
||||||
systemLanguage,
|
systemLanguage,
|
||||||
domainFull, personCache)
|
domainFull, personCache,
|
||||||
|
signingPrivateKeyPem,
|
||||||
|
blockedCache)
|
||||||
if postJsonObject2:
|
if postJsonObject2:
|
||||||
if hasObjectDict(postJsonObject2):
|
if hasObjectDict(postJsonObject2):
|
||||||
if postJsonObject2['object'].get('attributedTo') and \
|
if postJsonObject2['object'].get('attributedTo') and \
|
||||||
|
|
@ -742,7 +750,7 @@ def _readLocalBoxPost(session, nickname: str, domain: str,
|
||||||
if isPGPEncrypted(content):
|
if isPGPEncrypted(content):
|
||||||
sayStr = 'Encrypted message. Please enter your passphrase.'
|
sayStr = 'Encrypted message. Please enter your passphrase.'
|
||||||
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
|
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
|
||||||
content = pgpDecrypt(domain, content, actor)
|
content = pgpDecrypt(domain, content, actor, signingPrivateKeyPem)
|
||||||
if isPGPEncrypted(content):
|
if isPGPEncrypted(content):
|
||||||
sayStr = 'Message could not be decrypted'
|
sayStr = 'Message could not be decrypted'
|
||||||
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
|
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
|
||||||
|
|
@ -823,7 +831,7 @@ def _desktopShowProfile(session, nickname: str, domain: str,
|
||||||
systemLanguage: str,
|
systemLanguage: str,
|
||||||
screenreader: str, espeak,
|
screenreader: str, espeak,
|
||||||
translate: {}, yourActor: str,
|
translate: {}, yourActor: str,
|
||||||
postJsonObject: {}) -> {}:
|
postJsonObject: {}, signingPrivateKeyPem: str) -> {}:
|
||||||
"""Shows the profile of the actor for the given post
|
"""Shows the profile of the actor for the given post
|
||||||
Returns the actor json
|
Returns the actor json
|
||||||
"""
|
"""
|
||||||
|
|
@ -854,7 +862,8 @@ def _desktopShowProfile(session, nickname: str, domain: str,
|
||||||
if 'http://' in actor:
|
if 'http://' in actor:
|
||||||
isHttp = True
|
isHttp = True
|
||||||
actorJson, asHeader = \
|
actorJson, asHeader = \
|
||||||
getActorJson(domain, actor, isHttp, False, False, True)
|
getActorJson(domain, actor, isHttp, False, False, True,
|
||||||
|
signingPrivateKeyPem)
|
||||||
|
|
||||||
_desktopShowActor(baseDir, actorJson, translate,
|
_desktopShowActor(baseDir, actorJson, translate,
|
||||||
systemLanguage, screenreader, espeak)
|
systemLanguage, screenreader, espeak)
|
||||||
|
|
@ -868,12 +877,14 @@ def _desktopShowProfileFromHandle(session, nickname: str, domain: str,
|
||||||
systemLanguage: str,
|
systemLanguage: str,
|
||||||
screenreader: str, espeak,
|
screenreader: str, espeak,
|
||||||
translate: {}, yourActor: str,
|
translate: {}, yourActor: str,
|
||||||
postJsonObject: {}) -> {}:
|
postJsonObject: {},
|
||||||
|
signingPrivateKeyPem: str) -> {}:
|
||||||
"""Shows the profile for a handle
|
"""Shows the profile for a handle
|
||||||
Returns the actor json
|
Returns the actor json
|
||||||
"""
|
"""
|
||||||
actorJson, asHeader = \
|
actorJson, asHeader = \
|
||||||
getActorJson(domain, handle, False, False, False, True)
|
getActorJson(domain, handle, False, False, False, True,
|
||||||
|
signingPrivateKeyPem)
|
||||||
|
|
||||||
_desktopShowActor(baseDir, actorJson, translate,
|
_desktopShowActor(baseDir, actorJson, translate,
|
||||||
systemLanguage, screenreader, espeak)
|
systemLanguage, screenreader, espeak)
|
||||||
|
|
@ -1112,7 +1123,8 @@ def _desktopNewDM(session, toHandle: str,
|
||||||
cachedWebfingers: {}, personCache: {},
|
cachedWebfingers: {}, personCache: {},
|
||||||
debug: bool,
|
debug: bool,
|
||||||
screenreader: str, systemLanguage: str,
|
screenreader: str, systemLanguage: str,
|
||||||
espeak, lowBandwidth: bool) -> None:
|
espeak, lowBandwidth: bool,
|
||||||
|
signingPrivateKeyPem: str) -> None:
|
||||||
"""Use the desktop client to create a new direct message
|
"""Use the desktop client to create a new direct message
|
||||||
which can include multiple destination handles
|
which can include multiple destination handles
|
||||||
"""
|
"""
|
||||||
|
|
@ -1133,7 +1145,8 @@ def _desktopNewDM(session, toHandle: str,
|
||||||
cachedWebfingers, personCache,
|
cachedWebfingers, personCache,
|
||||||
debug,
|
debug,
|
||||||
screenreader, systemLanguage,
|
screenreader, systemLanguage,
|
||||||
espeak, lowBandwidth)
|
espeak, lowBandwidth,
|
||||||
|
signingPrivateKeyPem)
|
||||||
|
|
||||||
|
|
||||||
def _desktopNewDMbase(session, toHandle: str,
|
def _desktopNewDMbase(session, toHandle: str,
|
||||||
|
|
@ -1142,7 +1155,8 @@ def _desktopNewDMbase(session, toHandle: str,
|
||||||
cachedWebfingers: {}, personCache: {},
|
cachedWebfingers: {}, personCache: {},
|
||||||
debug: bool,
|
debug: bool,
|
||||||
screenreader: str, systemLanguage: str,
|
screenreader: str, systemLanguage: str,
|
||||||
espeak, lowBandwidth: bool) -> None:
|
espeak, lowBandwidth: bool,
|
||||||
|
signingPrivateKeyPem: str) -> None:
|
||||||
"""Use the desktop client to create a new direct message
|
"""Use the desktop client to create a new direct message
|
||||||
"""
|
"""
|
||||||
conversationId = None
|
conversationId = None
|
||||||
|
|
@ -1201,7 +1215,8 @@ def _desktopNewDMbase(session, toHandle: str,
|
||||||
for after in range(randint(1, 16)):
|
for after in range(randint(1, 16)):
|
||||||
paddedMessage += ' '
|
paddedMessage += ' '
|
||||||
cipherText = \
|
cipherText = \
|
||||||
pgpEncryptToActor(domain, paddedMessage, toHandle)
|
pgpEncryptToActor(domain, paddedMessage, toHandle,
|
||||||
|
signingPrivateKeyPem)
|
||||||
if not cipherText:
|
if not cipherText:
|
||||||
sayStr = \
|
sayStr = \
|
||||||
toHandle + ' has no PGP public key. ' + \
|
toHandle + ' has no PGP public key. ' + \
|
||||||
|
|
@ -1222,7 +1237,7 @@ def _desktopNewDMbase(session, toHandle: str,
|
||||||
|
|
||||||
sayStr = 'Sending'
|
sayStr = 'Sending'
|
||||||
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
|
_sayCommand(sayStr, sayStr, screenreader, systemLanguage, espeak)
|
||||||
if sendPostViaServer(__version__,
|
if sendPostViaServer(signingPrivateKeyPem, __version__,
|
||||||
baseDir, session, nickname, password,
|
baseDir, session, nickname, password,
|
||||||
domain, port,
|
domain, port,
|
||||||
toNickname, toDomain, toPort, ccUrl,
|
toNickname, toDomain, toPort, ccUrl,
|
||||||
|
|
@ -1301,6 +1316,11 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
|
||||||
"""Runs the desktop and screen reader client,
|
"""Runs the desktop and screen reader client,
|
||||||
which announces new inbox items
|
which announces new inbox items
|
||||||
"""
|
"""
|
||||||
|
# TODO: this should probably be retrieved somehow from the server
|
||||||
|
signingPrivateKeyPem = None
|
||||||
|
|
||||||
|
blockedCache = {}
|
||||||
|
|
||||||
indent = ' '
|
indent = ' '
|
||||||
if showNewPosts:
|
if showNewPosts:
|
||||||
indent = ''
|
indent = ''
|
||||||
|
|
@ -1400,7 +1420,8 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
|
||||||
nickname, password,
|
nickname, password,
|
||||||
domain, port, httpPrefix,
|
domain, port, httpPrefix,
|
||||||
cachedWebfingers, personCache,
|
cachedWebfingers, personCache,
|
||||||
debug, False)
|
debug, False,
|
||||||
|
signingPrivateKeyPem)
|
||||||
sayStr = indent + 'PGP public key uploaded'
|
sayStr = indent + 'PGP public key uploaded'
|
||||||
_sayCommand(sayStr, sayStr, screenreader,
|
_sayCommand(sayStr, sayStr, screenreader,
|
||||||
systemLanguage, espeak)
|
systemLanguage, espeak)
|
||||||
|
|
@ -1410,7 +1431,7 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
|
||||||
nickname, password,
|
nickname, password,
|
||||||
domain, port, httpPrefix,
|
domain, port, httpPrefix,
|
||||||
currTimeline, pageNumber,
|
currTimeline, pageNumber,
|
||||||
debug)
|
debug, signingPrivateKeyPem)
|
||||||
|
|
||||||
followRequestsJson = \
|
followRequestsJson = \
|
||||||
getFollowRequestsViaServer(baseDir, session,
|
getFollowRequestsViaServer(baseDir, session,
|
||||||
|
|
@ -1418,14 +1439,16 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
|
||||||
domain, port,
|
domain, port,
|
||||||
httpPrefix, 1,
|
httpPrefix, 1,
|
||||||
cachedWebfingers, personCache,
|
cachedWebfingers, personCache,
|
||||||
debug, __version__)
|
debug, __version__,
|
||||||
|
signingPrivateKeyPem)
|
||||||
|
|
||||||
if not (currTimeline == 'inbox' and pageNumber == 1):
|
if not (currTimeline == 'inbox' and pageNumber == 1):
|
||||||
# monitor the inbox to generate notifications
|
# monitor the inbox to generate notifications
|
||||||
inboxJson = c2sBoxJson(baseDir, session,
|
inboxJson = c2sBoxJson(baseDir, session,
|
||||||
nickname, password,
|
nickname, password,
|
||||||
domain, port, httpPrefix,
|
domain, port, httpPrefix,
|
||||||
'inbox', 1, debug)
|
'inbox', 1, debug,
|
||||||
|
signingPrivateKeyPem)
|
||||||
else:
|
else:
|
||||||
inboxJson = boxJson
|
inboxJson = boxJson
|
||||||
newDMsExist = False
|
newDMsExist = False
|
||||||
|
|
@ -1502,7 +1525,7 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
|
||||||
nickname, password,
|
nickname, password,
|
||||||
domain, port, httpPrefix,
|
domain, port, httpPrefix,
|
||||||
currTimeline, pageNumber,
|
currTimeline, pageNumber,
|
||||||
debug)
|
debug, signingPrivateKeyPem)
|
||||||
if boxJson:
|
if boxJson:
|
||||||
_desktopShowBox(indent, followRequestsJson,
|
_desktopShowBox(indent, followRequestsJson,
|
||||||
yourActor, currTimeline, boxJson,
|
yourActor, currTimeline, boxJson,
|
||||||
|
|
@ -1519,7 +1542,7 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
|
||||||
nickname, password,
|
nickname, password,
|
||||||
domain, port, httpPrefix,
|
domain, port, httpPrefix,
|
||||||
currTimeline, pageNumber,
|
currTimeline, pageNumber,
|
||||||
debug)
|
debug, signingPrivateKeyPem)
|
||||||
if boxJson:
|
if boxJson:
|
||||||
_desktopShowBox(indent, followRequestsJson,
|
_desktopShowBox(indent, followRequestsJson,
|
||||||
yourActor, currTimeline, boxJson,
|
yourActor, currTimeline, boxJson,
|
||||||
|
|
@ -1537,7 +1560,7 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
|
||||||
nickname, password,
|
nickname, password,
|
||||||
domain, port, httpPrefix,
|
domain, port, httpPrefix,
|
||||||
currTimeline, pageNumber,
|
currTimeline, pageNumber,
|
||||||
debug)
|
debug, signingPrivateKeyPem)
|
||||||
if boxJson:
|
if boxJson:
|
||||||
_desktopShowBox(indent, followRequestsJson,
|
_desktopShowBox(indent, followRequestsJson,
|
||||||
yourActor, currTimeline, boxJson,
|
yourActor, currTimeline, boxJson,
|
||||||
|
|
@ -1556,7 +1579,7 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
|
||||||
nickname, password,
|
nickname, password,
|
||||||
domain, port, httpPrefix,
|
domain, port, httpPrefix,
|
||||||
currTimeline, pageNumber,
|
currTimeline, pageNumber,
|
||||||
debug)
|
debug, signingPrivateKeyPem)
|
||||||
if boxJson:
|
if boxJson:
|
||||||
_desktopShowBox(indent, followRequestsJson,
|
_desktopShowBox(indent, followRequestsJson,
|
||||||
yourActor, currTimeline, boxJson,
|
yourActor, currTimeline, boxJson,
|
||||||
|
|
@ -1583,7 +1606,7 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
|
||||||
nickname, password,
|
nickname, password,
|
||||||
domain, port, httpPrefix,
|
domain, port, httpPrefix,
|
||||||
currTimeline, pageNumber,
|
currTimeline, pageNumber,
|
||||||
debug)
|
debug, signingPrivateKeyPem)
|
||||||
if boxJson:
|
if boxJson:
|
||||||
_desktopShowBox(indent, followRequestsJson,
|
_desktopShowBox(indent, followRequestsJson,
|
||||||
yourActor, currTimeline, boxJson,
|
yourActor, currTimeline, boxJson,
|
||||||
|
|
@ -1606,7 +1629,9 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
|
||||||
pageNumber, postIndex, boxJson,
|
pageNumber, postIndex, boxJson,
|
||||||
systemLanguage, screenreader,
|
systemLanguage, screenreader,
|
||||||
espeak, translate, yourActor,
|
espeak, translate, yourActor,
|
||||||
domainFull, personCache)
|
domainFull, personCache,
|
||||||
|
signingPrivateKeyPem,
|
||||||
|
blockedCache)
|
||||||
print('')
|
print('')
|
||||||
sayStr = 'Press Enter to continue...'
|
sayStr = 'Press Enter to continue...'
|
||||||
sayStr2 = _highlightText(sayStr)
|
sayStr2 = _highlightText(sayStr)
|
||||||
|
|
@ -1628,7 +1653,8 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
|
||||||
boxJson,
|
boxJson,
|
||||||
systemLanguage, screenreader,
|
systemLanguage, screenreader,
|
||||||
espeak, translate, yourActor,
|
espeak, translate, yourActor,
|
||||||
postJsonObject)
|
postJsonObject,
|
||||||
|
signingPrivateKeyPem)
|
||||||
else:
|
else:
|
||||||
postIndexStr = '1'
|
postIndexStr = '1'
|
||||||
else:
|
else:
|
||||||
|
|
@ -1643,7 +1669,7 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
|
||||||
currTimeline, profileHandle,
|
currTimeline, profileHandle,
|
||||||
systemLanguage, screenreader,
|
systemLanguage, screenreader,
|
||||||
espeak, translate, yourActor,
|
espeak, translate, yourActor,
|
||||||
None)
|
None, signingPrivateKeyPem)
|
||||||
sayStr = 'Press Enter to continue...'
|
sayStr = 'Press Enter to continue...'
|
||||||
sayStr2 = _highlightText(sayStr)
|
sayStr2 = _highlightText(sayStr)
|
||||||
_sayCommand(sayStr2, sayStr,
|
_sayCommand(sayStr2, sayStr,
|
||||||
|
|
@ -1661,7 +1687,7 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
|
||||||
pageNumber, postIndex, boxJson,
|
pageNumber, postIndex, boxJson,
|
||||||
systemLanguage, screenreader,
|
systemLanguage, screenreader,
|
||||||
espeak, translate, yourActor,
|
espeak, translate, yourActor,
|
||||||
None)
|
None, signingPrivateKeyPem)
|
||||||
sayStr = 'Press Enter to continue...'
|
sayStr = 'Press Enter to continue...'
|
||||||
sayStr2 = _highlightText(sayStr)
|
sayStr2 = _highlightText(sayStr)
|
||||||
_sayCommand(sayStr2, sayStr,
|
_sayCommand(sayStr2, sayStr,
|
||||||
|
|
@ -1689,7 +1715,8 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
|
||||||
debug, subject,
|
debug, subject,
|
||||||
screenreader, systemLanguage,
|
screenreader, systemLanguage,
|
||||||
espeak, conversationId,
|
espeak, conversationId,
|
||||||
lowBandwidth)
|
lowBandwidth,
|
||||||
|
signingPrivateKeyPem)
|
||||||
refreshTimeline = True
|
refreshTimeline = True
|
||||||
print('')
|
print('')
|
||||||
elif (commandStr == 'post' or commandStr == 'p' or
|
elif (commandStr == 'post' or commandStr == 'p' or
|
||||||
|
|
@ -1723,7 +1750,8 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
|
||||||
cachedWebfingers, personCache,
|
cachedWebfingers, personCache,
|
||||||
debug,
|
debug,
|
||||||
screenreader, systemLanguage,
|
screenreader, systemLanguage,
|
||||||
espeak, lowBandwidth)
|
espeak, lowBandwidth,
|
||||||
|
signingPrivateKeyPem)
|
||||||
refreshTimeline = True
|
refreshTimeline = True
|
||||||
else:
|
else:
|
||||||
# public post
|
# public post
|
||||||
|
|
@ -1733,7 +1761,8 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
|
||||||
cachedWebfingers, personCache,
|
cachedWebfingers, personCache,
|
||||||
debug,
|
debug,
|
||||||
screenreader, systemLanguage,
|
screenreader, systemLanguage,
|
||||||
espeak, lowBandwidth)
|
espeak, lowBandwidth,
|
||||||
|
signingPrivateKeyPem)
|
||||||
refreshTimeline = True
|
refreshTimeline = True
|
||||||
print('')
|
print('')
|
||||||
elif commandStr == 'like' or commandStr.startswith('like '):
|
elif commandStr == 'like' or commandStr.startswith('like '):
|
||||||
|
|
@ -1759,7 +1788,8 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
|
||||||
domain, port, httpPrefix,
|
domain, port, httpPrefix,
|
||||||
postJsonObject['id'],
|
postJsonObject['id'],
|
||||||
cachedWebfingers, personCache,
|
cachedWebfingers, personCache,
|
||||||
False, __version__)
|
False, __version__,
|
||||||
|
signingPrivateKeyPem)
|
||||||
refreshTimeline = True
|
refreshTimeline = True
|
||||||
print('')
|
print('')
|
||||||
elif (commandStr == 'undo mute' or
|
elif (commandStr == 'undo mute' or
|
||||||
|
|
@ -1797,7 +1827,8 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
|
||||||
domain, port,
|
domain, port,
|
||||||
httpPrefix, postJsonObject['id'],
|
httpPrefix, postJsonObject['id'],
|
||||||
cachedWebfingers, personCache,
|
cachedWebfingers, personCache,
|
||||||
False, __version__)
|
False, __version__,
|
||||||
|
signingPrivateKeyPem)
|
||||||
refreshTimeline = True
|
refreshTimeline = True
|
||||||
print('')
|
print('')
|
||||||
elif (commandStr == 'mute' or
|
elif (commandStr == 'mute' or
|
||||||
|
|
@ -1826,7 +1857,8 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
|
||||||
domain, port,
|
domain, port,
|
||||||
httpPrefix, postJsonObject['id'],
|
httpPrefix, postJsonObject['id'],
|
||||||
cachedWebfingers, personCache,
|
cachedWebfingers, personCache,
|
||||||
False, __version__)
|
False, __version__,
|
||||||
|
signingPrivateKeyPem)
|
||||||
refreshTimeline = True
|
refreshTimeline = True
|
||||||
print('')
|
print('')
|
||||||
elif (commandStr == 'undo bookmark' or
|
elif (commandStr == 'undo bookmark' or
|
||||||
|
|
@ -1867,7 +1899,8 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
|
||||||
postJsonObject['id'],
|
postJsonObject['id'],
|
||||||
cachedWebfingers,
|
cachedWebfingers,
|
||||||
personCache,
|
personCache,
|
||||||
False, __version__)
|
False, __version__,
|
||||||
|
signingPrivateKeyPem)
|
||||||
refreshTimeline = True
|
refreshTimeline = True
|
||||||
print('')
|
print('')
|
||||||
elif (commandStr == 'bookmark' or
|
elif (commandStr == 'bookmark' or
|
||||||
|
|
@ -1896,7 +1929,8 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
|
||||||
domain, port, httpPrefix,
|
domain, port, httpPrefix,
|
||||||
postJsonObject['id'],
|
postJsonObject['id'],
|
||||||
cachedWebfingers, personCache,
|
cachedWebfingers, personCache,
|
||||||
False, __version__)
|
False, __version__,
|
||||||
|
signingPrivateKeyPem)
|
||||||
refreshTimeline = True
|
refreshTimeline = True
|
||||||
print('')
|
print('')
|
||||||
elif (commandStr.startswith('undo block ') or
|
elif (commandStr.startswith('undo block ') or
|
||||||
|
|
@ -1931,7 +1965,8 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
|
||||||
blockActor,
|
blockActor,
|
||||||
cachedWebfingers,
|
cachedWebfingers,
|
||||||
personCache,
|
personCache,
|
||||||
False, __version__)
|
False, __version__,
|
||||||
|
signingPrivateKeyPem)
|
||||||
refreshTimeline = True
|
refreshTimeline = True
|
||||||
print('')
|
print('')
|
||||||
elif commandStr.startswith('block '):
|
elif commandStr.startswith('block '):
|
||||||
|
|
@ -1976,7 +2011,8 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
|
||||||
blockActor,
|
blockActor,
|
||||||
cachedWebfingers,
|
cachedWebfingers,
|
||||||
personCache,
|
personCache,
|
||||||
False, __version__)
|
False, __version__,
|
||||||
|
signingPrivateKeyPem)
|
||||||
refreshTimeline = True
|
refreshTimeline = True
|
||||||
print('')
|
print('')
|
||||||
elif commandStr == 'unlike' or commandStr == 'undo like':
|
elif commandStr == 'unlike' or commandStr == 'undo like':
|
||||||
|
|
@ -2003,7 +2039,8 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
|
||||||
domain, port, httpPrefix,
|
domain, port, httpPrefix,
|
||||||
postJsonObject['id'],
|
postJsonObject['id'],
|
||||||
cachedWebfingers, personCache,
|
cachedWebfingers, personCache,
|
||||||
False, __version__)
|
False, __version__,
|
||||||
|
signingPrivateKeyPem)
|
||||||
refreshTimeline = True
|
refreshTimeline = True
|
||||||
print('')
|
print('')
|
||||||
elif (commandStr.startswith('announce') or
|
elif (commandStr.startswith('announce') or
|
||||||
|
|
@ -2033,7 +2070,8 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
|
||||||
domain, port,
|
domain, port,
|
||||||
httpPrefix, postId,
|
httpPrefix, postId,
|
||||||
cachedWebfingers, personCache,
|
cachedWebfingers, personCache,
|
||||||
True, __version__)
|
True, __version__,
|
||||||
|
signingPrivateKeyPem)
|
||||||
refreshTimeline = True
|
refreshTimeline = True
|
||||||
print('')
|
print('')
|
||||||
elif (commandStr.startswith('unannounce') or
|
elif (commandStr.startswith('unannounce') or
|
||||||
|
|
@ -2067,7 +2105,8 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
|
||||||
httpPrefix, postId,
|
httpPrefix, postId,
|
||||||
cachedWebfingers,
|
cachedWebfingers,
|
||||||
personCache,
|
personCache,
|
||||||
True, __version__)
|
True, __version__,
|
||||||
|
signingPrivateKeyPem)
|
||||||
refreshTimeline = True
|
refreshTimeline = True
|
||||||
print('')
|
print('')
|
||||||
elif (commandStr == 'follow requests' or
|
elif (commandStr == 'follow requests' or
|
||||||
|
|
@ -2083,7 +2122,8 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
|
||||||
domain, port,
|
domain, port,
|
||||||
httpPrefix, currPage,
|
httpPrefix, currPage,
|
||||||
cachedWebfingers, personCache,
|
cachedWebfingers, personCache,
|
||||||
debug, __version__)
|
debug, __version__,
|
||||||
|
signingPrivateKeyPem)
|
||||||
if followRequestsJson:
|
if followRequestsJson:
|
||||||
if isinstance(followRequestsJson, dict):
|
if isinstance(followRequestsJson, dict):
|
||||||
_desktopShowFollowRequests(followRequestsJson,
|
_desktopShowFollowRequests(followRequestsJson,
|
||||||
|
|
@ -2102,7 +2142,8 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
|
||||||
domain, port,
|
domain, port,
|
||||||
httpPrefix, currPage,
|
httpPrefix, currPage,
|
||||||
cachedWebfingers, personCache,
|
cachedWebfingers, personCache,
|
||||||
debug, __version__)
|
debug, __version__,
|
||||||
|
signingPrivateKeyPem)
|
||||||
if followingJson:
|
if followingJson:
|
||||||
if isinstance(followingJson, dict):
|
if isinstance(followingJson, dict):
|
||||||
_desktopShowFollowing(followingJson, translate,
|
_desktopShowFollowing(followingJson, translate,
|
||||||
|
|
@ -2122,7 +2163,8 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
|
||||||
domain, port,
|
domain, port,
|
||||||
httpPrefix, currPage,
|
httpPrefix, currPage,
|
||||||
cachedWebfingers, personCache,
|
cachedWebfingers, personCache,
|
||||||
debug, __version__)
|
debug, __version__,
|
||||||
|
signingPrivateKeyPem)
|
||||||
if followersJson:
|
if followersJson:
|
||||||
if isinstance(followersJson, dict):
|
if isinstance(followersJson, dict):
|
||||||
_desktopShowFollowing(followersJson, translate,
|
_desktopShowFollowing(followersJson, translate,
|
||||||
|
|
@ -2161,7 +2203,8 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
|
||||||
httpPrefix,
|
httpPrefix,
|
||||||
cachedWebfingers,
|
cachedWebfingers,
|
||||||
personCache,
|
personCache,
|
||||||
debug, __version__)
|
debug, __version__,
|
||||||
|
signingPrivateKeyPem)
|
||||||
else:
|
else:
|
||||||
if followHandle:
|
if followHandle:
|
||||||
sayStr = followHandle + ' is not valid'
|
sayStr = followHandle + ' is not valid'
|
||||||
|
|
@ -2195,7 +2238,8 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
|
||||||
httpPrefix,
|
httpPrefix,
|
||||||
cachedWebfingers,
|
cachedWebfingers,
|
||||||
personCache,
|
personCache,
|
||||||
debug, __version__)
|
debug, __version__,
|
||||||
|
signingPrivateKeyPem)
|
||||||
else:
|
else:
|
||||||
sayStr = followHandle + ' is not valid'
|
sayStr = followHandle + ' is not valid'
|
||||||
_sayCommand(sayStr, sayStr,
|
_sayCommand(sayStr, sayStr,
|
||||||
|
|
@ -2224,7 +2268,8 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
|
||||||
cachedWebfingers,
|
cachedWebfingers,
|
||||||
personCache,
|
personCache,
|
||||||
debug,
|
debug,
|
||||||
__version__)
|
__version__,
|
||||||
|
signingPrivateKeyPem)
|
||||||
else:
|
else:
|
||||||
if approveHandle:
|
if approveHandle:
|
||||||
sayStr = approveHandle + ' is not valid'
|
sayStr = approveHandle + ' is not valid'
|
||||||
|
|
@ -2256,7 +2301,8 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
|
||||||
cachedWebfingers,
|
cachedWebfingers,
|
||||||
personCache,
|
personCache,
|
||||||
debug,
|
debug,
|
||||||
__version__)
|
__version__,
|
||||||
|
signingPrivateKeyPem)
|
||||||
else:
|
else:
|
||||||
if denyHandle:
|
if denyHandle:
|
||||||
sayStr = denyHandle + ' is not valid'
|
sayStr = denyHandle + ' is not valid'
|
||||||
|
|
@ -2331,6 +2377,7 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
|
||||||
recentPostsCache = {}
|
recentPostsCache = {}
|
||||||
allowLocalNetworkAccess = False
|
allowLocalNetworkAccess = False
|
||||||
YTReplacementDomain = None
|
YTReplacementDomain = None
|
||||||
|
twitterReplacementDomain = None
|
||||||
postJsonObject2 = \
|
postJsonObject2 = \
|
||||||
downloadAnnounce(session, baseDir,
|
downloadAnnounce(session, baseDir,
|
||||||
httpPrefix,
|
httpPrefix,
|
||||||
|
|
@ -2338,10 +2385,13 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
|
||||||
postJsonObject,
|
postJsonObject,
|
||||||
__version__, translate,
|
__version__, translate,
|
||||||
YTReplacementDomain,
|
YTReplacementDomain,
|
||||||
|
twitterReplacementDomain,
|
||||||
allowLocalNetworkAccess,
|
allowLocalNetworkAccess,
|
||||||
recentPostsCache, False,
|
recentPostsCache, False,
|
||||||
systemLanguage,
|
systemLanguage,
|
||||||
domainFull, personCache)
|
domainFull, personCache,
|
||||||
|
signingPrivateKeyPem,
|
||||||
|
blockedCache)
|
||||||
if postJsonObject2:
|
if postJsonObject2:
|
||||||
postJsonObject = postJsonObject2
|
postJsonObject = postJsonObject2
|
||||||
if postJsonObject:
|
if postJsonObject:
|
||||||
|
|
@ -2423,7 +2473,8 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
|
||||||
postJsonObject['id'],
|
postJsonObject['id'],
|
||||||
cachedWebfingers,
|
cachedWebfingers,
|
||||||
personCache,
|
personCache,
|
||||||
False, __version__)
|
False, __version__,
|
||||||
|
signingPrivateKeyPem)
|
||||||
refreshTimeline = True
|
refreshTimeline = True
|
||||||
print('')
|
print('')
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Security"
|
__module_group__ = "Security"
|
||||||
|
|
||||||
|
|
@ -44,7 +44,10 @@ def E2EEremoveDevice(baseDir: str, nickname: str, domain: str,
|
||||||
personDir = acctDir(baseDir, nickname, domain)
|
personDir = acctDir(baseDir, nickname, domain)
|
||||||
deviceFilename = personDir + '/devices/' + deviceId + '.json'
|
deviceFilename = personDir + '/devices/' + deviceId + '.json'
|
||||||
if os.path.isfile(deviceFilename):
|
if os.path.isfile(deviceFilename):
|
||||||
|
try:
|
||||||
os.remove(deviceFilename)
|
os.remove(deviceFilename)
|
||||||
|
except BaseException:
|
||||||
|
pass
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Profile Metadata"
|
__module_group__ = "Profile Metadata"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -769,5 +769,6 @@
|
||||||
"void": "void",
|
"void": "void",
|
||||||
"openbsd": "openbsd",
|
"openbsd": "openbsd",
|
||||||
"freebsd": "freebsd",
|
"freebsd": "freebsd",
|
||||||
"orgmode": "orgmode"
|
"orgmode": "orgmode",
|
||||||
|
"kde": "kde"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
After Width: | Height: | Size: 17 KiB |
|
|
@ -201,6 +201,13 @@ figure {
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mark {
|
||||||
|
background-color: var(--main-bg-color);
|
||||||
|
color: var(--main-fg-color);
|
||||||
|
font-size: 130%;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
.accesskeys {
|
.accesskeys {
|
||||||
border: 0;
|
border: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
@ -1383,6 +1390,26 @@ div.container {
|
||||||
margin-bottom: var(--button-bottom-margin);
|
margin-bottom: var(--button-bottom-margin);
|
||||||
margin-left: var(--button-left-margin);
|
margin-left: var(--button-left-margin);
|
||||||
}
|
}
|
||||||
|
.contactbutton {
|
||||||
|
border-radius: var(--button-corner-radius);
|
||||||
|
background-color: var(--button-background);
|
||||||
|
color: var(--button-text);
|
||||||
|
text-align: center;
|
||||||
|
font-size: var(--font-size-header);
|
||||||
|
font-family: var(--header-font);
|
||||||
|
padding: var(--button-height-padding);
|
||||||
|
width: 20%;
|
||||||
|
margin: var(--button-margin);
|
||||||
|
min-width: var(--button-width-chars);
|
||||||
|
transition: all 0.5s;
|
||||||
|
cursor: pointer;
|
||||||
|
border-top: var(--tab-border-width) solid var(--tab-border-color);
|
||||||
|
border-bottom: none;
|
||||||
|
border-left: var(--tab-border-width) solid var(--tab-border-color);
|
||||||
|
border-right: var(--tab-border-width) solid var(--tab-border-color);
|
||||||
|
margin-bottom: var(--button-bottom-margin);
|
||||||
|
margin-left: var(--button-left-margin);
|
||||||
|
}
|
||||||
.buttonDesktop {
|
.buttonDesktop {
|
||||||
border-radius: var(--button-corner-radius);
|
border-radius: var(--button-corner-radius);
|
||||||
background-color: var(--button-background);
|
background-color: var(--button-background);
|
||||||
|
|
@ -1667,6 +1694,8 @@ div.container {
|
||||||
.columnIcons img {
|
.columnIcons img {
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
|
.pageslist {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (min-width: 2200px) {
|
@media screen and (min-width: 2200px) {
|
||||||
|
|
@ -2017,6 +2046,25 @@ div.container {
|
||||||
border-right: var(--tab-border-width) solid var(--tab-border-color);
|
border-right: var(--tab-border-width) solid var(--tab-border-color);
|
||||||
margin-bottom: var(--button-bottom-margin);
|
margin-bottom: var(--button-bottom-margin);
|
||||||
}
|
}
|
||||||
|
.contactbutton {
|
||||||
|
border-radius: var(--button-corner-radius);
|
||||||
|
background-color: var(--button-background);
|
||||||
|
color: var(--button-text);
|
||||||
|
text-align: center;
|
||||||
|
font-size: var(--font-size-button-mobile);
|
||||||
|
font-family: var(--header-font);
|
||||||
|
padding: var(--button-height-padding-mobile);
|
||||||
|
width: 30%;
|
||||||
|
min-width: var(--button-width-chars);
|
||||||
|
transition: all 0.5s;
|
||||||
|
cursor: pointer;
|
||||||
|
margin: var(--button-margin);
|
||||||
|
border-top: var(--tab-border-width) solid var(--tab-border-color);
|
||||||
|
border-bottom: none;
|
||||||
|
border-left: var(--tab-border-width) solid var(--tab-border-color);
|
||||||
|
border-right: var(--tab-border-width) solid var(--tab-border-color);
|
||||||
|
margin-bottom: var(--button-bottom-margin);
|
||||||
|
}
|
||||||
.frontPageMobileButtons{
|
.frontPageMobileButtons{
|
||||||
display: block;
|
display: block;
|
||||||
border: var(--border-width-header) solid var(--border-color);
|
border: var(--border-width-header) solid var(--border-color);
|
||||||
|
|
@ -2323,4 +2371,6 @@ div.container {
|
||||||
float: right;
|
float: right;
|
||||||
margin-right: 1vw;
|
margin-right: 1vw;
|
||||||
}
|
}
|
||||||
|
.pageslist {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
333
epicyon.py
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Commandline Interface"
|
__module_group__ = "Commandline Interface"
|
||||||
|
|
||||||
|
|
@ -25,6 +25,7 @@ from roles import setRole
|
||||||
from webfinger import webfingerHandle
|
from webfinger import webfingerHandle
|
||||||
from bookmarks import sendBookmarkViaServer
|
from bookmarks import sendBookmarkViaServer
|
||||||
from bookmarks import sendUndoBookmarkViaServer
|
from bookmarks import sendUndoBookmarkViaServer
|
||||||
|
from posts import getInstanceActorKey
|
||||||
from posts import sendMuteViaServer
|
from posts import sendMuteViaServer
|
||||||
from posts import sendUndoMuteViaServer
|
from posts import sendUndoMuteViaServer
|
||||||
from posts import c2sBoxJson
|
from posts import c2sBoxJson
|
||||||
|
|
@ -169,6 +170,11 @@ parser.add_argument('--dormantMonths',
|
||||||
default=3,
|
default=3,
|
||||||
help='How many months does a followed account need to ' +
|
help='How many months does a followed account need to ' +
|
||||||
'be unseen for before being considered dormant')
|
'be unseen for before being considered dormant')
|
||||||
|
parser.add_argument('--defaultReplyIntervalHours',
|
||||||
|
dest='defaultReplyIntervalHours', type=int,
|
||||||
|
default=1000,
|
||||||
|
help='How many hours after publication of a post ' +
|
||||||
|
'are replies to it permitted')
|
||||||
parser.add_argument('--sendThreadsTimeoutMins',
|
parser.add_argument('--sendThreadsTimeoutMins',
|
||||||
dest='sendThreadsTimeoutMins', type=int,
|
dest='sendThreadsTimeoutMins', type=int,
|
||||||
default=30,
|
default=30,
|
||||||
|
|
@ -217,6 +223,9 @@ parser.add_argument('--path', dest='baseDir',
|
||||||
parser.add_argument('--ytdomain', dest='YTReplacementDomain',
|
parser.add_argument('--ytdomain', dest='YTReplacementDomain',
|
||||||
type=str, default=None,
|
type=str, default=None,
|
||||||
help='Domain used to replace youtube.com')
|
help='Domain used to replace youtube.com')
|
||||||
|
parser.add_argument('--twitterdomain', dest='twitterReplacementDomain',
|
||||||
|
type=str, default=None,
|
||||||
|
help='Domain used to replace twitter.com')
|
||||||
parser.add_argument('--language', dest='language',
|
parser.add_argument('--language', dest='language',
|
||||||
type=str, default=None,
|
type=str, default=None,
|
||||||
help='Language code, eg. en/fr/de/es')
|
help='Language code, eg. en/fr/de/es')
|
||||||
|
|
@ -406,10 +415,11 @@ parser.add_argument("--debug", type=str2bool, nargs='?',
|
||||||
parser.add_argument("--notificationSounds", type=str2bool, nargs='?',
|
parser.add_argument("--notificationSounds", type=str2bool, nargs='?',
|
||||||
const=True, default=True,
|
const=True, default=True,
|
||||||
help="Play notification sounds")
|
help="Play notification sounds")
|
||||||
parser.add_argument("--authenticatedFetch", type=str2bool, nargs='?',
|
parser.add_argument("--secureMode", type=str2bool, nargs='?',
|
||||||
const=True, default=False,
|
const=True, default=False,
|
||||||
help="Enable authentication on GET requests" +
|
help="Requires all GET requests to be signed, " +
|
||||||
" for json (authenticated fetch)")
|
"so that the sender can be identifies and " +
|
||||||
|
"blocked if neccessary")
|
||||||
parser.add_argument("--instanceOnlySkillsSearch", type=str2bool, nargs='?',
|
parser.add_argument("--instanceOnlySkillsSearch", type=str2bool, nargs='?',
|
||||||
const=True, default=False,
|
const=True, default=False,
|
||||||
help="Skills searches only return " +
|
help="Skills searches only return " +
|
||||||
|
|
@ -633,12 +643,13 @@ if args.tests:
|
||||||
sys.exit()
|
sys.exit()
|
||||||
if args.testsnetwork:
|
if args.testsnetwork:
|
||||||
print('Network Tests')
|
print('Network Tests')
|
||||||
testSharedItemsFederation()
|
baseDir = os.getcwd()
|
||||||
testGroupFollow()
|
testSharedItemsFederation(baseDir)
|
||||||
testPostMessageBetweenServers()
|
testGroupFollow(baseDir)
|
||||||
testFollowBetweenServers()
|
testPostMessageBetweenServers(baseDir)
|
||||||
testClientToServer()
|
testFollowBetweenServers(baseDir)
|
||||||
testUpdateActor()
|
testClientToServer(baseDir)
|
||||||
|
testUpdateActor(baseDir)
|
||||||
print('All tests succeeded')
|
print('All tests succeeded')
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
|
|
@ -662,6 +673,12 @@ if args.libretranslateApiKey:
|
||||||
setConfigParam(baseDir, 'libretranslateApiKey', args.libretranslateApiKey)
|
setConfigParam(baseDir, 'libretranslateApiKey', args.libretranslateApiKey)
|
||||||
|
|
||||||
if args.posts:
|
if args.posts:
|
||||||
|
if not args.domain:
|
||||||
|
originDomain = getConfigParam(baseDir, 'domain')
|
||||||
|
else:
|
||||||
|
originDomain = args.domain
|
||||||
|
if debug:
|
||||||
|
print('originDomain: ' + str(originDomain))
|
||||||
if '@' not in args.posts:
|
if '@' not in args.posts:
|
||||||
if '/users/' in args.posts:
|
if '/users/' in args.posts:
|
||||||
postsNickname = getNicknameFromActor(args.posts)
|
postsNickname = getNicknameFromActor(args.posts)
|
||||||
|
|
@ -688,9 +705,11 @@ if args.posts:
|
||||||
proxyType = 'gnunet'
|
proxyType = 'gnunet'
|
||||||
if not args.language:
|
if not args.language:
|
||||||
args.language = 'en'
|
args.language = 'en'
|
||||||
|
signingPrivateKeyPem = getInstanceActorKey(baseDir, originDomain)
|
||||||
getPublicPostsOfPerson(baseDir, nickname, domain, False, True,
|
getPublicPostsOfPerson(baseDir, nickname, domain, False, True,
|
||||||
proxyType, args.port, httpPrefix, debug,
|
proxyType, args.port, httpPrefix, debug,
|
||||||
__version__, args.language)
|
__version__, args.language,
|
||||||
|
signingPrivateKeyPem, originDomain)
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
if args.postDomains:
|
if args.postDomains:
|
||||||
|
|
@ -722,13 +741,22 @@ if args.postDomains:
|
||||||
domainList = []
|
domainList = []
|
||||||
if not args.language:
|
if not args.language:
|
||||||
args.language = 'en'
|
args.language = 'en'
|
||||||
|
signingPrivateKeyPem = None
|
||||||
|
if not args.domain:
|
||||||
|
originDomain = getConfigParam(baseDir, 'domain')
|
||||||
|
else:
|
||||||
|
originDomain = args.domain
|
||||||
|
if args.secureMode:
|
||||||
|
signingPrivateKeyPem = getInstanceActorKey(baseDir, originDomain)
|
||||||
domainList = getPublicPostDomains(None,
|
domainList = getPublicPostDomains(None,
|
||||||
baseDir, nickname, domain,
|
baseDir, nickname, domain,
|
||||||
|
originDomain,
|
||||||
proxyType, args.port,
|
proxyType, args.port,
|
||||||
httpPrefix, debug,
|
httpPrefix, debug,
|
||||||
__version__,
|
__version__,
|
||||||
wordFrequency, domainList,
|
wordFrequency, domainList,
|
||||||
args.language)
|
args.language,
|
||||||
|
signingPrivateKeyPem)
|
||||||
for postDomain in domainList:
|
for postDomain in domainList:
|
||||||
print(postDomain)
|
print(postDomain)
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
@ -765,13 +793,17 @@ if args.postDomainsBlocked:
|
||||||
domainList = []
|
domainList = []
|
||||||
if not args.language:
|
if not args.language:
|
||||||
args.language = 'en'
|
args.language = 'en'
|
||||||
|
signingPrivateKeyPem = None
|
||||||
|
if args.secureMode:
|
||||||
|
signingPrivateKeyPem = getInstanceActorKey(baseDir, domain)
|
||||||
domainList = getPublicPostDomainsBlocked(None,
|
domainList = getPublicPostDomainsBlocked(None,
|
||||||
baseDir, nickname, domain,
|
baseDir, nickname, domain,
|
||||||
proxyType, args.port,
|
proxyType, args.port,
|
||||||
httpPrefix, debug,
|
httpPrefix, debug,
|
||||||
__version__,
|
__version__,
|
||||||
wordFrequency, domainList,
|
wordFrequency, domainList,
|
||||||
args.language)
|
args.language,
|
||||||
|
signingPrivateKeyPem)
|
||||||
for postDomain in domainList:
|
for postDomain in domainList:
|
||||||
print(postDomain)
|
print(postDomain)
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
@ -806,12 +838,16 @@ if args.checkDomains:
|
||||||
maxBlockedDomains = 0
|
maxBlockedDomains = 0
|
||||||
if not args.language:
|
if not args.language:
|
||||||
args.language = 'en'
|
args.language = 'en'
|
||||||
|
signingPrivateKeyPem = None
|
||||||
|
if args.secureMode:
|
||||||
|
signingPrivateKeyPem = getInstanceActorKey(baseDir, domain)
|
||||||
checkDomains(None,
|
checkDomains(None,
|
||||||
baseDir, nickname, domain,
|
baseDir, nickname, domain,
|
||||||
proxyType, args.port,
|
proxyType, args.port,
|
||||||
httpPrefix, debug,
|
httpPrefix, debug,
|
||||||
__version__,
|
__version__,
|
||||||
maxBlockedDomains, False, args.language)
|
maxBlockedDomains, False, args.language,
|
||||||
|
signingPrivateKeyPem)
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
if args.socnet:
|
if args.socnet:
|
||||||
|
|
@ -825,10 +861,19 @@ if args.socnet:
|
||||||
proxyType = 'tor'
|
proxyType = 'tor'
|
||||||
if not args.language:
|
if not args.language:
|
||||||
args.language = 'en'
|
args.language = 'en'
|
||||||
|
if not args.domain:
|
||||||
|
args.domain = getConfigParam(baseDir, 'domain')
|
||||||
|
domain = ''
|
||||||
|
if args.domain:
|
||||||
|
domain = args.domain
|
||||||
|
signingPrivateKeyPem = None
|
||||||
|
if args.secureMode:
|
||||||
|
signingPrivateKeyPem = getInstanceActorKey(baseDir, domain)
|
||||||
dotGraph = instancesGraph(baseDir, args.socnet,
|
dotGraph = instancesGraph(baseDir, args.socnet,
|
||||||
proxyType, args.port,
|
proxyType, args.port,
|
||||||
httpPrefix, debug,
|
httpPrefix, debug,
|
||||||
__version__, args.language)
|
__version__, args.language,
|
||||||
|
signingPrivateKeyPem)
|
||||||
try:
|
try:
|
||||||
with open('socnet.dot', 'w+') as fp:
|
with open('socnet.dot', 'w+') as fp:
|
||||||
fp.write(dotGraph)
|
fp.write(dotGraph)
|
||||||
|
|
@ -838,6 +883,12 @@ if args.socnet:
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
if args.postsraw:
|
if args.postsraw:
|
||||||
|
if not args.domain:
|
||||||
|
originDomain = getConfigParam(baseDir, 'domain')
|
||||||
|
else:
|
||||||
|
originDomain = args.domain
|
||||||
|
if debug:
|
||||||
|
print('originDomain: ' + str(originDomain))
|
||||||
if '@' not in args.postsraw:
|
if '@' not in args.postsraw:
|
||||||
print('Syntax: --postsraw nickname@domain')
|
print('Syntax: --postsraw nickname@domain')
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
@ -854,9 +905,11 @@ if args.postsraw:
|
||||||
proxyType = 'gnunet'
|
proxyType = 'gnunet'
|
||||||
if not args.language:
|
if not args.language:
|
||||||
args.language = 'en'
|
args.language = 'en'
|
||||||
|
signingPrivateKeyPem = getInstanceActorKey(baseDir, originDomain)
|
||||||
getPublicPostsOfPerson(baseDir, nickname, domain, False, False,
|
getPublicPostsOfPerson(baseDir, nickname, domain, False, False,
|
||||||
proxyType, args.port, httpPrefix, debug,
|
proxyType, args.port, httpPrefix, debug,
|
||||||
__version__, args.language)
|
__version__, args.language,
|
||||||
|
signingPrivateKeyPem, originDomain)
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
if args.json:
|
if args.json:
|
||||||
|
|
@ -865,8 +918,20 @@ if args.json:
|
||||||
asHeader = {
|
asHeader = {
|
||||||
'Accept': 'application/ld+json; profile="' + profileStr + '"'
|
'Accept': 'application/ld+json; profile="' + profileStr + '"'
|
||||||
}
|
}
|
||||||
testJson = getJson(session, args.json, asHeader, None,
|
if not args.domain:
|
||||||
debug, __version__, httpPrefix, None)
|
args.domain = getConfigParam(baseDir, 'domain')
|
||||||
|
domain = ''
|
||||||
|
if args.domain:
|
||||||
|
domain = args.domain
|
||||||
|
signingPrivateKeyPem = getInstanceActorKey(baseDir, domain)
|
||||||
|
if debug:
|
||||||
|
print('baseDir: ' + str(baseDir))
|
||||||
|
if signingPrivateKeyPem:
|
||||||
|
print('Obtained instance actor signing key')
|
||||||
|
else:
|
||||||
|
print('Did not obtain instance actor key for ' + domain)
|
||||||
|
testJson = getJson(signingPrivateKeyPem, session, args.json, asHeader,
|
||||||
|
None, debug, __version__, httpPrefix, domain)
|
||||||
pprint(testJson)
|
pprint(testJson)
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
|
|
@ -1075,6 +1140,11 @@ if args.approve:
|
||||||
postLog = []
|
postLog = []
|
||||||
cachedWebfingers = {}
|
cachedWebfingers = {}
|
||||||
personCache = {}
|
personCache = {}
|
||||||
|
if not domain:
|
||||||
|
domain = getConfigParam(baseDir, 'domain')
|
||||||
|
signingPrivateKeyPem = None
|
||||||
|
if args.secureMode:
|
||||||
|
signingPrivateKeyPem = getInstanceActorKey(baseDir, domain)
|
||||||
manualApproveFollowRequest(session, baseDir,
|
manualApproveFollowRequest(session, baseDir,
|
||||||
httpPrefix,
|
httpPrefix,
|
||||||
args.nickname, domain, port,
|
args.nickname, domain, port,
|
||||||
|
|
@ -1082,7 +1152,8 @@ if args.approve:
|
||||||
federationList,
|
federationList,
|
||||||
sendThreads, postLog,
|
sendThreads, postLog,
|
||||||
cachedWebfingers, personCache,
|
cachedWebfingers, personCache,
|
||||||
debug, __version__)
|
debug, __version__,
|
||||||
|
signingPrivateKeyPem)
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
if args.deny:
|
if args.deny:
|
||||||
|
|
@ -1097,6 +1168,11 @@ if args.deny:
|
||||||
postLog = []
|
postLog = []
|
||||||
cachedWebfingers = {}
|
cachedWebfingers = {}
|
||||||
personCache = {}
|
personCache = {}
|
||||||
|
if not domain:
|
||||||
|
domain = getConfigParam(baseDir, 'domain')
|
||||||
|
signingPrivateKeyPem = None
|
||||||
|
if args.secureMode:
|
||||||
|
signingPrivateKeyPem = getInstanceActorKey(baseDir, domain)
|
||||||
manualDenyFollowRequest(session, baseDir,
|
manualDenyFollowRequest(session, baseDir,
|
||||||
httpPrefix,
|
httpPrefix,
|
||||||
args.nickname, domain, port,
|
args.nickname, domain, port,
|
||||||
|
|
@ -1104,7 +1180,8 @@ if args.deny:
|
||||||
federationList,
|
federationList,
|
||||||
sendThreads, postLog,
|
sendThreads, postLog,
|
||||||
cachedWebfingers, personCache,
|
cachedWebfingers, personCache,
|
||||||
debug, __version__)
|
debug, __version__,
|
||||||
|
signingPrivateKeyPem)
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
if args.followerspending:
|
if args.followerspending:
|
||||||
|
|
@ -1184,9 +1261,14 @@ if args.message:
|
||||||
replyTo = args.replyto
|
replyTo = args.replyto
|
||||||
followersOnly = False
|
followersOnly = False
|
||||||
isArticle = False
|
isArticle = False
|
||||||
|
if not domain:
|
||||||
|
domain = getConfigParam(baseDir, 'domain')
|
||||||
|
signingPrivateKeyPem = None
|
||||||
|
if args.secureMode:
|
||||||
|
signingPrivateKeyPem = getInstanceActorKey(baseDir, domain)
|
||||||
print('Sending post to ' + args.sendto)
|
print('Sending post to ' + args.sendto)
|
||||||
|
|
||||||
sendPostViaServer(__version__,
|
sendPostViaServer(signingPrivateKeyPem, __version__,
|
||||||
baseDir, session, args.nickname, args.password,
|
baseDir, session, args.nickname, args.password,
|
||||||
domain, port,
|
domain, port,
|
||||||
toNickname, toDomain, toPort, ccUrl,
|
toNickname, toDomain, toPort, ccUrl,
|
||||||
|
|
@ -1216,13 +1298,18 @@ if args.announce:
|
||||||
session = createSession(proxyType)
|
session = createSession(proxyType)
|
||||||
personCache = {}
|
personCache = {}
|
||||||
cachedWebfingers = {}
|
cachedWebfingers = {}
|
||||||
|
if not domain:
|
||||||
|
domain = getConfigParam(baseDir, 'domain')
|
||||||
|
signingPrivateKeyPem = None
|
||||||
|
if args.secureMode:
|
||||||
|
signingPrivateKeyPem = getInstanceActorKey(baseDir, domain)
|
||||||
print('Sending announce/repeat of ' + args.announce)
|
print('Sending announce/repeat of ' + args.announce)
|
||||||
|
|
||||||
sendAnnounceViaServer(baseDir, session, args.nickname, args.password,
|
sendAnnounceViaServer(baseDir, session, args.nickname, args.password,
|
||||||
domain, port,
|
domain, port,
|
||||||
httpPrefix, args.announce,
|
httpPrefix, args.announce,
|
||||||
cachedWebfingers, personCache,
|
cachedWebfingers, personCache,
|
||||||
True, __version__)
|
True, __version__, signingPrivateKeyPem)
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
# TODO detect send success/fail
|
# TODO detect send success/fail
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
@ -1255,13 +1342,18 @@ if args.box:
|
||||||
args.port = 80
|
args.port = 80
|
||||||
elif args.gnunet:
|
elif args.gnunet:
|
||||||
proxyType = 'gnunet'
|
proxyType = 'gnunet'
|
||||||
|
if not domain:
|
||||||
|
domain = getConfigParam(baseDir, 'domain')
|
||||||
|
signingPrivateKeyPem = None
|
||||||
|
if args.secureMode:
|
||||||
|
signingPrivateKeyPem = getInstanceActorKey(baseDir, domain)
|
||||||
|
|
||||||
session = createSession(proxyType)
|
session = createSession(proxyType)
|
||||||
boxJson = c2sBoxJson(baseDir, session,
|
boxJson = c2sBoxJson(baseDir, session,
|
||||||
args.nickname, args.password,
|
args.nickname, args.password,
|
||||||
domain, port, httpPrefix,
|
domain, port, httpPrefix,
|
||||||
args.box, args.pageNumber,
|
args.box, args.pageNumber,
|
||||||
args.debug)
|
args.debug, signingPrivateKeyPem)
|
||||||
if boxJson:
|
if boxJson:
|
||||||
pprint(boxJson)
|
pprint(boxJson)
|
||||||
else:
|
else:
|
||||||
|
|
@ -1311,6 +1403,11 @@ if args.itemName:
|
||||||
session = createSession(proxyType)
|
session = createSession(proxyType)
|
||||||
personCache = {}
|
personCache = {}
|
||||||
cachedWebfingers = {}
|
cachedWebfingers = {}
|
||||||
|
if not domain:
|
||||||
|
domain = getConfigParam(baseDir, 'domain')
|
||||||
|
signingPrivateKeyPem = None
|
||||||
|
if args.secureMode:
|
||||||
|
signingPrivateKeyPem = getInstanceActorKey(baseDir, domain)
|
||||||
print('Sending shared item: ' + args.itemName)
|
print('Sending shared item: ' + args.itemName)
|
||||||
|
|
||||||
sendShareViaServer(baseDir, session,
|
sendShareViaServer(baseDir, session,
|
||||||
|
|
@ -1327,7 +1424,8 @@ if args.itemName:
|
||||||
args.duration,
|
args.duration,
|
||||||
cachedWebfingers, personCache,
|
cachedWebfingers, personCache,
|
||||||
debug, __version__,
|
debug, __version__,
|
||||||
args.itemPrice, args.itemCurrency)
|
args.itemPrice, args.itemCurrency,
|
||||||
|
signingPrivateKeyPem)
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
# TODO detect send success/fail
|
# TODO detect send success/fail
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
@ -1348,6 +1446,11 @@ if args.undoItemName:
|
||||||
session = createSession(proxyType)
|
session = createSession(proxyType)
|
||||||
personCache = {}
|
personCache = {}
|
||||||
cachedWebfingers = {}
|
cachedWebfingers = {}
|
||||||
|
if not domain:
|
||||||
|
domain = getConfigParam(baseDir, 'domain')
|
||||||
|
signingPrivateKeyPem = None
|
||||||
|
if args.secureMode:
|
||||||
|
signingPrivateKeyPem = getInstanceActorKey(baseDir, domain)
|
||||||
print('Sending undo of shared item: ' + args.undoItemName)
|
print('Sending undo of shared item: ' + args.undoItemName)
|
||||||
|
|
||||||
sendUndoShareViaServer(baseDir, session,
|
sendUndoShareViaServer(baseDir, session,
|
||||||
|
|
@ -1356,7 +1459,7 @@ if args.undoItemName:
|
||||||
httpPrefix,
|
httpPrefix,
|
||||||
args.undoItemName,
|
args.undoItemName,
|
||||||
cachedWebfingers, personCache,
|
cachedWebfingers, personCache,
|
||||||
debug, __version__)
|
debug, __version__, signingPrivateKeyPem)
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
# TODO detect send success/fail
|
# TODO detect send success/fail
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
@ -1405,6 +1508,11 @@ if args.wantedItemName:
|
||||||
session = createSession(proxyType)
|
session = createSession(proxyType)
|
||||||
personCache = {}
|
personCache = {}
|
||||||
cachedWebfingers = {}
|
cachedWebfingers = {}
|
||||||
|
if not domain:
|
||||||
|
domain = getConfigParam(baseDir, 'domain')
|
||||||
|
signingPrivateKeyPem = None
|
||||||
|
if args.secureMode:
|
||||||
|
signingPrivateKeyPem = getInstanceActorKey(baseDir, domain)
|
||||||
print('Sending wanted item: ' + args.wantedItemName)
|
print('Sending wanted item: ' + args.wantedItemName)
|
||||||
|
|
||||||
sendWantedViaServer(baseDir, session,
|
sendWantedViaServer(baseDir, session,
|
||||||
|
|
@ -1421,7 +1529,8 @@ if args.wantedItemName:
|
||||||
args.duration,
|
args.duration,
|
||||||
cachedWebfingers, personCache,
|
cachedWebfingers, personCache,
|
||||||
debug, __version__,
|
debug, __version__,
|
||||||
args.itemPrice, args.itemCurrency)
|
args.itemPrice, args.itemCurrency,
|
||||||
|
signingPrivateKeyPem)
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
# TODO detect send success/fail
|
# TODO detect send success/fail
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
@ -1442,6 +1551,11 @@ if args.undoWantedItemName:
|
||||||
session = createSession(proxyType)
|
session = createSession(proxyType)
|
||||||
personCache = {}
|
personCache = {}
|
||||||
cachedWebfingers = {}
|
cachedWebfingers = {}
|
||||||
|
if not domain:
|
||||||
|
domain = getConfigParam(baseDir, 'domain')
|
||||||
|
signingPrivateKeyPem = None
|
||||||
|
if args.secureMode:
|
||||||
|
signingPrivateKeyPem = getInstanceActorKey(baseDir, domain)
|
||||||
print('Sending undo of wanted item: ' + args.undoWantedItemName)
|
print('Sending undo of wanted item: ' + args.undoWantedItemName)
|
||||||
|
|
||||||
sendUndoWantedViaServer(baseDir, session,
|
sendUndoWantedViaServer(baseDir, session,
|
||||||
|
|
@ -1450,7 +1564,7 @@ if args.undoWantedItemName:
|
||||||
httpPrefix,
|
httpPrefix,
|
||||||
args.undoWantedItemName,
|
args.undoWantedItemName,
|
||||||
cachedWebfingers, personCache,
|
cachedWebfingers, personCache,
|
||||||
debug, __version__)
|
debug, __version__, signingPrivateKeyPem)
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
# TODO detect send success/fail
|
# TODO detect send success/fail
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
@ -1471,6 +1585,11 @@ if args.like:
|
||||||
session = createSession(proxyType)
|
session = createSession(proxyType)
|
||||||
personCache = {}
|
personCache = {}
|
||||||
cachedWebfingers = {}
|
cachedWebfingers = {}
|
||||||
|
if not domain:
|
||||||
|
domain = getConfigParam(baseDir, 'domain')
|
||||||
|
signingPrivateKeyPem = None
|
||||||
|
if args.secureMode:
|
||||||
|
signingPrivateKeyPem = getInstanceActorKey(baseDir, domain)
|
||||||
print('Sending like of ' + args.like)
|
print('Sending like of ' + args.like)
|
||||||
|
|
||||||
sendLikeViaServer(baseDir, session,
|
sendLikeViaServer(baseDir, session,
|
||||||
|
|
@ -1478,7 +1597,7 @@ if args.like:
|
||||||
domain, port,
|
domain, port,
|
||||||
httpPrefix, args.like,
|
httpPrefix, args.like,
|
||||||
cachedWebfingers, personCache,
|
cachedWebfingers, personCache,
|
||||||
True, __version__)
|
True, __version__, signingPrivateKeyPem)
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
# TODO detect send success/fail
|
# TODO detect send success/fail
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
@ -1499,6 +1618,11 @@ if args.undolike:
|
||||||
session = createSession(proxyType)
|
session = createSession(proxyType)
|
||||||
personCache = {}
|
personCache = {}
|
||||||
cachedWebfingers = {}
|
cachedWebfingers = {}
|
||||||
|
if not domain:
|
||||||
|
domain = getConfigParam(baseDir, 'domain')
|
||||||
|
signingPrivateKeyPem = None
|
||||||
|
if args.secureMode:
|
||||||
|
signingPrivateKeyPem = getInstanceActorKey(baseDir, domain)
|
||||||
print('Sending undo like of ' + args.undolike)
|
print('Sending undo like of ' + args.undolike)
|
||||||
|
|
||||||
sendUndoLikeViaServer(baseDir, session,
|
sendUndoLikeViaServer(baseDir, session,
|
||||||
|
|
@ -1506,7 +1630,8 @@ if args.undolike:
|
||||||
domain, port,
|
domain, port,
|
||||||
httpPrefix, args.undolike,
|
httpPrefix, args.undolike,
|
||||||
cachedWebfingers, personCache,
|
cachedWebfingers, personCache,
|
||||||
True, __version__)
|
True, __version__,
|
||||||
|
signingPrivateKeyPem)
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
# TODO detect send success/fail
|
# TODO detect send success/fail
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
@ -1527,6 +1652,11 @@ if args.bookmark:
|
||||||
session = createSession(proxyType)
|
session = createSession(proxyType)
|
||||||
personCache = {}
|
personCache = {}
|
||||||
cachedWebfingers = {}
|
cachedWebfingers = {}
|
||||||
|
if not domain:
|
||||||
|
domain = getConfigParam(baseDir, 'domain')
|
||||||
|
signingPrivateKeyPem = None
|
||||||
|
if args.secureMode:
|
||||||
|
signingPrivateKeyPem = getInstanceActorKey(baseDir, domain)
|
||||||
print('Sending bookmark of ' + args.bookmark)
|
print('Sending bookmark of ' + args.bookmark)
|
||||||
|
|
||||||
sendBookmarkViaServer(baseDir, session,
|
sendBookmarkViaServer(baseDir, session,
|
||||||
|
|
@ -1534,7 +1664,8 @@ if args.bookmark:
|
||||||
domain, port,
|
domain, port,
|
||||||
httpPrefix, args.bookmark,
|
httpPrefix, args.bookmark,
|
||||||
cachedWebfingers, personCache,
|
cachedWebfingers, personCache,
|
||||||
True, __version__)
|
True, __version__,
|
||||||
|
signingPrivateKeyPem)
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
# TODO detect send success/fail
|
# TODO detect send success/fail
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
@ -1555,6 +1686,11 @@ if args.unbookmark:
|
||||||
session = createSession(proxyType)
|
session = createSession(proxyType)
|
||||||
personCache = {}
|
personCache = {}
|
||||||
cachedWebfingers = {}
|
cachedWebfingers = {}
|
||||||
|
if not domain:
|
||||||
|
domain = getConfigParam(baseDir, 'domain')
|
||||||
|
signingPrivateKeyPem = None
|
||||||
|
if args.secureMode:
|
||||||
|
signingPrivateKeyPem = getInstanceActorKey(baseDir, domain)
|
||||||
print('Sending undo bookmark of ' + args.unbookmark)
|
print('Sending undo bookmark of ' + args.unbookmark)
|
||||||
|
|
||||||
sendUndoBookmarkViaServer(baseDir, session,
|
sendUndoBookmarkViaServer(baseDir, session,
|
||||||
|
|
@ -1562,7 +1698,7 @@ if args.unbookmark:
|
||||||
domain, port,
|
domain, port,
|
||||||
httpPrefix, args.unbookmark,
|
httpPrefix, args.unbookmark,
|
||||||
cachedWebfingers, personCache,
|
cachedWebfingers, personCache,
|
||||||
True, __version__)
|
True, __version__, signingPrivateKeyPem)
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
# TODO detect send success/fail
|
# TODO detect send success/fail
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
@ -1583,6 +1719,11 @@ if args.delete:
|
||||||
session = createSession(proxyType)
|
session = createSession(proxyType)
|
||||||
personCache = {}
|
personCache = {}
|
||||||
cachedWebfingers = {}
|
cachedWebfingers = {}
|
||||||
|
if not domain:
|
||||||
|
domain = getConfigParam(baseDir, 'domain')
|
||||||
|
signingPrivateKeyPem = None
|
||||||
|
if args.secureMode:
|
||||||
|
signingPrivateKeyPem = getInstanceActorKey(baseDir, domain)
|
||||||
print('Sending delete request of ' + args.delete)
|
print('Sending delete request of ' + args.delete)
|
||||||
|
|
||||||
sendDeleteViaServer(baseDir, session,
|
sendDeleteViaServer(baseDir, session,
|
||||||
|
|
@ -1590,7 +1731,7 @@ if args.delete:
|
||||||
domain, port,
|
domain, port,
|
||||||
httpPrefix, args.delete,
|
httpPrefix, args.delete,
|
||||||
cachedWebfingers, personCache,
|
cachedWebfingers, personCache,
|
||||||
True, __version__)
|
True, __version__, signingPrivateKeyPem)
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
# TODO detect send success/fail
|
# TODO detect send success/fail
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
@ -1623,6 +1764,11 @@ if args.follow:
|
||||||
followHttpPrefix = httpPrefix
|
followHttpPrefix = httpPrefix
|
||||||
if args.follow.startswith('https'):
|
if args.follow.startswith('https'):
|
||||||
followHttpPrefix = 'https'
|
followHttpPrefix = 'https'
|
||||||
|
if not domain:
|
||||||
|
domain = getConfigParam(baseDir, 'domain')
|
||||||
|
signingPrivateKeyPem = None
|
||||||
|
if args.secureMode:
|
||||||
|
signingPrivateKeyPem = getInstanceActorKey(baseDir, domain)
|
||||||
|
|
||||||
sendFollowRequestViaServer(baseDir, session,
|
sendFollowRequestViaServer(baseDir, session,
|
||||||
args.nickname, args.password,
|
args.nickname, args.password,
|
||||||
|
|
@ -1630,7 +1776,7 @@ if args.follow:
|
||||||
followNickname, followDomain, followPort,
|
followNickname, followDomain, followPort,
|
||||||
httpPrefix,
|
httpPrefix,
|
||||||
cachedWebfingers, personCache,
|
cachedWebfingers, personCache,
|
||||||
debug, __version__)
|
debug, __version__, signingPrivateKeyPem)
|
||||||
for t in range(20):
|
for t in range(20):
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
# TODO some method to know if it worked
|
# TODO some method to know if it worked
|
||||||
|
|
@ -1664,6 +1810,11 @@ if args.unfollow:
|
||||||
followHttpPrefix = httpPrefix
|
followHttpPrefix = httpPrefix
|
||||||
if args.follow.startswith('https'):
|
if args.follow.startswith('https'):
|
||||||
followHttpPrefix = 'https'
|
followHttpPrefix = 'https'
|
||||||
|
if not domain:
|
||||||
|
domain = getConfigParam(baseDir, 'domain')
|
||||||
|
signingPrivateKeyPem = None
|
||||||
|
if args.secureMode:
|
||||||
|
signingPrivateKeyPem = getInstanceActorKey(baseDir, domain)
|
||||||
|
|
||||||
sendUnfollowRequestViaServer(baseDir, session,
|
sendUnfollowRequestViaServer(baseDir, session,
|
||||||
args.nickname, args.password,
|
args.nickname, args.password,
|
||||||
|
|
@ -1671,7 +1822,7 @@ if args.unfollow:
|
||||||
followNickname, followDomain, followPort,
|
followNickname, followDomain, followPort,
|
||||||
httpPrefix,
|
httpPrefix,
|
||||||
cachedWebfingers, personCache,
|
cachedWebfingers, personCache,
|
||||||
debug, __version__)
|
debug, __version__, signingPrivateKeyPem)
|
||||||
for t in range(20):
|
for t in range(20):
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
# TODO some method to know if it worked
|
# TODO some method to know if it worked
|
||||||
|
|
@ -1694,6 +1845,11 @@ if args.followingList:
|
||||||
personCache = {}
|
personCache = {}
|
||||||
cachedWebfingers = {}
|
cachedWebfingers = {}
|
||||||
followHttpPrefix = httpPrefix
|
followHttpPrefix = httpPrefix
|
||||||
|
if not domain:
|
||||||
|
domain = getConfigParam(baseDir, 'domain')
|
||||||
|
signingPrivateKeyPem = None
|
||||||
|
if args.secureMode:
|
||||||
|
signingPrivateKeyPem = getInstanceActorKey(baseDir, domain)
|
||||||
|
|
||||||
followingJson = \
|
followingJson = \
|
||||||
getFollowingViaServer(baseDir, session,
|
getFollowingViaServer(baseDir, session,
|
||||||
|
|
@ -1701,7 +1857,7 @@ if args.followingList:
|
||||||
domain, port,
|
domain, port,
|
||||||
httpPrefix, args.pageNumber,
|
httpPrefix, args.pageNumber,
|
||||||
cachedWebfingers, personCache,
|
cachedWebfingers, personCache,
|
||||||
debug, __version__)
|
debug, __version__, signingPrivateKeyPem)
|
||||||
if followingJson:
|
if followingJson:
|
||||||
pprint(followingJson)
|
pprint(followingJson)
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
@ -1722,6 +1878,11 @@ if args.followersList:
|
||||||
personCache = {}
|
personCache = {}
|
||||||
cachedWebfingers = {}
|
cachedWebfingers = {}
|
||||||
followHttpPrefix = httpPrefix
|
followHttpPrefix = httpPrefix
|
||||||
|
if not domain:
|
||||||
|
domain = getConfigParam(baseDir, 'domain')
|
||||||
|
signingPrivateKeyPem = None
|
||||||
|
if args.secureMode:
|
||||||
|
signingPrivateKeyPem = getInstanceActorKey(baseDir, domain)
|
||||||
|
|
||||||
followersJson = \
|
followersJson = \
|
||||||
getFollowersViaServer(baseDir, session,
|
getFollowersViaServer(baseDir, session,
|
||||||
|
|
@ -1729,7 +1890,8 @@ if args.followersList:
|
||||||
domain, port,
|
domain, port,
|
||||||
httpPrefix, args.pageNumber,
|
httpPrefix, args.pageNumber,
|
||||||
cachedWebfingers, personCache,
|
cachedWebfingers, personCache,
|
||||||
debug, __version__)
|
debug, __version__,
|
||||||
|
signingPrivateKeyPem)
|
||||||
if followersJson:
|
if followersJson:
|
||||||
pprint(followersJson)
|
pprint(followersJson)
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
@ -1750,6 +1912,11 @@ if args.followRequestsList:
|
||||||
personCache = {}
|
personCache = {}
|
||||||
cachedWebfingers = {}
|
cachedWebfingers = {}
|
||||||
followHttpPrefix = httpPrefix
|
followHttpPrefix = httpPrefix
|
||||||
|
if not domain:
|
||||||
|
domain = getConfigParam(baseDir, 'domain')
|
||||||
|
signingPrivateKeyPem = None
|
||||||
|
if args.secureMode:
|
||||||
|
signingPrivateKeyPem = getInstanceActorKey(baseDir, domain)
|
||||||
|
|
||||||
followRequestsJson = \
|
followRequestsJson = \
|
||||||
getFollowRequestsViaServer(baseDir, session,
|
getFollowRequestsViaServer(baseDir, session,
|
||||||
|
|
@ -1757,7 +1924,7 @@ if args.followRequestsList:
|
||||||
domain, port,
|
domain, port,
|
||||||
httpPrefix, args.pageNumber,
|
httpPrefix, args.pageNumber,
|
||||||
cachedWebfingers, personCache,
|
cachedWebfingers, personCache,
|
||||||
debug, __version__)
|
debug, __version__, signingPrivateKeyPem)
|
||||||
if followRequestsJson:
|
if followRequestsJson:
|
||||||
pprint(followRequestsJson)
|
pprint(followRequestsJson)
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
@ -1797,9 +1964,14 @@ if args.migrations:
|
||||||
httpPrefix = 'https'
|
httpPrefix = 'https'
|
||||||
port = 443
|
port = 443
|
||||||
session = createSession(proxyType)
|
session = createSession(proxyType)
|
||||||
|
if not domain:
|
||||||
|
domain = getConfigParam(baseDir, 'domain')
|
||||||
|
signingPrivateKeyPem = None
|
||||||
|
if args.secureMode:
|
||||||
|
signingPrivateKeyPem = getInstanceActorKey(baseDir, domain)
|
||||||
ctr = migrateAccounts(baseDir, session,
|
ctr = migrateAccounts(baseDir, session,
|
||||||
httpPrefix, cachedWebfingers,
|
httpPrefix, cachedWebfingers,
|
||||||
True)
|
True, signingPrivateKeyPem)
|
||||||
if ctr == 0:
|
if ctr == 0:
|
||||||
print('No followed accounts have moved')
|
print('No followed accounts have moved')
|
||||||
else:
|
else:
|
||||||
|
|
@ -1807,7 +1979,17 @@ if args.migrations:
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
if args.actor:
|
if args.actor:
|
||||||
getActorJson(args.domain, args.actor, args.http, args.gnunet, debug)
|
if not domain:
|
||||||
|
domain = getConfigParam(baseDir, 'domain')
|
||||||
|
signingPrivateKeyPem = getInstanceActorKey(baseDir, domain)
|
||||||
|
if debug:
|
||||||
|
print('baseDir: ' + str(baseDir))
|
||||||
|
if signingPrivateKeyPem:
|
||||||
|
print('Obtained instance actor signing key')
|
||||||
|
else:
|
||||||
|
print('Did not obtain instance actor key for ' + domain)
|
||||||
|
getActorJson(domain, args.actor, args.http, args.gnunet,
|
||||||
|
debug, False, signingPrivateKeyPem)
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
if args.followers:
|
if args.followers:
|
||||||
|
|
@ -1882,10 +2064,17 @@ if args.followers:
|
||||||
if nickname == 'inbox':
|
if nickname == 'inbox':
|
||||||
nickname = domain
|
nickname = domain
|
||||||
|
|
||||||
|
hostDomain = None
|
||||||
|
if args.domain:
|
||||||
|
hostDomain = args.domain
|
||||||
handle = nickname + '@' + domain
|
handle = nickname + '@' + domain
|
||||||
|
signingPrivateKeyPem = None
|
||||||
|
if args.secureMode:
|
||||||
|
signingPrivateKeyPem = getInstanceActorKey(baseDir, domain)
|
||||||
wfRequest = webfingerHandle(session, handle,
|
wfRequest = webfingerHandle(session, handle,
|
||||||
httpPrefix, cachedWebfingers,
|
httpPrefix, cachedWebfingers,
|
||||||
None, __version__, debug, False)
|
hostDomain, __version__, debug, False,
|
||||||
|
signingPrivateKeyPem)
|
||||||
if not wfRequest:
|
if not wfRequest:
|
||||||
print('Unable to webfinger ' + handle)
|
print('Unable to webfinger ' + handle)
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
@ -1927,9 +2116,12 @@ if args.followers:
|
||||||
asHeader = {
|
asHeader = {
|
||||||
'Accept': 'application/ld+json; profile="' + profileStr + '"'
|
'Accept': 'application/ld+json; profile="' + profileStr + '"'
|
||||||
}
|
}
|
||||||
|
signingPrivateKeyPem = None
|
||||||
|
if args.secureMode:
|
||||||
|
signingPrivateKeyPem = getInstanceActorKey(baseDir, domain)
|
||||||
followersList = \
|
followersList = \
|
||||||
downloadFollowCollection('followers', session,
|
downloadFollowCollection(signingPrivateKeyPem,
|
||||||
|
'followers', session,
|
||||||
httpPrefix, personUrl, 1, 3)
|
httpPrefix, personUrl, 1, 3)
|
||||||
if followersList:
|
if followersList:
|
||||||
for actor in followersList:
|
for actor in followersList:
|
||||||
|
|
@ -2179,6 +2371,11 @@ if args.skill:
|
||||||
session = createSession(proxyType)
|
session = createSession(proxyType)
|
||||||
personCache = {}
|
personCache = {}
|
||||||
cachedWebfingers = {}
|
cachedWebfingers = {}
|
||||||
|
if not domain:
|
||||||
|
domain = getConfigParam(baseDir, 'domain')
|
||||||
|
signingPrivateKeyPem = None
|
||||||
|
if args.secureMode:
|
||||||
|
signingPrivateKeyPem = getInstanceActorKey(baseDir, domain)
|
||||||
print('Sending ' + args.skill + ' skill level ' +
|
print('Sending ' + args.skill + ' skill level ' +
|
||||||
str(args.skillLevelPercent) + ' for ' + nickname)
|
str(args.skillLevelPercent) + ' for ' + nickname)
|
||||||
|
|
||||||
|
|
@ -2188,7 +2385,7 @@ if args.skill:
|
||||||
httpPrefix,
|
httpPrefix,
|
||||||
args.skill, args.skillLevelPercent,
|
args.skill, args.skillLevelPercent,
|
||||||
cachedWebfingers, personCache,
|
cachedWebfingers, personCache,
|
||||||
True, __version__)
|
True, __version__, signingPrivateKeyPem)
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
# TODO detect send success/fail
|
# TODO detect send success/fail
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
@ -2209,6 +2406,11 @@ if args.availability:
|
||||||
session = createSession(proxyType)
|
session = createSession(proxyType)
|
||||||
personCache = {}
|
personCache = {}
|
||||||
cachedWebfingers = {}
|
cachedWebfingers = {}
|
||||||
|
if not domain:
|
||||||
|
domain = getConfigParam(baseDir, 'domain')
|
||||||
|
signingPrivateKeyPem = None
|
||||||
|
if args.secureMode:
|
||||||
|
signingPrivateKeyPem = getInstanceActorKey(baseDir, domain)
|
||||||
print('Sending availability status of ' + nickname +
|
print('Sending availability status of ' + nickname +
|
||||||
' as ' + args.availability)
|
' as ' + args.availability)
|
||||||
|
|
||||||
|
|
@ -2217,7 +2419,7 @@ if args.availability:
|
||||||
httpPrefix,
|
httpPrefix,
|
||||||
args.availability,
|
args.availability,
|
||||||
cachedWebfingers, personCache,
|
cachedWebfingers, personCache,
|
||||||
True, __version__)
|
True, __version__, signingPrivateKeyPem)
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
# TODO detect send success/fail
|
# TODO detect send success/fail
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
@ -2318,13 +2520,18 @@ if args.block:
|
||||||
session = createSession(proxyType)
|
session = createSession(proxyType)
|
||||||
personCache = {}
|
personCache = {}
|
||||||
cachedWebfingers = {}
|
cachedWebfingers = {}
|
||||||
|
if not domain:
|
||||||
|
domain = getConfigParam(baseDir, 'domain')
|
||||||
|
signingPrivateKeyPem = None
|
||||||
|
if args.secureMode:
|
||||||
|
signingPrivateKeyPem = getInstanceActorKey(baseDir, domain)
|
||||||
print('Sending block of ' + args.block)
|
print('Sending block of ' + args.block)
|
||||||
|
|
||||||
sendBlockViaServer(baseDir, session, nickname, args.password,
|
sendBlockViaServer(baseDir, session, nickname, args.password,
|
||||||
domain, port,
|
domain, port,
|
||||||
httpPrefix, args.block,
|
httpPrefix, args.block,
|
||||||
cachedWebfingers, personCache,
|
cachedWebfingers, personCache,
|
||||||
True, __version__)
|
True, __version__, signingPrivateKeyPem)
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
# TODO detect send success/fail
|
# TODO detect send success/fail
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
@ -2345,13 +2552,18 @@ if args.mute:
|
||||||
session = createSession(proxyType)
|
session = createSession(proxyType)
|
||||||
personCache = {}
|
personCache = {}
|
||||||
cachedWebfingers = {}
|
cachedWebfingers = {}
|
||||||
|
if not domain:
|
||||||
|
domain = getConfigParam(baseDir, 'domain')
|
||||||
|
signingPrivateKeyPem = None
|
||||||
|
if args.secureMode:
|
||||||
|
signingPrivateKeyPem = getInstanceActorKey(baseDir, domain)
|
||||||
print('Sending mute of ' + args.mute)
|
print('Sending mute of ' + args.mute)
|
||||||
|
|
||||||
sendMuteViaServer(baseDir, session, nickname, args.password,
|
sendMuteViaServer(baseDir, session, nickname, args.password,
|
||||||
domain, port,
|
domain, port,
|
||||||
httpPrefix, args.mute,
|
httpPrefix, args.mute,
|
||||||
cachedWebfingers, personCache,
|
cachedWebfingers, personCache,
|
||||||
True, __version__)
|
True, __version__, signingPrivateKeyPem)
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
# TODO detect send success/fail
|
# TODO detect send success/fail
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
@ -2372,13 +2584,18 @@ if args.unmute:
|
||||||
session = createSession(proxyType)
|
session = createSession(proxyType)
|
||||||
personCache = {}
|
personCache = {}
|
||||||
cachedWebfingers = {}
|
cachedWebfingers = {}
|
||||||
|
if not domain:
|
||||||
|
domain = getConfigParam(baseDir, 'domain')
|
||||||
|
signingPrivateKeyPem = None
|
||||||
|
if args.secureMode:
|
||||||
|
signingPrivateKeyPem = getInstanceActorKey(baseDir, domain)
|
||||||
print('Sending undo mute of ' + args.unmute)
|
print('Sending undo mute of ' + args.unmute)
|
||||||
|
|
||||||
sendUndoMuteViaServer(baseDir, session, nickname, args.password,
|
sendUndoMuteViaServer(baseDir, session, nickname, args.password,
|
||||||
domain, port,
|
domain, port,
|
||||||
httpPrefix, args.unmute,
|
httpPrefix, args.unmute,
|
||||||
cachedWebfingers, personCache,
|
cachedWebfingers, personCache,
|
||||||
True, __version__)
|
True, __version__, signingPrivateKeyPem)
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
# TODO detect send success/fail
|
# TODO detect send success/fail
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
@ -2411,13 +2628,18 @@ if args.unblock:
|
||||||
session = createSession(proxyType)
|
session = createSession(proxyType)
|
||||||
personCache = {}
|
personCache = {}
|
||||||
cachedWebfingers = {}
|
cachedWebfingers = {}
|
||||||
|
if not domain:
|
||||||
|
domain = getConfigParam(baseDir, 'domain')
|
||||||
|
signingPrivateKeyPem = None
|
||||||
|
if args.secureMode:
|
||||||
|
signingPrivateKeyPem = getInstanceActorKey(baseDir, domain)
|
||||||
print('Sending undo block of ' + args.unblock)
|
print('Sending undo block of ' + args.unblock)
|
||||||
|
|
||||||
sendUndoBlockViaServer(baseDir, session, nickname, args.password,
|
sendUndoBlockViaServer(baseDir, session, nickname, args.password,
|
||||||
domain, port,
|
domain, port,
|
||||||
httpPrefix, args.unblock,
|
httpPrefix, args.unblock,
|
||||||
cachedWebfingers, personCache,
|
cachedWebfingers, personCache,
|
||||||
True, __version__)
|
True, __version__, signingPrivateKeyPem)
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
# TODO detect send success/fail
|
# TODO detect send success/fail
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
@ -2803,6 +3025,15 @@ if YTDomain:
|
||||||
if '.' in YTDomain:
|
if '.' in YTDomain:
|
||||||
args.YTReplacementDomain = YTDomain
|
args.YTReplacementDomain = YTDomain
|
||||||
|
|
||||||
|
twitterDomain = getConfigParam(baseDir, 'twitterdomain')
|
||||||
|
if twitterDomain:
|
||||||
|
if '://' in twitterDomain:
|
||||||
|
twitterDomain = twitterDomain.split('://')[1]
|
||||||
|
if '/' in twitterDomain:
|
||||||
|
twitterDomain = twitterDomain.split('/')[0]
|
||||||
|
if '.' in twitterDomain:
|
||||||
|
args.twitterReplacementDomain = twitterDomain
|
||||||
|
|
||||||
if setTheme(baseDir, themeName, domain,
|
if setTheme(baseDir, themeName, domain,
|
||||||
args.allowLocalNetworkAccess, args.language):
|
args.allowLocalNetworkAccess, args.language):
|
||||||
print('Theme set to ' + themeName)
|
print('Theme set to ' + themeName)
|
||||||
|
|
@ -2833,7 +3064,8 @@ if args.defaultCurrency:
|
||||||
print('Default currency set to ' + args.defaultCurrency)
|
print('Default currency set to ' + args.defaultCurrency)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
runDaemon(args.lowBandwidth, args.maxLikeCount,
|
runDaemon(args.defaultReplyIntervalHours,
|
||||||
|
args.lowBandwidth, args.maxLikeCount,
|
||||||
sharedItemsFederatedDomains,
|
sharedItemsFederatedDomains,
|
||||||
userAgentsBlocked,
|
userAgentsBlocked,
|
||||||
args.logLoginFailures,
|
args.logLoginFailures,
|
||||||
|
|
@ -2869,9 +3101,10 @@ if __name__ == "__main__":
|
||||||
instanceId, args.client, baseDir,
|
instanceId, args.client, baseDir,
|
||||||
domain, onionDomain, i2pDomain,
|
domain, onionDomain, i2pDomain,
|
||||||
args.YTReplacementDomain,
|
args.YTReplacementDomain,
|
||||||
|
args.twitterReplacementDomain,
|
||||||
port, proxyPort, httpPrefix,
|
port, proxyPort, httpPrefix,
|
||||||
federationList, args.maxMentions,
|
federationList, args.maxMentions,
|
||||||
args.maxEmoji, args.authenticatedFetch,
|
args.maxEmoji, args.secureMode,
|
||||||
proxyType, args.maxReplies,
|
proxyType, args.maxReplies,
|
||||||
args.domainMaxPostsPerDay,
|
args.domainMaxPostsPerDay,
|
||||||
args.accountMaxPostsPerDay,
|
args.accountMaxPostsPerDay,
|
||||||
|
|
|
||||||
2
feeds.py
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "RSS Feeds"
|
__module_group__ = "RSS Feeds"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Moderation"
|
__module_group__ = "Moderation"
|
||||||
|
|
||||||
|
|
|
||||||
95
follow.py
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "ActivityPub"
|
__module_group__ = "ActivityPub"
|
||||||
|
|
||||||
|
|
@ -211,6 +211,12 @@ def isFollowerOfPerson(baseDir: str, nickname: str, domain: str,
|
||||||
followerNickname: str, followerDomain: str) -> bool:
|
followerNickname: str, followerDomain: str) -> bool:
|
||||||
"""is the given nickname a follower of followerNickname?
|
"""is the given nickname a follower of followerNickname?
|
||||||
"""
|
"""
|
||||||
|
if not followerDomain:
|
||||||
|
print('No followerDomain')
|
||||||
|
return False
|
||||||
|
if not followerNickname:
|
||||||
|
print('No followerNickname for ' + followerDomain)
|
||||||
|
return False
|
||||||
domain = removeDomainPort(domain)
|
domain = removeDomainPort(domain)
|
||||||
followersFile = acctDir(baseDir, nickname, domain) + '/followers.txt'
|
followersFile = acctDir(baseDir, nickname, domain) + '/followers.txt'
|
||||||
if not os.path.isfile(followersFile):
|
if not os.path.isfile(followersFile):
|
||||||
|
|
@ -308,7 +314,10 @@ def clearFollows(baseDir: str, nickname: str, domain: str,
|
||||||
os.mkdir(baseDir + '/accounts/' + handle)
|
os.mkdir(baseDir + '/accounts/' + handle)
|
||||||
filename = baseDir + '/accounts/' + handle + '/' + followFile
|
filename = baseDir + '/accounts/' + handle + '/' + followFile
|
||||||
if os.path.isfile(filename):
|
if os.path.isfile(filename):
|
||||||
|
try:
|
||||||
os.remove(filename)
|
os.remove(filename)
|
||||||
|
except BaseException:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def clearFollowers(baseDir: str, nickname: str, domain: str) -> None:
|
def clearFollowers(baseDir: str, nickname: str, domain: str) -> None:
|
||||||
|
|
@ -631,7 +640,8 @@ def receiveFollowRequest(session, baseDir: str, httpPrefix: str,
|
||||||
cachedWebfingers: {}, personCache: {},
|
cachedWebfingers: {}, personCache: {},
|
||||||
messageJson: {}, federationList: [],
|
messageJson: {}, federationList: [],
|
||||||
debug: bool, projectVersion: str,
|
debug: bool, projectVersion: str,
|
||||||
maxFollowers: int, onionDomain: str) -> bool:
|
maxFollowers: int, onionDomain: str,
|
||||||
|
signingPrivateKeyPem: str) -> bool:
|
||||||
"""Receives a follow request within the POST section of HTTPServer
|
"""Receives a follow request within the POST section of HTTPServer
|
||||||
"""
|
"""
|
||||||
if not messageJson['type'].startswith('Follow'):
|
if not messageJson['type'].startswith('Follow'):
|
||||||
|
|
@ -743,7 +753,8 @@ def receiveFollowRequest(session, baseDir: str, httpPrefix: str,
|
||||||
print('Obtaining the following actor: ' + messageJson['actor'])
|
print('Obtaining the following actor: ' + messageJson['actor'])
|
||||||
if not getPersonPubKey(baseDir, session, messageJson['actor'],
|
if not getPersonPubKey(baseDir, session, messageJson['actor'],
|
||||||
personCache, debug, projectVersion,
|
personCache, debug, projectVersion,
|
||||||
httpPrefix, domainToFollow, onionDomain):
|
httpPrefix, domainToFollow, onionDomain,
|
||||||
|
signingPrivateKeyPem):
|
||||||
if debug:
|
if debug:
|
||||||
print('Unable to obtain following actor: ' +
|
print('Unable to obtain following actor: ' +
|
||||||
messageJson['actor'])
|
messageJson['actor'])
|
||||||
|
|
@ -779,7 +790,8 @@ def receiveFollowRequest(session, baseDir: str, httpPrefix: str,
|
||||||
print('Obtaining the following actor: ' + messageJson['actor'])
|
print('Obtaining the following actor: ' + messageJson['actor'])
|
||||||
if not getPersonPubKey(baseDir, session, messageJson['actor'],
|
if not getPersonPubKey(baseDir, session, messageJson['actor'],
|
||||||
personCache, debug, projectVersion,
|
personCache, debug, projectVersion,
|
||||||
httpPrefix, domainToFollow, onionDomain):
|
httpPrefix, domainToFollow, onionDomain,
|
||||||
|
signingPrivateKeyPem):
|
||||||
if debug:
|
if debug:
|
||||||
print('Unable to obtain following actor: ' +
|
print('Unable to obtain following actor: ' +
|
||||||
messageJson['actor'])
|
messageJson['actor'])
|
||||||
|
|
@ -824,7 +836,8 @@ def receiveFollowRequest(session, baseDir: str, httpPrefix: str,
|
||||||
messageJson['actor'], federationList,
|
messageJson['actor'], federationList,
|
||||||
messageJson, sendThreads, postLog,
|
messageJson, sendThreads, postLog,
|
||||||
cachedWebfingers, personCache,
|
cachedWebfingers, personCache,
|
||||||
debug, projectVersion, True)
|
debug, projectVersion, True,
|
||||||
|
signingPrivateKeyPem)
|
||||||
|
|
||||||
|
|
||||||
def followedAccountAccepts(session, baseDir: str, httpPrefix: str,
|
def followedAccountAccepts(session, baseDir: str, httpPrefix: str,
|
||||||
|
|
@ -835,7 +848,8 @@ def followedAccountAccepts(session, baseDir: str, httpPrefix: str,
|
||||||
followJson: {}, sendThreads: [], postLog: [],
|
followJson: {}, sendThreads: [], postLog: [],
|
||||||
cachedWebfingers: {}, personCache: {},
|
cachedWebfingers: {}, personCache: {},
|
||||||
debug: bool, projectVersion: str,
|
debug: bool, projectVersion: str,
|
||||||
removeFollowActivity: bool):
|
removeFollowActivity: bool,
|
||||||
|
signingPrivateKeyPem: str):
|
||||||
"""The person receiving a follow request accepts the new follower
|
"""The person receiving a follow request accepts the new follower
|
||||||
and sends back an Accept activity
|
and sends back an Accept activity
|
||||||
"""
|
"""
|
||||||
|
|
@ -884,7 +898,8 @@ def followedAccountAccepts(session, baseDir: str, httpPrefix: str,
|
||||||
federationList,
|
federationList,
|
||||||
sendThreads, postLog, cachedWebfingers,
|
sendThreads, postLog, cachedWebfingers,
|
||||||
personCache, debug, projectVersion, None,
|
personCache, debug, projectVersion, None,
|
||||||
groupAccount)
|
groupAccount, signingPrivateKeyPem,
|
||||||
|
7856837)
|
||||||
|
|
||||||
|
|
||||||
def followedAccountRejects(session, baseDir: str, httpPrefix: str,
|
def followedAccountRejects(session, baseDir: str, httpPrefix: str,
|
||||||
|
|
@ -894,7 +909,8 @@ def followedAccountRejects(session, baseDir: str, httpPrefix: str,
|
||||||
federationList: [],
|
federationList: [],
|
||||||
sendThreads: [], postLog: [],
|
sendThreads: [], postLog: [],
|
||||||
cachedWebfingers: {}, personCache: {},
|
cachedWebfingers: {}, personCache: {},
|
||||||
debug: bool, projectVersion: str):
|
debug: bool, projectVersion: str,
|
||||||
|
signingPrivateKeyPem: str):
|
||||||
"""The person receiving a follow request rejects the new follower
|
"""The person receiving a follow request rejects the new follower
|
||||||
and sends back a Reject activity
|
and sends back a Reject activity
|
||||||
"""
|
"""
|
||||||
|
|
@ -949,7 +965,8 @@ def followedAccountRejects(session, baseDir: str, httpPrefix: str,
|
||||||
federationList,
|
federationList,
|
||||||
sendThreads, postLog, cachedWebfingers,
|
sendThreads, postLog, cachedWebfingers,
|
||||||
personCache, debug, projectVersion, None,
|
personCache, debug, projectVersion, None,
|
||||||
groupAccount)
|
groupAccount, signingPrivateKeyPem,
|
||||||
|
6393063)
|
||||||
|
|
||||||
|
|
||||||
def sendFollowRequest(session, baseDir: str,
|
def sendFollowRequest(session, baseDir: str,
|
||||||
|
|
@ -960,9 +977,12 @@ def sendFollowRequest(session, baseDir: str,
|
||||||
clientToServer: bool, federationList: [],
|
clientToServer: bool, federationList: [],
|
||||||
sendThreads: [], postLog: [], cachedWebfingers: {},
|
sendThreads: [], postLog: [], cachedWebfingers: {},
|
||||||
personCache: {}, debug: bool,
|
personCache: {}, debug: bool,
|
||||||
projectVersion: str) -> {}:
|
projectVersion: str, signingPrivateKeyPem: str) -> {}:
|
||||||
"""Gets the json object for sending a follow request
|
"""Gets the json object for sending a follow request
|
||||||
"""
|
"""
|
||||||
|
if not signingPrivateKeyPem:
|
||||||
|
print('WARN: follow request without signing key')
|
||||||
|
|
||||||
if not domainPermitted(followDomain, federationList):
|
if not domainPermitted(followDomain, federationList):
|
||||||
print('You are not permitted to follow the domain ' + followDomain)
|
print('You are not permitted to follow the domain ' + followDomain)
|
||||||
return None
|
return None
|
||||||
|
|
@ -1016,7 +1036,8 @@ def sendFollowRequest(session, baseDir: str,
|
||||||
httpPrefix, True, clientToServer,
|
httpPrefix, True, clientToServer,
|
||||||
federationList,
|
federationList,
|
||||||
sendThreads, postLog, cachedWebfingers, personCache,
|
sendThreads, postLog, cachedWebfingers, personCache,
|
||||||
debug, projectVersion, None, groupAccount)
|
debug, projectVersion, None, groupAccount,
|
||||||
|
signingPrivateKeyPem, 8234389)
|
||||||
|
|
||||||
return newFollowJson
|
return newFollowJson
|
||||||
|
|
||||||
|
|
@ -1028,7 +1049,8 @@ def sendFollowRequestViaServer(baseDir: str, session,
|
||||||
followPort: int,
|
followPort: int,
|
||||||
httpPrefix: str,
|
httpPrefix: str,
|
||||||
cachedWebfingers: {}, personCache: {},
|
cachedWebfingers: {}, personCache: {},
|
||||||
debug: bool, projectVersion: str) -> {}:
|
debug: bool, projectVersion: str,
|
||||||
|
signingPrivateKeyPem: str) -> {}:
|
||||||
"""Creates a follow request via c2s
|
"""Creates a follow request via c2s
|
||||||
"""
|
"""
|
||||||
if not session:
|
if not session:
|
||||||
|
|
@ -1057,7 +1079,8 @@ def sendFollowRequestViaServer(baseDir: str, session,
|
||||||
# lookup the inbox for the To handle
|
# lookup the inbox for the To handle
|
||||||
wfRequest = \
|
wfRequest = \
|
||||||
webfingerHandle(session, handle, httpPrefix, cachedWebfingers,
|
webfingerHandle(session, handle, httpPrefix, cachedWebfingers,
|
||||||
fromDomain, projectVersion, debug, False)
|
fromDomain, projectVersion, debug, False,
|
||||||
|
signingPrivateKeyPem)
|
||||||
if not wfRequest:
|
if not wfRequest:
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: follow request webfinger failed for ' + handle)
|
print('DEBUG: follow request webfinger failed for ' + handle)
|
||||||
|
|
@ -1070,9 +1093,11 @@ def sendFollowRequestViaServer(baseDir: str, session,
|
||||||
postToBox = 'outbox'
|
postToBox = 'outbox'
|
||||||
|
|
||||||
# get the actor inbox for the To handle
|
# get the actor inbox for the To handle
|
||||||
|
originDomain = fromDomain
|
||||||
(inboxUrl, pubKeyId, pubKey,
|
(inboxUrl, pubKeyId, pubKey,
|
||||||
fromPersonId, sharedInbox, avatarUrl,
|
fromPersonId, sharedInbox, avatarUrl,
|
||||||
displayName) = getPersonBox(baseDir, session, wfRequest, personCache,
|
displayName, _) = getPersonBox(signingPrivateKeyPem, originDomain,
|
||||||
|
baseDir, session, wfRequest, personCache,
|
||||||
projectVersion, httpPrefix, fromNickname,
|
projectVersion, httpPrefix, fromNickname,
|
||||||
fromDomain, postToBox, 52025)
|
fromDomain, postToBox, 52025)
|
||||||
|
|
||||||
|
|
@ -1114,7 +1139,8 @@ def sendUnfollowRequestViaServer(baseDir: str, session,
|
||||||
followPort: int,
|
followPort: int,
|
||||||
httpPrefix: str,
|
httpPrefix: str,
|
||||||
cachedWebfingers: {}, personCache: {},
|
cachedWebfingers: {}, personCache: {},
|
||||||
debug: bool, projectVersion: str) -> {}:
|
debug: bool, projectVersion: str,
|
||||||
|
signingPrivateKeyPem: str) -> {}:
|
||||||
"""Creates a unfollow request via c2s
|
"""Creates a unfollow request via c2s
|
||||||
"""
|
"""
|
||||||
if not session:
|
if not session:
|
||||||
|
|
@ -1147,7 +1173,8 @@ def sendUnfollowRequestViaServer(baseDir: str, session,
|
||||||
# lookup the inbox for the To handle
|
# lookup the inbox for the To handle
|
||||||
wfRequest = \
|
wfRequest = \
|
||||||
webfingerHandle(session, handle, httpPrefix, cachedWebfingers,
|
webfingerHandle(session, handle, httpPrefix, cachedWebfingers,
|
||||||
fromDomain, projectVersion, debug, False)
|
fromDomain, projectVersion, debug, False,
|
||||||
|
signingPrivateKeyPem)
|
||||||
if not wfRequest:
|
if not wfRequest:
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: unfollow webfinger failed for ' + handle)
|
print('DEBUG: unfollow webfinger failed for ' + handle)
|
||||||
|
|
@ -1160,9 +1187,11 @@ def sendUnfollowRequestViaServer(baseDir: str, session,
|
||||||
postToBox = 'outbox'
|
postToBox = 'outbox'
|
||||||
|
|
||||||
# get the actor inbox for the To handle
|
# get the actor inbox for the To handle
|
||||||
(inboxUrl, pubKeyId, pubKey,
|
originDomain = fromDomain
|
||||||
fromPersonId, sharedInbox,
|
(inboxUrl, pubKeyId, pubKey, fromPersonId, sharedInbox, avatarUrl,
|
||||||
avatarUrl, displayName) = getPersonBox(baseDir, session,
|
displayName, _) = getPersonBox(signingPrivateKeyPem,
|
||||||
|
originDomain,
|
||||||
|
baseDir, session,
|
||||||
wfRequest, personCache,
|
wfRequest, personCache,
|
||||||
projectVersion, httpPrefix,
|
projectVersion, httpPrefix,
|
||||||
fromNickname,
|
fromNickname,
|
||||||
|
|
@ -1205,7 +1234,8 @@ def getFollowingViaServer(baseDir: str, session,
|
||||||
domain: str, port: int,
|
domain: str, port: int,
|
||||||
httpPrefix: str, pageNumber: int,
|
httpPrefix: str, pageNumber: int,
|
||||||
cachedWebfingers: {}, personCache: {},
|
cachedWebfingers: {}, personCache: {},
|
||||||
debug: bool, projectVersion: str) -> {}:
|
debug: bool, projectVersion: str,
|
||||||
|
signingPrivateKeyPem: str) -> {}:
|
||||||
"""Gets a page from the following collection as json
|
"""Gets a page from the following collection as json
|
||||||
"""
|
"""
|
||||||
if not session:
|
if not session:
|
||||||
|
|
@ -1227,9 +1257,8 @@ def getFollowingViaServer(baseDir: str, session,
|
||||||
pageNumber = 1
|
pageNumber = 1
|
||||||
url = followActor + '/following?page=' + str(pageNumber)
|
url = followActor + '/following?page=' + str(pageNumber)
|
||||||
followingJson = \
|
followingJson = \
|
||||||
getJson(session, url, headers, {}, debug,
|
getJson(signingPrivateKeyPem, session, url, headers, {}, debug,
|
||||||
__version__, httpPrefix,
|
__version__, httpPrefix, domain, 10, True)
|
||||||
domain, 10, True)
|
|
||||||
if not followingJson:
|
if not followingJson:
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: GET following list failed for c2s to ' + url)
|
print('DEBUG: GET following list failed for c2s to ' + url)
|
||||||
|
|
@ -1246,7 +1275,8 @@ def getFollowersViaServer(baseDir: str, session,
|
||||||
domain: str, port: int,
|
domain: str, port: int,
|
||||||
httpPrefix: str, pageNumber: int,
|
httpPrefix: str, pageNumber: int,
|
||||||
cachedWebfingers: {}, personCache: {},
|
cachedWebfingers: {}, personCache: {},
|
||||||
debug: bool, projectVersion: str) -> {}:
|
debug: bool, projectVersion: str,
|
||||||
|
signingPrivateKeyPem: str) -> {}:
|
||||||
"""Gets a page from the followers collection as json
|
"""Gets a page from the followers collection as json
|
||||||
"""
|
"""
|
||||||
if not session:
|
if not session:
|
||||||
|
|
@ -1268,7 +1298,7 @@ def getFollowersViaServer(baseDir: str, session,
|
||||||
pageNumber = 1
|
pageNumber = 1
|
||||||
url = followActor + '/followers?page=' + str(pageNumber)
|
url = followActor + '/followers?page=' + str(pageNumber)
|
||||||
followersJson = \
|
followersJson = \
|
||||||
getJson(session, url, headers, {}, debug,
|
getJson(signingPrivateKeyPem, session, url, headers, {}, debug,
|
||||||
__version__, httpPrefix, domain, 10, True)
|
__version__, httpPrefix, domain, 10, True)
|
||||||
if not followersJson:
|
if not followersJson:
|
||||||
if debug:
|
if debug:
|
||||||
|
|
@ -1286,7 +1316,8 @@ def getFollowRequestsViaServer(baseDir: str, session,
|
||||||
domain: str, port: int,
|
domain: str, port: int,
|
||||||
httpPrefix: str, pageNumber: int,
|
httpPrefix: str, pageNumber: int,
|
||||||
cachedWebfingers: {}, personCache: {},
|
cachedWebfingers: {}, personCache: {},
|
||||||
debug: bool, projectVersion: str) -> {}:
|
debug: bool, projectVersion: str,
|
||||||
|
signingPrivateKeyPem: str) -> {}:
|
||||||
"""Gets a page from the follow requests collection as json
|
"""Gets a page from the follow requests collection as json
|
||||||
"""
|
"""
|
||||||
if not session:
|
if not session:
|
||||||
|
|
@ -1308,7 +1339,7 @@ def getFollowRequestsViaServer(baseDir: str, session,
|
||||||
pageNumber = 1
|
pageNumber = 1
|
||||||
url = followActor + '/followrequests?page=' + str(pageNumber)
|
url = followActor + '/followrequests?page=' + str(pageNumber)
|
||||||
followersJson = \
|
followersJson = \
|
||||||
getJson(session, url, headers, {}, debug,
|
getJson(signingPrivateKeyPem, session, url, headers, {}, debug,
|
||||||
__version__, httpPrefix, domain, 10, True)
|
__version__, httpPrefix, domain, 10, True)
|
||||||
if not followersJson:
|
if not followersJson:
|
||||||
if debug:
|
if debug:
|
||||||
|
|
@ -1326,7 +1357,8 @@ def approveFollowRequestViaServer(baseDir: str, session,
|
||||||
domain: str, port: int,
|
domain: str, port: int,
|
||||||
httpPrefix: str, approveHandle: int,
|
httpPrefix: str, approveHandle: int,
|
||||||
cachedWebfingers: {}, personCache: {},
|
cachedWebfingers: {}, personCache: {},
|
||||||
debug: bool, projectVersion: str) -> str:
|
debug: bool, projectVersion: str,
|
||||||
|
signingPrivateKeyPem: str) -> str:
|
||||||
"""Approves a follow request
|
"""Approves a follow request
|
||||||
This is not exactly via c2s though. It simulates pressing the Approve
|
This is not exactly via c2s though. It simulates pressing the Approve
|
||||||
button on the web interface
|
button on the web interface
|
||||||
|
|
@ -1348,7 +1380,7 @@ def approveFollowRequestViaServer(baseDir: str, session,
|
||||||
|
|
||||||
url = actor + '/followapprove=' + approveHandle
|
url = actor + '/followapprove=' + approveHandle
|
||||||
approveHtml = \
|
approveHtml = \
|
||||||
getJson(session, url, headers, {}, debug,
|
getJson(signingPrivateKeyPem, session, url, headers, {}, debug,
|
||||||
__version__, httpPrefix, domain, 10, True)
|
__version__, httpPrefix, domain, 10, True)
|
||||||
if not approveHtml:
|
if not approveHtml:
|
||||||
if debug:
|
if debug:
|
||||||
|
|
@ -1366,7 +1398,8 @@ def denyFollowRequestViaServer(baseDir: str, session,
|
||||||
domain: str, port: int,
|
domain: str, port: int,
|
||||||
httpPrefix: str, denyHandle: int,
|
httpPrefix: str, denyHandle: int,
|
||||||
cachedWebfingers: {}, personCache: {},
|
cachedWebfingers: {}, personCache: {},
|
||||||
debug: bool, projectVersion: str) -> str:
|
debug: bool, projectVersion: str,
|
||||||
|
signingPrivateKeyPem: str) -> str:
|
||||||
"""Denies a follow request
|
"""Denies a follow request
|
||||||
This is not exactly via c2s though. It simulates pressing the Deny
|
This is not exactly via c2s though. It simulates pressing the Deny
|
||||||
button on the web interface
|
button on the web interface
|
||||||
|
|
@ -1388,7 +1421,7 @@ def denyFollowRequestViaServer(baseDir: str, session,
|
||||||
|
|
||||||
url = actor + '/followdeny=' + denyHandle
|
url = actor + '/followdeny=' + denyHandle
|
||||||
denyHtml = \
|
denyHtml = \
|
||||||
getJson(session, url, headers, {}, debug,
|
getJson(signingPrivateKeyPem, session, url, headers, {}, debug,
|
||||||
__version__, httpPrefix, domain, 10, True)
|
__version__, httpPrefix, domain, 10, True)
|
||||||
if not denyHtml:
|
if not denyHtml:
|
||||||
if debug:
|
if debug:
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Calendar"
|
__module_group__ = "Calendar"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -62,8 +62,6 @@ Create a web server configuration:
|
||||||
|
|
||||||
And paste the following:
|
And paste the following:
|
||||||
|
|
||||||
proxy_cache_path /var/www/cache levels=1:2 keys_zone=my_cache:10m max_size=10g
|
|
||||||
inactive=60m use_temp_path=off;
|
|
||||||
server {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
listen [::]:80;
|
listen [::]:80;
|
||||||
|
|
@ -118,8 +116,6 @@ And paste the following:
|
||||||
location / {
|
location / {
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
client_max_body_size 31M;
|
client_max_body_size 31M;
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
|
||||||
proxy_set_header Connection "upgrade";
|
|
||||||
proxy_set_header Host $http_host;
|
proxy_set_header Host $http_host;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;
|
||||||
|
|
@ -135,10 +131,6 @@ And paste the following:
|
||||||
proxy_redirect off;
|
proxy_redirect off;
|
||||||
proxy_request_buffering off;
|
proxy_request_buffering off;
|
||||||
proxy_buffering off;
|
proxy_buffering off;
|
||||||
location ~ ^/accounts/(avatars|headers)/(.*).(png|jpg|gif|webp|svg) {
|
|
||||||
expires 1d;
|
|
||||||
proxy_pass http://localhost:7156;
|
|
||||||
}
|
|
||||||
proxy_pass http://localhost:7156;
|
proxy_pass http://localhost:7156;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -146,7 +138,6 @@ And paste the following:
|
||||||
Enable the site:
|
Enable the site:
|
||||||
|
|
||||||
ln -s /etc/nginx/sites-available/YOUR_DOMAIN /etc/nginx/sites-enabled/
|
ln -s /etc/nginx/sites-available/YOUR_DOMAIN /etc/nginx/sites-enabled/
|
||||||
mkdir /var/www/cache
|
|
||||||
|
|
||||||
Forward port 443 from your internet router to your server. If you have dynamic DNS make sure its configured. Add a TLS certificate:
|
Forward port 443 from your internet router to your server. If you have dynamic DNS make sure its configured. Add a TLS certificate:
|
||||||
|
|
||||||
|
|
|
||||||
2
git.py
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Profile Metadata"
|
__module_group__ = "Profile Metadata"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Core"
|
__module_group__ = "Core"
|
||||||
|
|
||||||
|
|
|
||||||
96
httpsig.py
|
|
@ -4,7 +4,7 @@ __credits__ = ['lamia']
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Security"
|
__module_group__ = "Security"
|
||||||
|
|
||||||
|
|
@ -24,6 +24,7 @@ from time import gmtime, strftime
|
||||||
import datetime
|
import datetime
|
||||||
from utils import getFullDomain
|
from utils import getFullDomain
|
||||||
from utils import getSHA256
|
from utils import getSHA256
|
||||||
|
from utils import getSHA512
|
||||||
from utils import localActorUrl
|
from utils import localActorUrl
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -39,7 +40,8 @@ def signPostHeaders(dateStr: str, privateKeyPem: str,
|
||||||
toDomain: str, toPort: int,
|
toDomain: str, toPort: int,
|
||||||
path: str,
|
path: str,
|
||||||
httpPrefix: str,
|
httpPrefix: str,
|
||||||
messageBodyJsonStr: str) -> str:
|
messageBodyJsonStr: str,
|
||||||
|
contentType: str) -> str:
|
||||||
"""Returns a raw signature string that can be plugged into a header and
|
"""Returns a raw signature string that can be plugged into a header and
|
||||||
used to verify the authenticity of an HTTP transmission.
|
used to verify the authenticity of an HTTP transmission.
|
||||||
"""
|
"""
|
||||||
|
|
@ -49,13 +51,18 @@ def signPostHeaders(dateStr: str, privateKeyPem: str,
|
||||||
|
|
||||||
if not dateStr:
|
if not dateStr:
|
||||||
dateStr = strftime("%a, %d %b %Y %H:%M:%S %Z", gmtime())
|
dateStr = strftime("%a, %d %b %Y %H:%M:%S %Z", gmtime())
|
||||||
keyID = localActorUrl(httpPrefix, nickname, domain) + '#main-key'
|
if nickname != domain and nickname.lower() != 'actor':
|
||||||
|
keyID = localActorUrl(httpPrefix, nickname, domain)
|
||||||
|
else:
|
||||||
|
# instance actor
|
||||||
|
keyID = httpPrefix + '://' + domain + '/actor'
|
||||||
|
keyID += '#main-key'
|
||||||
if not messageBodyJsonStr:
|
if not messageBodyJsonStr:
|
||||||
headers = {
|
headers = {
|
||||||
'(request-target)': f'post {path}',
|
'(request-target)': f'get {path}',
|
||||||
'host': toDomain,
|
'host': toDomain,
|
||||||
'date': dateStr,
|
'date': dateStr,
|
||||||
'content-type': 'application/json'
|
'accept': contentType
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
bodyDigest = messageContentDigest(messageBodyJsonStr)
|
bodyDigest = messageContentDigest(messageBodyJsonStr)
|
||||||
|
|
@ -78,7 +85,8 @@ def signPostHeaders(dateStr: str, privateKeyPem: str,
|
||||||
signedHeaderText = ''
|
signedHeaderText = ''
|
||||||
for headerKey in signedHeaderKeys:
|
for headerKey in signedHeaderKeys:
|
||||||
signedHeaderText += f'{headerKey}: {headers[headerKey]}\n'
|
signedHeaderText += f'{headerKey}: {headers[headerKey]}\n'
|
||||||
signedHeaderText = signedHeaderText.strip()
|
# strip the trailing linefeed
|
||||||
|
signedHeaderText = signedHeaderText.rstrip('\n')
|
||||||
# signedHeaderText.encode('ascii') matches
|
# signedHeaderText.encode('ascii') matches
|
||||||
headerDigest = getSHA256(signedHeaderText.encode('ascii'))
|
headerDigest = getSHA256(signedHeaderText.encode('ascii'))
|
||||||
# print('headerDigest2: ' + str(headerDigest))
|
# print('headerDigest2: ' + str(headerDigest))
|
||||||
|
|
@ -155,11 +163,18 @@ def signPostHeadersNew(dateStr: str, privateKeyPem: str,
|
||||||
for headerKey in signedHeaderKeys:
|
for headerKey in signedHeaderKeys:
|
||||||
signedHeaderText += f'{headerKey}: {headers[headerKey]}\n'
|
signedHeaderText += f'{headerKey}: {headers[headerKey]}\n'
|
||||||
signedHeaderText = signedHeaderText.strip()
|
signedHeaderText = signedHeaderText.strip()
|
||||||
headerDigest = getSHA256(signedHeaderText.encode('ascii'))
|
|
||||||
|
|
||||||
# Sign the digest. Potentially other signing algorithms can be added here.
|
# Sign the digest. Potentially other signing algorithms can be added here.
|
||||||
signature = ''
|
signature = ''
|
||||||
if algorithm == 'rsa-sha256':
|
if algorithm == 'rsa-sha512':
|
||||||
|
headerDigest = getSHA512(signedHeaderText.encode('ascii'))
|
||||||
|
rawSignature = key.sign(headerDigest,
|
||||||
|
padding.PKCS1v15(),
|
||||||
|
hazutils.Prehashed(hashes.SHA512()))
|
||||||
|
signature = base64.b64encode(rawSignature).decode('ascii')
|
||||||
|
else:
|
||||||
|
# default sha256
|
||||||
|
headerDigest = getSHA256(signedHeaderText.encode('ascii'))
|
||||||
rawSignature = key.sign(headerDigest,
|
rawSignature = key.sign(headerDigest,
|
||||||
padding.PKCS1v15(),
|
padding.PKCS1v15(),
|
||||||
hazutils.Prehashed(hashes.SHA256()))
|
hazutils.Prehashed(hashes.SHA256()))
|
||||||
|
|
@ -184,27 +199,35 @@ def signPostHeadersNew(dateStr: str, privateKeyPem: str,
|
||||||
return signatureIndexHeader, signatureHeader
|
return signatureIndexHeader, signatureHeader
|
||||||
|
|
||||||
|
|
||||||
def createSignedHeader(privateKeyPem: str, nickname: str,
|
def createSignedHeader(dateStr: str, privateKeyPem: str, nickname: str,
|
||||||
domain: str, port: int,
|
domain: str, port: int,
|
||||||
toDomain: str, toPort: int,
|
toDomain: str, toPort: int,
|
||||||
path: str, httpPrefix: str, withDigest: bool,
|
path: str, httpPrefix: str, withDigest: bool,
|
||||||
messageBodyJsonStr: str) -> {}:
|
messageBodyJsonStr: str,
|
||||||
|
contentType: str) -> {}:
|
||||||
"""Note that the domain is the destination, not the sender
|
"""Note that the domain is the destination, not the sender
|
||||||
"""
|
"""
|
||||||
contentType = 'application/activity+json'
|
|
||||||
headerDomain = getFullDomain(toDomain, toPort)
|
headerDomain = getFullDomain(toDomain, toPort)
|
||||||
|
|
||||||
|
# if no date is given then create one
|
||||||
|
if not dateStr:
|
||||||
dateStr = strftime("%a, %d %b %Y %H:%M:%S %Z", gmtime())
|
dateStr = strftime("%a, %d %b %Y %H:%M:%S %Z", gmtime())
|
||||||
|
|
||||||
|
# Content-Type or Accept header
|
||||||
|
if not contentType:
|
||||||
|
contentType = 'application/activity+json'
|
||||||
|
|
||||||
if not withDigest:
|
if not withDigest:
|
||||||
headers = {
|
headers = {
|
||||||
'(request-target)': f'post {path}',
|
'(request-target)': f'get {path}',
|
||||||
'host': headerDomain,
|
'host': headerDomain,
|
||||||
'date': dateStr
|
'date': dateStr,
|
||||||
|
'accept': contentType
|
||||||
}
|
}
|
||||||
signatureHeader = \
|
signatureHeader = \
|
||||||
signPostHeaders(dateStr, privateKeyPem, nickname,
|
signPostHeaders(dateStr, privateKeyPem, nickname,
|
||||||
domain, port, toDomain, toPort,
|
domain, port, toDomain, toPort,
|
||||||
path, httpPrefix, None)
|
path, httpPrefix, None, contentType)
|
||||||
else:
|
else:
|
||||||
bodyDigest = messageContentDigest(messageBodyJsonStr)
|
bodyDigest = messageContentDigest(messageBodyJsonStr)
|
||||||
contentLength = len(messageBodyJsonStr)
|
contentLength = len(messageBodyJsonStr)
|
||||||
|
|
@ -220,7 +243,8 @@ def createSignedHeader(privateKeyPem: str, nickname: str,
|
||||||
signPostHeaders(dateStr, privateKeyPem, nickname,
|
signPostHeaders(dateStr, privateKeyPem, nickname,
|
||||||
domain, port,
|
domain, port,
|
||||||
toDomain, toPort,
|
toDomain, toPort,
|
||||||
path, httpPrefix, messageBodyJsonStr)
|
path, httpPrefix, messageBodyJsonStr,
|
||||||
|
contentType)
|
||||||
headers['signature'] = signatureHeader
|
headers['signature'] = signatureHeader
|
||||||
return headers
|
return headers
|
||||||
|
|
||||||
|
|
@ -302,9 +326,13 @@ def verifyPostHeaders(httpPrefix: str, publicKeyPem: str, headers: dict,
|
||||||
for k, v in [i.split('=', 1) for i in signatureHeader.split(',')]
|
for k, v in [i.split('=', 1) for i in signatureHeader.split(',')]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if debug:
|
||||||
|
print('signatureDict: ' + str(signatureDict))
|
||||||
|
|
||||||
# Unpack the signed headers and set values based on current headers and
|
# Unpack the signed headers and set values based on current headers and
|
||||||
# body (if a digest was included)
|
# body (if a digest was included)
|
||||||
signedHeaderList = []
|
signedHeaderList = []
|
||||||
|
algorithm = 'rsa-sha256'
|
||||||
for signedHeader in signatureDict[requestTargetKey].split(fieldSep2):
|
for signedHeader in signatureDict[requestTargetKey].split(fieldSep2):
|
||||||
signedHeader = signedHeader.strip()
|
signedHeader = signedHeader.strip()
|
||||||
if debug:
|
if debug:
|
||||||
|
|
@ -323,6 +351,9 @@ def verifyPostHeaders(httpPrefix: str, publicKeyPem: str, headers: dict,
|
||||||
# if ')' in appendStr:
|
# if ')' in appendStr:
|
||||||
# appendStr = appendStr.split(')')[0]
|
# appendStr = appendStr.split(')')[0]
|
||||||
signedHeaderList.append(appendStr)
|
signedHeaderList.append(appendStr)
|
||||||
|
elif signedHeader == 'algorithm':
|
||||||
|
if headers.get(signedHeader):
|
||||||
|
algorithm = headers[signedHeader]
|
||||||
elif signedHeader == 'digest':
|
elif signedHeader == 'digest':
|
||||||
if messageBodyDigest:
|
if messageBodyDigest:
|
||||||
bodyDigest = messageBodyDigest
|
bodyDigest = messageBodyDigest
|
||||||
|
|
@ -333,12 +364,10 @@ def verifyPostHeaders(httpPrefix: str, publicKeyPem: str, headers: dict,
|
||||||
if headers.get(signedHeader):
|
if headers.get(signedHeader):
|
||||||
appendStr = f'content-length: {headers[signedHeader]}'
|
appendStr = f'content-length: {headers[signedHeader]}'
|
||||||
signedHeaderList.append(appendStr)
|
signedHeaderList.append(appendStr)
|
||||||
else:
|
elif headers.get('Content-Length'):
|
||||||
if headers.get('Content-Length'):
|
|
||||||
contentLength = headers['Content-Length']
|
contentLength = headers['Content-Length']
|
||||||
signedHeaderList.append(f'content-length: {contentLength}')
|
signedHeaderList.append(f'content-length: {contentLength}')
|
||||||
else:
|
elif headers.get('Content-length'):
|
||||||
if headers.get('Content-length'):
|
|
||||||
contentLength = headers['Content-length']
|
contentLength = headers['Content-length']
|
||||||
appendStr = f'content-length: {contentLength}'
|
appendStr = f'content-length: {contentLength}'
|
||||||
signedHeaderList.append(appendStr)
|
signedHeaderList.append(appendStr)
|
||||||
|
|
@ -395,11 +424,10 @@ def verifyPostHeaders(httpPrefix: str, publicKeyPem: str, headers: dict,
|
||||||
signedHeaderList.append(
|
signedHeaderList.append(
|
||||||
f'{signedHeader}: {headers[signedHeaderCap]}')
|
f'{signedHeader}: {headers[signedHeaderCap]}')
|
||||||
|
|
||||||
if debug:
|
|
||||||
print('DEBUG: signedHeaderList: ' + str(signedHeaderList))
|
|
||||||
# Now we have our header data digest
|
# Now we have our header data digest
|
||||||
signedHeaderText = '\n'.join(signedHeaderList)
|
signedHeaderText = '\n'.join(signedHeaderList)
|
||||||
headerDigest = getSHA256(signedHeaderText.encode('ascii'))
|
if debug:
|
||||||
|
print('signedHeaderText:\n' + signedHeaderText + 'END')
|
||||||
|
|
||||||
# Get the signature, verify with public key, return result
|
# Get the signature, verify with public key, return result
|
||||||
signature = None
|
signature = None
|
||||||
|
|
@ -415,13 +443,27 @@ def verifyPostHeaders(httpPrefix: str, publicKeyPem: str, headers: dict,
|
||||||
else:
|
else:
|
||||||
# Original Mastodon signature
|
# Original Mastodon signature
|
||||||
signature = base64.b64decode(signatureDict['signature'])
|
signature = base64.b64decode(signatureDict['signature'])
|
||||||
|
if debug:
|
||||||
|
print('signature: ' + algorithm + ' ' +
|
||||||
|
signatureDict['signature'])
|
||||||
|
|
||||||
|
# If extra signing algorithms need to be added then do it here
|
||||||
|
if algorithm == 'rsa-sha256':
|
||||||
|
headerDigest = getSHA256(signedHeaderText.encode('ascii'))
|
||||||
|
paddingStr = padding.PKCS1v15()
|
||||||
|
alg = hazutils.Prehashed(hashes.SHA256())
|
||||||
|
elif algorithm == 'rsa-sha512':
|
||||||
|
headerDigest = getSHA512(signedHeaderText.encode('ascii'))
|
||||||
|
paddingStr = padding.PKCS1v15()
|
||||||
|
alg = hazutils.Prehashed(hashes.SHA512())
|
||||||
|
else:
|
||||||
|
print('Unknown http signature algorithm: ' + algorithm)
|
||||||
|
paddingStr = padding.PKCS1v15()
|
||||||
|
alg = hazutils.Prehashed(hashes.SHA256())
|
||||||
|
headerDigest = ''
|
||||||
|
|
||||||
try:
|
try:
|
||||||
pubkey.verify(
|
pubkey.verify(signature, headerDigest, paddingStr, alg)
|
||||||
signature,
|
|
||||||
headerDigest,
|
|
||||||
padding.PKCS1v15(),
|
|
||||||
hazutils.Prehashed(hashes.SHA256()))
|
|
||||||
return True
|
return True
|
||||||
except BaseException:
|
except BaseException:
|
||||||
if debug:
|
if debug:
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.1.0"
|
__version__ = "1.1.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
|
|
||||||
import base64, hashlib, sys
|
import base64, hashlib, sys
|
||||||
|
|
|
||||||
|
After Width: | Height: | Size: 131 KiB |
2
jami.py
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Profile Metadata"
|
__module_group__ = "Profile Metadata"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Core"
|
__module_group__ = "Core"
|
||||||
|
|
||||||
|
|
|
||||||
111
like.py
|
|
@ -3,10 +3,12 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "ActivityPub"
|
__module_group__ = "ActivityPub"
|
||||||
|
|
||||||
|
import os
|
||||||
|
from pprint import pprint
|
||||||
from utils import removeDomainPort
|
from utils import removeDomainPort
|
||||||
from utils import hasObjectDict
|
from utils import hasObjectDict
|
||||||
from utils import hasUsersPath
|
from utils import hasUsersPath
|
||||||
|
|
@ -16,10 +18,13 @@ from utils import urlPermitted
|
||||||
from utils import getNicknameFromActor
|
from utils import getNicknameFromActor
|
||||||
from utils import getDomainFromActor
|
from utils import getDomainFromActor
|
||||||
from utils import locatePost
|
from utils import locatePost
|
||||||
from utils import updateLikesCollection
|
|
||||||
from utils import undoLikesCollectionEntry
|
from utils import undoLikesCollectionEntry
|
||||||
from utils import hasGroupType
|
from utils import hasGroupType
|
||||||
from utils import localActorUrl
|
from utils import localActorUrl
|
||||||
|
from utils import loadJson
|
||||||
|
from utils import saveJson
|
||||||
|
from utils import removePostFromCache
|
||||||
|
from utils import getCachedPostFilename
|
||||||
from posts import sendSignedJson
|
from posts import sendSignedJson
|
||||||
from session import postJson
|
from session import postJson
|
||||||
from webfinger import webfingerHandle
|
from webfinger import webfingerHandle
|
||||||
|
|
@ -62,7 +67,8 @@ def _like(recentPostsCache: {},
|
||||||
clientToServer: bool,
|
clientToServer: bool,
|
||||||
sendThreads: [], postLog: [],
|
sendThreads: [], postLog: [],
|
||||||
personCache: {}, cachedWebfingers: {},
|
personCache: {}, cachedWebfingers: {},
|
||||||
debug: bool, projectVersion: str) -> {}:
|
debug: bool, projectVersion: str,
|
||||||
|
signingPrivateKeyPem: str) -> {}:
|
||||||
"""Creates a like
|
"""Creates a like
|
||||||
actor is the person doing the liking
|
actor is the person doing the liking
|
||||||
'to' might be a specific person (actor) whose post was liked
|
'to' might be a specific person (actor) whose post was liked
|
||||||
|
|
@ -122,7 +128,8 @@ def _like(recentPostsCache: {},
|
||||||
'https://www.w3.org/ns/activitystreams#Public',
|
'https://www.w3.org/ns/activitystreams#Public',
|
||||||
httpPrefix, True, clientToServer, federationList,
|
httpPrefix, True, clientToServer, federationList,
|
||||||
sendThreads, postLog, cachedWebfingers, personCache,
|
sendThreads, postLog, cachedWebfingers, personCache,
|
||||||
debug, projectVersion, None, groupAccount)
|
debug, projectVersion, None, groupAccount,
|
||||||
|
signingPrivateKeyPem, 7367374)
|
||||||
|
|
||||||
return newLikeJson
|
return newLikeJson
|
||||||
|
|
||||||
|
|
@ -135,7 +142,8 @@ def likePost(recentPostsCache: {},
|
||||||
likeStatusNumber: int, clientToServer: bool,
|
likeStatusNumber: int, clientToServer: bool,
|
||||||
sendThreads: [], postLog: [],
|
sendThreads: [], postLog: [],
|
||||||
personCache: {}, cachedWebfingers: {},
|
personCache: {}, cachedWebfingers: {},
|
||||||
debug: bool, projectVersion: str) -> {}:
|
debug: bool, projectVersion: str,
|
||||||
|
signingPrivateKeyPem: str) -> {}:
|
||||||
"""Likes a given status post. This is only used by unit tests
|
"""Likes a given status post. This is only used by unit tests
|
||||||
"""
|
"""
|
||||||
likeDomain = getFullDomain(likeDomain, likePort)
|
likeDomain = getFullDomain(likeDomain, likePort)
|
||||||
|
|
@ -147,7 +155,7 @@ def likePost(recentPostsCache: {},
|
||||||
session, baseDir, federationList, nickname, domain, port,
|
session, baseDir, federationList, nickname, domain, port,
|
||||||
ccList, httpPrefix, objectUrl, actorLiked, clientToServer,
|
ccList, httpPrefix, objectUrl, actorLiked, clientToServer,
|
||||||
sendThreads, postLog, personCache, cachedWebfingers,
|
sendThreads, postLog, personCache, cachedWebfingers,
|
||||||
debug, projectVersion)
|
debug, projectVersion, signingPrivateKeyPem)
|
||||||
|
|
||||||
|
|
||||||
def sendLikeViaServer(baseDir: str, session,
|
def sendLikeViaServer(baseDir: str, session,
|
||||||
|
|
@ -155,7 +163,8 @@ def sendLikeViaServer(baseDir: str, session,
|
||||||
fromDomain: str, fromPort: int,
|
fromDomain: str, fromPort: int,
|
||||||
httpPrefix: str, likeUrl: str,
|
httpPrefix: str, likeUrl: str,
|
||||||
cachedWebfingers: {}, personCache: {},
|
cachedWebfingers: {}, personCache: {},
|
||||||
debug: bool, projectVersion: str) -> {}:
|
debug: bool, projectVersion: str,
|
||||||
|
signingPrivateKeyPem: str) -> {}:
|
||||||
"""Creates a like via c2s
|
"""Creates a like via c2s
|
||||||
"""
|
"""
|
||||||
if not session:
|
if not session:
|
||||||
|
|
@ -178,7 +187,8 @@ def sendLikeViaServer(baseDir: str, session,
|
||||||
# lookup the inbox for the To handle
|
# lookup the inbox for the To handle
|
||||||
wfRequest = webfingerHandle(session, handle, httpPrefix,
|
wfRequest = webfingerHandle(session, handle, httpPrefix,
|
||||||
cachedWebfingers,
|
cachedWebfingers,
|
||||||
fromDomain, projectVersion, debug, False)
|
fromDomain, projectVersion, debug, False,
|
||||||
|
signingPrivateKeyPem)
|
||||||
if not wfRequest:
|
if not wfRequest:
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: like webfinger failed for ' + handle)
|
print('DEBUG: like webfinger failed for ' + handle)
|
||||||
|
|
@ -191,8 +201,11 @@ def sendLikeViaServer(baseDir: str, session,
|
||||||
postToBox = 'outbox'
|
postToBox = 'outbox'
|
||||||
|
|
||||||
# get the actor inbox for the To handle
|
# get the actor inbox for the To handle
|
||||||
(inboxUrl, pubKeyId, pubKey, fromPersonId, sharedInbox,
|
originDomain = fromDomain
|
||||||
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
(inboxUrl, pubKeyId, pubKey, fromPersonId, sharedInbox, avatarUrl,
|
||||||
|
displayName, _) = getPersonBox(signingPrivateKeyPem,
|
||||||
|
originDomain,
|
||||||
|
baseDir, session, wfRequest,
|
||||||
personCache,
|
personCache,
|
||||||
projectVersion, httpPrefix,
|
projectVersion, httpPrefix,
|
||||||
fromNickname, fromDomain,
|
fromNickname, fromDomain,
|
||||||
|
|
@ -233,7 +246,8 @@ def sendUndoLikeViaServer(baseDir: str, session,
|
||||||
fromDomain: str, fromPort: int,
|
fromDomain: str, fromPort: int,
|
||||||
httpPrefix: str, likeUrl: str,
|
httpPrefix: str, likeUrl: str,
|
||||||
cachedWebfingers: {}, personCache: {},
|
cachedWebfingers: {}, personCache: {},
|
||||||
debug: bool, projectVersion: str) -> {}:
|
debug: bool, projectVersion: str,
|
||||||
|
signingPrivateKeyPem: str) -> {}:
|
||||||
"""Undo a like via c2s
|
"""Undo a like via c2s
|
||||||
"""
|
"""
|
||||||
if not session:
|
if not session:
|
||||||
|
|
@ -260,7 +274,8 @@ def sendUndoLikeViaServer(baseDir: str, session,
|
||||||
# lookup the inbox for the To handle
|
# lookup the inbox for the To handle
|
||||||
wfRequest = webfingerHandle(session, handle, httpPrefix,
|
wfRequest = webfingerHandle(session, handle, httpPrefix,
|
||||||
cachedWebfingers,
|
cachedWebfingers,
|
||||||
fromDomain, projectVersion, debug, False)
|
fromDomain, projectVersion, debug, False,
|
||||||
|
signingPrivateKeyPem)
|
||||||
if not wfRequest:
|
if not wfRequest:
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: unlike webfinger failed for ' + handle)
|
print('DEBUG: unlike webfinger failed for ' + handle)
|
||||||
|
|
@ -274,8 +289,11 @@ def sendUndoLikeViaServer(baseDir: str, session,
|
||||||
postToBox = 'outbox'
|
postToBox = 'outbox'
|
||||||
|
|
||||||
# get the actor inbox for the To handle
|
# get the actor inbox for the To handle
|
||||||
(inboxUrl, pubKeyId, pubKey, fromPersonId, sharedInbox,
|
originDomain = fromDomain
|
||||||
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
(inboxUrl, pubKeyId, pubKey, fromPersonId, sharedInbox, avatarUrl,
|
||||||
|
displayName, _) = getPersonBox(signingPrivateKeyPem,
|
||||||
|
originDomain,
|
||||||
|
baseDir, session, wfRequest,
|
||||||
personCache, projectVersion,
|
personCache, projectVersion,
|
||||||
httpPrefix, fromNickname,
|
httpPrefix, fromNickname,
|
||||||
fromDomain, postToBox,
|
fromDomain, postToBox,
|
||||||
|
|
@ -398,3 +416,68 @@ def outboxUndoLike(recentPostsCache: {},
|
||||||
domain, debug)
|
domain, debug)
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: post undo liked via c2s - ' + postFilename)
|
print('DEBUG: post undo liked via c2s - ' + postFilename)
|
||||||
|
|
||||||
|
|
||||||
|
def updateLikesCollection(recentPostsCache: {},
|
||||||
|
baseDir: str, postFilename: str,
|
||||||
|
objectUrl: str, actor: str,
|
||||||
|
nickname: str, domain: str, debug: bool) -> None:
|
||||||
|
"""Updates the likes collection within a post
|
||||||
|
"""
|
||||||
|
postJsonObject = loadJson(postFilename)
|
||||||
|
if not postJsonObject:
|
||||||
|
return
|
||||||
|
|
||||||
|
# remove any cached version of this post so that the
|
||||||
|
# like icon is changed
|
||||||
|
removePostFromCache(postJsonObject, recentPostsCache)
|
||||||
|
cachedPostFilename = getCachedPostFilename(baseDir, nickname,
|
||||||
|
domain, postJsonObject)
|
||||||
|
if cachedPostFilename:
|
||||||
|
if os.path.isfile(cachedPostFilename):
|
||||||
|
try:
|
||||||
|
os.remove(cachedPostFilename)
|
||||||
|
except BaseException:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if not hasObjectDict(postJsonObject):
|
||||||
|
if debug:
|
||||||
|
pprint(postJsonObject)
|
||||||
|
print('DEBUG: post ' + objectUrl + ' has no object')
|
||||||
|
return
|
||||||
|
if not objectUrl.endswith('/likes'):
|
||||||
|
objectUrl = objectUrl + '/likes'
|
||||||
|
if not postJsonObject['object'].get('likes'):
|
||||||
|
if debug:
|
||||||
|
print('DEBUG: Adding initial like to ' + objectUrl)
|
||||||
|
likesJson = {
|
||||||
|
"@context": "https://www.w3.org/ns/activitystreams",
|
||||||
|
'id': objectUrl,
|
||||||
|
'type': 'Collection',
|
||||||
|
"totalItems": 1,
|
||||||
|
'items': [{
|
||||||
|
'type': 'Like',
|
||||||
|
'actor': actor
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
postJsonObject['object']['likes'] = likesJson
|
||||||
|
else:
|
||||||
|
if not postJsonObject['object']['likes'].get('items'):
|
||||||
|
postJsonObject['object']['likes']['items'] = []
|
||||||
|
for likeItem in postJsonObject['object']['likes']['items']:
|
||||||
|
if likeItem.get('actor'):
|
||||||
|
if likeItem['actor'] == actor:
|
||||||
|
# already liked
|
||||||
|
return
|
||||||
|
newLike = {
|
||||||
|
'type': 'Like',
|
||||||
|
'actor': actor
|
||||||
|
}
|
||||||
|
postJsonObject['object']['likes']['items'].append(newLike)
|
||||||
|
itlen = len(postJsonObject['object']['likes']['items'])
|
||||||
|
postJsonObject['object']['likes']['totalItems'] = itlen
|
||||||
|
|
||||||
|
if debug:
|
||||||
|
print('DEBUG: saving post with likes added')
|
||||||
|
pprint(postJsonObject)
|
||||||
|
saveJson(postJsonObject, postFilename)
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ __credits__ = ['Based on ' +
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Security"
|
__module_group__ = "Security"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "ActivityPub"
|
__module_group__ = "ActivityPub"
|
||||||
|
|
||||||
|
|
@ -26,7 +26,8 @@ def manualDenyFollowRequest(session, baseDir: str,
|
||||||
sendThreads: [], postLog: [],
|
sendThreads: [], postLog: [],
|
||||||
cachedWebfingers: {}, personCache: {},
|
cachedWebfingers: {}, personCache: {},
|
||||||
debug: bool,
|
debug: bool,
|
||||||
projectVersion: str) -> None:
|
projectVersion: str,
|
||||||
|
signingPrivateKeyPem: str) -> None:
|
||||||
"""Manually deny a follow request
|
"""Manually deny a follow request
|
||||||
"""
|
"""
|
||||||
accountsDir = acctDir(baseDir, nickname, domain)
|
accountsDir = acctDir(baseDir, nickname, domain)
|
||||||
|
|
@ -60,7 +61,8 @@ def manualDenyFollowRequest(session, baseDir: str,
|
||||||
federationList,
|
federationList,
|
||||||
sendThreads, postLog,
|
sendThreads, postLog,
|
||||||
cachedWebfingers, personCache,
|
cachedWebfingers, personCache,
|
||||||
debug, projectVersion)
|
debug, projectVersion,
|
||||||
|
signingPrivateKeyPem)
|
||||||
|
|
||||||
print('Follow request from ' + denyHandle + ' was denied.')
|
print('Follow request from ' + denyHandle + ' was denied.')
|
||||||
|
|
||||||
|
|
@ -87,7 +89,8 @@ def manualApproveFollowRequest(session, baseDir: str,
|
||||||
sendThreads: [], postLog: [],
|
sendThreads: [], postLog: [],
|
||||||
cachedWebfingers: {}, personCache: {},
|
cachedWebfingers: {}, personCache: {},
|
||||||
debug: bool,
|
debug: bool,
|
||||||
projectVersion: str) -> None:
|
projectVersion: str,
|
||||||
|
signingPrivateKeyPem: str) -> None:
|
||||||
"""Manually approve a follow request
|
"""Manually approve a follow request
|
||||||
"""
|
"""
|
||||||
handle = nickname + '@' + domain
|
handle = nickname + '@' + domain
|
||||||
|
|
@ -176,7 +179,8 @@ def manualApproveFollowRequest(session, baseDir: str,
|
||||||
cachedWebfingers,
|
cachedWebfingers,
|
||||||
personCache,
|
personCache,
|
||||||
debug,
|
debug,
|
||||||
projectVersion, False)
|
projectVersion, False,
|
||||||
|
signingPrivateKeyPem)
|
||||||
updateApprovedFollowers = True
|
updateApprovedFollowers = True
|
||||||
else:
|
else:
|
||||||
# this isn't the approved follow so it will remain
|
# this isn't the approved follow so it will remain
|
||||||
|
|
@ -218,6 +222,12 @@ def manualApproveFollowRequest(session, baseDir: str,
|
||||||
# remove the .follow file
|
# remove the .follow file
|
||||||
if followActivityfilename:
|
if followActivityfilename:
|
||||||
if os.path.isfile(followActivityfilename):
|
if os.path.isfile(followActivityfilename):
|
||||||
|
try:
|
||||||
os.remove(followActivityfilename)
|
os.remove(followActivityfilename)
|
||||||
|
except BaseException:
|
||||||
|
pass
|
||||||
else:
|
else:
|
||||||
|
try:
|
||||||
os.remove(approveFollowsFilename + '.new')
|
os.remove(approveFollowsFilename + '.new')
|
||||||
|
except BaseException:
|
||||||
|
pass
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Web Interface"
|
__module_group__ = "Web Interface"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "API"
|
__module_group__ = "API"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Profile Metadata"
|
__module_group__ = "Profile Metadata"
|
||||||
|
|
||||||
|
|
|
||||||
30
media.py
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Timeline"
|
__module_group__ = "Timeline"
|
||||||
|
|
||||||
|
|
@ -28,10 +28,10 @@ from shutil import move
|
||||||
from city import spoofGeolocation
|
from city import spoofGeolocation
|
||||||
|
|
||||||
|
|
||||||
def replaceYouTube(postJsonObject: {}, replacementDomain: str,
|
def _replaceSiloDomain(postJsonObject: {},
|
||||||
|
siloDomain: str, replacementDomain: str,
|
||||||
systemLanguage: str) -> None:
|
systemLanguage: str) -> None:
|
||||||
"""Replace YouTube with a replacement domain
|
"""Replace a silo domain with a replacement domain
|
||||||
This denies Google some, but not all, tracking data
|
|
||||||
"""
|
"""
|
||||||
if not replacementDomain:
|
if not replacementDomain:
|
||||||
return
|
return
|
||||||
|
|
@ -40,14 +40,32 @@ def replaceYouTube(postJsonObject: {}, replacementDomain: str,
|
||||||
if not postJsonObject['object'].get('content'):
|
if not postJsonObject['object'].get('content'):
|
||||||
return
|
return
|
||||||
contentStr = getBaseContentFromPost(postJsonObject, systemLanguage)
|
contentStr = getBaseContentFromPost(postJsonObject, systemLanguage)
|
||||||
if 'www.youtube.com' not in contentStr:
|
if siloDomain not in contentStr:
|
||||||
return
|
return
|
||||||
contentStr = contentStr.replace('www.youtube.com', replacementDomain)
|
contentStr = contentStr.replace(siloDomain, replacementDomain)
|
||||||
postJsonObject['object']['content'] = contentStr
|
postJsonObject['object']['content'] = contentStr
|
||||||
if postJsonObject['object'].get('contentMap'):
|
if postJsonObject['object'].get('contentMap'):
|
||||||
postJsonObject['object']['contentMap'][systemLanguage] = contentStr
|
postJsonObject['object']['contentMap'][systemLanguage] = contentStr
|
||||||
|
|
||||||
|
|
||||||
|
def replaceYouTube(postJsonObject: {}, replacementDomain: str,
|
||||||
|
systemLanguage: str) -> None:
|
||||||
|
"""Replace YouTube with a replacement domain
|
||||||
|
This denies Google some, but not all, tracking data
|
||||||
|
"""
|
||||||
|
_replaceSiloDomain(postJsonObject, 'www.youtube.com',
|
||||||
|
replacementDomain, systemLanguage)
|
||||||
|
|
||||||
|
|
||||||
|
def replaceTwitter(postJsonObject: {}, replacementDomain: str,
|
||||||
|
systemLanguage: str) -> None:
|
||||||
|
"""Replace Twitter with a replacement domain
|
||||||
|
This allows you to view twitter posts without having a twitter account
|
||||||
|
"""
|
||||||
|
_replaceSiloDomain(postJsonObject, 'twitter.com',
|
||||||
|
replacementDomain, systemLanguage)
|
||||||
|
|
||||||
|
|
||||||
def _removeMetaData(imageFilename: str, outputFilename: str) -> None:
|
def _removeMetaData(imageFilename: str, outputFilename: str) -> None:
|
||||||
"""Attempts to do this with pure python didn't work well,
|
"""Attempts to do this with pure python didn't work well,
|
||||||
so better to use a dedicated tool if one is installed
|
so better to use a dedicated tool if one is installed
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Metadata"
|
__module_group__ = "Metadata"
|
||||||
|
|
||||||
|
|
|
||||||
20
migrate.py
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Core"
|
__module_group__ = "Core"
|
||||||
|
|
||||||
|
|
@ -23,7 +23,8 @@ from person import getActorJson
|
||||||
def _moveFollowingHandlesForAccount(baseDir: str, nickname: str, domain: str,
|
def _moveFollowingHandlesForAccount(baseDir: str, nickname: str, domain: str,
|
||||||
session,
|
session,
|
||||||
httpPrefix: str, cachedWebfingers: {},
|
httpPrefix: str, cachedWebfingers: {},
|
||||||
debug: bool) -> int:
|
debug: bool,
|
||||||
|
signingPrivateKeyPem: str) -> int:
|
||||||
"""Goes through all follows for an account and updates any that have moved
|
"""Goes through all follows for an account and updates any that have moved
|
||||||
"""
|
"""
|
||||||
ctr = 0
|
ctr = 0
|
||||||
|
|
@ -38,14 +39,14 @@ def _moveFollowingHandlesForAccount(baseDir: str, nickname: str, domain: str,
|
||||||
_updateMovedHandle(baseDir, nickname, domain,
|
_updateMovedHandle(baseDir, nickname, domain,
|
||||||
followHandle, session,
|
followHandle, session,
|
||||||
httpPrefix, cachedWebfingers,
|
httpPrefix, cachedWebfingers,
|
||||||
debug)
|
debug, signingPrivateKeyPem)
|
||||||
return ctr
|
return ctr
|
||||||
|
|
||||||
|
|
||||||
def _updateMovedHandle(baseDir: str, nickname: str, domain: str,
|
def _updateMovedHandle(baseDir: str, nickname: str, domain: str,
|
||||||
handle: str, session,
|
handle: str, session,
|
||||||
httpPrefix: str, cachedWebfingers: {},
|
httpPrefix: str, cachedWebfingers: {},
|
||||||
debug: bool) -> int:
|
debug: bool, signingPrivateKeyPem: str) -> int:
|
||||||
"""Check if an account has moved, and if so then alter following.txt
|
"""Check if an account has moved, and if so then alter following.txt
|
||||||
for each account.
|
for each account.
|
||||||
Returns 1 if moved, 0 otherwise
|
Returns 1 if moved, 0 otherwise
|
||||||
|
|
@ -59,7 +60,8 @@ def _updateMovedHandle(baseDir: str, nickname: str, domain: str,
|
||||||
handle = handle[1:]
|
handle = handle[1:]
|
||||||
wfRequest = webfingerHandle(session, handle,
|
wfRequest = webfingerHandle(session, handle,
|
||||||
httpPrefix, cachedWebfingers,
|
httpPrefix, cachedWebfingers,
|
||||||
None, __version__, debug, False)
|
domain, __version__, debug, False,
|
||||||
|
signingPrivateKeyPem)
|
||||||
if not wfRequest:
|
if not wfRequest:
|
||||||
print('updateMovedHandle unable to webfinger ' + handle)
|
print('updateMovedHandle unable to webfinger ' + handle)
|
||||||
return ctr
|
return ctr
|
||||||
|
|
@ -83,7 +85,8 @@ def _updateMovedHandle(baseDir: str, nickname: str, domain: str,
|
||||||
if httpPrefix == 'gnunet':
|
if httpPrefix == 'gnunet':
|
||||||
gnunet = True
|
gnunet = True
|
||||||
personJson = \
|
personJson = \
|
||||||
getActorJson(domain, personUrl, httpPrefix, gnunet, debug)
|
getActorJson(domain, personUrl, httpPrefix, gnunet, debug, False,
|
||||||
|
signingPrivateKeyPem)
|
||||||
if not personJson:
|
if not personJson:
|
||||||
return ctr
|
return ctr
|
||||||
if not personJson.get('movedTo'):
|
if not personJson.get('movedTo'):
|
||||||
|
|
@ -172,7 +175,7 @@ def _updateMovedHandle(baseDir: str, nickname: str, domain: str,
|
||||||
|
|
||||||
def migrateAccounts(baseDir: str, session,
|
def migrateAccounts(baseDir: str, session,
|
||||||
httpPrefix: str, cachedWebfingers: {},
|
httpPrefix: str, cachedWebfingers: {},
|
||||||
debug: bool) -> int:
|
debug: bool, signingPrivateKeyPem: str) -> int:
|
||||||
"""If followed accounts change then this modifies the
|
"""If followed accounts change then this modifies the
|
||||||
following lists for each account accordingly.
|
following lists for each account accordingly.
|
||||||
Returns the number of accounts migrated
|
Returns the number of accounts migrated
|
||||||
|
|
@ -188,6 +191,7 @@ def migrateAccounts(baseDir: str, session,
|
||||||
ctr += \
|
ctr += \
|
||||||
_moveFollowingHandlesForAccount(baseDir, nickname, domain,
|
_moveFollowingHandlesForAccount(baseDir, nickname, domain,
|
||||||
session, httpPrefix,
|
session, httpPrefix,
|
||||||
cachedWebfingers, debug)
|
cachedWebfingers, debug,
|
||||||
|
signingPrivateKeyPem)
|
||||||
break
|
break
|
||||||
return ctr
|
return ctr
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Web Interface Columns"
|
__module_group__ = "Web Interface Columns"
|
||||||
|
|
||||||
|
|
@ -526,6 +526,7 @@ def _convertRSStoActivityPub(baseDir: str, httpPrefix: str,
|
||||||
"""Converts rss items in a newswire into posts
|
"""Converts rss items in a newswire into posts
|
||||||
"""
|
"""
|
||||||
if not newswire:
|
if not newswire:
|
||||||
|
print('No newswire to convert')
|
||||||
return
|
return
|
||||||
|
|
||||||
basePath = baseDir + '/accounts/news@' + domain + '/outbox'
|
basePath = baseDir + '/accounts/news@' + domain + '/outbox'
|
||||||
|
|
@ -542,9 +543,18 @@ def _convertRSStoActivityPub(baseDir: str, httpPrefix: str,
|
||||||
dateStr = dateStr.replace(' ', 'T')
|
dateStr = dateStr.replace(' ', 'T')
|
||||||
dateStr = dateStr.replace('+00:00', 'Z')
|
dateStr = dateStr.replace('+00:00', 'Z')
|
||||||
else:
|
else:
|
||||||
|
try:
|
||||||
dateStrWithOffset = \
|
dateStrWithOffset = \
|
||||||
datetime.datetime.strptime(dateStr, "%Y-%m-%d %H:%M:%S%z")
|
datetime.datetime.strptime(dateStr, "%Y-%m-%d %H:%M:%S%z")
|
||||||
|
except BaseException:
|
||||||
|
print('Newswire strptime failed ' + str(dateStr))
|
||||||
|
continue
|
||||||
|
try:
|
||||||
dateStr = dateStrWithOffset.strftime("%Y-%m-%dT%H:%M:%SZ")
|
dateStr = dateStrWithOffset.strftime("%Y-%m-%dT%H:%M:%SZ")
|
||||||
|
except BaseException:
|
||||||
|
print('Newswire dateStrWithOffset failed ' +
|
||||||
|
str(dateStrWithOffset))
|
||||||
|
continue
|
||||||
|
|
||||||
statusNumber, published = getStatusNumber(dateStr)
|
statusNumber, published = getStatusNumber(dateStr)
|
||||||
newPostId = \
|
newPostId = \
|
||||||
|
|
@ -702,7 +712,10 @@ def _convertRSStoActivityPub(baseDir: str, httpPrefix: str,
|
||||||
blog['object']['arrived'])
|
blog['object']['arrived'])
|
||||||
else:
|
else:
|
||||||
if os.path.isfile(filename + '.arrived'):
|
if os.path.isfile(filename + '.arrived'):
|
||||||
|
try:
|
||||||
os.remove(filename + '.arrived')
|
os.remove(filename + '.arrived')
|
||||||
|
except BaseException:
|
||||||
|
pass
|
||||||
|
|
||||||
# setting the url here links to the activitypub object
|
# setting the url here links to the activitypub object
|
||||||
# stored locally
|
# stored locally
|
||||||
|
|
@ -750,6 +763,7 @@ def runNewswireDaemon(baseDir: str, httpd,
|
||||||
print('Newswire daemon session established')
|
print('Newswire daemon session established')
|
||||||
|
|
||||||
# try to update the feeds
|
# try to update the feeds
|
||||||
|
print('Updating newswire feeds')
|
||||||
newNewswire = \
|
newNewswire = \
|
||||||
getDictFromNewswire(httpd.session, baseDir, domain,
|
getDictFromNewswire(httpd.session, baseDir, domain,
|
||||||
httpd.maxNewswirePostsPerSource,
|
httpd.maxNewswirePostsPerSource,
|
||||||
|
|
@ -761,16 +775,22 @@ def runNewswireDaemon(baseDir: str, httpd,
|
||||||
httpd.systemLanguage)
|
httpd.systemLanguage)
|
||||||
|
|
||||||
if not httpd.newswire:
|
if not httpd.newswire:
|
||||||
|
print('Newswire feeds not updated')
|
||||||
if os.path.isfile(newswireStateFilename):
|
if os.path.isfile(newswireStateFilename):
|
||||||
|
print('Loading newswire from file')
|
||||||
httpd.newswire = loadJson(newswireStateFilename)
|
httpd.newswire = loadJson(newswireStateFilename)
|
||||||
|
|
||||||
|
print('Merging with previous newswire')
|
||||||
_mergeWithPreviousNewswire(httpd.newswire, newNewswire)
|
_mergeWithPreviousNewswire(httpd.newswire, newNewswire)
|
||||||
|
|
||||||
httpd.newswire = newNewswire
|
httpd.newswire = newNewswire
|
||||||
if newNewswire:
|
if newNewswire:
|
||||||
saveJson(httpd.newswire, newswireStateFilename)
|
saveJson(httpd.newswire, newswireStateFilename)
|
||||||
print('Newswire updated')
|
print('Newswire updated')
|
||||||
|
else:
|
||||||
|
print('No new newswire')
|
||||||
|
|
||||||
|
print('Converting newswire to activitypub format')
|
||||||
_convertRSStoActivityPub(baseDir,
|
_convertRSStoActivityPub(baseDir,
|
||||||
httpPrefix, domain, port,
|
httpPrefix, domain, port,
|
||||||
newNewswire, translate,
|
newNewswire, translate,
|
||||||
|
|
@ -792,6 +812,7 @@ def runNewswireDaemon(baseDir: str, httpd,
|
||||||
archiveDir = baseDir + '/archive'
|
archiveDir = baseDir + '/archive'
|
||||||
archiveSubdir = \
|
archiveSubdir = \
|
||||||
archiveDir + '/accounts/news@' + domain + '/outbox'
|
archiveDir + '/accounts/news@' + domain + '/outbox'
|
||||||
|
print('Archiving news posts')
|
||||||
archivePostsForPerson(httpPrefix, 'news',
|
archivePostsForPerson(httpPrefix, 'news',
|
||||||
domain, baseDir, 'outbox',
|
domain, baseDir, 'outbox',
|
||||||
archiveSubdir,
|
archiveSubdir,
|
||||||
|
|
|
||||||
13
newswire.py
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Web Interface Columns"
|
__module_group__ = "Web Interface Columns"
|
||||||
|
|
||||||
|
|
@ -192,9 +192,9 @@ def parseFeedDate(pubDate: str) -> str:
|
||||||
formats = ("%a, %d %b %Y %H:%M:%S %z",
|
formats = ("%a, %d %b %Y %H:%M:%S %z",
|
||||||
"%a, %d %b %Y %H:%M:%S EST",
|
"%a, %d %b %Y %H:%M:%S EST",
|
||||||
"%a, %d %b %Y %H:%M:%S UT",
|
"%a, %d %b %Y %H:%M:%S UT",
|
||||||
|
"%a, %d %b %Y %H:%M:%S GMT",
|
||||||
"%Y-%m-%dT%H:%M:%SZ",
|
"%Y-%m-%dT%H:%M:%SZ",
|
||||||
"%Y-%m-%dT%H:%M:%S%z")
|
"%Y-%m-%dT%H:%M:%S%z")
|
||||||
|
|
||||||
publishedDate = None
|
publishedDate = None
|
||||||
for dateFormat in formats:
|
for dateFormat in formats:
|
||||||
if ',' in pubDate and ',' not in dateFormat:
|
if ',' in pubDate and ',' not in dateFormat:
|
||||||
|
|
@ -207,6 +207,8 @@ def parseFeedDate(pubDate: str) -> str:
|
||||||
continue
|
continue
|
||||||
if 'EST' not in pubDate and 'EST' in dateFormat:
|
if 'EST' not in pubDate and 'EST' in dateFormat:
|
||||||
continue
|
continue
|
||||||
|
if 'GMT' not in pubDate and 'GMT' in dateFormat:
|
||||||
|
continue
|
||||||
if 'EST' in pubDate and 'EST' not in dateFormat:
|
if 'EST' in pubDate and 'EST' not in dateFormat:
|
||||||
continue
|
continue
|
||||||
if 'UT' not in pubDate and 'UT' in dateFormat:
|
if 'UT' not in pubDate and 'UT' in dateFormat:
|
||||||
|
|
@ -218,8 +220,6 @@ def parseFeedDate(pubDate: str) -> str:
|
||||||
publishedDate = \
|
publishedDate = \
|
||||||
datetime.strptime(pubDate, dateFormat)
|
datetime.strptime(pubDate, dateFormat)
|
||||||
except BaseException:
|
except BaseException:
|
||||||
print('WARN: unrecognized date format: ' +
|
|
||||||
pubDate + ' ' + dateFormat)
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if publishedDate:
|
if publishedDate:
|
||||||
|
|
@ -238,6 +238,8 @@ def parseFeedDate(pubDate: str) -> str:
|
||||||
pubDateStr = str(publishedDate)
|
pubDateStr = str(publishedDate)
|
||||||
if not pubDateStr.endswith('+00:00'):
|
if not pubDateStr.endswith('+00:00'):
|
||||||
pubDateStr += '+00:00'
|
pubDateStr += '+00:00'
|
||||||
|
else:
|
||||||
|
print('WARN: unrecognized date format: ' + pubDate)
|
||||||
|
|
||||||
return pubDateStr
|
return pubDateStr
|
||||||
|
|
||||||
|
|
@ -1028,7 +1030,10 @@ def _addBlogsToNewswire(baseDir: str, domain: str, newswire: {},
|
||||||
else:
|
else:
|
||||||
# remove the file if there is nothing to moderate
|
# remove the file if there is nothing to moderate
|
||||||
if os.path.isfile(newswireModerationFilename):
|
if os.path.isfile(newswireModerationFilename):
|
||||||
|
try:
|
||||||
os.remove(newswireModerationFilename)
|
os.remove(newswireModerationFilename)
|
||||||
|
except BaseException:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def getDictFromNewswire(session, baseDir: str, domain: str,
|
def getDictFromNewswire(session, baseDir: str, domain: str,
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Calendar"
|
__module_group__ = "Calendar"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,95 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<Ontology xmlns="http://www.w3.org/2002/07/owl#"
|
||||||
|
xml:base="http://static.datafoodconsortium.org/ontologies/DFC_FullModel.owl"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:xml="http://www.w3.org/XML/1998/namespace"
|
||||||
|
xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
|
||||||
|
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
|
||||||
|
ontologyIRI="http://static.datafoodconsortium.org/ontologies/DFC_FullModel.owl">
|
||||||
|
<Prefix name="" IRI="http://static.datafoodconsortium.org/ontologies/DFC_FullModel.owl#"/>
|
||||||
|
<Prefix name="cc" IRI="http://creativecommons.org/ns#"/>
|
||||||
|
<Prefix name="dc" IRI="http://purl.org/dc/terms/"/>
|
||||||
|
<Prefix name="owl" IRI="http://www.w3.org/2002/07/owl#"/>
|
||||||
|
<Prefix name="rdf" IRI="http://www.w3.org/1999/02/22-rdf-syntax-ns#"/>
|
||||||
|
<Prefix name="xml" IRI="http://www.w3.org/XML/1998/namespace"/>
|
||||||
|
<Prefix name="xsd" IRI="http://www.w3.org/2001/XMLSchema#"/>
|
||||||
|
<Prefix name="xsp" IRI="http://www.owl-ontologies.com/2005/08/07/xsp.owl#"/>
|
||||||
|
<Prefix name="foaf" IRI="http://xmlns.com/foaf/0.1/"/>
|
||||||
|
<Prefix name="rdfs" IRI="http://www.w3.org/2000/01/rdf-schema#"/>
|
||||||
|
<Prefix name="swrl" IRI="http://www.w3.org/2003/11/swrl#"/>
|
||||||
|
<Prefix name="vann" IRI="http://purl.org/vocab/vann/"/>
|
||||||
|
<Prefix name="swrlb" IRI="http://www.w3.org/2003/11/swrlb#"/>
|
||||||
|
<Prefix name="protege" IRI="http://protege.stanford.edu/plugins/owl/protege#"/>
|
||||||
|
<Import>http://static.datafoodconsortium.org/ontologies/DFC_BusinessOntology.owl</Import>
|
||||||
|
<Import>http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl</Import>
|
||||||
|
<Import>http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl</Import>
|
||||||
|
<Annotation>
|
||||||
|
<AnnotationProperty abbreviatedIRI="cc:license"/>
|
||||||
|
<IRI>https://www.gnu.org/licenses/agpl-3.0.en.html</IRI>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation>
|
||||||
|
<AnnotationProperty abbreviatedIRI="dc:contributor"/>
|
||||||
|
<IRI>http://static.datafoodconsortium.org/data/publication.rdf#rachelA</IRI>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation>
|
||||||
|
<AnnotationProperty abbreviatedIRI="dc:contributor"/>
|
||||||
|
<IRI>http://static.datafoodconsortium.org/data/publication.rdf#simonL</IRI>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation>
|
||||||
|
<AnnotationProperty abbreviatedIRI="dc:creator"/>
|
||||||
|
<IRI>http://static.datafoodconsortium.org/data/publication.rdf#bernardC</IRI>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation>
|
||||||
|
<AnnotationProperty abbreviatedIRI="dc:description"/>
|
||||||
|
<Literal xml:lang="en">A common vocabulary for digital food platforms</Literal>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation>
|
||||||
|
<AnnotationProperty abbreviatedIRI="dc:issued"/>
|
||||||
|
<Literal datatypeIRI="http://www.w3.org/2001/XMLSchema#date">2018-05-28</Literal>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation>
|
||||||
|
<AnnotationProperty abbreviatedIRI="dc:modified"/>
|
||||||
|
<Literal datatypeIRI="http://www.w3.org/2001/XMLSchema#date">2019-10-21</Literal>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation>
|
||||||
|
<AnnotationProperty abbreviatedIRI="dc:publisher"/>
|
||||||
|
<IRI>http://static.datafoodconsortium.org/data/publication.rdf#dataFoodConsortium</IRI>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation>
|
||||||
|
<AnnotationProperty abbreviatedIRI="dc:title"/>
|
||||||
|
<Literal xml:lang="en">Data Food Consortium</Literal>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation>
|
||||||
|
<AnnotationProperty abbreviatedIRI="vann:preferredNamespacePrefix"/>
|
||||||
|
<Literal>dfc</Literal>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:comment"/>
|
||||||
|
<Literal xml:lang="en">A common vocabulary for digital food platforms</Literal>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation>
|
||||||
|
<AnnotationProperty abbreviatedIRI="owl:versionInfo"/>
|
||||||
|
<Literal datatypeIRI="http://www.w3.org/2001/XMLSchema#decimal">4.0</Literal>
|
||||||
|
</Annotation>
|
||||||
|
<ClassAssertion>
|
||||||
|
<Class abbreviatedIRI="foaf:Person"/>
|
||||||
|
<NamedIndividual IRI="http://static.datafoodconsortium.org/data/publication.rdf#bernardC"/>
|
||||||
|
</ClassAssertion>
|
||||||
|
<ClassAssertion>
|
||||||
|
<Class abbreviatedIRI="foaf:Organization"/>
|
||||||
|
<NamedIndividual IRI="http://static.datafoodconsortium.org/data/publication.rdf#dataFoodConsortium"/>
|
||||||
|
</ClassAssertion>
|
||||||
|
<ClassAssertion>
|
||||||
|
<Class abbreviatedIRI="foaf:Person"/>
|
||||||
|
<NamedIndividual IRI="http://static.datafoodconsortium.org/data/publication.rdf#rachelA"/>
|
||||||
|
</ClassAssertion>
|
||||||
|
<ClassAssertion>
|
||||||
|
<Class abbreviatedIRI="foaf:Person"/>
|
||||||
|
<NamedIndividual IRI="http://static.datafoodconsortium.org/data/publication.rdf#simonL"/>
|
||||||
|
</ClassAssertion>
|
||||||
|
</Ontology>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Generated by the OWL API (version 4.5.9.2019-02-01T07:24:44Z) https://github.com/owlcs/owlapi -->
|
||||||
|
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<rdf:RDF xmlns="http://static.datafoodconsortium.org/ontologies/DFC_FullModel.owl#"
|
||||||
|
xml:base="http://static.datafoodconsortium.org/ontologies/DFC_FullModel.owl"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:dc="http://purl.org/dc/terms/"
|
||||||
|
xmlns:owl="http://www.w3.org/2002/07/owl#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:xml="http://www.w3.org/XML/1998/namespace"
|
||||||
|
xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
|
||||||
|
xmlns:xsp="http://www.owl-ontologies.com/2005/08/07/xsp.owl#"
|
||||||
|
xmlns:foaf="http://xmlns.com/foaf/0.1/"
|
||||||
|
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
|
||||||
|
xmlns:swrl="http://www.w3.org/2003/11/swrl#"
|
||||||
|
xmlns:vann="http://purl.org/vocab/vann/"
|
||||||
|
xmlns:swrlb="http://www.w3.org/2003/11/swrlb#"
|
||||||
|
xmlns:protege="http://protege.stanford.edu/plugins/owl/protege#">
|
||||||
|
|
||||||
|
<owl:Ontology rdf:about="http://static.datafoodconsortium.org/ontologies/DFC_FullModel.owl">
|
||||||
|
<rdf:type rdf:resource="http://purl.org/vocommons/voaf#Vocabulary"/>
|
||||||
|
<vann:preferredNamespacePrefix>dfc</vann:preferredNamespacePrefix>
|
||||||
|
<vann:preferredNamespaceUri>http://static.datafoodconsortium.org/ontologies/DFC_FullModel.owl#</vann:preferredNamespaceUri>
|
||||||
|
<owl:imports rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_BusinessOntology.owl"/>
|
||||||
|
<owl:imports rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl"/>
|
||||||
|
<owl:imports rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl"/>
|
||||||
|
<cc:license rdf:resource="https://www.gnu.org/licenses/agpl-3.0.en.html"/>
|
||||||
|
<dc:contributor rdf:resource="http://static.datafoodconsortium.org/data/publication.rdf#rachelA"/>
|
||||||
|
<dc:contributor rdf:resource="http://static.datafoodconsortium.org/data/publication.rdf#simonL"/>
|
||||||
|
<dc:creator rdf:resource="http://static.datafoodconsortium.org/data/publication.rdf#bernardC"/>
|
||||||
|
<dc:description xml:lang="en">A common vocabulary for digital food platforms</dc:description>
|
||||||
|
<dc:issued rdf:datatype="http://www.w3.org/2001/XMLSchema#date">2018-05-28</dc:issued>
|
||||||
|
<dc:modified rdf:datatype="http://www.w3.org/2001/XMLSchema#date">2019-10-21</dc:modified>
|
||||||
|
<dc:publisher rdf:resource="http://static.datafoodconsortium.org/data/publication.rdf#dataFoodConsortium"/>
|
||||||
|
<dc:title xml:lang="en">Data Food Consortium</dc:title>
|
||||||
|
<rdfs:comment xml:lang="en">A common vocabulary for digital food platforms</rdfs:comment>
|
||||||
|
<owl:versionInfo rdf:datatype="http://www.w3.org/2001/XMLSchema#decimal">4.0</owl:versionInfo>
|
||||||
|
</owl:Ontology>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Individuals
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://static.datafoodconsortium.org/data/publication.rdf#bernardC -->
|
||||||
|
|
||||||
|
<rdf:Description rdf:about="http://static.datafoodconsortium.org/data/publication.rdf#bernardC">
|
||||||
|
<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/>
|
||||||
|
</rdf:Description>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://static.datafoodconsortium.org/data/publication.rdf#dataFoodConsortium -->
|
||||||
|
|
||||||
|
<rdf:Description rdf:about="http://static.datafoodconsortium.org/data/publication.rdf#dataFoodConsortium">
|
||||||
|
<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Organization"/>
|
||||||
|
</rdf:Description>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://static.datafoodconsortium.org/data/publication.rdf#rachelA -->
|
||||||
|
|
||||||
|
<rdf:Description rdf:about="http://static.datafoodconsortium.org/data/publication.rdf#rachelA">
|
||||||
|
<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/>
|
||||||
|
</rdf:Description>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://static.datafoodconsortium.org/data/publication.rdf#simonL -->
|
||||||
|
|
||||||
|
<rdf:Description rdf:about="http://static.datafoodconsortium.org/data/publication.rdf#simonL">
|
||||||
|
<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/>
|
||||||
|
</rdf:Description>
|
||||||
|
</rdf:RDF>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Generated by the OWL API (version 4.5.9.2019-02-01T07:24:44Z) https://github.com/owlcs/owlapi -->
|
||||||
|
|
@ -0,0 +1,549 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<Ontology xmlns="http://www.w3.org/2002/07/owl#"
|
||||||
|
xml:base="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:xml="http://www.w3.org/XML/1998/namespace"
|
||||||
|
xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
|
||||||
|
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
|
||||||
|
ontologyIRI="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl">
|
||||||
|
<Prefix name="" IRI="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl"/>
|
||||||
|
<Prefix name="cc" IRI="http://creativecommons.org/ns#"/>
|
||||||
|
<Prefix name="dc" IRI="http://purl.org/dc/terms/"/>
|
||||||
|
<Prefix name="owl" IRI="http://www.w3.org/2002/07/owl#"/>
|
||||||
|
<Prefix name="rdf" IRI="http://www.w3.org/1999/02/22-rdf-syntax-ns#"/>
|
||||||
|
<Prefix name="xml" IRI="http://www.w3.org/XML/1998/namespace"/>
|
||||||
|
<Prefix name="xsd" IRI="http://www.w3.org/2001/XMLSchema#"/>
|
||||||
|
<Prefix name="xsp" IRI="http://www.owl-ontologies.com/2005/08/07/xsp.owl#"/>
|
||||||
|
<Prefix name="foaf" IRI="http://xmlns.com/foaf/0.1/"/>
|
||||||
|
<Prefix name="rdfs" IRI="http://www.w3.org/2000/01/rdf-schema#"/>
|
||||||
|
<Prefix name="swrl" IRI="http://www.w3.org/2003/11/swrl#"/>
|
||||||
|
<Prefix name="vann" IRI="http://purl.org/vocab/vann/"/>
|
||||||
|
<Prefix name="swrlb" IRI="http://www.w3.org/2003/11/swrlb#"/>
|
||||||
|
<Prefix name="protege" IRI="http://protege.stanford.edu/plugins/owl/protege#"/>
|
||||||
|
<Import>http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl</Import>
|
||||||
|
<Annotation>
|
||||||
|
<AnnotationProperty abbreviatedIRI="cc:license"/>
|
||||||
|
<IRI>https://www.gnu.org/licenses/agpl-3.0.en.html</IRI>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation>
|
||||||
|
<AnnotationProperty abbreviatedIRI="dc:contributor"/>
|
||||||
|
<IRI>http://static.datafoodconsortium.org/data/publication.rdf#rachelA</IRI>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation>
|
||||||
|
<AnnotationProperty abbreviatedIRI="dc:contributor"/>
|
||||||
|
<IRI>http://static.datafoodconsortium.org/data/publication.rdf#simonL</IRI>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation>
|
||||||
|
<AnnotationProperty abbreviatedIRI="dc:creator"/>
|
||||||
|
<IRI>http://static.datafoodconsortium.org/data/publication.rdf#bernardC</IRI>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation>
|
||||||
|
<AnnotationProperty abbreviatedIRI="dc:description"/>
|
||||||
|
<Literal xml:lang="en">A common vocabulary for digital food platforms (Product Glossary Part)</Literal>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation>
|
||||||
|
<AnnotationProperty abbreviatedIRI="dc:issued"/>
|
||||||
|
<Literal datatypeIRI="http://www.w3.org/2001/XMLSchema#date">2018-05-28</Literal>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation>
|
||||||
|
<AnnotationProperty abbreviatedIRI="dc:modified"/>
|
||||||
|
<Literal datatypeIRI="http://www.w3.org/2001/XMLSchema#date">2019-10-21</Literal>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation>
|
||||||
|
<AnnotationProperty abbreviatedIRI="dc:publisher"/>
|
||||||
|
<IRI>http://static.datafoodconsortium.org/data/publication.rdf#dataFoodConsortium</IRI>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation>
|
||||||
|
<AnnotationProperty abbreviatedIRI="dc:title"/>
|
||||||
|
<Literal xml:lang="en">Data Food Consortium Product</Literal>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation>
|
||||||
|
<AnnotationProperty abbreviatedIRI="vann:preferredNamespacePrefix"/>
|
||||||
|
<Literal>dfc-p</Literal>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:comment"/>
|
||||||
|
<Literal xml:lang="en">A common vocabulary for digital food platforms (Product Glossary Part)</Literal>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation>
|
||||||
|
<AnnotationProperty abbreviatedIRI="owl:versionInfo"/>
|
||||||
|
<Literal datatypeIRI="http://www.w3.org/2001/XMLSchema#decimal">4.0</Literal>
|
||||||
|
</Annotation>
|
||||||
|
<Declaration>
|
||||||
|
<Class IRI="#Certification"/>
|
||||||
|
</Declaration>
|
||||||
|
<Declaration>
|
||||||
|
<Class IRI="#DFC_ProductGlossary_Facet"/>
|
||||||
|
</Declaration>
|
||||||
|
<Declaration>
|
||||||
|
<Class IRI="#DFC_ProductGlossary_Measure"/>
|
||||||
|
</Declaration>
|
||||||
|
<Declaration>
|
||||||
|
<Class IRI="#DFC_ProductGlossary_Type"/>
|
||||||
|
</Declaration>
|
||||||
|
<Declaration>
|
||||||
|
<Class IRI="#Dimension"/>
|
||||||
|
</Declaration>
|
||||||
|
<Declaration>
|
||||||
|
<Class IRI="#GlobalGenericOrigin"/>
|
||||||
|
</Declaration>
|
||||||
|
<Declaration>
|
||||||
|
<Class IRI="#NatureOrigin"/>
|
||||||
|
</Declaration>
|
||||||
|
<Declaration>
|
||||||
|
<Class IRI="#PartOrigin"/>
|
||||||
|
</Declaration>
|
||||||
|
<Declaration>
|
||||||
|
<Class IRI="#Process"/>
|
||||||
|
</Declaration>
|
||||||
|
<Declaration>
|
||||||
|
<Class IRI="#ProductType"/>
|
||||||
|
</Declaration>
|
||||||
|
<Declaration>
|
||||||
|
<Class IRI="#TerritorialOrigin"/>
|
||||||
|
</Declaration>
|
||||||
|
<Declaration>
|
||||||
|
<Class IRI="#Unit"/>
|
||||||
|
</Declaration>
|
||||||
|
<Declaration>
|
||||||
|
<ObjectProperty IRI="#DFC_ProductGlossary_ObjectProperty"/>
|
||||||
|
</Declaration>
|
||||||
|
<Declaration>
|
||||||
|
<ObjectProperty IRI="#generalizes"/>
|
||||||
|
</Declaration>
|
||||||
|
<Declaration>
|
||||||
|
<ObjectProperty IRI="#measuredBy"/>
|
||||||
|
</Declaration>
|
||||||
|
<Declaration>
|
||||||
|
<ObjectProperty IRI="#measures"/>
|
||||||
|
</Declaration>
|
||||||
|
<Declaration>
|
||||||
|
<ObjectProperty IRI="#specializes"/>
|
||||||
|
</Declaration>
|
||||||
|
<Declaration>
|
||||||
|
<NamedIndividual IRI="http://static.datafoodconsortium.org/data/publication.rdf#bernardC"/>
|
||||||
|
</Declaration>
|
||||||
|
<Declaration>
|
||||||
|
<NamedIndividual IRI="http://static.datafoodconsortium.org/data/publication.rdf#rachelA"/>
|
||||||
|
</Declaration>
|
||||||
|
<Declaration>
|
||||||
|
<AnnotationProperty abbreviatedIRI="dc:contributor"/>
|
||||||
|
</Declaration>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#Certification"/>
|
||||||
|
<Class IRI="#DFC_ProductGlossary_Facet"/>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#Certification"/>
|
||||||
|
<ObjectAllValuesFrom>
|
||||||
|
<ObjectProperty IRI="#generalizes"/>
|
||||||
|
<Class IRI="#Certification"/>
|
||||||
|
</ObjectAllValuesFrom>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#Certification"/>
|
||||||
|
<ObjectAllValuesFrom>
|
||||||
|
<ObjectProperty IRI="#specializes"/>
|
||||||
|
<Class IRI="#Certification"/>
|
||||||
|
</ObjectAllValuesFrom>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#DFC_ProductGlossary_Facet"/>
|
||||||
|
<Class IRI="http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#RepresentedThing"/>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#DFC_ProductGlossary_Facet"/>
|
||||||
|
<ObjectAllValuesFrom>
|
||||||
|
<ObjectProperty IRI="#generalizes"/>
|
||||||
|
<Class IRI="#DFC_ProductGlossary_Facet"/>
|
||||||
|
</ObjectAllValuesFrom>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#DFC_ProductGlossary_Facet"/>
|
||||||
|
<ObjectAllValuesFrom>
|
||||||
|
<ObjectProperty IRI="#specializes"/>
|
||||||
|
<Class IRI="#DFC_ProductGlossary_Facet"/>
|
||||||
|
</ObjectAllValuesFrom>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#DFC_ProductGlossary_Facet"/>
|
||||||
|
<ObjectExactCardinality cardinality="1">
|
||||||
|
<ObjectProperty IRI="#specializes"/>
|
||||||
|
</ObjectExactCardinality>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#DFC_ProductGlossary_Measure"/>
|
||||||
|
<Class IRI="http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#RepresentedThing"/>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#DFC_ProductGlossary_Type"/>
|
||||||
|
<Class IRI="http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#RepresentedThing"/>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#DFC_ProductGlossary_Type"/>
|
||||||
|
<ObjectAllValuesFrom>
|
||||||
|
<ObjectProperty IRI="#generalizes"/>
|
||||||
|
<Class IRI="#DFC_ProductGlossary_Type"/>
|
||||||
|
</ObjectAllValuesFrom>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#DFC_ProductGlossary_Type"/>
|
||||||
|
<ObjectAllValuesFrom>
|
||||||
|
<ObjectProperty IRI="#specializes"/>
|
||||||
|
<Class IRI="#DFC_ProductGlossary_Type"/>
|
||||||
|
</ObjectAllValuesFrom>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#DFC_ProductGlossary_Type"/>
|
||||||
|
<ObjectExactCardinality cardinality="1">
|
||||||
|
<ObjectProperty IRI="#specializes"/>
|
||||||
|
</ObjectExactCardinality>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#Dimension"/>
|
||||||
|
<Class IRI="#DFC_ProductGlossary_Measure"/>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#Dimension"/>
|
||||||
|
<ObjectAllValuesFrom>
|
||||||
|
<ObjectProperty IRI="#measuredBy"/>
|
||||||
|
<Class IRI="#Unit"/>
|
||||||
|
</ObjectAllValuesFrom>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#GlobalGenericOrigin"/>
|
||||||
|
<Class IRI="#DFC_ProductGlossary_Facet"/>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#GlobalGenericOrigin"/>
|
||||||
|
<ObjectSomeValuesFrom>
|
||||||
|
<ObjectProperty IRI="#specializes"/>
|
||||||
|
<Class IRI="#GlobalGenericOrigin"/>
|
||||||
|
</ObjectSomeValuesFrom>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#GlobalGenericOrigin"/>
|
||||||
|
<ObjectAllValuesFrom>
|
||||||
|
<ObjectProperty IRI="#generalizes"/>
|
||||||
|
<Class IRI="#GlobalGenericOrigin"/>
|
||||||
|
</ObjectAllValuesFrom>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#NatureOrigin"/>
|
||||||
|
<Class IRI="#DFC_ProductGlossary_Facet"/>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#NatureOrigin"/>
|
||||||
|
<ObjectAllValuesFrom>
|
||||||
|
<ObjectProperty IRI="#generalizes"/>
|
||||||
|
<Class IRI="#NatureOrigin"/>
|
||||||
|
</ObjectAllValuesFrom>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#NatureOrigin"/>
|
||||||
|
<ObjectAllValuesFrom>
|
||||||
|
<ObjectProperty IRI="#specializes"/>
|
||||||
|
<Class IRI="#NatureOrigin"/>
|
||||||
|
</ObjectAllValuesFrom>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#PartOrigin"/>
|
||||||
|
<Class IRI="#DFC_ProductGlossary_Facet"/>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#PartOrigin"/>
|
||||||
|
<ObjectAllValuesFrom>
|
||||||
|
<ObjectProperty IRI="#generalizes"/>
|
||||||
|
<Class IRI="#PartOrigin"/>
|
||||||
|
</ObjectAllValuesFrom>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#PartOrigin"/>
|
||||||
|
<ObjectAllValuesFrom>
|
||||||
|
<ObjectProperty IRI="#specializes"/>
|
||||||
|
<Class IRI="#PartOrigin"/>
|
||||||
|
</ObjectAllValuesFrom>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#Process"/>
|
||||||
|
<Class IRI="#DFC_ProductGlossary_Facet"/>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#Process"/>
|
||||||
|
<ObjectAllValuesFrom>
|
||||||
|
<ObjectProperty IRI="#generalizes"/>
|
||||||
|
<Class IRI="#Process"/>
|
||||||
|
</ObjectAllValuesFrom>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#Process"/>
|
||||||
|
<ObjectAllValuesFrom>
|
||||||
|
<ObjectProperty IRI="#specializes"/>
|
||||||
|
<Class IRI="#Process"/>
|
||||||
|
</ObjectAllValuesFrom>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#ProductType"/>
|
||||||
|
<Class IRI="#DFC_ProductGlossary_Type"/>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#ProductType"/>
|
||||||
|
<ObjectAllValuesFrom>
|
||||||
|
<ObjectProperty IRI="#generalizes"/>
|
||||||
|
<Class IRI="#ProductType"/>
|
||||||
|
</ObjectAllValuesFrom>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#ProductType"/>
|
||||||
|
<ObjectAllValuesFrom>
|
||||||
|
<ObjectProperty IRI="#specializes"/>
|
||||||
|
<Class IRI="#ProductType"/>
|
||||||
|
</ObjectAllValuesFrom>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#TerritorialOrigin"/>
|
||||||
|
<Class IRI="#DFC_ProductGlossary_Facet"/>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#TerritorialOrigin"/>
|
||||||
|
<ObjectAllValuesFrom>
|
||||||
|
<ObjectProperty IRI="#generalizes"/>
|
||||||
|
<Class IRI="#TerritorialOrigin"/>
|
||||||
|
</ObjectAllValuesFrom>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#TerritorialOrigin"/>
|
||||||
|
<ObjectAllValuesFrom>
|
||||||
|
<ObjectProperty IRI="#specializes"/>
|
||||||
|
<Class IRI="#TerritorialOrigin"/>
|
||||||
|
</ObjectAllValuesFrom>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#Unit"/>
|
||||||
|
<Class IRI="#DFC_ProductGlossary_Measure"/>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#Unit"/>
|
||||||
|
<ObjectAllValuesFrom>
|
||||||
|
<ObjectProperty IRI="#measures"/>
|
||||||
|
<Class IRI="#Dimension"/>
|
||||||
|
</ObjectAllValuesFrom>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#Unit"/>
|
||||||
|
<ObjectExactCardinality cardinality="1">
|
||||||
|
<ObjectProperty IRI="#measures"/>
|
||||||
|
</ObjectExactCardinality>
|
||||||
|
</SubClassOf>
|
||||||
|
<ClassAssertion>
|
||||||
|
<Class abbreviatedIRI="foaf:Person"/>
|
||||||
|
<NamedIndividual IRI="http://static.datafoodconsortium.org/data/publication.rdf#bernardC"/>
|
||||||
|
</ClassAssertion>
|
||||||
|
<ClassAssertion>
|
||||||
|
<Class abbreviatedIRI="foaf:Organization"/>
|
||||||
|
<NamedIndividual IRI="http://static.datafoodconsortium.org/data/publication.rdf#dataFoodConsortium"/>
|
||||||
|
</ClassAssertion>
|
||||||
|
<ClassAssertion>
|
||||||
|
<Class abbreviatedIRI="foaf:Person"/>
|
||||||
|
<NamedIndividual IRI="http://static.datafoodconsortium.org/data/publication.rdf#rachelA"/>
|
||||||
|
</ClassAssertion>
|
||||||
|
<ClassAssertion>
|
||||||
|
<Class abbreviatedIRI="foaf:Person"/>
|
||||||
|
<NamedIndividual IRI="http://static.datafoodconsortium.org/data/publication.rdf#simonL"/>
|
||||||
|
</ClassAssertion>
|
||||||
|
<SubObjectPropertyOf>
|
||||||
|
<ObjectProperty IRI="#generalizes"/>
|
||||||
|
<ObjectProperty IRI="#DFC_ProductGlossary_ObjectProperty"/>
|
||||||
|
</SubObjectPropertyOf>
|
||||||
|
<SubObjectPropertyOf>
|
||||||
|
<ObjectProperty IRI="#measuredBy"/>
|
||||||
|
<ObjectProperty IRI="#DFC_ProductGlossary_ObjectProperty"/>
|
||||||
|
</SubObjectPropertyOf>
|
||||||
|
<SubObjectPropertyOf>
|
||||||
|
<ObjectProperty IRI="#measures"/>
|
||||||
|
<ObjectProperty IRI="#DFC_ProductGlossary_ObjectProperty"/>
|
||||||
|
</SubObjectPropertyOf>
|
||||||
|
<SubObjectPropertyOf>
|
||||||
|
<ObjectProperty IRI="#specializes"/>
|
||||||
|
<ObjectProperty IRI="#DFC_ProductGlossary_ObjectProperty"/>
|
||||||
|
</SubObjectPropertyOf>
|
||||||
|
<InverseObjectProperties>
|
||||||
|
<ObjectProperty IRI="#generalizes"/>
|
||||||
|
<ObjectProperty IRI="#specializes"/>
|
||||||
|
</InverseObjectProperties>
|
||||||
|
<InverseObjectProperties>
|
||||||
|
<ObjectProperty IRI="#measuredBy"/>
|
||||||
|
<ObjectProperty IRI="#measures"/>
|
||||||
|
</InverseObjectProperties>
|
||||||
|
<ObjectPropertyDomain>
|
||||||
|
<ObjectProperty IRI="#generalizes"/>
|
||||||
|
<Class IRI="#DFC_ProductGlossary_Facet"/>
|
||||||
|
</ObjectPropertyDomain>
|
||||||
|
<ObjectPropertyDomain>
|
||||||
|
<ObjectProperty IRI="#measuredBy"/>
|
||||||
|
<Class IRI="#Dimension"/>
|
||||||
|
</ObjectPropertyDomain>
|
||||||
|
<ObjectPropertyDomain>
|
||||||
|
<ObjectProperty IRI="#measures"/>
|
||||||
|
<Class IRI="#Unit"/>
|
||||||
|
</ObjectPropertyDomain>
|
||||||
|
<ObjectPropertyDomain>
|
||||||
|
<ObjectProperty IRI="#specializes"/>
|
||||||
|
<Class IRI="#DFC_ProductGlossary_Facet"/>
|
||||||
|
</ObjectPropertyDomain>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:label"/>
|
||||||
|
<IRI>#Certification</IRI>
|
||||||
|
<Literal xml:lang="en">certification</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:label"/>
|
||||||
|
<IRI>#Certification</IRI>
|
||||||
|
<Literal xml:lang="fr">certification</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:label"/>
|
||||||
|
<IRI>#DFC_ProductGlossary_Facet</IRI>
|
||||||
|
<Literal xml:lang="en">Subject of the facets thesaurus</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:label"/>
|
||||||
|
<IRI>#DFC_ProductGlossary_Facet</IRI>
|
||||||
|
<Literal xml:lang="fr">Sujet du Thésaurus à Facettes</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:label"/>
|
||||||
|
<IRI>#DFC_ProductGlossary_Measure</IRI>
|
||||||
|
<Literal xml:lang="fr">thesaurus des unités de mesure</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:label"/>
|
||||||
|
<IRI>#DFC_ProductGlossary_Measure</IRI>
|
||||||
|
<Literal xml:lang="en">unit of measures thesaurus</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:label"/>
|
||||||
|
<IRI>#Dimension</IRI>
|
||||||
|
<Literal xml:lang="en">dimension</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:label"/>
|
||||||
|
<IRI>#Dimension</IRI>
|
||||||
|
<Literal xml:lang="fr">dimension</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:label"/>
|
||||||
|
<IRI>#GlobalGenericOrigin</IRI>
|
||||||
|
<Literal xml:lang="en">Global generic origin</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:label"/>
|
||||||
|
<IRI>#GlobalGenericOrigin</IRI>
|
||||||
|
<Literal xml:lang="fr">Origines génériques globales</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:label"/>
|
||||||
|
<IRI>#NatureOrigin</IRI>
|
||||||
|
<Literal xml:lang="en">natural "living" origin</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:label"/>
|
||||||
|
<IRI>#NatureOrigin</IRI>
|
||||||
|
<Literal xml:lang="fr">source "vivante" d'origine</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:label"/>
|
||||||
|
<IRI>#PartOrigin</IRI>
|
||||||
|
<Literal xml:lang="en">part of natural "living" origin concerned</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:label"/>
|
||||||
|
<IRI>#PartOrigin</IRI>
|
||||||
|
<Literal xml:lang="fr">partie de la source "vivante" d'origine concernée</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:label"/>
|
||||||
|
<IRI>#Process</IRI>
|
||||||
|
<Literal xml:lang="en">process applied</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:label"/>
|
||||||
|
<IRI>#Process</IRI>
|
||||||
|
<Literal xml:lang="fr">procédé appliqué</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:label"/>
|
||||||
|
<IRI>#ProductType</IRI>
|
||||||
|
<Literal xml:lang="en">product type (general taxonomy)</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:label"/>
|
||||||
|
<IRI>#ProductType</IRI>
|
||||||
|
<Literal xml:lang="fr">type de produit (classification générale)</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:label"/>
|
||||||
|
<IRI>#TerritorialOrigin</IRI>
|
||||||
|
<Literal xml:lang="fr">origine territoriale</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:label"/>
|
||||||
|
<IRI>#TerritorialOrigin</IRI>
|
||||||
|
<Literal xml:lang="en">territorial origin</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:label"/>
|
||||||
|
<IRI>#Unit</IRI>
|
||||||
|
<Literal xml:lang="en">unit</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:label"/>
|
||||||
|
<IRI>#Unit</IRI>
|
||||||
|
<Literal xml:lang="fr">unité</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:label"/>
|
||||||
|
<IRI>#generalizes</IRI>
|
||||||
|
<Literal xml:lang="en">generalizes</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:label"/>
|
||||||
|
<IRI>#generalizes</IRI>
|
||||||
|
<Literal xml:lang="fr">généralise</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:label"/>
|
||||||
|
<IRI>#measuredBy</IRI>
|
||||||
|
<Literal xml:lang="en">measured by</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:label"/>
|
||||||
|
<IRI>#measuredBy</IRI>
|
||||||
|
<Literal xml:lang="fr">mesuré en</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:label"/>
|
||||||
|
<IRI>#measures</IRI>
|
||||||
|
<Literal xml:lang="en">measures</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:label"/>
|
||||||
|
<IRI>#measures</IRI>
|
||||||
|
<Literal xml:lang="fr">mesure</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:label"/>
|
||||||
|
<IRI>#specializes</IRI>
|
||||||
|
<Literal xml:lang="en">specializes</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:label"/>
|
||||||
|
<IRI>#specializes</IRI>
|
||||||
|
<Literal xml:lang="fr">spécialise</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
</Ontology>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Generated by the OWL API (version 4.5.9.2019-02-01T07:24:44Z) https://github.com/owlcs/owlapi -->
|
||||||
|
|
||||||
|
|
@ -0,0 +1,428 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<rdf:RDF xmlns="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl"
|
||||||
|
xml:base="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:dc="http://purl.org/dc/terms/"
|
||||||
|
xmlns:owl="http://www.w3.org/2002/07/owl#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:xml="http://www.w3.org/XML/1998/namespace"
|
||||||
|
xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
|
||||||
|
xmlns:xsp="http://www.owl-ontologies.com/2005/08/07/xsp.owl#"
|
||||||
|
xmlns:foaf="http://xmlns.com/foaf/0.1/"
|
||||||
|
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
|
||||||
|
xmlns:swrl="http://www.w3.org/2003/11/swrl#"
|
||||||
|
xmlns:vann="http://purl.org/vocab/vann/"
|
||||||
|
xmlns:swrlb="http://www.w3.org/2003/11/swrlb#"
|
||||||
|
xmlns:protege="http://protege.stanford.edu/plugins/owl/protege#">
|
||||||
|
<owl:Ontology rdf:about="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl">
|
||||||
|
<rdf:type rdf:resource="http://purl.org/vocommons/voaf#Vocabulary"/>
|
||||||
|
<vann:preferredNamespacePrefix>dfc-p</vann:preferredNamespacePrefix>
|
||||||
|
<vann:preferredNamespaceUri>http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#</vann:preferredNamespaceUri>
|
||||||
|
<owl:imports rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl"/>
|
||||||
|
<cc:license rdf:resource="https://www.gnu.org/licenses/agpl-3.0.en.html"/>
|
||||||
|
<dc:contributor rdf:resource="http://static.datafoodconsortium.org/data/publication.rdf#rachelA"/>
|
||||||
|
<dc:contributor rdf:resource="http://static.datafoodconsortium.org/data/publication.rdf#simonL"/>
|
||||||
|
<dc:creator rdf:resource="http://static.datafoodconsortium.org/data/publication.rdf#bernardC"/>
|
||||||
|
<dc:description xml:lang="en">A common vocabulary for digital food platforms (Product Glossary Part)</dc:description>
|
||||||
|
<dc:issued rdf:datatype="http://www.w3.org/2001/XMLSchema#date">2018-05-28</dc:issued>
|
||||||
|
<dc:modified rdf:datatype="http://www.w3.org/2001/XMLSchema#date">2019-10-21</dc:modified>
|
||||||
|
<dc:publisher rdf:resource="http://static.datafoodconsortium.org/data/publication.rdf#dataFoodConsortium"/>
|
||||||
|
<dc:title xml:lang="en">Data Food Consortium Product</dc:title>
|
||||||
|
<rdfs:comment xml:lang="en">A common vocabulary for digital food platforms (Product Glossary Part)</rdfs:comment>
|
||||||
|
<owl:versionInfo rdf:datatype="http://www.w3.org/2001/XMLSchema#decimal">4.0</owl:versionInfo>
|
||||||
|
</owl:Ontology>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Annotation properties
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://purl.org/dc/terms/contributor -->
|
||||||
|
|
||||||
|
<owl:AnnotationProperty rdf:about="http://purl.org/dc/terms/contributor"/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Object Properties
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#DFC_ProductGlossary_ObjectProperty -->
|
||||||
|
|
||||||
|
<owl:ObjectProperty rdf:about="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#DFC_ProductGlossary_ObjectProperty"/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#generalizes -->
|
||||||
|
|
||||||
|
<owl:ObjectProperty rdf:about="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#generalizes">
|
||||||
|
<rdfs:subPropertyOf rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#DFC_ProductGlossary_ObjectProperty"/>
|
||||||
|
<owl:inverseOf rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#specializes"/>
|
||||||
|
<rdfs:domain rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#DFC_ProductGlossary_Facet"/>
|
||||||
|
<rdfs:label xml:lang="en">generalizes</rdfs:label>
|
||||||
|
<rdfs:label xml:lang="fr">généralise</rdfs:label>
|
||||||
|
</owl:ObjectProperty>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#measuredBy -->
|
||||||
|
|
||||||
|
<owl:ObjectProperty rdf:about="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#measuredBy">
|
||||||
|
<rdfs:subPropertyOf rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#DFC_ProductGlossary_ObjectProperty"/>
|
||||||
|
<owl:inverseOf rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#measures"/>
|
||||||
|
<rdfs:domain rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#Dimension"/>
|
||||||
|
<rdfs:label xml:lang="en">measured by</rdfs:label>
|
||||||
|
<rdfs:label xml:lang="fr">mesuré en</rdfs:label>
|
||||||
|
</owl:ObjectProperty>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#measures -->
|
||||||
|
|
||||||
|
<owl:ObjectProperty rdf:about="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#measures">
|
||||||
|
<rdfs:subPropertyOf rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#DFC_ProductGlossary_ObjectProperty"/>
|
||||||
|
<rdfs:domain rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#Unit"/>
|
||||||
|
<rdfs:label xml:lang="en">measures</rdfs:label>
|
||||||
|
<rdfs:label xml:lang="fr">mesure</rdfs:label>
|
||||||
|
</owl:ObjectProperty>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#specializes -->
|
||||||
|
|
||||||
|
<owl:ObjectProperty rdf:about="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#specializes">
|
||||||
|
<rdfs:subPropertyOf rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#DFC_ProductGlossary_ObjectProperty"/>
|
||||||
|
<rdfs:domain rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#DFC_ProductGlossary_Facet"/>
|
||||||
|
<rdfs:label xml:lang="en">specializes</rdfs:label>
|
||||||
|
<rdfs:label xml:lang="fr">spécialise</rdfs:label>
|
||||||
|
</owl:ObjectProperty>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Classes
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#Certification -->
|
||||||
|
|
||||||
|
<owl:Class rdf:about="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#Certification">
|
||||||
|
<rdfs:subClassOf rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#DFC_ProductGlossary_Facet"/>
|
||||||
|
<rdfs:subClassOf>
|
||||||
|
<owl:Restriction>
|
||||||
|
<owl:onProperty rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#generalizes"/>
|
||||||
|
<owl:allValuesFrom rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#Certification"/>
|
||||||
|
</owl:Restriction>
|
||||||
|
</rdfs:subClassOf>
|
||||||
|
<rdfs:subClassOf>
|
||||||
|
<owl:Restriction>
|
||||||
|
<owl:onProperty rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#specializes"/>
|
||||||
|
<owl:allValuesFrom rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#Certification"/>
|
||||||
|
</owl:Restriction>
|
||||||
|
</rdfs:subClassOf>
|
||||||
|
<rdfs:label xml:lang="en">certification</rdfs:label>
|
||||||
|
<rdfs:label xml:lang="fr">certification</rdfs:label>
|
||||||
|
</owl:Class>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#DFC_ProductGlossary_Facet -->
|
||||||
|
|
||||||
|
<owl:Class rdf:about="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#DFC_ProductGlossary_Facet">
|
||||||
|
<rdfs:subClassOf rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#RepresentedThing"/>
|
||||||
|
<rdfs:subClassOf>
|
||||||
|
<owl:Restriction>
|
||||||
|
<owl:onProperty rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#generalizes"/>
|
||||||
|
<owl:allValuesFrom rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#DFC_ProductGlossary_Facet"/>
|
||||||
|
</owl:Restriction>
|
||||||
|
</rdfs:subClassOf>
|
||||||
|
<rdfs:subClassOf>
|
||||||
|
<owl:Restriction>
|
||||||
|
<owl:onProperty rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#specializes"/>
|
||||||
|
<owl:allValuesFrom rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#DFC_ProductGlossary_Facet"/>
|
||||||
|
</owl:Restriction>
|
||||||
|
</rdfs:subClassOf>
|
||||||
|
<rdfs:subClassOf>
|
||||||
|
<owl:Restriction>
|
||||||
|
<owl:onProperty rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#specializes"/>
|
||||||
|
<owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
|
||||||
|
</owl:Restriction>
|
||||||
|
</rdfs:subClassOf>
|
||||||
|
<rdfs:label xml:lang="en">Subject of the facets thesaurus</rdfs:label>
|
||||||
|
<rdfs:label xml:lang="fr">Sujet du Thésaurus à Facettes</rdfs:label>
|
||||||
|
</owl:Class>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#DFC_ProductGlossary_Measure -->
|
||||||
|
|
||||||
|
<owl:Class rdf:about="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#DFC_ProductGlossary_Measure">
|
||||||
|
<rdfs:subClassOf rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#RepresentedThing"/>
|
||||||
|
<rdfs:label xml:lang="fr">thesaurus des unités de mesure</rdfs:label>
|
||||||
|
<rdfs:label xml:lang="en">unit of measures thesaurus</rdfs:label>
|
||||||
|
</owl:Class>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#DFC_ProductGlossary_Type -->
|
||||||
|
|
||||||
|
<owl:Class rdf:about="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#DFC_ProductGlossary_Type">
|
||||||
|
<rdfs:subClassOf rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#RepresentedThing"/>
|
||||||
|
<rdfs:subClassOf>
|
||||||
|
<owl:Restriction>
|
||||||
|
<owl:onProperty rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#generalizes"/>
|
||||||
|
<owl:allValuesFrom rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#DFC_ProductGlossary_Type"/>
|
||||||
|
</owl:Restriction>
|
||||||
|
</rdfs:subClassOf>
|
||||||
|
<rdfs:subClassOf>
|
||||||
|
<owl:Restriction>
|
||||||
|
<owl:onProperty rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#specializes"/>
|
||||||
|
<owl:allValuesFrom rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#DFC_ProductGlossary_Type"/>
|
||||||
|
</owl:Restriction>
|
||||||
|
</rdfs:subClassOf>
|
||||||
|
<rdfs:subClassOf>
|
||||||
|
<owl:Restriction>
|
||||||
|
<owl:onProperty rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#specializes"/>
|
||||||
|
<owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
|
||||||
|
</owl:Restriction>
|
||||||
|
</rdfs:subClassOf>
|
||||||
|
</owl:Class>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#Dimension -->
|
||||||
|
|
||||||
|
<owl:Class rdf:about="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#Dimension">
|
||||||
|
<rdfs:subClassOf rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#DFC_ProductGlossary_Measure"/>
|
||||||
|
<rdfs:subClassOf>
|
||||||
|
<owl:Restriction>
|
||||||
|
<owl:onProperty rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#measuredBy"/>
|
||||||
|
<owl:allValuesFrom rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#Unit"/>
|
||||||
|
</owl:Restriction>
|
||||||
|
</rdfs:subClassOf>
|
||||||
|
<rdfs:label xml:lang="en">dimension</rdfs:label>
|
||||||
|
<rdfs:label xml:lang="fr">dimension</rdfs:label>
|
||||||
|
</owl:Class>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#GlobalGenericOrigin -->
|
||||||
|
|
||||||
|
<owl:Class rdf:about="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#GlobalGenericOrigin">
|
||||||
|
<rdfs:subClassOf rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#DFC_ProductGlossary_Facet"/>
|
||||||
|
<rdfs:subClassOf>
|
||||||
|
<owl:Restriction>
|
||||||
|
<owl:onProperty rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#specializes"/>
|
||||||
|
<owl:someValuesFrom rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#GlobalGenericOrigin"/>
|
||||||
|
</owl:Restriction>
|
||||||
|
</rdfs:subClassOf>
|
||||||
|
<rdfs:subClassOf>
|
||||||
|
<owl:Restriction>
|
||||||
|
<owl:onProperty rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#generalizes"/>
|
||||||
|
<owl:allValuesFrom rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#GlobalGenericOrigin"/>
|
||||||
|
</owl:Restriction>
|
||||||
|
</rdfs:subClassOf>
|
||||||
|
<rdfs:label xml:lang="en">Global generic origin</rdfs:label>
|
||||||
|
<rdfs:label xml:lang="fr">Origines génériques globales</rdfs:label>
|
||||||
|
</owl:Class>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#NatureOrigin -->
|
||||||
|
|
||||||
|
<owl:Class rdf:about="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#NatureOrigin">
|
||||||
|
<rdfs:subClassOf rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#DFC_ProductGlossary_Facet"/>
|
||||||
|
<rdfs:subClassOf>
|
||||||
|
<owl:Restriction>
|
||||||
|
<owl:onProperty rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#generalizes"/>
|
||||||
|
<owl:allValuesFrom rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#NatureOrigin"/>
|
||||||
|
</owl:Restriction>
|
||||||
|
</rdfs:subClassOf>
|
||||||
|
<rdfs:subClassOf>
|
||||||
|
<owl:Restriction>
|
||||||
|
<owl:onProperty rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#specializes"/>
|
||||||
|
<owl:allValuesFrom rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#NatureOrigin"/>
|
||||||
|
</owl:Restriction>
|
||||||
|
</rdfs:subClassOf>
|
||||||
|
<rdfs:label xml:lang="en">natural "living" origin</rdfs:label>
|
||||||
|
<rdfs:label xml:lang="fr">source "vivante" d'origine</rdfs:label>
|
||||||
|
</owl:Class>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#PartOrigin -->
|
||||||
|
|
||||||
|
<owl:Class rdf:about="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#PartOrigin">
|
||||||
|
<rdfs:subClassOf rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#DFC_ProductGlossary_Facet"/>
|
||||||
|
<rdfs:subClassOf>
|
||||||
|
<owl:Restriction>
|
||||||
|
<owl:onProperty rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#generalizes"/>
|
||||||
|
<owl:allValuesFrom rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#PartOrigin"/>
|
||||||
|
</owl:Restriction>
|
||||||
|
</rdfs:subClassOf>
|
||||||
|
<rdfs:subClassOf>
|
||||||
|
<owl:Restriction>
|
||||||
|
<owl:onProperty rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#specializes"/>
|
||||||
|
<owl:allValuesFrom rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#PartOrigin"/>
|
||||||
|
</owl:Restriction>
|
||||||
|
</rdfs:subClassOf>
|
||||||
|
<rdfs:label xml:lang="en">part of natural "living" origin concerned</rdfs:label>
|
||||||
|
<rdfs:label xml:lang="fr">partie de la source "vivante" d'origine concernée</rdfs:label>
|
||||||
|
</owl:Class>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#Process -->
|
||||||
|
|
||||||
|
<owl:Class rdf:about="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#Process">
|
||||||
|
<rdfs:subClassOf rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#DFC_ProductGlossary_Facet"/>
|
||||||
|
<rdfs:subClassOf>
|
||||||
|
<owl:Restriction>
|
||||||
|
<owl:onProperty rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#generalizes"/>
|
||||||
|
<owl:allValuesFrom rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#Process"/>
|
||||||
|
</owl:Restriction>
|
||||||
|
</rdfs:subClassOf>
|
||||||
|
<rdfs:subClassOf>
|
||||||
|
<owl:Restriction>
|
||||||
|
<owl:onProperty rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#specializes"/>
|
||||||
|
<owl:allValuesFrom rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#Process"/>
|
||||||
|
</owl:Restriction>
|
||||||
|
</rdfs:subClassOf>
|
||||||
|
<rdfs:label xml:lang="en">process applied</rdfs:label>
|
||||||
|
<rdfs:label xml:lang="fr">procédé appliqué</rdfs:label>
|
||||||
|
</owl:Class>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#ProductType -->
|
||||||
|
|
||||||
|
<owl:Class rdf:about="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#ProductType">
|
||||||
|
<rdfs:subClassOf rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#DFC_ProductGlossary_Type"/>
|
||||||
|
<rdfs:subClassOf>
|
||||||
|
<owl:Restriction>
|
||||||
|
<owl:onProperty rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#generalizes"/>
|
||||||
|
<owl:allValuesFrom rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#ProductType"/>
|
||||||
|
</owl:Restriction>
|
||||||
|
</rdfs:subClassOf>
|
||||||
|
<rdfs:subClassOf>
|
||||||
|
<owl:Restriction>
|
||||||
|
<owl:onProperty rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#specializes"/>
|
||||||
|
<owl:allValuesFrom rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#ProductType"/>
|
||||||
|
</owl:Restriction>
|
||||||
|
</rdfs:subClassOf>
|
||||||
|
<rdfs:label xml:lang="en">product type (general taxonomy)</rdfs:label>
|
||||||
|
<rdfs:label xml:lang="fr">type de produit (classification générale)</rdfs:label>
|
||||||
|
</owl:Class>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#TerritorialOrigin -->
|
||||||
|
|
||||||
|
<owl:Class rdf:about="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#TerritorialOrigin">
|
||||||
|
<rdfs:subClassOf rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#DFC_ProductGlossary_Facet"/>
|
||||||
|
<rdfs:subClassOf>
|
||||||
|
<owl:Restriction>
|
||||||
|
<owl:onProperty rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#generalizes"/>
|
||||||
|
<owl:allValuesFrom rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#TerritorialOrigin"/>
|
||||||
|
</owl:Restriction>
|
||||||
|
</rdfs:subClassOf>
|
||||||
|
<rdfs:subClassOf>
|
||||||
|
<owl:Restriction>
|
||||||
|
<owl:onProperty rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#specializes"/>
|
||||||
|
<owl:allValuesFrom rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#TerritorialOrigin"/>
|
||||||
|
</owl:Restriction>
|
||||||
|
</rdfs:subClassOf>
|
||||||
|
<rdfs:label xml:lang="fr">origine territoriale</rdfs:label>
|
||||||
|
<rdfs:label xml:lang="en">territorial origin</rdfs:label>
|
||||||
|
</owl:Class>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#Unit -->
|
||||||
|
|
||||||
|
<owl:Class rdf:about="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#Unit">
|
||||||
|
<rdfs:subClassOf rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#DFC_ProductGlossary_Measure"/>
|
||||||
|
<rdfs:subClassOf>
|
||||||
|
<owl:Restriction>
|
||||||
|
<owl:onProperty rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#measures"/>
|
||||||
|
<owl:allValuesFrom rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#Dimension"/>
|
||||||
|
</owl:Restriction>
|
||||||
|
</rdfs:subClassOf>
|
||||||
|
<rdfs:subClassOf>
|
||||||
|
<owl:Restriction>
|
||||||
|
<owl:onProperty rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#measures"/>
|
||||||
|
<owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:cardinality>
|
||||||
|
</owl:Restriction>
|
||||||
|
</rdfs:subClassOf>
|
||||||
|
<rdfs:label xml:lang="en">unit</rdfs:label>
|
||||||
|
<rdfs:label xml:lang="fr">unité</rdfs:label>
|
||||||
|
</owl:Class>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Individuals
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://static.datafoodconsortium.org/data/publication.rdf#bernardC -->
|
||||||
|
|
||||||
|
<owl:NamedIndividual rdf:about="http://static.datafoodconsortium.org/data/publication.rdf#bernardC">
|
||||||
|
<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/>
|
||||||
|
</owl:NamedIndividual>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://static.datafoodconsortium.org/data/publication.rdf#dataFoodConsortium -->
|
||||||
|
|
||||||
|
<rdf:Description rdf:about="http://static.datafoodconsortium.org/data/publication.rdf#dataFoodConsortium">
|
||||||
|
<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Organization"/>
|
||||||
|
</rdf:Description>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://static.datafoodconsortium.org/data/publication.rdf#rachelA -->
|
||||||
|
|
||||||
|
<owl:NamedIndividual rdf:about="http://static.datafoodconsortium.org/data/publication.rdf#rachelA">
|
||||||
|
<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/>
|
||||||
|
</owl:NamedIndividual>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://static.datafoodconsortium.org/data/publication.rdf#simonL -->
|
||||||
|
|
||||||
|
<rdf:Description rdf:about="http://static.datafoodconsortium.org/data/publication.rdf#simonL">
|
||||||
|
<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/>
|
||||||
|
</rdf:Description>
|
||||||
|
</rdf:RDF>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Generated by the OWL API (version 4.5.9.2019-02-01T07:24:44Z) https://github.com/owlcs/owlapi -->
|
||||||
|
|
@ -0,0 +1,269 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<Ontology xmlns="http://www.w3.org/2002/07/owl#"
|
||||||
|
xml:base="http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:xml="http://www.w3.org/XML/1998/namespace"
|
||||||
|
xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
|
||||||
|
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
|
||||||
|
ontologyIRI="http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl">
|
||||||
|
<Prefix name="" IRI="http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl"/>
|
||||||
|
<Prefix name="cc" IRI="http://creativecommons.org/ns#"/>
|
||||||
|
<Prefix name="dc" IRI="http://purl.org/dc/terms/"/>
|
||||||
|
<Prefix name="owl" IRI="http://www.w3.org/2002/07/owl#"/>
|
||||||
|
<Prefix name="rdf" IRI="http://www.w3.org/1999/02/22-rdf-syntax-ns#"/>
|
||||||
|
<Prefix name="xml" IRI="http://www.w3.org/XML/1998/namespace"/>
|
||||||
|
<Prefix name="xsd" IRI="http://www.w3.org/2001/XMLSchema#"/>
|
||||||
|
<Prefix name="xsp" IRI="http://www.owl-ontologies.com/2005/08/07/xsp.owl#"/>
|
||||||
|
<Prefix name="foaf" IRI="http://xmlns.com/foaf/0.1/"/>
|
||||||
|
<Prefix name="rdfs" IRI="http://www.w3.org/2000/01/rdf-schema#"/>
|
||||||
|
<Prefix name="swrl" IRI="http://www.w3.org/2003/11/swrl#"/>
|
||||||
|
<Prefix name="vann" IRI="http://purl.org/vocab/vann/"/>
|
||||||
|
<Prefix name="swrlb" IRI="http://www.w3.org/2003/11/swrlb#"/>
|
||||||
|
<Prefix name="protege" IRI="http://protege.stanford.edu/plugins/owl/protege#"/>
|
||||||
|
<Annotation>
|
||||||
|
<AnnotationProperty abbreviatedIRI="cc:license"/>
|
||||||
|
<IRI>https://www.gnu.org/licenses/agpl-3.0.en.html</IRI>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation>
|
||||||
|
<AnnotationProperty abbreviatedIRI="dc:creator"/>
|
||||||
|
<IRI>http://static.datafoodconsortium.org/data/publication.rdf#simonL</IRI>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation>
|
||||||
|
<AnnotationProperty abbreviatedIRI="dc:description"/>
|
||||||
|
<Literal xml:lang="en">A common vocabulary for digital food platforms (Technical Part)</Literal>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation>
|
||||||
|
<AnnotationProperty abbreviatedIRI="dc:issued"/>
|
||||||
|
<Literal datatypeIRI="http://www.w3.org/2001/XMLSchema#date">2018-05-28</Literal>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation>
|
||||||
|
<AnnotationProperty abbreviatedIRI="dc:modified"/>
|
||||||
|
<Literal datatypeIRI="http://www.w3.org/2001/XMLSchema#date">2019-10-21</Literal>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation>
|
||||||
|
<AnnotationProperty abbreviatedIRI="dc:publisher"/>
|
||||||
|
<IRI>http://static.datafoodconsortium.org/data/publication.rdf#dataFoodConsortium</IRI>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation>
|
||||||
|
<AnnotationProperty abbreviatedIRI="dc:title"/>
|
||||||
|
<Literal xml:lang="en">Data Food Consortium Technical</Literal>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation>
|
||||||
|
<AnnotationProperty abbreviatedIRI="vann:preferredNamespacePrefix"/>
|
||||||
|
<Literal>dfc-t</Literal>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:comment"/>
|
||||||
|
<Literal xml:lang="en">A common vocabulary for digital food platforms (Technical Part)</Literal>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation>
|
||||||
|
<AnnotationProperty abbreviatedIRI="owl:versionInfo"/>
|
||||||
|
<Literal datatypeIRI="http://www.w3.org/2001/XMLSchema#decimal">4.0</Literal>
|
||||||
|
</Annotation>
|
||||||
|
<Declaration>
|
||||||
|
<Class IRI="#DFC_DitributedRepresentation"/>
|
||||||
|
</Declaration>
|
||||||
|
<Declaration>
|
||||||
|
<Class IRI="#Platform"/>
|
||||||
|
</Declaration>
|
||||||
|
<Declaration>
|
||||||
|
<Class IRI="#RepresentationPivot"/>
|
||||||
|
</Declaration>
|
||||||
|
<Declaration>
|
||||||
|
<Class IRI="#RepresentedThing"/>
|
||||||
|
</Declaration>
|
||||||
|
<Declaration>
|
||||||
|
<Class abbreviatedIRI="foaf:Organization"/>
|
||||||
|
</Declaration>
|
||||||
|
<Declaration>
|
||||||
|
<Class abbreviatedIRI="foaf:Person"/>
|
||||||
|
</Declaration>
|
||||||
|
<Declaration>
|
||||||
|
<ObjectProperty IRI="http://static.datafoodconsortium.org/ontologies/DFC_BusinessOntology.owl#DFC_TechnicalOntology_ObjectProperty"/>
|
||||||
|
</Declaration>
|
||||||
|
<Declaration>
|
||||||
|
<ObjectProperty IRI="#hasPivot"/>
|
||||||
|
</Declaration>
|
||||||
|
<Declaration>
|
||||||
|
<ObjectProperty IRI="#hostedBy"/>
|
||||||
|
</Declaration>
|
||||||
|
<Declaration>
|
||||||
|
<ObjectProperty IRI="#represent"/>
|
||||||
|
</Declaration>
|
||||||
|
<Declaration>
|
||||||
|
<NamedIndividual IRI="http://static.datafoodconsortium.org/data/publication.rdf#dataFoodConsortium"/>
|
||||||
|
</Declaration>
|
||||||
|
<Declaration>
|
||||||
|
<NamedIndividual IRI="http://static.datafoodconsortium.org/data/publication.rdf#simonL"/>
|
||||||
|
</Declaration>
|
||||||
|
<Declaration>
|
||||||
|
<AnnotationProperty abbreviatedIRI="cc:license"/>
|
||||||
|
</Declaration>
|
||||||
|
<Declaration>
|
||||||
|
<AnnotationProperty abbreviatedIRI="dc:creator"/>
|
||||||
|
</Declaration>
|
||||||
|
<Declaration>
|
||||||
|
<AnnotationProperty abbreviatedIRI="dc:description"/>
|
||||||
|
</Declaration>
|
||||||
|
<Declaration>
|
||||||
|
<AnnotationProperty abbreviatedIRI="dc:issued"/>
|
||||||
|
</Declaration>
|
||||||
|
<Declaration>
|
||||||
|
<AnnotationProperty abbreviatedIRI="dc:modified"/>
|
||||||
|
</Declaration>
|
||||||
|
<Declaration>
|
||||||
|
<AnnotationProperty abbreviatedIRI="dc:publisher"/>
|
||||||
|
</Declaration>
|
||||||
|
<Declaration>
|
||||||
|
<AnnotationProperty abbreviatedIRI="dc:title"/>
|
||||||
|
</Declaration>
|
||||||
|
<Declaration>
|
||||||
|
<AnnotationProperty abbreviatedIRI="vann:preferredNamespacePrefix"/>
|
||||||
|
</Declaration>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#Platform"/>
|
||||||
|
<Class IRI="#DFC_DitributedRepresentation"/>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#Platform"/>
|
||||||
|
<ObjectAllValuesFrom>
|
||||||
|
<ObjectProperty IRI="#hostedBy"/>
|
||||||
|
<Class abbreviatedIRI="owl:Thing"/>
|
||||||
|
</ObjectAllValuesFrom>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#RepresentationPivot"/>
|
||||||
|
<Class IRI="#DFC_DitributedRepresentation"/>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#RepresentationPivot"/>
|
||||||
|
<ObjectAllValuesFrom>
|
||||||
|
<ObjectProperty IRI="#represent"/>
|
||||||
|
<Class IRI="#RepresentedThing"/>
|
||||||
|
</ObjectAllValuesFrom>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#RepresentationPivot"/>
|
||||||
|
<ObjectMinCardinality cardinality="1">
|
||||||
|
<ObjectProperty IRI="#represent"/>
|
||||||
|
<Class IRI="#RepresentedThing"/>
|
||||||
|
</ObjectMinCardinality>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#RepresentedThing"/>
|
||||||
|
<Class IRI="#DFC_DitributedRepresentation"/>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#RepresentedThing"/>
|
||||||
|
<ObjectAllValuesFrom>
|
||||||
|
<ObjectProperty IRI="#hasPivot"/>
|
||||||
|
<Class IRI="#RepresentationPivot"/>
|
||||||
|
</ObjectAllValuesFrom>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#RepresentedThing"/>
|
||||||
|
<ObjectAllValuesFrom>
|
||||||
|
<ObjectProperty IRI="#hostedBy"/>
|
||||||
|
<Class IRI="#Platform"/>
|
||||||
|
</ObjectAllValuesFrom>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#RepresentedThing"/>
|
||||||
|
<ObjectExactCardinality cardinality="1">
|
||||||
|
<ObjectProperty IRI="#hasPivot"/>
|
||||||
|
<Class IRI="#RepresentationPivot"/>
|
||||||
|
</ObjectExactCardinality>
|
||||||
|
</SubClassOf>
|
||||||
|
<SubClassOf>
|
||||||
|
<Class IRI="#RepresentedThing"/>
|
||||||
|
<ObjectExactCardinality cardinality="1">
|
||||||
|
<ObjectProperty IRI="#hostedBy"/>
|
||||||
|
<Class IRI="#Platform"/>
|
||||||
|
</ObjectExactCardinality>
|
||||||
|
</SubClassOf>
|
||||||
|
<DisjointClasses>
|
||||||
|
<Class IRI="#Platform"/>
|
||||||
|
<Class IRI="#RepresentationPivot"/>
|
||||||
|
<Class IRI="#RepresentedThing"/>
|
||||||
|
</DisjointClasses>
|
||||||
|
<ClassAssertion>
|
||||||
|
<Class abbreviatedIRI="foaf:Organization"/>
|
||||||
|
<NamedIndividual IRI="http://static.datafoodconsortium.org/data/publication.rdf#dataFoodConsortium"/>
|
||||||
|
</ClassAssertion>
|
||||||
|
<ClassAssertion>
|
||||||
|
<Class abbreviatedIRI="foaf:Person"/>
|
||||||
|
<NamedIndividual IRI="http://static.datafoodconsortium.org/data/publication.rdf#simonL"/>
|
||||||
|
</ClassAssertion>
|
||||||
|
<SubObjectPropertyOf>
|
||||||
|
<ObjectProperty IRI="#hasPivot"/>
|
||||||
|
<ObjectProperty abbreviatedIRI="owl:topObjectProperty"/>
|
||||||
|
</SubObjectPropertyOf>
|
||||||
|
<SubObjectPropertyOf>
|
||||||
|
<ObjectProperty IRI="#hostedBy"/>
|
||||||
|
<ObjectProperty abbreviatedIRI="owl:topObjectProperty"/>
|
||||||
|
</SubObjectPropertyOf>
|
||||||
|
<SubObjectPropertyOf>
|
||||||
|
<ObjectProperty IRI="#represent"/>
|
||||||
|
<ObjectProperty abbreviatedIRI="owl:topObjectProperty"/>
|
||||||
|
</SubObjectPropertyOf>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:label"/>
|
||||||
|
<IRI>#DFC_DitributedRepresentation</IRI>
|
||||||
|
<Literal xml:lang="fr">Concepts de réconciliation de représentation distribuée</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:label"/>
|
||||||
|
<IRI>#DFC_DitributedRepresentation</IRI>
|
||||||
|
<Literal xml:lang="en">ditributed représentation reconcialition concepts</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:comment"/>
|
||||||
|
<IRI>#Platform</IRI>
|
||||||
|
<Literal xml:lang="fr">Organisation qui heberge la donnée</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:label"/>
|
||||||
|
<IRI>#Platform</IRI>
|
||||||
|
<Literal xml:lang="fr">Plateforme</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:comment"/>
|
||||||
|
<IRI>#RepresentationPivot</IRI>
|
||||||
|
<Literal xml:lang="fr">Permet de designer tous les RepresentatedThing qui sont équivalents et d'etre désigné par un RepresentedThing pour connaitre ses équivalence par transitivité</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:label"/>
|
||||||
|
<IRI>#RepresentationPivot</IRI>
|
||||||
|
<Literal xml:lang="fr">Pivot de représentation</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:comment"/>
|
||||||
|
<IRI>#RepresentedThing</IRI>
|
||||||
|
<Literal xml:lang="fr">Chose représentée sur une platefome posadant des equivalences sur d'autres plateformes</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:label"/>
|
||||||
|
<IRI>#RepresentedThing</IRI>
|
||||||
|
<Literal xml:lang="fr">Chose représentée</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:comment"/>
|
||||||
|
<IRI>#hasPivot</IRI>
|
||||||
|
<Literal xml:lang="fr">possède un point pivot</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:label"/>
|
||||||
|
<IRI>#hostedBy</IRI>
|
||||||
|
<Literal xml:lang="fr">hébergé par</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
<AnnotationAssertion>
|
||||||
|
<AnnotationProperty abbreviatedIRI="rdfs:label"/>
|
||||||
|
<IRI>#represent</IRI>
|
||||||
|
<Literal xml:lang="fr">représente</Literal>
|
||||||
|
</AnnotationAssertion>
|
||||||
|
</Ontology>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Generated by the OWL API (version 4.5.9.2019-02-01T07:24:44Z) https://github.com/owlcs/owlapi -->
|
||||||
|
|
||||||
|
|
@ -0,0 +1,291 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<rdf:RDF xmlns="http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl"
|
||||||
|
xml:base="http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:dc="http://purl.org/dc/terms/"
|
||||||
|
xmlns:owl="http://www.w3.org/2002/07/owl#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:xml="http://www.w3.org/XML/1998/namespace"
|
||||||
|
xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
|
||||||
|
xmlns:xsp="http://www.owl-ontologies.com/2005/08/07/xsp.owl#"
|
||||||
|
xmlns:foaf="http://xmlns.com/foaf/0.1/"
|
||||||
|
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
|
||||||
|
xmlns:swrl="http://www.w3.org/2003/11/swrl#"
|
||||||
|
xmlns:vann="http://purl.org/vocab/vann/"
|
||||||
|
xmlns:swrlb="http://www.w3.org/2003/11/swrlb#"
|
||||||
|
xmlns:protege="http://protege.stanford.edu/plugins/owl/protege#">
|
||||||
|
<owl:Ontology rdf:about="http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl">
|
||||||
|
<rdf:type rdf:resource="http://purl.org/vocommons/voaf#Vocabulary"/>
|
||||||
|
<vann:preferredNamespacePrefix>dfc-t</vann:preferredNamespacePrefix>
|
||||||
|
<vann:preferredNamespaceUri>http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#</vann:preferredNamespaceUri>
|
||||||
|
<cc:license rdf:resource="https://www.gnu.org/licenses/agpl-3.0.en.html"/>
|
||||||
|
<dc:creator rdf:resource="http://static.datafoodconsortium.org/data/publication.rdf#simonL"/>
|
||||||
|
<dc:description xml:lang="en">A common vocabulary for digital food platforms (Technical Part)</dc:description>
|
||||||
|
<dc:issued rdf:datatype="http://www.w3.org/2001/XMLSchema#date">2018-05-28</dc:issued>
|
||||||
|
<dc:modified rdf:datatype="http://www.w3.org/2001/XMLSchema#date">2019-10-21</dc:modified>
|
||||||
|
<dc:publisher rdf:resource="http://static.datafoodconsortium.org/data/publication.rdf#dataFoodConsortium"/>
|
||||||
|
<dc:title xml:lang="en">Data Food Consortium Technical</dc:title>
|
||||||
|
<rdfs:comment xml:lang="en">A common vocabulary for digital food platforms (Technical Part)</rdfs:comment>
|
||||||
|
<owl:versionInfo rdf:datatype="http://www.w3.org/2001/XMLSchema#decimal">4.0</owl:versionInfo>
|
||||||
|
</owl:Ontology>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Annotation properties
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://creativecommons.org/ns#license -->
|
||||||
|
|
||||||
|
<owl:AnnotationProperty rdf:about="http://creativecommons.org/ns#license"/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://purl.org/dc/terms/creator -->
|
||||||
|
|
||||||
|
<owl:AnnotationProperty rdf:about="http://purl.org/dc/terms/creator"/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://purl.org/dc/terms/description -->
|
||||||
|
|
||||||
|
<owl:AnnotationProperty rdf:about="http://purl.org/dc/terms/description"/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://purl.org/dc/terms/issued -->
|
||||||
|
|
||||||
|
<owl:AnnotationProperty rdf:about="http://purl.org/dc/terms/issued"/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://purl.org/dc/terms/modified -->
|
||||||
|
|
||||||
|
<owl:AnnotationProperty rdf:about="http://purl.org/dc/terms/modified"/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://purl.org/dc/terms/publisher -->
|
||||||
|
|
||||||
|
<owl:AnnotationProperty rdf:about="http://purl.org/dc/terms/publisher"/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://purl.org/dc/terms/title -->
|
||||||
|
|
||||||
|
<owl:AnnotationProperty rdf:about="http://purl.org/dc/terms/title"/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://purl.org/vocab/vann/preferredNamespacePrefix -->
|
||||||
|
|
||||||
|
<owl:AnnotationProperty rdf:about="http://purl.org/vocab/vann/preferredNamespacePrefix"/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Object Properties
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://static.datafoodconsortium.org/ontologies/DFC_BusinessOntology.owl#DFC_TechnicalOntology_ObjectProperty -->
|
||||||
|
|
||||||
|
<owl:ObjectProperty rdf:about="http://static.datafoodconsortium.org/ontologies/DFC_BusinessOntology.owl#DFC_TechnicalOntology_ObjectProperty"/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#hasPivot -->
|
||||||
|
|
||||||
|
<owl:ObjectProperty rdf:about="http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#hasPivot">
|
||||||
|
<rdfs:subPropertyOf rdf:resource="http://www.w3.org/2002/07/owl#topObjectProperty"/>
|
||||||
|
<rdfs:comment xml:lang="fr">possède un point pivot</rdfs:comment>
|
||||||
|
</owl:ObjectProperty>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#hostedBy -->
|
||||||
|
|
||||||
|
<owl:ObjectProperty rdf:about="http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#hostedBy">
|
||||||
|
<rdfs:subPropertyOf rdf:resource="http://www.w3.org/2002/07/owl#topObjectProperty"/>
|
||||||
|
<rdfs:label xml:lang="fr">hébergé par</rdfs:label>
|
||||||
|
</owl:ObjectProperty>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#represent -->
|
||||||
|
|
||||||
|
<owl:ObjectProperty rdf:about="http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#represent">
|
||||||
|
<rdfs:subPropertyOf rdf:resource="http://www.w3.org/2002/07/owl#topObjectProperty"/>
|
||||||
|
<rdfs:label xml:lang="fr">représente</rdfs:label>
|
||||||
|
</owl:ObjectProperty>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Classes
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#DFC_DitributedRepresentation -->
|
||||||
|
|
||||||
|
<owl:Class rdf:about="http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#DFC_DitributedRepresentation">
|
||||||
|
<rdfs:label xml:lang="fr">Concepts de réconciliation de représentation distribuée</rdfs:label>
|
||||||
|
<rdfs:label xml:lang="en">ditributed représentation reconcialition concepts</rdfs:label>
|
||||||
|
</owl:Class>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#Platform -->
|
||||||
|
|
||||||
|
<owl:Class rdf:about="http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#Platform">
|
||||||
|
<rdfs:subClassOf rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#DFC_DitributedRepresentation"/>
|
||||||
|
<rdfs:subClassOf>
|
||||||
|
<owl:Restriction>
|
||||||
|
<owl:onProperty rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#hostedBy"/>
|
||||||
|
<owl:allValuesFrom rdf:resource="http://www.w3.org/2002/07/owl#Thing"/>
|
||||||
|
</owl:Restriction>
|
||||||
|
</rdfs:subClassOf>
|
||||||
|
<rdfs:comment xml:lang="fr">Organisation qui heberge la donnée</rdfs:comment>
|
||||||
|
<rdfs:label xml:lang="fr">Plateforme</rdfs:label>
|
||||||
|
</owl:Class>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#RepresentationPivot -->
|
||||||
|
|
||||||
|
<owl:Class rdf:about="http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#RepresentationPivot">
|
||||||
|
<rdfs:subClassOf rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#DFC_DitributedRepresentation"/>
|
||||||
|
<rdfs:subClassOf>
|
||||||
|
<owl:Restriction>
|
||||||
|
<owl:onProperty rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#represent"/>
|
||||||
|
<owl:allValuesFrom rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#RepresentedThing"/>
|
||||||
|
</owl:Restriction>
|
||||||
|
</rdfs:subClassOf>
|
||||||
|
<rdfs:subClassOf>
|
||||||
|
<owl:Restriction>
|
||||||
|
<owl:onProperty rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#represent"/>
|
||||||
|
<owl:minQualifiedCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:minQualifiedCardinality>
|
||||||
|
<owl:onClass rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#RepresentedThing"/>
|
||||||
|
</owl:Restriction>
|
||||||
|
</rdfs:subClassOf>
|
||||||
|
<rdfs:comment xml:lang="fr">Permet de designer tous les RepresentatedThing qui sont équivalents et d'etre désigné par un RepresentedThing pour connaitre ses équivalence par transitivité</rdfs:comment>
|
||||||
|
<rdfs:label xml:lang="fr">Pivot de représentation</rdfs:label>
|
||||||
|
</owl:Class>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#RepresentedThing -->
|
||||||
|
|
||||||
|
<owl:Class rdf:about="http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#RepresentedThing">
|
||||||
|
<rdfs:subClassOf rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#DFC_DitributedRepresentation"/>
|
||||||
|
<rdfs:subClassOf>
|
||||||
|
<owl:Restriction>
|
||||||
|
<owl:onProperty rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#hasPivot"/>
|
||||||
|
<owl:allValuesFrom rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#RepresentationPivot"/>
|
||||||
|
</owl:Restriction>
|
||||||
|
</rdfs:subClassOf>
|
||||||
|
<rdfs:subClassOf>
|
||||||
|
<owl:Restriction>
|
||||||
|
<owl:onProperty rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#hostedBy"/>
|
||||||
|
<owl:allValuesFrom rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#Platform"/>
|
||||||
|
</owl:Restriction>
|
||||||
|
</rdfs:subClassOf>
|
||||||
|
<rdfs:subClassOf>
|
||||||
|
<owl:Restriction>
|
||||||
|
<owl:onProperty rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#hasPivot"/>
|
||||||
|
<owl:qualifiedCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:qualifiedCardinality>
|
||||||
|
<owl:onClass rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#RepresentationPivot"/>
|
||||||
|
</owl:Restriction>
|
||||||
|
</rdfs:subClassOf>
|
||||||
|
<rdfs:subClassOf>
|
||||||
|
<owl:Restriction>
|
||||||
|
<owl:onProperty rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#hostedBy"/>
|
||||||
|
<owl:qualifiedCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#nonNegativeInteger">1</owl:qualifiedCardinality>
|
||||||
|
<owl:onClass rdf:resource="http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#Platform"/>
|
||||||
|
</owl:Restriction>
|
||||||
|
</rdfs:subClassOf>
|
||||||
|
<rdfs:comment xml:lang="fr">Chose représentée sur une platefome posadant des equivalences sur d'autres plateformes</rdfs:comment>
|
||||||
|
<rdfs:label xml:lang="fr">Chose représentée</rdfs:label>
|
||||||
|
</owl:Class>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://xmlns.com/foaf/0.1/Organization -->
|
||||||
|
|
||||||
|
<owl:Class rdf:about="http://xmlns.com/foaf/0.1/Organization"/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://xmlns.com/foaf/0.1/Person -->
|
||||||
|
|
||||||
|
<owl:Class rdf:about="http://xmlns.com/foaf/0.1/Person"/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Individuals
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://static.datafoodconsortium.org/data/publication.rdf#dataFoodConsortium -->
|
||||||
|
|
||||||
|
<owl:NamedIndividual rdf:about="http://static.datafoodconsortium.org/data/publication.rdf#dataFoodConsortium">
|
||||||
|
<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Organization"/>
|
||||||
|
</owl:NamedIndividual>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- http://static.datafoodconsortium.org/data/publication.rdf#simonL -->
|
||||||
|
|
||||||
|
<owl:NamedIndividual rdf:about="http://static.datafoodconsortium.org/data/publication.rdf#simonL">
|
||||||
|
<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/>
|
||||||
|
</owl:NamedIndividual>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// General axioms
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
-->
|
||||||
|
|
||||||
|
<rdf:Description>
|
||||||
|
<rdf:type rdf:resource="http://www.w3.org/2002/07/owl#AllDisjointClasses"/>
|
||||||
|
<owl:members rdf:parseType="Collection">
|
||||||
|
<rdf:Description rdf:about="http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#Platform"/>
|
||||||
|
<rdf:Description rdf:about="http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#RepresentationPivot"/>
|
||||||
|
<rdf:Description rdf:about="http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#RepresentedThing"/>
|
||||||
|
</owl:members>
|
||||||
|
</rdf:Description>
|
||||||
|
</rdf:RDF>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Generated by the OWL API (version 4.5.9.2019-02-01T07:24:44Z) https://github.com/owlcs/owlapi -->
|
||||||
|
|
@ -0,0 +1,989 @@
|
||||||
|
{
|
||||||
|
"@context": {
|
||||||
|
"rdfs": "http://www.w3.org/2000/01/rdf-schema#",
|
||||||
|
"dfc-b": "http://static.datafoodconsortium.org/ontologies/DFC_BusinessOntology.owl#",
|
||||||
|
"dfc-p": "http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#",
|
||||||
|
"dfc-t": "http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#",
|
||||||
|
"dfc-u": "http://static.datafoodconsortium.org/data/units.json#",
|
||||||
|
"dfc-p:specialize": {
|
||||||
|
"@type": "@id"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@graph": [
|
||||||
|
{
|
||||||
|
"@id": "http://static.datafoodconsortium.org/data/accommodationTypes.json#EntirePlace",
|
||||||
|
"rdfs:label": [
|
||||||
|
{
|
||||||
|
"@value": "Entire Place",
|
||||||
|
"@language": "en"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Entire Place",
|
||||||
|
"@language": "ar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Entire Place",
|
||||||
|
"@language": "ku"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Entire Place",
|
||||||
|
"@language": "es"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Posto intero",
|
||||||
|
"@language": "it"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Gesamter Ort",
|
||||||
|
"@language": "de"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Entire Place",
|
||||||
|
"@language": "sw"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Lugar completo",
|
||||||
|
"@language": "pt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Entire Place",
|
||||||
|
"@language": "oc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Все место",
|
||||||
|
"@language": "ru"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Entire Place",
|
||||||
|
"@language": "cy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "集合場所",
|
||||||
|
"@language": "ja"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Áit Eintire",
|
||||||
|
"@language": "ga"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "जगह",
|
||||||
|
"@language": "hi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "入口",
|
||||||
|
"@language": "zh"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Entire Place",
|
||||||
|
"@language": "fr"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Entire Place",
|
||||||
|
"@language": "ca"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/accommodationTypes.json#EntirePlace",
|
||||||
|
"@type": "dfc-p:ProductType"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@id": "http://static.datafoodconsortium.org/data/accommodationTypes.json#PrivateRoom",
|
||||||
|
"rdfs:label": [
|
||||||
|
{
|
||||||
|
"@value": "Private Room",
|
||||||
|
"@language": "en"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "الغرفة الخاصة",
|
||||||
|
"@language": "ar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Private Room",
|
||||||
|
"@language": "ku"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Habitación privada",
|
||||||
|
"@language": "es"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Stanza privata",
|
||||||
|
"@language": "it"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Privatzimmer",
|
||||||
|
"@language": "de"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Private Room",
|
||||||
|
"@language": "sw"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Quarto privado",
|
||||||
|
"@language": "pt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Private Room",
|
||||||
|
"@language": "oc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Частная комната",
|
||||||
|
"@language": "ru"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Private Room",
|
||||||
|
"@language": "cy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "プライベートルーム",
|
||||||
|
"@language": "ja"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Seomra na nDaoine",
|
||||||
|
"@language": "ga"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "निजी कक्ष",
|
||||||
|
"@language": "hi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "私人会议室",
|
||||||
|
"@language": "zh"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Salle privée",
|
||||||
|
"@language": "fr"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Private Room",
|
||||||
|
"@language": "ca"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/accommodationTypes.json#PrivateRoom",
|
||||||
|
"@type": "dfc-p:ProductType"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@id": "http://static.datafoodconsortium.org/data/accommodationTypes.json#HotelRoom",
|
||||||
|
"rdfs:label": [
|
||||||
|
{
|
||||||
|
"@value": "Hotel Room",
|
||||||
|
"@language": "en"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "فندق",
|
||||||
|
"@language": "ar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Hotel Room",
|
||||||
|
"@language": "ku"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Hotel Room",
|
||||||
|
"@language": "es"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Camera dell'hotel",
|
||||||
|
"@language": "it"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Hotelzimmer",
|
||||||
|
"@language": "de"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Hotel Room",
|
||||||
|
"@language": "sw"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Quarto de Hotel",
|
||||||
|
"@language": "pt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Hotel Room",
|
||||||
|
"@language": "oc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Номер в отеле",
|
||||||
|
"@language": "ru"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Hotel Room",
|
||||||
|
"@language": "cy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "ホテル ルーム",
|
||||||
|
"@language": "ja"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Seomra Óstán",
|
||||||
|
"@language": "ga"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "होटल",
|
||||||
|
"@language": "hi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "旅馆",
|
||||||
|
"@language": "zh"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Hotel Room",
|
||||||
|
"@language": "fr"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Hotel Room",
|
||||||
|
"@language": "ca"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/accommodationTypes.json#HotelRoom",
|
||||||
|
"@type": "dfc-p:ProductType"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@id": "http://static.datafoodconsortium.org/data/accommodationTypes.json#SharedRoom",
|
||||||
|
"rdfs:label": [
|
||||||
|
{
|
||||||
|
"@value": "Shared Room",
|
||||||
|
"@language": "en"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "الغرفة المشتركة",
|
||||||
|
"@language": "ar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Shared Room",
|
||||||
|
"@language": "ku"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Habitación compartida",
|
||||||
|
"@language": "es"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Camera condivisa",
|
||||||
|
"@language": "it"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Zimmer",
|
||||||
|
"@language": "de"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Shared Room",
|
||||||
|
"@language": "sw"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Quarto compartilhado",
|
||||||
|
"@language": "pt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Shared Room",
|
||||||
|
"@language": "oc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Общая комната",
|
||||||
|
"@language": "ru"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Shared Room",
|
||||||
|
"@language": "cy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "シェアルーム",
|
||||||
|
"@language": "ja"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Seomra Comhroinnte",
|
||||||
|
"@language": "ga"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "साझा कक्ष",
|
||||||
|
"@language": "hi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "共有会议室",
|
||||||
|
"@language": "zh"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Salle partagée",
|
||||||
|
"@language": "fr"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Shared Room",
|
||||||
|
"@language": "ca"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/accommodationTypes.json#SharedRoom",
|
||||||
|
"@type": "dfc-p:ProductType"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@id": "http://static.datafoodconsortium.org/data/accommodationTypes.json#Sofa",
|
||||||
|
"rdfs:label": [
|
||||||
|
{
|
||||||
|
"@value": "Sofa",
|
||||||
|
"@language": "en"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Sofa",
|
||||||
|
"@language": "ar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Sofa",
|
||||||
|
"@language": "ku"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Sofa",
|
||||||
|
"@language": "es"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Divano",
|
||||||
|
"@language": "it"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Sofa",
|
||||||
|
"@language": "de"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Sofa",
|
||||||
|
"@language": "sw"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Sofá",
|
||||||
|
"@language": "pt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Sofa",
|
||||||
|
"@language": "oc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Диван",
|
||||||
|
"@language": "ru"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Sofa",
|
||||||
|
"@language": "cy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "ソファ",
|
||||||
|
"@language": "ja"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Toir agus Crainn",
|
||||||
|
"@language": "ga"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "सोफा",
|
||||||
|
"@language": "hi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Sofa",
|
||||||
|
"@language": "zh"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Sofa",
|
||||||
|
"@language": "fr"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Sofa",
|
||||||
|
"@language": "ca"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/accommodationTypes.json#Sofa",
|
||||||
|
"@type": "dfc-p:ProductType"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@id": "http://static.datafoodconsortium.org/data/accommodationTypes.json#Boat",
|
||||||
|
"rdfs:label": [
|
||||||
|
{
|
||||||
|
"@value": "Boat",
|
||||||
|
"@language": "en"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Boat",
|
||||||
|
"@language": "ar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Boat",
|
||||||
|
"@language": "ku"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "El barco",
|
||||||
|
"@language": "es"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Barca",
|
||||||
|
"@language": "it"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Boote",
|
||||||
|
"@language": "de"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Boat",
|
||||||
|
"@language": "sw"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Barco",
|
||||||
|
"@language": "pt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Boat",
|
||||||
|
"@language": "oc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Лодка",
|
||||||
|
"@language": "ru"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Boat",
|
||||||
|
"@language": "cy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "ボート",
|
||||||
|
"@language": "ja"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "taiseachas aeir: fliuch",
|
||||||
|
"@language": "ga"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "नाव",
|
||||||
|
"@language": "hi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "B. 博塔",
|
||||||
|
"@language": "zh"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Boat",
|
||||||
|
"@language": "fr"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Boat",
|
||||||
|
"@language": "ca"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/accommodationTypes.json#Boat",
|
||||||
|
"@type": "dfc-p:ProductType"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@id": "http://static.datafoodconsortium.org/data/accommodationTypes.json#Barge",
|
||||||
|
"rdfs:label": [
|
||||||
|
{
|
||||||
|
"@value": "Barge",
|
||||||
|
"@language": "en"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Barge",
|
||||||
|
"@language": "ar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Barge",
|
||||||
|
"@language": "ku"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Barge",
|
||||||
|
"@language": "es"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Barge",
|
||||||
|
"@language": "it"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Barrel",
|
||||||
|
"@language": "de"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Barge",
|
||||||
|
"@language": "sw"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Barco",
|
||||||
|
"@language": "pt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Barge",
|
||||||
|
"@language": "oc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Барж",
|
||||||
|
"@language": "ru"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Barge",
|
||||||
|
"@language": "cy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "バージ",
|
||||||
|
"@language": "ja"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Toir agus Crainn",
|
||||||
|
"@language": "ga"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "बार्ज",
|
||||||
|
"@language": "hi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "律师协会",
|
||||||
|
"@language": "zh"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Barge",
|
||||||
|
"@language": "fr"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Barge",
|
||||||
|
"@language": "ca"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/accommodationTypes.json#Boat",
|
||||||
|
"@type": "dfc-p:ProductType"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@id": "http://static.datafoodconsortium.org/data/accommodationTypes.json#Tent",
|
||||||
|
"rdfs:label": [
|
||||||
|
{
|
||||||
|
"@value": "Tent",
|
||||||
|
"@language": "en"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "الخيمة",
|
||||||
|
"@language": "ar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Tent",
|
||||||
|
"@language": "ku"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Tent",
|
||||||
|
"@language": "es"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Tenda",
|
||||||
|
"@language": "it"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Zelt",
|
||||||
|
"@language": "de"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Tent",
|
||||||
|
"@language": "sw"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Tenda",
|
||||||
|
"@language": "pt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Tent",
|
||||||
|
"@language": "oc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Тент",
|
||||||
|
"@language": "ru"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Tent",
|
||||||
|
"@language": "cy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "テント",
|
||||||
|
"@language": "ja"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Tent",
|
||||||
|
"@language": "ga"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "टेंट",
|
||||||
|
"@language": "hi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "答辩",
|
||||||
|
"@language": "zh"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Tent",
|
||||||
|
"@language": "fr"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Tent",
|
||||||
|
"@language": "ca"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/accommodationTypes.json#Tent",
|
||||||
|
"@type": "dfc-p:ProductType"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@id": "http://static.datafoodconsortium.org/data/accommodationTypes.json#Caravan",
|
||||||
|
"rdfs:label": [
|
||||||
|
{
|
||||||
|
"@value": "Caravan",
|
||||||
|
"@language": "en"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Caravan",
|
||||||
|
"@language": "ar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Caravan",
|
||||||
|
"@language": "ku"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Caravan",
|
||||||
|
"@language": "es"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Caravan",
|
||||||
|
"@language": "it"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Wohnwagen",
|
||||||
|
"@language": "de"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Caravan",
|
||||||
|
"@language": "sw"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Caravana",
|
||||||
|
"@language": "pt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Caravan",
|
||||||
|
"@language": "oc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Караван",
|
||||||
|
"@language": "ru"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Caravan",
|
||||||
|
"@language": "cy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "キャラバン",
|
||||||
|
"@language": "ja"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Amharc ar gach eolas",
|
||||||
|
"@language": "ga"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "कारवां",
|
||||||
|
"@language": "hi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "车队",
|
||||||
|
"@language": "zh"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Caravan",
|
||||||
|
"@language": "fr"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Caravan",
|
||||||
|
"@language": "ca"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/accommodationTypes.json#Caravan",
|
||||||
|
"@type": "dfc-p:ProductType"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@id": "http://static.datafoodconsortium.org/data/accommodationTypes.json#Hostel",
|
||||||
|
"rdfs:label": [
|
||||||
|
{
|
||||||
|
"@value": "Hostel",
|
||||||
|
"@language": "en"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Hostel",
|
||||||
|
"@language": "ar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Hostel",
|
||||||
|
"@language": "ku"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Hostel",
|
||||||
|
"@language": "es"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Ostello",
|
||||||
|
"@language": "it"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Hostel",
|
||||||
|
"@language": "de"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Hostel",
|
||||||
|
"@language": "sw"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Albergue",
|
||||||
|
"@language": "pt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Hostel",
|
||||||
|
"@language": "oc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Хостел",
|
||||||
|
"@language": "ru"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Hostel",
|
||||||
|
"@language": "cy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "ホステル",
|
||||||
|
"@language": "ja"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "brú",
|
||||||
|
"@language": "ga"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "छात्रावास",
|
||||||
|
"@language": "hi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "人质",
|
||||||
|
"@language": "zh"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Hostel",
|
||||||
|
"@language": "fr"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Hostel",
|
||||||
|
"@language": "ca"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/accommodationTypes.json#Hostel",
|
||||||
|
"@type": "dfc-p:ProductType"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@id": "http://static.datafoodconsortium.org/data/accommodationTypes.json#Yurt",
|
||||||
|
"rdfs:label": [
|
||||||
|
{
|
||||||
|
"@value": "Yurt",
|
||||||
|
"@language": "en"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "يوت",
|
||||||
|
"@language": "ar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Yurt",
|
||||||
|
"@language": "ku"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Yurt",
|
||||||
|
"@language": "es"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Yurt",
|
||||||
|
"@language": "it"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Rind",
|
||||||
|
"@language": "de"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Yurt",
|
||||||
|
"@language": "sw"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Yurt.",
|
||||||
|
"@language": "pt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Yurt",
|
||||||
|
"@language": "oc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Юрт",
|
||||||
|
"@language": "ru"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Yurt",
|
||||||
|
"@language": "cy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "ユルト",
|
||||||
|
"@language": "ja"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "taiseachas aeir: fliuch",
|
||||||
|
"@language": "ga"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "युर्ट",
|
||||||
|
"@language": "hi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "导 言",
|
||||||
|
"@language": "zh"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Yurt",
|
||||||
|
"@language": "fr"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Yurt",
|
||||||
|
"@language": "ca"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/accommodationTypes.json#Yurt",
|
||||||
|
"@type": "dfc-p:ProductType"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@id": "http://static.datafoodconsortium.org/data/accommodationTypes.json#Tipi",
|
||||||
|
"rdfs:label": [
|
||||||
|
{
|
||||||
|
"@value": "Tipi",
|
||||||
|
"@language": "en"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Tipi",
|
||||||
|
"@language": "ar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Tipi",
|
||||||
|
"@language": "ku"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Tipi",
|
||||||
|
"@language": "es"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Tipi di",
|
||||||
|
"@language": "it"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Tipi",
|
||||||
|
"@language": "de"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Tipi",
|
||||||
|
"@language": "sw"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Sugestões",
|
||||||
|
"@language": "pt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Tipi",
|
||||||
|
"@language": "oc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Советы",
|
||||||
|
"@language": "ru"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Tipi",
|
||||||
|
"@language": "cy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "ログイン",
|
||||||
|
"@language": "ja"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "An tSeapáin",
|
||||||
|
"@language": "ga"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "टीका",
|
||||||
|
"@language": "hi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "注",
|
||||||
|
"@language": "zh"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Tipi",
|
||||||
|
"@language": "fr"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Tipi",
|
||||||
|
"@language": "ca"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/accommodationTypes.json#Tipi",
|
||||||
|
"@type": "dfc-p:ProductType"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@id": "http://static.datafoodconsortium.org/data/accommodationTypes.json#RV",
|
||||||
|
"rdfs:label": [
|
||||||
|
{
|
||||||
|
"@value": "RV",
|
||||||
|
"@language": "en"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "RV",
|
||||||
|
"@language": "ar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "RV",
|
||||||
|
"@language": "ku"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "RV",
|
||||||
|
"@language": "es"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "RV",
|
||||||
|
"@language": "it"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "RV",
|
||||||
|
"@language": "de"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "RV",
|
||||||
|
"@language": "sw"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "RV",
|
||||||
|
"@language": "pt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "RV",
|
||||||
|
"@language": "oc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "РВ",
|
||||||
|
"@language": "ru"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "RV",
|
||||||
|
"@language": "cy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "RVの特長",
|
||||||
|
"@language": "ja"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "RV",
|
||||||
|
"@language": "ga"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "आरवी",
|
||||||
|
"@language": "hi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "RV",
|
||||||
|
"@language": "zh"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "RV",
|
||||||
|
"@language": "fr"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "RV",
|
||||||
|
"@language": "ca"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/accommodationTypes.json#RV",
|
||||||
|
"@type": "dfc-p:ProductType"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -2,16 +2,16 @@
|
||||||
"@context": {
|
"@context": {
|
||||||
"rdfs": "http://www.w3.org/2000/01/rdf-schema#",
|
"rdfs": "http://www.w3.org/2000/01/rdf-schema#",
|
||||||
"dfc-b": "http://static.datafoodconsortium.org/ontologies/DFC_BusinessOntology.owl#",
|
"dfc-b": "http://static.datafoodconsortium.org/ontologies/DFC_BusinessOntology.owl#",
|
||||||
"dfc-p": "http://static.datafoodconsortium.org/ontologies/DFC_ProductOntology.owl#",
|
"dfc-p": "http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#",
|
||||||
"dfc-t": "http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#",
|
"dfc-t": "http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#",
|
||||||
"dfc-u": "http://static.datafoodconsortium.org/data/units.rdf#",
|
"dfc-u": "http://static.datafoodconsortium.org/data/units.json#",
|
||||||
"dfc-p:specialize": {
|
"dfc-p:specialize": {
|
||||||
"@type": "@id"
|
"@type": "@id"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@graph": [
|
"@graph": [
|
||||||
{
|
{
|
||||||
"@id": "https://clothes/data/clothesTypes.rdf#shirt",
|
"@id": "http://static.datafoodconsortium.org/data/clothesTypes.json#shirt",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "La chemise",
|
"@value": "La chemise",
|
||||||
|
|
@ -82,11 +82,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://clothes/data/clothesTypes.rdf#shirt",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/clothesTypes.json#shirt",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://clothes/data/clothesTypes.rdf#belt",
|
"@id": "http://static.datafoodconsortium.org/data/clothesTypes.json#belt",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Ceinture",
|
"@value": "Ceinture",
|
||||||
|
|
@ -157,11 +157,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://clothes/data/toolTypes.rdf#belt",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/toolTypes.rdf#belt",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://clothes/data/clothesTypes.rdf#childrens-clothing",
|
"@id": "http://static.datafoodconsortium.org/data/clothesTypes.json#childrens-clothing",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Vêtements pour enfants",
|
"@value": "Vêtements pour enfants",
|
||||||
|
|
@ -232,11 +232,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://clothes/data/toolTypes.rdf#childrens-clothing",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/toolTypes.rdf#childrens-clothing",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://clothes/data/clothesTypes.rdf#coat",
|
"@id": "http://static.datafoodconsortium.org/data/clothesTypes.json#coat",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Manteau",
|
"@value": "Manteau",
|
||||||
|
|
@ -307,11 +307,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://clothes/data/toolTypes.rdf#coat",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/toolTypes.rdf#coat",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://clothes/data/clothesTypes.rdf#dress",
|
"@id": "http://static.datafoodconsortium.org/data/clothesTypes.json#dress",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Robe",
|
"@value": "Robe",
|
||||||
|
|
@ -382,11 +382,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://clothes/data/toolTypes.rdf#womens",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/toolTypes.rdf#womens",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://clothes/data/clothesTypes.rdf#shoes",
|
"@id": "http://static.datafoodconsortium.org/data/clothesTypes.json#shoes",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Des chaussures",
|
"@value": "Des chaussures",
|
||||||
|
|
@ -457,11 +457,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://clothes/data/toolTypes.rdf#footwear",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/toolTypes.rdf#footwear",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://clothes/data/clothesTypes.rdf#boots",
|
"@id": "http://static.datafoodconsortium.org/data/clothesTypes.json#boots",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Bottes",
|
"@value": "Bottes",
|
||||||
|
|
@ -532,11 +532,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://clothes/data/toolTypes.rdf#footwear",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/toolTypes.rdf#footwear",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://clothes/data/clothesTypes.rdf#gown",
|
"@id": "http://static.datafoodconsortium.org/data/clothesTypes.json#gown",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Robe",
|
"@value": "Robe",
|
||||||
|
|
@ -607,11 +607,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://clothes/data/toolTypes.rdf#gown",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/toolTypes.rdf#gown",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://clothes/data/clothesTypes.rdf#hat",
|
"@id": "http://static.datafoodconsortium.org/data/clothesTypes.json#hat",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Chapeau",
|
"@value": "Chapeau",
|
||||||
|
|
@ -682,11 +682,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://clothes/data/toolTypes.rdf#hat",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/toolTypes.rdf#hat",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://clothes/data/clothesTypes.rdf#hosiery",
|
"@id": "http://static.datafoodconsortium.org/data/clothesTypes.json#hosiery",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Hosiery",
|
"@value": "Hosiery",
|
||||||
|
|
@ -757,11 +757,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://clothes/data/toolTypes.rdf#hosiery",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/toolTypes.rdf#hosiery",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://clothes/data/clothesTypes.rdf#jacket",
|
"@id": "http://static.datafoodconsortium.org/data/clothesTypes.json#jacket",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Veste",
|
"@value": "Veste",
|
||||||
|
|
@ -832,11 +832,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://clothes/data/toolTypes.rdf#jacket",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/toolTypes.rdf#jacket",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://clothes/data/clothesTypes.rdf#jeans",
|
"@id": "http://static.datafoodconsortium.org/data/clothesTypes.json#jeans",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Jeans",
|
"@value": "Jeans",
|
||||||
|
|
@ -907,11 +907,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://clothes/data/toolTypes.rdf#jeans",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/toolTypes.rdf#jeans",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://clothes/data/clothesTypes.rdf#mask",
|
"@id": "http://static.datafoodconsortium.org/data/clothesTypes.json#mask",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Masquer",
|
"@value": "Masquer",
|
||||||
|
|
@ -982,11 +982,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://clothes/data/toolTypes.rdf#mask",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/toolTypes.rdf#mask",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://clothes/data/clothesTypes.rdf#neckwear",
|
"@id": "http://static.datafoodconsortium.org/data/clothesTypes.json#neckwear",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Vêtements de cou",
|
"@value": "Vêtements de cou",
|
||||||
|
|
@ -1057,11 +1057,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://clothes/data/toolTypes.rdf#neckwear",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/toolTypes.rdf#neckwear",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://clothes/data/clothesTypes.rdf#scarf",
|
"@id": "http://static.datafoodconsortium.org/data/clothesTypes.json#scarf",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Écharpe",
|
"@value": "Écharpe",
|
||||||
|
|
@ -1132,11 +1132,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://clothes/data/toolTypes.rdf#neckwear",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/toolTypes.rdf#neckwear",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://clothes/data/clothesTypes.rdf#suit",
|
"@id": "http://static.datafoodconsortium.org/data/clothesTypes.json#suit",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Costume",
|
"@value": "Costume",
|
||||||
|
|
@ -1207,11 +1207,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://clothes/data/toolTypes.rdf#suit",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/toolTypes.rdf#suit",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://clothes/data/clothesTypes.rdf#poncho",
|
"@id": "http://static.datafoodconsortium.org/data/clothesTypes.json#poncho",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Poncho",
|
"@value": "Poncho",
|
||||||
|
|
@ -1282,11 +1282,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://clothes/data/toolTypes.rdf#poncho",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/toolTypes.rdf#poncho",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://clothes/data/clothesTypes.rdf#cloak",
|
"@id": "http://static.datafoodconsortium.org/data/clothesTypes.json#cloak",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Manteau",
|
"@value": "Manteau",
|
||||||
|
|
@ -1357,11 +1357,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://clothes/data/toolTypes.rdf#cloak",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/toolTypes.rdf#cloak",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://clothes/data/clothesTypes.rdf#sari",
|
"@id": "http://static.datafoodconsortium.org/data/clothesTypes.json#sari",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Sari",
|
"@value": "Sari",
|
||||||
|
|
@ -1432,11 +1432,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://clothes/data/toolTypes.rdf#womens",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/toolTypes.rdf#womens",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://clothes/data/clothesTypes.rdf#sash",
|
"@id": "http://static.datafoodconsortium.org/data/clothesTypes.json#sash",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Ceinture",
|
"@value": "Ceinture",
|
||||||
|
|
@ -1507,11 +1507,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://clothes/data/toolTypes.rdf#sash",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/toolTypes.rdf#sash",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://clothes/data/clothesTypes.rdf#shawl",
|
"@id": "http://static.datafoodconsortium.org/data/clothesTypes.json#shawl",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Châle",
|
"@value": "Châle",
|
||||||
|
|
@ -1582,11 +1582,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://clothes/data/toolTypes.rdf#womens",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/toolTypes.rdf#womens",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://clothes/data/clothesTypes.rdf#skirt",
|
"@id": "http://static.datafoodconsortium.org/data/clothesTypes.json#skirt",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Jupe",
|
"@value": "Jupe",
|
||||||
|
|
@ -1657,11 +1657,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://clothes/data/toolTypes.rdf#womens",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/toolTypes.rdf#womens",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://clothes/data/clothesTypes.rdf#trousers",
|
"@id": "http://static.datafoodconsortium.org/data/clothesTypes.json#trousers",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Pantalon",
|
"@value": "Pantalon",
|
||||||
|
|
@ -1732,11 +1732,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://clothes/data/toolTypes.rdf#trousers",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/toolTypes.rdf#trousers",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://clothes/data/clothesTypes.rdf#shorts",
|
"@id": "http://static.datafoodconsortium.org/data/clothesTypes.json#shorts",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Shorts",
|
"@value": "Shorts",
|
||||||
|
|
@ -1807,11 +1807,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://clothes/data/toolTypes.rdf#shorts",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/toolTypes.rdf#shorts",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://clothes/data/clothesTypes.rdf#underwear",
|
"@id": "http://static.datafoodconsortium.org/data/clothesTypes.json#underwear",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Sous-vêtement",
|
"@value": "Sous-vêtement",
|
||||||
|
|
@ -1882,11 +1882,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://clothes/data/toolTypes.rdf#underwear",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/toolTypes.rdf#underwear",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://clothes/data/clothesTypes.rdf#socks",
|
"@id": "http://static.datafoodconsortium.org/data/clothesTypes.json#socks",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Des chaussettes",
|
"@value": "Des chaussettes",
|
||||||
|
|
@ -1957,11 +1957,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://clothes/data/toolTypes.rdf#footwear",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/toolTypes.rdf#footwear",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://clothes/data/clothesTypes.rdf#helmet",
|
"@id": "http://static.datafoodconsortium.org/data/clothesTypes.json#helmet",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Casque",
|
"@value": "Casque",
|
||||||
|
|
@ -2032,11 +2032,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://clothes/data/toolTypes.rdf#helmet",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/toolTypes.rdf#helmet",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://clothes/data/clothesTypes.rdf#gloves",
|
"@id": "http://static.datafoodconsortium.org/data/clothesTypes.json#gloves",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Gants",
|
"@value": "Gants",
|
||||||
|
|
@ -2107,11 +2107,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://clothes/data/toolTypes.rdf#gloves",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/toolTypes.rdf#gloves",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://clothes/data/clothesTypes.rdf#kurta",
|
"@id": "http://static.datafoodconsortium.org/data/clothesTypes.json#kurta",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Kurta",
|
"@value": "Kurta",
|
||||||
|
|
@ -2182,11 +2182,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://clothes/data/toolTypes.rdf#kurta",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/toolTypes.rdf#kurta",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://clothes/data/clothesTypes.rdf#sherwani",
|
"@id": "http://static.datafoodconsortium.org/data/clothesTypes.json#sherwani",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Sherwani",
|
"@value": "Sherwani",
|
||||||
|
|
@ -2257,11 +2257,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://clothes/data/toolTypes.rdf#mens",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/toolTypes.rdf#mens",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://clothes/data/clothesTypes.rdf#shalwar-kameez",
|
"@id": "http://static.datafoodconsortium.org/data/clothesTypes.json#shalwar-kameez",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Shalwar Kameez",
|
"@value": "Shalwar Kameez",
|
||||||
|
|
@ -2332,11 +2332,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://clothes/data/toolTypes.rdf#womens",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/toolTypes.rdf#womens",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://clothes/data/clothesTypes.rdf#cheongsam",
|
"@id": "http://static.datafoodconsortium.org/data/clothesTypes.json#cheongsam",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Cheongsam",
|
"@value": "Cheongsam",
|
||||||
|
|
@ -2407,11 +2407,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://clothes/data/toolTypes.rdf#womens",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/toolTypes.rdf#womens",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://clothes/data/clothesTypes.rdf#áo-bà-ba",
|
"@id": "http://static.datafoodconsortium.org/data/clothesTypes.json#áo-bà-ba",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Áo bà ba",
|
"@value": "Áo bà ba",
|
||||||
|
|
@ -2482,11 +2482,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://clothes/data/toolTypes.rdf#áo-bà-ba",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/toolTypes.rdf#áo-bà-ba",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://clothes/data/clothesTypes.rdf#áo-dài",
|
"@id": "http://static.datafoodconsortium.org/data/clothesTypes.json#áo-dài",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Áo dài",
|
"@value": "Áo dài",
|
||||||
|
|
@ -2557,11 +2557,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://clothes/data/toolTypes.rdf#áo-dài",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/toolTypes.rdf#áo-dài",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://clothes/data/clothesTypes.rdf#halter-top",
|
"@id": "http://static.datafoodconsortium.org/data/clothesTypes.json#halter-top",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Halter haut",
|
"@value": "Halter haut",
|
||||||
|
|
@ -2632,11 +2632,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://clothes/data/toolTypes.rdf#womens",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/toolTypes.rdf#womens",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://clothes/data/clothesTypes.rdf#sandals",
|
"@id": "http://static.datafoodconsortium.org/data/clothesTypes.json#sandals",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Des sandales",
|
"@value": "Des sandales",
|
||||||
|
|
@ -2707,11 +2707,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://clothes/data/toolTypes.rdf#footwear",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/toolTypes.rdf#footwear",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://clothes/data/clothesTypes.rdf#slippers",
|
"@id": "http://static.datafoodconsortium.org/data/clothesTypes.json#slippers",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Chaussons",
|
"@value": "Chaussons",
|
||||||
|
|
@ -2782,11 +2782,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://clothes/data/toolTypes.rdf#footwear",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/toolTypes.rdf#footwear",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://clothes/data/clothesTypes.rdf#kilt",
|
"@id": "http://static.datafoodconsortium.org/data/clothesTypes.json#kilt",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Kilt",
|
"@value": "Kilt",
|
||||||
|
|
@ -2857,7 +2857,157 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://clothes/data/toolTypes.rdf#kilt",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/toolTypes.rdf#kilt",
|
||||||
|
"@type": "dfc-p:ProductType"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@id": "http://static.datafoodconsortium.org/data/clothesTypes.json#apron",
|
||||||
|
"rdfs:label": [
|
||||||
|
{
|
||||||
|
"@value": "Apron",
|
||||||
|
"@language": "en"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Apron",
|
||||||
|
"@language": "ar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Apron",
|
||||||
|
"@language": "ku"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Apron",
|
||||||
|
"@language": "es"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Grembiule",
|
||||||
|
"@language": "it"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Apres",
|
||||||
|
"@language": "de"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Apron",
|
||||||
|
"@language": "sw"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Avental",
|
||||||
|
"@language": "pt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Apron",
|
||||||
|
"@language": "oc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Абон",
|
||||||
|
"@language": "ru"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Apron",
|
||||||
|
"@language": "cy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "エプロン",
|
||||||
|
"@language": "ja"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "An tAthrú",
|
||||||
|
"@language": "ga"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "एप्रन",
|
||||||
|
"@language": "hi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "环境",
|
||||||
|
"@language": "zh"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Apron",
|
||||||
|
"@language": "fr"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Apron",
|
||||||
|
"@language": "ca"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/toolTypes.rdf#apron",
|
||||||
|
"@type": "dfc-p:ProductType"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@id": "http://static.datafoodconsortium.org/data/clothesTypes.json#corset",
|
||||||
|
"rdfs:label": [
|
||||||
|
{
|
||||||
|
"@value": "Corset",
|
||||||
|
"@language": "en"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Corset",
|
||||||
|
"@language": "ar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Corset",
|
||||||
|
"@language": "ku"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Corset",
|
||||||
|
"@language": "es"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Corse",
|
||||||
|
"@language": "it"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Korsett",
|
||||||
|
"@language": "de"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Corset",
|
||||||
|
"@language": "sw"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Espartilho",
|
||||||
|
"@language": "pt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Corset",
|
||||||
|
"@language": "oc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Корсет",
|
||||||
|
"@language": "ru"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Corset",
|
||||||
|
"@language": "cy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "コルセット",
|
||||||
|
"@language": "ja"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Sraith",
|
||||||
|
"@language": "ga"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "कोर्सेट",
|
||||||
|
"@language": "hi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Cset",
|
||||||
|
"@language": "zh"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Corset",
|
||||||
|
"@language": "fr"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@value": "Corset",
|
||||||
|
"@language": "ca"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/toolTypes.rdf#corset",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,16 @@
|
||||||
"@context": {
|
"@context": {
|
||||||
"rdfs": "http://www.w3.org/2000/01/rdf-schema#",
|
"rdfs": "http://www.w3.org/2000/01/rdf-schema#",
|
||||||
"dfc-b": "http://static.datafoodconsortium.org/ontologies/DFC_BusinessOntology.owl#",
|
"dfc-b": "http://static.datafoodconsortium.org/ontologies/DFC_BusinessOntology.owl#",
|
||||||
"dfc-p": "http://static.datafoodconsortium.org/ontologies/DFC_ProductOntology.owl#",
|
"dfc-p": "http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#",
|
||||||
"dfc-t": "http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#",
|
"dfc-t": "http://static.datafoodconsortium.org/ontologies/DFC_TechnicalOntology.owl#",
|
||||||
"dfc-u": "http://static.datafoodconsortium.org/data/units.rdf#",
|
"dfc-u": "http://static.datafoodconsortium.org/data/units.json#",
|
||||||
"dfc-p:specialize": {
|
"dfc-p:specialize": {
|
||||||
"@type": "@id"
|
"@type": "@id"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@graph": [
|
"@graph": [
|
||||||
{
|
{
|
||||||
"@id": "https://medical/data/medicalTypes.rdf#gas-mask",
|
"@id": "http://static.datafoodconsortium.org/data/medicalTypes.json#gas-mask",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Gas Mask",
|
"@value": "Gas Mask",
|
||||||
|
|
@ -82,11 +82,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://medical/data/medicalTypes.rdf#body-protection",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/medicalTypes.json#body-protection",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://medical/data/medicalTypes.rdf#gas-mask-filter",
|
"@id": "http://static.datafoodconsortium.org/data/medicalTypes.json#gas-mask-filter",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Gas Mask Filter",
|
"@value": "Gas Mask Filter",
|
||||||
|
|
@ -157,11 +157,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://medical/data/medicalTypes.rdf#body-protection",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/medicalTypes.json#body-protection",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://medical/data/medicalTypes.rdf#bandages",
|
"@id": "http://static.datafoodconsortium.org/data/medicalTypes.json#bandages",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Bandages",
|
"@value": "Bandages",
|
||||||
|
|
@ -232,11 +232,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://medical/data/medicalTypes.rdf#bandages",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/medicalTypes.json#bandages",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://medical/data/medicalTypes.rdf#gauze-wrap",
|
"@id": "http://static.datafoodconsortium.org/data/medicalTypes.json#gauze-wrap",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Gauze Wrap",
|
"@value": "Gauze Wrap",
|
||||||
|
|
@ -307,11 +307,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://medical/data/medicalTypes.rdf#bandages",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/medicalTypes.json#bandages",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://medical/data/medicalTypes.rdf#gauze-pad",
|
"@id": "http://static.datafoodconsortium.org/data/medicalTypes.json#gauze-pad",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Gauze Pad",
|
"@value": "Gauze Pad",
|
||||||
|
|
@ -382,11 +382,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://medical/data/medicalTypes.rdf#bandages",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/medicalTypes.json#bandages",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://medical/data/medicalTypes.rdf#nonstick-pad",
|
"@id": "http://static.datafoodconsortium.org/data/medicalTypes.json#nonstick-pad",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Nonstick Pad",
|
"@value": "Nonstick Pad",
|
||||||
|
|
@ -457,11 +457,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://medical/data/medicalTypes.rdf#bandages",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/medicalTypes.json#bandages",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://medical/data/medicalTypes.rdf#triangle-bandage",
|
"@id": "http://static.datafoodconsortium.org/data/medicalTypes.json#triangle-bandage",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Triangle Bandage",
|
"@value": "Triangle Bandage",
|
||||||
|
|
@ -532,11 +532,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://medical/data/medicalTypes.rdf#bandages",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/medicalTypes.json#bandages",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://medical/data/medicalTypes.rdf#wound-closure-strip",
|
"@id": "http://static.datafoodconsortium.org/data/medicalTypes.json#wound-closure-strip",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Wound Closure Strip",
|
"@value": "Wound Closure Strip",
|
||||||
|
|
@ -607,11 +607,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://medical/data/medicalTypes.rdf#bandages",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/medicalTypes.json#bandages",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://medical/data/medicalTypes.rdf#paper-tape",
|
"@id": "http://static.datafoodconsortium.org/data/medicalTypes.json#paper-tape",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Paper Tape",
|
"@value": "Paper Tape",
|
||||||
|
|
@ -682,11 +682,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://medical/data/medicalTypes.rdf#tape",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/medicalTypes.json#tape",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://medical/data/medicalTypes.rdf#plastic-tape",
|
"@id": "http://static.datafoodconsortium.org/data/medicalTypes.json#plastic-tape",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Plastic Tape",
|
"@value": "Plastic Tape",
|
||||||
|
|
@ -757,11 +757,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://medical/data/medicalTypes.rdf#tape",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/medicalTypes.json#tape",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://medical/data/medicalTypes.rdf#examination-gloves",
|
"@id": "http://static.datafoodconsortium.org/data/medicalTypes.json#examination-gloves",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Examination Gloves",
|
"@value": "Examination Gloves",
|
||||||
|
|
@ -832,11 +832,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://medical/data/medicalTypes.rdf#gloves",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/medicalTypes.json#gloves",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://medical/data/medicalTypes.rdf#stick-on-bandage",
|
"@id": "http://static.datafoodconsortium.org/data/medicalTypes.json#stick-on-bandage",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Stick-on Bandage",
|
"@value": "Stick-on Bandage",
|
||||||
|
|
@ -907,11 +907,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://medical/data/medicalTypes.rdf#bandages",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/medicalTypes.json#bandages",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://medical/data/medicalTypes.rdf#saline-solution",
|
"@id": "http://static.datafoodconsortium.org/data/medicalTypes.json#saline-solution",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Saline Solution",
|
"@value": "Saline Solution",
|
||||||
|
|
@ -982,11 +982,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://medical/data/medicalTypes.rdf#fluid",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/medicalTypes.json#fluid",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://medical/data/medicalTypes.rdf#antibiotic-ointment",
|
"@id": "http://static.datafoodconsortium.org/data/medicalTypes.json#antibiotic-ointment",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Antibiotic Ointment",
|
"@value": "Antibiotic Ointment",
|
||||||
|
|
@ -1057,11 +1057,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://medical/data/medicalTypes.rdf#medicine",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/medicalTypes.json#medicine",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://medical/data/medicalTypes.rdf#anti-hemorrhagic-agent",
|
"@id": "http://static.datafoodconsortium.org/data/medicalTypes.json#anti-hemorrhagic-agent",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Anti-hemorrhagic Agent",
|
"@value": "Anti-hemorrhagic Agent",
|
||||||
|
|
@ -1132,11 +1132,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://medical/data/medicalTypes.rdf#fluids",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/medicalTypes.json#fluids",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://medical/data/medicalTypes.rdf#sunblock",
|
"@id": "http://static.datafoodconsortium.org/data/medicalTypes.json#sunblock",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Sunblock",
|
"@value": "Sunblock",
|
||||||
|
|
@ -1207,11 +1207,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://medical/data/medicalTypes.rdf#body-protection",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/medicalTypes.json#body-protection",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://medical/data/medicalTypes.rdf#bandage-shears",
|
"@id": "http://static.datafoodconsortium.org/data/medicalTypes.json#bandage-shears",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Bandage Shears",
|
"@value": "Bandage Shears",
|
||||||
|
|
@ -1282,11 +1282,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://medical/data/medicalTypes.rdf#bandages",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/medicalTypes.json#bandages",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://medical/data/medicalTypes.rdf#tweezers",
|
"@id": "http://static.datafoodconsortium.org/data/medicalTypes.json#tweezers",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Tweezers",
|
"@value": "Tweezers",
|
||||||
|
|
@ -1357,11 +1357,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://medical/data/medicalTypes.rdf#medical-tools",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/medicalTypes.json#medical-tools",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://medical/data/medicalTypes.rdf#protein-bar",
|
"@id": "http://static.datafoodconsortium.org/data/medicalTypes.json#protein-bar",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Protein Bar",
|
"@value": "Protein Bar",
|
||||||
|
|
@ -1432,11 +1432,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://medical/data/medicalTypes.rdf#energy",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/medicalTypes.json#energy",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://medical/data/medicalTypes.rdf#bandanna",
|
"@id": "http://static.datafoodconsortium.org/data/medicalTypes.json#bandanna",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Bandanna",
|
"@value": "Bandanna",
|
||||||
|
|
@ -1507,11 +1507,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://medical/data/medicalTypes.rdf#body-protection",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/medicalTypes.json#body-protection",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://medical/data/medicalTypes.rdf#water-bottle",
|
"@id": "http://static.datafoodconsortium.org/data/medicalTypes.json#water-bottle",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Water Bottle",
|
"@value": "Water Bottle",
|
||||||
|
|
@ -1582,11 +1582,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://medical/data/medicalTypes.rdf#fluids",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/medicalTypes.json#fluids",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://medical/data/medicalTypes.rdf#ice-pack",
|
"@id": "http://static.datafoodconsortium.org/data/medicalTypes.json#ice-pack",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Ice Pack",
|
"@value": "Ice Pack",
|
||||||
|
|
@ -1657,11 +1657,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://medical/data/medicalTypes.rdf#anti-inflamatory",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/medicalTypes.json#anti-inflamatory",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://medical/data/medicalTypes.rdf#messenger-bag",
|
"@id": "http://static.datafoodconsortium.org/data/medicalTypes.json#messenger-bag",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Messenger Bag",
|
"@value": "Messenger Bag",
|
||||||
|
|
@ -1732,11 +1732,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://medical/data/medicalTypes.rdf#bag",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/medicalTypes.json#bag",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://medical/data/medicalTypes.rdf#glucose-tablets",
|
"@id": "http://static.datafoodconsortium.org/data/medicalTypes.json#glucose-tablets",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Glucose tablets",
|
"@value": "Glucose tablets",
|
||||||
|
|
@ -1807,11 +1807,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://medical/data/medicalTypes.rdf#energy",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/medicalTypes.json#energy",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://medical/data/medicalTypes.rdf#liquid-antacid-water-mixture",
|
"@id": "http://static.datafoodconsortium.org/data/medicalTypes.json#liquid-antacid-water-mixture",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Liquid Antacid Water Mixture",
|
"@value": "Liquid Antacid Water Mixture",
|
||||||
|
|
@ -1882,11 +1882,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://medical/data/medicalTypes.rdf#fluids",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/medicalTypes.json#fluids",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://medical/data/medicalTypes.rdf#re-hydration-mixture",
|
"@id": "http://static.datafoodconsortium.org/data/medicalTypes.json#re-hydration-mixture",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Re-hydration Mixture",
|
"@value": "Re-hydration Mixture",
|
||||||
|
|
@ -1957,11 +1957,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://medical/data/medicalTypes.rdf#fluids",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/medicalTypes.json#fluids",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://medical/data/medicalTypes.rdf#ear-plugs",
|
"@id": "http://static.datafoodconsortium.org/data/medicalTypes.json#ear-plugs",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "Ear Plugs",
|
"@value": "Ear Plugs",
|
||||||
|
|
@ -2032,11 +2032,11 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://medical/data/medicalTypes.rdf#body-protection",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/medicalTypes.json#body-protection",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@id": "https://medical/data/medicalTypes.rdf#cpr-mask",
|
"@id": "http://static.datafoodconsortium.org/data/medicalTypes.json#cpr-mask",
|
||||||
"rdfs:label": [
|
"rdfs:label": [
|
||||||
{
|
{
|
||||||
"@value": "CPR Mask",
|
"@value": "CPR Mask",
|
||||||
|
|
@ -2107,7 +2107,7 @@
|
||||||
"@language": "ca"
|
"@language": "ca"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dfc-p:specialize": "https://medical/data/medicalTypes.rdf#mask",
|
"dfc-p:specialize": "http://static.datafoodconsortium.org/data/medicalTypes.json#mask",
|
||||||
"@type": "dfc-p:ProductType"
|
"@type": "dfc-p:ProductType"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:foaf="http://xmlns.com/foaf/0.1/"
|
||||||
|
xmlns:owl="http://www.w3.org/2002/07/owl#">
|
||||||
|
|
||||||
|
<foaf:Person rdf:about="http://static.datafoodconsortium.org/data/publication.rdf#simonL">
|
||||||
|
<foaf:familyName xml:lang="fr">Louvet</foaf:familyName>
|
||||||
|
<foaf:firstName xml:lang="fr">Simon</foaf:firstName>
|
||||||
|
<owl:sameAs rdf:resource="https://orcid.org/0000-0002-3528-6577"/>
|
||||||
|
</foaf:Person>
|
||||||
|
<foaf:Person rdf:about="http://static.datafoodconsortium.org/data/publication.rdf#rachelA">
|
||||||
|
<foaf:familyName xml:lang="fr">Arnould</foaf:familyName>
|
||||||
|
<foaf:firstName xml:lang="fr">Rachel</foaf:firstName>
|
||||||
|
</foaf:Person>
|
||||||
|
<foaf:Person rdf:about="http://static.datafoodconsortium.org/data/publication.rdf#bernardC">
|
||||||
|
<foaf:familyName xml:lang="fr">Chabot</foaf:familyName>
|
||||||
|
<foaf:firstName xml:lang="fr">Bernard</foaf:firstName>
|
||||||
|
</foaf:Person>
|
||||||
|
<foaf:Organization rdf:about="http://static.datafoodconsortium.org/data/publication.rdf#dataFoodConsortium">
|
||||||
|
<foaf:homepage rdf:resource="http://static.datafoodconsortium.org/"/>
|
||||||
|
<foaf:name xml:lang="fr">Data Food Consortium</foaf:name>
|
||||||
|
</foaf:Organization>
|
||||||
|
</rdf:RDF>
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"@context":{
|
"@context":{
|
||||||
"dfc-p": "http://static.datafoodconsortium.org/ontologies/dfc_ProductGlossary.owl#",
|
"dfc-p": "http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#",
|
||||||
"dfc-u":"http://static.datafoodconsortium.org/data/units.rdf#"
|
"dfc-u":"http://static.datafoodconsortium.org/data/units.rdf#"
|
||||||
},
|
},
|
||||||
"@graph":[
|
"@graph":[
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
|
||||||
|
xmlns:dfc-u="http://static.datafoodconsortium.org/data/units.rdf#"
|
||||||
|
xmlns:dfc-b="http://static.datafoodconsortium.org/ontologies/DFC_ProductGlossary.owl#">
|
||||||
|
|
||||||
|
<dfc-b:Unit rdf:about="http://static.datafoodconsortium.org/data/unit.rdf#kg">
|
||||||
|
<rdfs:label rdf:datatype="http://www.w3.org/2001/XMLSchema#string">kilogramme</rdfs:label>
|
||||||
|
</dfc-b:Unit>
|
||||||
|
|
||||||
|
<dfc-b:Unit rdf:about="http://static.datafoodconsortium.org/data/unit.rdf#u">
|
||||||
|
<rdfs:label rdf:datatype="http://www.w3.org/2001/XMLSchema#string">unité</rdfs:label>
|
||||||
|
</dfc-b:Unit>
|
||||||
|
|
||||||
|
<dfc-b:Unit rdf:about="http://static.datafoodconsortium.org/data/unit.rdf#g">
|
||||||
|
<rdfs:label rdf:datatype="http://www.w3.org/2001/XMLSchema#string">gramme</rdfs:label>
|
||||||
|
</dfc-b:Unit>
|
||||||
|
|
||||||
|
<dfc-b:Unit rdf:about="http://static.datafoodconsortium.org/data/unit.rdf#l">
|
||||||
|
<rdfs:label rdf:datatype="http://www.w3.org/2001/XMLSchema#string">litre</rdfs:label>
|
||||||
|
</dfc-b:Unit>
|
||||||
|
|
||||||
|
</rdf:RDF>
|
||||||
64
outbox.py
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Timeline"
|
__module_group__ = "Timeline"
|
||||||
|
|
||||||
|
|
@ -34,12 +34,14 @@ from blocking import outboxUndoBlock
|
||||||
from blocking import outboxMute
|
from blocking import outboxMute
|
||||||
from blocking import outboxUndoMute
|
from blocking import outboxUndoMute
|
||||||
from media import replaceYouTube
|
from media import replaceYouTube
|
||||||
|
from media import replaceTwitter
|
||||||
from media import getMediaPath
|
from media import getMediaPath
|
||||||
from media import createMediaDirs
|
from media import createMediaDirs
|
||||||
from inbox import inboxUpdateIndex
|
from inbox import inboxUpdateIndex
|
||||||
from announce import outboxAnnounce
|
from announce import outboxAnnounce
|
||||||
from announce import outboxUndoAnnounce
|
from announce import outboxUndoAnnounce
|
||||||
from follow import outboxUndoFollow
|
from follow import outboxUndoFollow
|
||||||
|
from follow import followerApprovalActive
|
||||||
from skills import outboxSkills
|
from skills import outboxSkills
|
||||||
from availability import outboxAvailability
|
from availability import outboxAvailability
|
||||||
from like import outboxLike
|
from like import outboxLike
|
||||||
|
|
@ -49,6 +51,7 @@ from bookmarks import outboxUndoBookmark
|
||||||
from delete import outboxDelete
|
from delete import outboxDelete
|
||||||
from shares import outboxShareUpload
|
from shares import outboxShareUpload
|
||||||
from shares import outboxUndoShareUpload
|
from shares import outboxUndoShareUpload
|
||||||
|
from webapp_post import individualPostAsHtml
|
||||||
|
|
||||||
|
|
||||||
def _outboxPersonReceiveUpdate(recentPostsCache: {},
|
def _outboxPersonReceiveUpdate(recentPostsCache: {},
|
||||||
|
|
@ -189,12 +192,17 @@ def postMessageToOutbox(session, translate: {},
|
||||||
personCache: {}, allowDeletion: bool,
|
personCache: {}, allowDeletion: bool,
|
||||||
proxyType: str, version: str, debug: bool,
|
proxyType: str, version: str, debug: bool,
|
||||||
YTReplacementDomain: str,
|
YTReplacementDomain: str,
|
||||||
|
twitterReplacementDomain: str,
|
||||||
showPublishedDateOnly: bool,
|
showPublishedDateOnly: bool,
|
||||||
allowLocalNetworkAccess: bool,
|
allowLocalNetworkAccess: bool,
|
||||||
city: str, systemLanguage: str,
|
city: str, systemLanguage: str,
|
||||||
sharedItemsFederatedDomains: [],
|
sharedItemsFederatedDomains: [],
|
||||||
sharedItemFederationTokens: {},
|
sharedItemFederationTokens: {},
|
||||||
lowBandwidth: bool) -> bool:
|
lowBandwidth: bool,
|
||||||
|
signingPrivateKeyPem: str,
|
||||||
|
peertubeInstances: str, theme: str,
|
||||||
|
maxLikeCount: int,
|
||||||
|
maxRecentPosts: int) -> bool:
|
||||||
"""post is received by the outbox
|
"""post is received by the outbox
|
||||||
Client to server message post
|
Client to server message post
|
||||||
https://www.w3.org/TR/activitypub/#client-to-server-outbox-delivery
|
https://www.w3.org/TR/activitypub/#client-to-server-outbox-delivery
|
||||||
|
|
@ -281,6 +289,9 @@ def postMessageToOutbox(session, translate: {},
|
||||||
return False
|
return False
|
||||||
# replace youtube, so that google gets less tracking data
|
# replace youtube, so that google gets less tracking data
|
||||||
replaceYouTube(messageJson, YTReplacementDomain, systemLanguage)
|
replaceYouTube(messageJson, YTReplacementDomain, systemLanguage)
|
||||||
|
# replace twitter, so that twitter posts can be shown without
|
||||||
|
# having a twitter account
|
||||||
|
replaceTwitter(messageJson, twitterReplacementDomain, systemLanguage)
|
||||||
# https://www.w3.org/TR/activitypub/#create-activity-outbox
|
# https://www.w3.org/TR/activitypub/#create-activity-outbox
|
||||||
messageJson['object']['attributedTo'] = messageJson['actor']
|
messageJson['object']['attributedTo'] = messageJson['actor']
|
||||||
if messageJson['object'].get('attachment'):
|
if messageJson['object'].get('attachment'):
|
||||||
|
|
@ -318,7 +329,7 @@ def postMessageToOutbox(session, translate: {},
|
||||||
# generate a path for the uploaded image
|
# generate a path for the uploaded image
|
||||||
mPath = getMediaPath()
|
mPath = getMediaPath()
|
||||||
mediaPath = mPath + '/' + \
|
mediaPath = mPath + '/' + \
|
||||||
createPassword(32) + '.' + fileExtension
|
createPassword(16).lower() + '.' + fileExtension
|
||||||
createMediaDirs(baseDir, mPath)
|
createMediaDirs(baseDir, mPath)
|
||||||
mediaFilename = baseDir + '/' + mediaPath
|
mediaFilename = baseDir + '/' + mediaPath
|
||||||
# move the uploaded image to its new path
|
# move the uploaded image to its new path
|
||||||
|
|
@ -384,7 +395,10 @@ def postMessageToOutbox(session, translate: {},
|
||||||
baseDir + '/accounts/' + \
|
baseDir + '/accounts/' + \
|
||||||
postToNickname + '@' + domain + '/.citations.txt'
|
postToNickname + '@' + domain + '/.citations.txt'
|
||||||
if os.path.isfile(citationsFilename):
|
if os.path.isfile(citationsFilename):
|
||||||
|
try:
|
||||||
os.remove(citationsFilename)
|
os.remove(citationsFilename)
|
||||||
|
except BaseException:
|
||||||
|
pass
|
||||||
|
|
||||||
# The following activity types get added to the index files
|
# The following activity types get added to the index files
|
||||||
indexedActivities = (
|
indexedActivities = (
|
||||||
|
|
@ -404,10 +418,13 @@ def postMessageToOutbox(session, translate: {},
|
||||||
if isImageMedia(session, baseDir, httpPrefix,
|
if isImageMedia(session, baseDir, httpPrefix,
|
||||||
postToNickname, domain,
|
postToNickname, domain,
|
||||||
messageJson,
|
messageJson,
|
||||||
translate, YTReplacementDomain,
|
translate,
|
||||||
|
YTReplacementDomain,
|
||||||
|
twitterReplacementDomain,
|
||||||
allowLocalNetworkAccess,
|
allowLocalNetworkAccess,
|
||||||
recentPostsCache, debug, systemLanguage,
|
recentPostsCache, debug, systemLanguage,
|
||||||
domainFull, personCache):
|
domainFull, personCache,
|
||||||
|
signingPrivateKeyPem):
|
||||||
inboxUpdateIndex('tlmedia', baseDir,
|
inboxUpdateIndex('tlmedia', baseDir,
|
||||||
postToNickname + '@' + domain,
|
postToNickname + '@' + domain,
|
||||||
savedFilename, debug)
|
savedFilename, debug)
|
||||||
|
|
@ -423,6 +440,37 @@ def postMessageToOutbox(session, translate: {},
|
||||||
inboxUpdateIndex(boxNameIndex, baseDir,
|
inboxUpdateIndex(boxNameIndex, baseDir,
|
||||||
postToNickname + '@' + domain,
|
postToNickname + '@' + domain,
|
||||||
savedFilename, debug)
|
savedFilename, debug)
|
||||||
|
|
||||||
|
# regenerate the html
|
||||||
|
useCacheOnly = False
|
||||||
|
pageNumber = 1
|
||||||
|
showIndividualPostIcons = True
|
||||||
|
manuallyApproveFollowers = \
|
||||||
|
followerApprovalActive(baseDir, postToNickname, domain)
|
||||||
|
individualPostAsHtml(signingPrivateKeyPem,
|
||||||
|
False, recentPostsCache,
|
||||||
|
maxRecentPosts,
|
||||||
|
translate, pageNumber,
|
||||||
|
baseDir, session,
|
||||||
|
cachedWebfingers,
|
||||||
|
personCache,
|
||||||
|
postToNickname, domain, port,
|
||||||
|
messageJson, None, True,
|
||||||
|
allowDeletion,
|
||||||
|
httpPrefix, __version__,
|
||||||
|
boxNameIndex,
|
||||||
|
YTReplacementDomain,
|
||||||
|
twitterReplacementDomain,
|
||||||
|
showPublishedDateOnly,
|
||||||
|
peertubeInstances,
|
||||||
|
allowLocalNetworkAccess,
|
||||||
|
theme, systemLanguage,
|
||||||
|
maxLikeCount,
|
||||||
|
boxNameIndex != 'dm',
|
||||||
|
showIndividualPostIcons,
|
||||||
|
manuallyApproveFollowers,
|
||||||
|
False, True, useCacheOnly)
|
||||||
|
|
||||||
if outboxAnnounce(recentPostsCache,
|
if outboxAnnounce(recentPostsCache,
|
||||||
baseDir, messageJson, debug):
|
baseDir, messageJson, debug):
|
||||||
if debug:
|
if debug:
|
||||||
|
|
@ -468,7 +516,8 @@ def postMessageToOutbox(session, translate: {},
|
||||||
messageJson, debug,
|
messageJson, debug,
|
||||||
version,
|
version,
|
||||||
sharedItemsFederatedDomains,
|
sharedItemsFederatedDomains,
|
||||||
sharedItemFederationTokens)
|
sharedItemFederationTokens,
|
||||||
|
signingPrivateKeyPem)
|
||||||
followersThreads.append(followersThread)
|
followersThreads.append(followersThread)
|
||||||
|
|
||||||
if debug:
|
if debug:
|
||||||
|
|
@ -592,5 +641,6 @@ def postMessageToOutbox(session, translate: {},
|
||||||
messageJson, debug,
|
messageJson, debug,
|
||||||
version,
|
version,
|
||||||
sharedItemsFederatedDomains,
|
sharedItemsFederatedDomains,
|
||||||
sharedItemFederationTokens)
|
sharedItemFederationTokens,
|
||||||
|
signingPrivateKeyPem)
|
||||||
return True
|
return True
|
||||||
|
|
|
||||||
190
person.py
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "ActivityPub"
|
__module_group__ = "ActivityPub"
|
||||||
|
|
||||||
|
|
@ -37,6 +37,7 @@ from roles import setRole
|
||||||
from roles import setRolesFromList
|
from roles import setRolesFromList
|
||||||
from roles import getActorRolesList
|
from roles import getActorRolesList
|
||||||
from media import processMetaData
|
from media import processMetaData
|
||||||
|
from utils import replaceUsersWithAt
|
||||||
from utils import removeLineEndings
|
from utils import removeLineEndings
|
||||||
from utils import removeDomainPort
|
from utils import removeDomainPort
|
||||||
from utils import getStatusNumber
|
from utils import getStatusNumber
|
||||||
|
|
@ -55,6 +56,7 @@ from utils import acctDir
|
||||||
from utils import getUserPaths
|
from utils import getUserPaths
|
||||||
from utils import getGroupPaths
|
from utils import getGroupPaths
|
||||||
from utils import localActorUrl
|
from utils import localActorUrl
|
||||||
|
from utils import dangerousSVG
|
||||||
from session import createSession
|
from session import createSession
|
||||||
from session import getJson
|
from session import getJson
|
||||||
from webfinger import webfingerHandle
|
from webfinger import webfingerHandle
|
||||||
|
|
@ -185,6 +187,117 @@ def randomizeActorImages(personJson: {}) -> None:
|
||||||
'/image' + randStr + '.' + existingExtension
|
'/image' + randStr + '.' + existingExtension
|
||||||
|
|
||||||
|
|
||||||
|
def getActorUpdateJson(actorJson: {}) -> {}:
|
||||||
|
"""Returns the json for an Person Update
|
||||||
|
"""
|
||||||
|
pubNumber, _ = getStatusNumber()
|
||||||
|
manuallyApprovesFollowers = actorJson['manuallyApprovesFollowers']
|
||||||
|
return {
|
||||||
|
'@context': [
|
||||||
|
"https://www.w3.org/ns/activitystreams",
|
||||||
|
"https://w3id.org/security/v1",
|
||||||
|
{
|
||||||
|
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
|
||||||
|
"toot": "http://joinmastodon.org/ns#",
|
||||||
|
"featured":
|
||||||
|
{
|
||||||
|
"@id": "toot:featured",
|
||||||
|
"@type": "@id"
|
||||||
|
},
|
||||||
|
"featuredTags":
|
||||||
|
{
|
||||||
|
"@id": "toot:featuredTags",
|
||||||
|
"@type": "@id"
|
||||||
|
},
|
||||||
|
"alsoKnownAs":
|
||||||
|
{
|
||||||
|
"@id": "as:alsoKnownAs",
|
||||||
|
"@type": "@id"
|
||||||
|
},
|
||||||
|
"movedTo":
|
||||||
|
{
|
||||||
|
"@id": "as:movedTo",
|
||||||
|
"@type": "@id"
|
||||||
|
},
|
||||||
|
"schema": "http://schema.org#",
|
||||||
|
"PropertyValue": "schema:PropertyValue",
|
||||||
|
"value": "schema:value",
|
||||||
|
"IdentityProof": "toot:IdentityProof",
|
||||||
|
"discoverable": "toot:discoverable",
|
||||||
|
"Device": "toot:Device",
|
||||||
|
"Ed25519Signature": "toot:Ed25519Signature",
|
||||||
|
"Ed25519Key": "toot:Ed25519Key",
|
||||||
|
"Curve25519Key": "toot:Curve25519Key",
|
||||||
|
"EncryptedMessage": "toot:EncryptedMessage",
|
||||||
|
"publicKeyBase64": "toot:publicKeyBase64",
|
||||||
|
"deviceId": "toot:deviceId",
|
||||||
|
"claim":
|
||||||
|
{
|
||||||
|
"@type": "@id",
|
||||||
|
"@id": "toot:claim"
|
||||||
|
},
|
||||||
|
"fingerprintKey":
|
||||||
|
{
|
||||||
|
"@type": "@id",
|
||||||
|
"@id": "toot:fingerprintKey"
|
||||||
|
},
|
||||||
|
"identityKey":
|
||||||
|
{
|
||||||
|
"@type": "@id",
|
||||||
|
"@id": "toot:identityKey"
|
||||||
|
},
|
||||||
|
"devices":
|
||||||
|
{
|
||||||
|
"@type": "@id",
|
||||||
|
"@id": "toot:devices"
|
||||||
|
},
|
||||||
|
"messageFranking": "toot:messageFranking",
|
||||||
|
"messageType": "toot:messageType",
|
||||||
|
"cipherText": "toot:cipherText",
|
||||||
|
"suspended": "toot:suspended",
|
||||||
|
"focalPoint":
|
||||||
|
{
|
||||||
|
"@container": "@list",
|
||||||
|
"@id": "toot:focalPoint"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'id': actorJson['id'] + '#updates/' + pubNumber,
|
||||||
|
'type': 'Update',
|
||||||
|
'actor': actorJson['id'],
|
||||||
|
'to': ['https://www.w3.org/ns/activitystreams#Public'],
|
||||||
|
'cc': [actorJson['id'] + '/followers'],
|
||||||
|
'object': {
|
||||||
|
'id': actorJson['id'],
|
||||||
|
'type': actorJson['type'],
|
||||||
|
'icon': {
|
||||||
|
'type': 'Image',
|
||||||
|
'url': actorJson['icon']['url']
|
||||||
|
},
|
||||||
|
'image': {
|
||||||
|
'type': 'Image',
|
||||||
|
'url': actorJson['image']['url']
|
||||||
|
},
|
||||||
|
'attachment': actorJson['attachment'],
|
||||||
|
'following': actorJson['id'] + '/following',
|
||||||
|
'followers': actorJson['id'] + '/followers',
|
||||||
|
'inbox': actorJson['id'] + '/inbox',
|
||||||
|
'outbox': actorJson['id'] + '/outbox',
|
||||||
|
'featured': actorJson['id'] + '/collections/featured',
|
||||||
|
'featuredTags': actorJson['id'] + '/collections/tags',
|
||||||
|
'preferredUsername': actorJson['preferredUsername'],
|
||||||
|
'name': actorJson['name'],
|
||||||
|
'summary': actorJson['summary'],
|
||||||
|
'url': actorJson['url'],
|
||||||
|
'manuallyApprovesFollowers': manuallyApprovesFollowers,
|
||||||
|
'discoverable': actorJson['discoverable'],
|
||||||
|
'published': actorJson['published'],
|
||||||
|
'devices': actorJson['devices'],
|
||||||
|
"publicKey": actorJson['publicKey'],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def getDefaultPersonContext() -> str:
|
def getDefaultPersonContext() -> str:
|
||||||
"""Gets the default actor context
|
"""Gets the default actor context
|
||||||
"""
|
"""
|
||||||
|
|
@ -702,7 +815,7 @@ def personUpgradeActor(baseDir: str, personJson: {},
|
||||||
# update domain/@nickname in actors cache
|
# update domain/@nickname in actors cache
|
||||||
actorCacheFilename = \
|
actorCacheFilename = \
|
||||||
baseDir + '/accounts/cache/actors/' + \
|
baseDir + '/accounts/cache/actors/' + \
|
||||||
personJson['id'].replace('/users/', '/@').replace('/', '#') + \
|
replaceUsersWithAt(personJson['id']).replace('/', '#') + \
|
||||||
'.json'
|
'.json'
|
||||||
if os.path.isfile(actorCacheFilename):
|
if os.path.isfile(actorCacheFilename):
|
||||||
saveJson(personJson, actorCacheFilename)
|
saveJson(personJson, actorCacheFilename)
|
||||||
|
|
@ -717,7 +830,7 @@ def personLookup(domain: str, path: str, baseDir: str) -> {}:
|
||||||
isSharedInbox = False
|
isSharedInbox = False
|
||||||
if path == '/inbox' or path == '/users/inbox' or path == '/sharedInbox':
|
if path == '/inbox' or path == '/users/inbox' or path == '/sharedInbox':
|
||||||
# shared inbox actor on @domain@domain
|
# shared inbox actor on @domain@domain
|
||||||
path = '/users/' + domain
|
path = '/users/inbox'
|
||||||
isSharedInbox = True
|
isSharedInbox = True
|
||||||
else:
|
else:
|
||||||
notPersonLookup = ('/inbox', '/outbox', '/outboxarchive',
|
notPersonLookup = ('/inbox', '/outbox', '/outboxarchive',
|
||||||
|
|
@ -741,6 +854,7 @@ def personLookup(domain: str, path: str, baseDir: str) -> {}:
|
||||||
if not os.path.isfile(filename):
|
if not os.path.isfile(filename):
|
||||||
return None
|
return None
|
||||||
personJson = loadJson(filename)
|
personJson = loadJson(filename)
|
||||||
|
if not isSharedInbox:
|
||||||
personUpgradeActor(baseDir, personJson, handle, filename)
|
personUpgradeActor(baseDir, personJson, handle, filename)
|
||||||
# if not personJson:
|
# if not personJson:
|
||||||
# personJson={"user": "unknown"}
|
# personJson={"user": "unknown"}
|
||||||
|
|
@ -917,10 +1031,16 @@ def suspendAccount(baseDir: str, nickname: str, domain: str) -> None:
|
||||||
|
|
||||||
saltFilename = acctDir(baseDir, nickname, domain) + '/.salt'
|
saltFilename = acctDir(baseDir, nickname, domain) + '/.salt'
|
||||||
if os.path.isfile(saltFilename):
|
if os.path.isfile(saltFilename):
|
||||||
|
try:
|
||||||
os.remove(saltFilename)
|
os.remove(saltFilename)
|
||||||
|
except BaseException:
|
||||||
|
pass
|
||||||
tokenFilename = acctDir(baseDir, nickname, domain) + '/.token'
|
tokenFilename = acctDir(baseDir, nickname, domain) + '/.token'
|
||||||
if os.path.isfile(tokenFilename):
|
if os.path.isfile(tokenFilename):
|
||||||
|
try:
|
||||||
os.remove(tokenFilename)
|
os.remove(tokenFilename)
|
||||||
|
except BaseException:
|
||||||
|
pass
|
||||||
|
|
||||||
suspendedFilename = baseDir + '/accounts/suspended.txt'
|
suspendedFilename = baseDir + '/accounts/suspended.txt'
|
||||||
if os.path.isfile(suspendedFilename):
|
if os.path.isfile(suspendedFilename):
|
||||||
|
|
@ -1023,17 +1143,32 @@ def removeAccount(baseDir: str, nickname: str,
|
||||||
if os.path.isdir(baseDir + '/accounts/' + handle):
|
if os.path.isdir(baseDir + '/accounts/' + handle):
|
||||||
shutil.rmtree(baseDir + '/accounts/' + handle)
|
shutil.rmtree(baseDir + '/accounts/' + handle)
|
||||||
if os.path.isfile(baseDir + '/accounts/' + handle + '.json'):
|
if os.path.isfile(baseDir + '/accounts/' + handle + '.json'):
|
||||||
|
try:
|
||||||
os.remove(baseDir + '/accounts/' + handle + '.json')
|
os.remove(baseDir + '/accounts/' + handle + '.json')
|
||||||
|
except BaseException:
|
||||||
|
pass
|
||||||
if os.path.isfile(baseDir + '/wfendpoints/' + handle + '.json'):
|
if os.path.isfile(baseDir + '/wfendpoints/' + handle + '.json'):
|
||||||
|
try:
|
||||||
os.remove(baseDir + '/wfendpoints/' + handle + '.json')
|
os.remove(baseDir + '/wfendpoints/' + handle + '.json')
|
||||||
|
except BaseException:
|
||||||
|
pass
|
||||||
if os.path.isfile(baseDir + '/keys/private/' + handle + '.key'):
|
if os.path.isfile(baseDir + '/keys/private/' + handle + '.key'):
|
||||||
|
try:
|
||||||
os.remove(baseDir + '/keys/private/' + handle + '.key')
|
os.remove(baseDir + '/keys/private/' + handle + '.key')
|
||||||
|
except BaseException:
|
||||||
|
pass
|
||||||
if os.path.isfile(baseDir + '/keys/public/' + handle + '.pem'):
|
if os.path.isfile(baseDir + '/keys/public/' + handle + '.pem'):
|
||||||
|
try:
|
||||||
os.remove(baseDir + '/keys/public/' + handle + '.pem')
|
os.remove(baseDir + '/keys/public/' + handle + '.pem')
|
||||||
|
except BaseException:
|
||||||
|
pass
|
||||||
if os.path.isdir(baseDir + '/sharefiles/' + nickname):
|
if os.path.isdir(baseDir + '/sharefiles/' + nickname):
|
||||||
shutil.rmtree(baseDir + '/sharefiles/' + nickname)
|
shutil.rmtree(baseDir + '/sharefiles/' + nickname)
|
||||||
if os.path.isfile(baseDir + '/wfdeactivated/' + handle + '.json'):
|
if os.path.isfile(baseDir + '/wfdeactivated/' + handle + '.json'):
|
||||||
|
try:
|
||||||
os.remove(baseDir + '/wfdeactivated/' + handle + '.json')
|
os.remove(baseDir + '/wfdeactivated/' + handle + '.json')
|
||||||
|
except BaseException:
|
||||||
|
pass
|
||||||
if os.path.isdir(baseDir + '/sharefilesdeactivated/' + nickname):
|
if os.path.isdir(baseDir + '/sharefilesdeactivated/' + nickname):
|
||||||
shutil.rmtree(baseDir + '/sharefilesdeactivated/' + nickname)
|
shutil.rmtree(baseDir + '/sharefilesdeactivated/' + nickname)
|
||||||
|
|
||||||
|
|
@ -1215,7 +1350,8 @@ def _detectUsersPath(url: str) -> str:
|
||||||
|
|
||||||
|
|
||||||
def getActorJson(hostDomain: str, handle: str, http: bool, gnunet: bool,
|
def getActorJson(hostDomain: str, handle: str, http: bool, gnunet: bool,
|
||||||
debug: bool, quiet: bool = False) -> ({}, {}):
|
debug: bool, quiet: bool,
|
||||||
|
signingPrivateKeyPem: str) -> ({}, {}):
|
||||||
"""Returns the actor json
|
"""Returns the actor json
|
||||||
"""
|
"""
|
||||||
if debug:
|
if debug:
|
||||||
|
|
@ -1302,11 +1438,24 @@ def getActorJson(hostDomain: str, handle: str, http: bool, gnunet: bool,
|
||||||
if nickname == 'inbox':
|
if nickname == 'inbox':
|
||||||
nickname = domain
|
nickname = domain
|
||||||
|
|
||||||
|
personUrl = None
|
||||||
|
wfRequest = None
|
||||||
|
|
||||||
|
if '://' in originalActor and \
|
||||||
|
originalActor.lower().endswith('/actor'):
|
||||||
|
if debug:
|
||||||
|
print(originalActor + ' is an instance actor')
|
||||||
|
personUrl = originalActor
|
||||||
|
elif '://' in originalActor and groupAccount:
|
||||||
|
if debug:
|
||||||
|
print(originalActor + ' is a group actor')
|
||||||
|
personUrl = originalActor
|
||||||
|
else:
|
||||||
handle = nickname + '@' + domain
|
handle = nickname + '@' + domain
|
||||||
wfRequest = webfingerHandle(session, handle,
|
wfRequest = webfingerHandle(session, handle,
|
||||||
httpPrefix, cachedWebfingers,
|
httpPrefix, cachedWebfingers,
|
||||||
None, __version__, debug,
|
hostDomain, __version__, debug,
|
||||||
groupAccount)
|
groupAccount, signingPrivateKeyPem)
|
||||||
if not wfRequest:
|
if not wfRequest:
|
||||||
if not quiet:
|
if not quiet:
|
||||||
print('getActorJson Unable to webfinger ' + handle)
|
print('getActorJson Unable to webfinger ' + handle)
|
||||||
|
|
@ -1320,7 +1469,6 @@ def getActorJson(hostDomain: str, handle: str, http: bool, gnunet: bool,
|
||||||
if not quiet:
|
if not quiet:
|
||||||
pprint(wfRequest)
|
pprint(wfRequest)
|
||||||
|
|
||||||
personUrl = None
|
|
||||||
if wfRequest.get('errors'):
|
if wfRequest.get('errors'):
|
||||||
if not quiet or debug:
|
if not quiet or debug:
|
||||||
print('getActorJson wfRequest error: ' +
|
print('getActorJson wfRequest error: ' +
|
||||||
|
|
@ -1336,18 +1484,22 @@ def getActorJson(hostDomain: str, handle: str, http: bool, gnunet: bool,
|
||||||
headersList = (
|
headersList = (
|
||||||
"activity+json", "ld+json", "jrd+json"
|
"activity+json", "ld+json", "jrd+json"
|
||||||
)
|
)
|
||||||
if not personUrl:
|
if not personUrl and wfRequest:
|
||||||
personUrl = getUserUrl(wfRequest, 0, debug)
|
personUrl = getUserUrl(wfRequest, 0, debug)
|
||||||
if nickname == domain:
|
if nickname == domain:
|
||||||
paths = getUserPaths()
|
paths = getUserPaths()
|
||||||
for userPath in paths:
|
for userPath in paths:
|
||||||
personUrl = personUrl.replace(userPath, '/actor/')
|
personUrl = personUrl.replace(userPath, '/actor/')
|
||||||
|
if not personUrl and groupAccount:
|
||||||
|
personUrl = httpPrefix + '://' + domain + '/c/' + nickname
|
||||||
if not personUrl:
|
if not personUrl:
|
||||||
# try single user instance
|
# try single user instance
|
||||||
personUrl = httpPrefix + '://' + domain + '/' + nickname
|
personUrl = httpPrefix + '://' + domain + '/' + nickname
|
||||||
headersList = (
|
headersList = (
|
||||||
"ld+json", "jrd+json", "activity+json"
|
"ld+json", "jrd+json", "activity+json"
|
||||||
)
|
)
|
||||||
|
if debug:
|
||||||
|
print('Trying single user instance ' + personUrl)
|
||||||
if '/channel/' in personUrl or '/accounts/' in personUrl:
|
if '/channel/' in personUrl or '/accounts/' in personUrl:
|
||||||
headersList = (
|
headersList = (
|
||||||
"ld+json", "jrd+json", "activity+json"
|
"ld+json", "jrd+json", "activity+json"
|
||||||
|
|
@ -1360,7 +1512,7 @@ def getActorJson(hostDomain: str, handle: str, http: bool, gnunet: bool,
|
||||||
'Accept': headerMimeType + '; profile="' + profileStr + '"'
|
'Accept': headerMimeType + '; profile="' + profileStr + '"'
|
||||||
}
|
}
|
||||||
personJson = \
|
personJson = \
|
||||||
getJson(session, personUrl, asHeader, None,
|
getJson(signingPrivateKeyPem, session, personUrl, asHeader, None,
|
||||||
debug, __version__, httpPrefix, hostDomain, 20, quiet)
|
debug, __version__, httpPrefix, hostDomain, 20, quiet)
|
||||||
if personJson:
|
if personJson:
|
||||||
if not quiet:
|
if not quiet:
|
||||||
|
|
@ -1386,12 +1538,24 @@ def getPersonAvatarUrl(baseDir: str, personUrl: str, personCache: {},
|
||||||
|
|
||||||
imageExtension = getImageExtensions()
|
imageExtension = getImageExtensions()
|
||||||
for ext in imageExtension:
|
for ext in imageExtension:
|
||||||
if os.path.isfile(avatarImagePath + '.' + ext):
|
imFilename = avatarImagePath + '.' + ext
|
||||||
return '/avatars/' + actorStr + '.' + ext
|
imPath = '/avatars/' + actorStr + '.' + ext
|
||||||
elif os.path.isfile(avatarImagePath.lower() + '.' + ext):
|
if not os.path.isfile(imFilename):
|
||||||
return '/avatars/' + actorStr.lower() + '.' + ext
|
imFilename = avatarImagePath.lower() + '.' + ext
|
||||||
|
imPath = '/avatars/' + actorStr.lower() + '.' + ext
|
||||||
|
if not os.path.isfile(imFilename):
|
||||||
|
continue
|
||||||
|
if ext != 'svg':
|
||||||
|
return imPath
|
||||||
|
else:
|
||||||
|
content = ''
|
||||||
|
with open(imFilename, 'r') as fp:
|
||||||
|
content = fp.read()
|
||||||
|
if not dangerousSVG(content, False):
|
||||||
|
return imPath
|
||||||
|
|
||||||
if personJson.get('icon'):
|
if personJson.get('icon'):
|
||||||
if personJson['icon'].get('url'):
|
if personJson['icon'].get('url'):
|
||||||
|
if '.svg' not in personJson['icon']['url'].lower():
|
||||||
return personJson['icon']['url']
|
return personJson['icon']['url']
|
||||||
return None
|
return None
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Core"
|
__module_group__ = "Core"
|
||||||
|
|
||||||
|
|
|
||||||
42
pgp.py
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Profile Metadata"
|
__module_group__ = "Profile Metadata"
|
||||||
|
|
||||||
|
|
@ -16,6 +16,7 @@ from utils import isPGPEncrypted
|
||||||
from utils import getFullDomain
|
from utils import getFullDomain
|
||||||
from utils import getStatusNumber
|
from utils import getStatusNumber
|
||||||
from utils import localActorUrl
|
from utils import localActorUrl
|
||||||
|
from utils import replaceUsersWithAt
|
||||||
from webfinger import webfingerHandle
|
from webfinger import webfingerHandle
|
||||||
from posts import getPersonBox
|
from posts import getPersonBox
|
||||||
from auth import createBasicAuthHeader
|
from auth import createBasicAuthHeader
|
||||||
|
|
@ -333,14 +334,16 @@ def _pgpEncrypt(content: str, recipientPubKey: str) -> str:
|
||||||
return encryptResult
|
return encryptResult
|
||||||
|
|
||||||
|
|
||||||
def _getPGPPublicKeyFromActor(domain: str, handle: str,
|
def _getPGPPublicKeyFromActor(signingPrivateKeyPem: str,
|
||||||
|
domain: str, handle: str,
|
||||||
actorJson: {} = None) -> str:
|
actorJson: {} = None) -> str:
|
||||||
"""Searches tags on the actor to see if there is any PGP
|
"""Searches tags on the actor to see if there is any PGP
|
||||||
public key specified
|
public key specified
|
||||||
"""
|
"""
|
||||||
if not actorJson:
|
if not actorJson:
|
||||||
actorJson, asHeader = \
|
actorJson, asHeader = \
|
||||||
getActorJson(domain, handle, False, False, False, True)
|
getActorJson(domain, handle, False, False, False, True,
|
||||||
|
signingPrivateKeyPem)
|
||||||
if not actorJson:
|
if not actorJson:
|
||||||
return None
|
return None
|
||||||
if not actorJson.get('attachment'):
|
if not actorJson.get('attachment'):
|
||||||
|
|
@ -372,18 +375,21 @@ def hasLocalPGPkey() -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def pgpEncryptToActor(domain: str, content: str, toHandle: str) -> str:
|
def pgpEncryptToActor(domain: str, content: str, toHandle: str,
|
||||||
|
signingPrivateKeyPem: str) -> str:
|
||||||
"""PGP encrypt a message to the given actor or handle
|
"""PGP encrypt a message to the given actor or handle
|
||||||
"""
|
"""
|
||||||
# get the actor and extract the pgp public key from it
|
# get the actor and extract the pgp public key from it
|
||||||
recipientPubKey = _getPGPPublicKeyFromActor(domain, toHandle)
|
recipientPubKey = \
|
||||||
|
_getPGPPublicKeyFromActor(signingPrivateKeyPem, domain, toHandle)
|
||||||
if not recipientPubKey:
|
if not recipientPubKey:
|
||||||
return None
|
return None
|
||||||
# encrypt using the recipient public key
|
# encrypt using the recipient public key
|
||||||
return _pgpEncrypt(content, recipientPubKey)
|
return _pgpEncrypt(content, recipientPubKey)
|
||||||
|
|
||||||
|
|
||||||
def pgpDecrypt(domain: str, content: str, fromHandle: str) -> str:
|
def pgpDecrypt(domain: str, content: str, fromHandle: str,
|
||||||
|
signingPrivateKeyPem: str) -> str:
|
||||||
""" Encrypt using your default pgp key to the given recipient
|
""" Encrypt using your default pgp key to the given recipient
|
||||||
fromHandle can be a handle or actor url
|
fromHandle can be a handle or actor url
|
||||||
"""
|
"""
|
||||||
|
|
@ -394,7 +400,9 @@ def pgpDecrypt(domain: str, content: str, fromHandle: str) -> str:
|
||||||
if containsPGPPublicKey(content):
|
if containsPGPPublicKey(content):
|
||||||
pubKey = extractPGPPublicKey(content)
|
pubKey = extractPGPPublicKey(content)
|
||||||
else:
|
else:
|
||||||
pubKey = _getPGPPublicKeyFromActor(domain, content, fromHandle)
|
pubKey = \
|
||||||
|
_getPGPPublicKeyFromActor(signingPrivateKeyPem,
|
||||||
|
domain, content, fromHandle)
|
||||||
if pubKey:
|
if pubKey:
|
||||||
_pgpImportPubKey(pubKey)
|
_pgpImportPubKey(pubKey)
|
||||||
|
|
||||||
|
|
@ -449,7 +457,8 @@ def pgpPublicKeyUpload(baseDir: str, session,
|
||||||
domain: str, port: int,
|
domain: str, port: int,
|
||||||
httpPrefix: str,
|
httpPrefix: str,
|
||||||
cachedWebfingers: {}, personCache: {},
|
cachedWebfingers: {}, personCache: {},
|
||||||
debug: bool, test: str) -> {}:
|
debug: bool, test: str,
|
||||||
|
signingPrivateKeyPem: str) -> {}:
|
||||||
if debug:
|
if debug:
|
||||||
print('pgpPublicKeyUpload')
|
print('pgpPublicKeyUpload')
|
||||||
|
|
||||||
|
|
@ -481,7 +490,8 @@ def pgpPublicKeyUpload(baseDir: str, session,
|
||||||
print('Getting actor for ' + handle)
|
print('Getting actor for ' + handle)
|
||||||
|
|
||||||
actorJson, asHeader = \
|
actorJson, asHeader = \
|
||||||
getActorJson(domain, handle, False, False, debug, True)
|
getActorJson(domainFull, handle, False, False, debug, True,
|
||||||
|
signingPrivateKeyPem)
|
||||||
if not actorJson:
|
if not actorJson:
|
||||||
if debug:
|
if debug:
|
||||||
print('No actor returned for ' + handle)
|
print('No actor returned for ' + handle)
|
||||||
|
|
@ -491,7 +501,7 @@ def pgpPublicKeyUpload(baseDir: str, session,
|
||||||
print('Actor for ' + handle + ' obtained')
|
print('Actor for ' + handle + ' obtained')
|
||||||
|
|
||||||
actor = localActorUrl(httpPrefix, nickname, domainFull)
|
actor = localActorUrl(httpPrefix, nickname, domainFull)
|
||||||
handle = actor.replace('/users/', '/@')
|
handle = replaceUsersWithAt(actor)
|
||||||
|
|
||||||
# check that this looks like the correct actor
|
# check that this looks like the correct actor
|
||||||
if not actorJson.get('id'):
|
if not actorJson.get('id'):
|
||||||
|
|
@ -548,7 +558,8 @@ def pgpPublicKeyUpload(baseDir: str, session,
|
||||||
# lookup the inbox for the To handle
|
# lookup the inbox for the To handle
|
||||||
wfRequest = \
|
wfRequest = \
|
||||||
webfingerHandle(session, handle, httpPrefix, cachedWebfingers,
|
webfingerHandle(session, handle, httpPrefix, cachedWebfingers,
|
||||||
domain, __version__, debug, False)
|
domain, __version__, debug, False,
|
||||||
|
signingPrivateKeyPem)
|
||||||
if not wfRequest:
|
if not wfRequest:
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: pgp actor update webfinger failed for ' +
|
print('DEBUG: pgp actor update webfinger failed for ' +
|
||||||
|
|
@ -563,11 +574,12 @@ def pgpPublicKeyUpload(baseDir: str, session,
|
||||||
postToBox = 'outbox'
|
postToBox = 'outbox'
|
||||||
|
|
||||||
# get the actor inbox for the To handle
|
# get the actor inbox for the To handle
|
||||||
(inboxUrl, pubKeyId, pubKey,
|
originDomain = domain
|
||||||
fromPersonId, sharedInbox, avatarUrl,
|
(inboxUrl, pubKeyId, pubKey, fromPersonId, sharedInbox, avatarUrl,
|
||||||
displayName) = getPersonBox(baseDir, session, wfRequest, personCache,
|
displayName, _) = getPersonBox(signingPrivateKeyPem, originDomain,
|
||||||
|
baseDir, session, wfRequest, personCache,
|
||||||
__version__, httpPrefix, nickname,
|
__version__, httpPrefix, nickname,
|
||||||
domain, postToBox, 52025)
|
domain, postToBox, 35725)
|
||||||
|
|
||||||
if not inboxUrl:
|
if not inboxUrl:
|
||||||
if debug:
|
if debug:
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "ActivityPub"
|
__module_group__ = "ActivityPub"
|
||||||
|
|
||||||
|
|
|
||||||
2
roles.py
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Profile Metadata"
|
__module_group__ = "Profile Metadata"
|
||||||
|
|
||||||
|
|
|
||||||
22
schedule.py
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Calendar"
|
__module_group__ = "Calendar"
|
||||||
|
|
||||||
|
|
@ -46,7 +46,10 @@ def _updatePostSchedule(baseDir: str, handle: str, httpd,
|
||||||
if deleteSchedulePost:
|
if deleteSchedulePost:
|
||||||
# delete extraneous scheduled posts
|
# delete extraneous scheduled posts
|
||||||
if os.path.isfile(postFilename):
|
if os.path.isfile(postFilename):
|
||||||
|
try:
|
||||||
os.remove(postFilename)
|
os.remove(postFilename)
|
||||||
|
except BaseException:
|
||||||
|
pass
|
||||||
continue
|
continue
|
||||||
# create the new index file
|
# create the new index file
|
||||||
indexLines.append(line)
|
indexLines.append(line)
|
||||||
|
|
@ -110,14 +113,23 @@ def _updatePostSchedule(baseDir: str, handle: str, httpd,
|
||||||
httpd.projectVersion,
|
httpd.projectVersion,
|
||||||
httpd.debug,
|
httpd.debug,
|
||||||
httpd.YTReplacementDomain,
|
httpd.YTReplacementDomain,
|
||||||
|
httpd.twitterReplacementDomain,
|
||||||
httpd.showPublishedDateOnly,
|
httpd.showPublishedDateOnly,
|
||||||
httpd.allowLocalNetworkAccess,
|
httpd.allowLocalNetworkAccess,
|
||||||
httpd.city, httpd.systemLanguage,
|
httpd.city, httpd.systemLanguage,
|
||||||
httpd.sharedItemsFederatedDomains,
|
httpd.sharedItemsFederatedDomains,
|
||||||
httpd.sharedItemFederationTokens,
|
httpd.sharedItemFederationTokens,
|
||||||
httpd.lowBandwidth):
|
httpd.lowBandwidth,
|
||||||
|
httpd.signingPrivateKeyPem,
|
||||||
|
httpd.peertubeInstances,
|
||||||
|
httpd.themeName,
|
||||||
|
httpd.maxLikeCount,
|
||||||
|
httpd.maxRecentPosts):
|
||||||
indexLines.remove(line)
|
indexLines.remove(line)
|
||||||
|
try:
|
||||||
os.remove(postFilename)
|
os.remove(postFilename)
|
||||||
|
except BaseException:
|
||||||
|
pass
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# move to the outbox
|
# move to the outbox
|
||||||
|
|
@ -185,7 +197,10 @@ def removeScheduledPosts(baseDir: str, nickname: str, domain: str) -> None:
|
||||||
scheduleIndexFilename = \
|
scheduleIndexFilename = \
|
||||||
acctDir(baseDir, nickname, domain) + '/schedule.index'
|
acctDir(baseDir, nickname, domain) + '/schedule.index'
|
||||||
if os.path.isfile(scheduleIndexFilename):
|
if os.path.isfile(scheduleIndexFilename):
|
||||||
|
try:
|
||||||
os.remove(scheduleIndexFilename)
|
os.remove(scheduleIndexFilename)
|
||||||
|
except BaseException:
|
||||||
|
pass
|
||||||
# remove the scheduled posts
|
# remove the scheduled posts
|
||||||
scheduledDir = acctDir(baseDir, nickname, domain) + '/scheduled'
|
scheduledDir = acctDir(baseDir, nickname, domain) + '/scheduled'
|
||||||
if not os.path.isdir(scheduledDir):
|
if not os.path.isdir(scheduledDir):
|
||||||
|
|
@ -194,6 +209,9 @@ def removeScheduledPosts(baseDir: str, nickname: str, domain: str) -> None:
|
||||||
filePath = os.path.join(scheduledDir, scheduledPostFilename)
|
filePath = os.path.join(scheduledDir, scheduledPostFilename)
|
||||||
try:
|
try:
|
||||||
if os.path.isfile(filePath):
|
if os.path.isfile(filePath):
|
||||||
|
try:
|
||||||
os.remove(filePath)
|
os.remove(filePath)
|
||||||
except BaseException:
|
except BaseException:
|
||||||
pass
|
pass
|
||||||
|
except BaseException:
|
||||||
|
pass
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
# License
|
# License
|
||||||
# =======
|
# =======
|
||||||
#
|
#
|
||||||
# Copyright (C) 2020-2021 Bob Mottram <bob@freedombone.net>
|
# Copyright (C) 2020-2021 Bob Mottram <bob@libreserver.org>
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU Affero General Public License as published by
|
# it under the terms of the GNU Affero General Public License as published by
|
||||||
|
|
|
||||||
150
session.py
|
|
@ -3,14 +3,15 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Core"
|
__module_group__ = "Session"
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import requests
|
import requests
|
||||||
from utils import urlPermitted
|
from utils import urlPermitted
|
||||||
from utils import isImageFile
|
from utils import isImageFile
|
||||||
|
from httpsig import createSignedHeader
|
||||||
import json
|
import json
|
||||||
from socket import error as SocketError
|
from socket import error as SocketError
|
||||||
import errno
|
import errno
|
||||||
|
|
@ -84,43 +85,23 @@ def urlExists(session, url: str, timeoutSec: int = 3,
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def getJson(session, url: str, headers: {}, params: {}, debug: bool,
|
def _getJsonRequest(session, url: str, domainFull: str, sessionHeaders: {},
|
||||||
version: str = '1.2.0', httpPrefix: str = 'https',
|
sessionParams: {}, timeoutSec: int,
|
||||||
domain: str = 'testdomain',
|
signingPrivateKeyPem: str, quiet: bool, debug: bool) -> {}:
|
||||||
timeoutSec: int = 20, quiet: bool = False) -> {}:
|
"""http GET for json
|
||||||
if not isinstance(url, str):
|
"""
|
||||||
if debug and not quiet:
|
|
||||||
print('url: ' + str(url))
|
|
||||||
print('ERROR: getJson failed, url should be a string')
|
|
||||||
return None
|
|
||||||
sessionParams = {}
|
|
||||||
sessionHeaders = {}
|
|
||||||
if headers:
|
|
||||||
sessionHeaders = headers
|
|
||||||
if params:
|
|
||||||
sessionParams = params
|
|
||||||
sessionHeaders['User-Agent'] = 'Epicyon/' + version
|
|
||||||
if domain:
|
|
||||||
sessionHeaders['User-Agent'] += \
|
|
||||||
'; +' + httpPrefix + '://' + domain + '/'
|
|
||||||
if not session:
|
|
||||||
if not quiet:
|
|
||||||
print('WARN: getJson failed, no session specified for getJson')
|
|
||||||
return None
|
|
||||||
|
|
||||||
if debug:
|
|
||||||
HTTPConnection.debuglevel = 1
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
result = session.get(url, headers=sessionHeaders,
|
result = session.get(url, headers=sessionHeaders,
|
||||||
params=sessionParams, timeout=timeoutSec)
|
params=sessionParams, timeout=timeoutSec)
|
||||||
if result.status_code != 200:
|
if result.status_code != 200:
|
||||||
if result.status_code == 401:
|
if result.status_code == 401:
|
||||||
print('WARN: getJson Unauthorized url: ' + url)
|
print("WARN: getJson " + url + ' rejected by secure mode')
|
||||||
elif result.status_code == 403:
|
elif result.status_code == 403:
|
||||||
print('WARN: getJson Forbidden url: ' + url)
|
print('WARN: getJson Forbidden url: ' + url)
|
||||||
elif result.status_code == 404:
|
elif result.status_code == 404:
|
||||||
print('WARN: getJson Not Found url: ' + url)
|
print('WARN: getJson Not Found url: ' + url)
|
||||||
|
elif result.status_code == 410:
|
||||||
|
print('WARN: getJson no longer available url: ' + url)
|
||||||
else:
|
else:
|
||||||
print('WARN: getJson url: ' + url +
|
print('WARN: getJson url: ' + url +
|
||||||
' failed with error code ' +
|
' failed with error code ' +
|
||||||
|
|
@ -151,6 +132,115 @@ def getJson(session, url: str, headers: {}, params: {}, debug: bool,
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _getJsonSigned(session, url: str, domainFull: str, sessionHeaders: {},
|
||||||
|
sessionParams: {}, timeoutSec: int,
|
||||||
|
signingPrivateKeyPem: str, quiet: bool, debug: bool) -> {}:
|
||||||
|
"""Authorized fetch - a signed version of GET
|
||||||
|
"""
|
||||||
|
if not domainFull:
|
||||||
|
if debug:
|
||||||
|
print('No sending domain for signed GET')
|
||||||
|
return None
|
||||||
|
if '://' not in url:
|
||||||
|
print('Invalid url: ' + url)
|
||||||
|
return None
|
||||||
|
httpPrefix = url.split('://')[0]
|
||||||
|
toDomainFull = url.split('://')[1]
|
||||||
|
if '/' in toDomainFull:
|
||||||
|
toDomainFull = toDomainFull.split('/')[0]
|
||||||
|
|
||||||
|
if ':' in domainFull:
|
||||||
|
domain = domainFull.split(':')[0]
|
||||||
|
port = domainFull.split(':')[1]
|
||||||
|
else:
|
||||||
|
domain = domainFull
|
||||||
|
if httpPrefix == 'https':
|
||||||
|
port = 443
|
||||||
|
else:
|
||||||
|
port = 80
|
||||||
|
|
||||||
|
if ':' in toDomainFull:
|
||||||
|
toDomain = toDomainFull.split(':')[0]
|
||||||
|
toPort = toDomainFull.split(':')[1]
|
||||||
|
else:
|
||||||
|
toDomain = toDomainFull
|
||||||
|
if httpPrefix == 'https':
|
||||||
|
toPort = 443
|
||||||
|
else:
|
||||||
|
toPort = 80
|
||||||
|
|
||||||
|
if debug:
|
||||||
|
print('Signed GET domain: ' + domain + ' ' + str(port))
|
||||||
|
print('Signed GET toDomain: ' + toDomain + ' ' + str(toPort))
|
||||||
|
print('Signed GET url: ' + url)
|
||||||
|
print('Signed GET httpPrefix: ' + httpPrefix)
|
||||||
|
messageStr = ''
|
||||||
|
withDigest = False
|
||||||
|
if toDomainFull + '/' in url:
|
||||||
|
path = '/' + url.split(toDomainFull + '/')[1]
|
||||||
|
else:
|
||||||
|
path = '/actor'
|
||||||
|
contentType = 'application/activity+json'
|
||||||
|
if sessionHeaders.get('Accept'):
|
||||||
|
contentType = sessionHeaders['Accept']
|
||||||
|
signatureHeaderJson = \
|
||||||
|
createSignedHeader(None, signingPrivateKeyPem, 'actor', domain, port,
|
||||||
|
toDomain, toPort, path, httpPrefix, withDigest,
|
||||||
|
messageStr, contentType)
|
||||||
|
if debug:
|
||||||
|
print('Signed GET signatureHeaderJson ' + str(signatureHeaderJson))
|
||||||
|
# update the session headers from the signature headers
|
||||||
|
sessionHeaders['Host'] = signatureHeaderJson['host']
|
||||||
|
sessionHeaders['Date'] = signatureHeaderJson['date']
|
||||||
|
sessionHeaders['Accept'] = signatureHeaderJson['accept']
|
||||||
|
sessionHeaders['Signature'] = signatureHeaderJson['signature']
|
||||||
|
sessionHeaders['Content-Length'] = '0'
|
||||||
|
# if debug:
|
||||||
|
print('Signed GET sessionHeaders ' + str(sessionHeaders))
|
||||||
|
|
||||||
|
return _getJsonRequest(session, url, domainFull, sessionHeaders,
|
||||||
|
sessionParams, timeoutSec, None, quiet, debug)
|
||||||
|
|
||||||
|
|
||||||
|
def getJson(signingPrivateKeyPem: str,
|
||||||
|
session, url: str, headers: {}, params: {}, debug: bool,
|
||||||
|
version: str = '1.2.0', httpPrefix: str = 'https',
|
||||||
|
domain: str = 'testdomain',
|
||||||
|
timeoutSec: int = 20, quiet: bool = False) -> {}:
|
||||||
|
if not isinstance(url, str):
|
||||||
|
if debug and not quiet:
|
||||||
|
print('url: ' + str(url))
|
||||||
|
print('ERROR: getJson failed, url should be a string')
|
||||||
|
return None
|
||||||
|
sessionParams = {}
|
||||||
|
sessionHeaders = {}
|
||||||
|
if headers:
|
||||||
|
sessionHeaders = headers
|
||||||
|
if params:
|
||||||
|
sessionParams = params
|
||||||
|
sessionHeaders['User-Agent'] = 'Epicyon/' + version
|
||||||
|
if domain:
|
||||||
|
sessionHeaders['User-Agent'] += \
|
||||||
|
'; +' + httpPrefix + '://' + domain + '/'
|
||||||
|
if not session:
|
||||||
|
if not quiet:
|
||||||
|
print('WARN: getJson failed, no session specified for getJson')
|
||||||
|
return None
|
||||||
|
|
||||||
|
if debug:
|
||||||
|
HTTPConnection.debuglevel = 1
|
||||||
|
|
||||||
|
if signingPrivateKeyPem:
|
||||||
|
return _getJsonSigned(session, url, domain,
|
||||||
|
sessionHeaders, sessionParams,
|
||||||
|
timeoutSec, signingPrivateKeyPem,
|
||||||
|
quiet, debug)
|
||||||
|
else:
|
||||||
|
return _getJsonRequest(session, url, domain, sessionHeaders,
|
||||||
|
sessionParams, timeoutSec,
|
||||||
|
None, quiet, debug)
|
||||||
|
|
||||||
|
|
||||||
def postJson(httpPrefix: str, domainFull: str,
|
def postJson(httpPrefix: str, domainFull: str,
|
||||||
session, postJsonObject: {}, federationList: [],
|
session, postJsonObject: {}, federationList: [],
|
||||||
inboxUrl: str, headers: {}, timeoutSec: int = 60,
|
inboxUrl: str, headers: {}, timeoutSec: int = 60,
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@
|
||||||
name = epicyon
|
name = epicyon
|
||||||
version = 1.3.0
|
version = 1.3.0
|
||||||
author = Bob Mottram
|
author = Bob Mottram
|
||||||
author_email = bob@freedombone.net
|
author_email = bob@libreserver.org
|
||||||
maintainer = Bob Mottram
|
maintainer = Bob Mottram
|
||||||
maintainer_email = bob@freedombone.net
|
maintainer_email = bob@libreserver.org
|
||||||
description = A modern ActivityPub compliant server implementing both S2S and C2S protocols.
|
description = A modern ActivityPub compliant server implementing both S2S and C2S protocols.
|
||||||
long_description = file: README.md
|
long_description = file: README.md
|
||||||
long_description_content_type = text/markdown
|
long_description_content_type = text/markdown
|
||||||
|
|
|
||||||
138
shares.py
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Timeline"
|
__module_group__ = "Timeline"
|
||||||
|
|
||||||
|
|
@ -47,7 +47,8 @@ from blocking import isBlocked
|
||||||
|
|
||||||
|
|
||||||
def _loadDfcIds(baseDir: str, systemLanguage: str,
|
def _loadDfcIds(baseDir: str, systemLanguage: str,
|
||||||
productType: str) -> {}:
|
productType: str,
|
||||||
|
httpPrefix: str, domainFull: str) -> {}:
|
||||||
"""Loads the product types ontology
|
"""Loads the product types ontology
|
||||||
This is used to add an id to shared items
|
This is used to add an id to shared items
|
||||||
"""
|
"""
|
||||||
|
|
@ -92,7 +93,10 @@ def _loadDfcIds(baseDir: str, systemLanguage: str,
|
||||||
if not label.get('@value'):
|
if not label.get('@value'):
|
||||||
continue
|
continue
|
||||||
if label['@language'] == systemLanguage:
|
if label['@language'] == systemLanguage:
|
||||||
dfcIds[label['@value'].lower()] = item['@id']
|
itemId = \
|
||||||
|
item['@id'].replace('http://static.datafoodconsortium.org',
|
||||||
|
httpPrefix + '://' + domainFull)
|
||||||
|
dfcIds[label['@value'].lower()] = itemId
|
||||||
break
|
break
|
||||||
return dfcIds
|
return dfcIds
|
||||||
|
|
||||||
|
|
@ -142,7 +146,10 @@ def removeSharedItem(baseDir: str, nickname: str, domain: str,
|
||||||
for ext in formats:
|
for ext in formats:
|
||||||
if sharesJson[itemID]['imageUrl'].endswith('.' + ext):
|
if sharesJson[itemID]['imageUrl'].endswith('.' + ext):
|
||||||
if os.path.isfile(itemIDfile + '.' + ext):
|
if os.path.isfile(itemIDfile + '.' + ext):
|
||||||
|
try:
|
||||||
os.remove(itemIDfile + '.' + ext)
|
os.remove(itemIDfile + '.' + ext)
|
||||||
|
except BaseException:
|
||||||
|
pass
|
||||||
# remove the item itself
|
# remove the item itself
|
||||||
del sharesJson[itemID]
|
del sharesJson[itemID]
|
||||||
saveJson(sharesJson, sharesFilename)
|
saveJson(sharesJson, sharesFilename)
|
||||||
|
|
@ -193,7 +200,9 @@ def _dfcProductTypeFromCategory(baseDir: str,
|
||||||
|
|
||||||
def _getshareDfcId(baseDir: str, systemLanguage: str,
|
def _getshareDfcId(baseDir: str, systemLanguage: str,
|
||||||
itemType: str, itemCategory: str,
|
itemType: str, itemCategory: str,
|
||||||
translate: {}, dfcIds: {} = None) -> str:
|
translate: {},
|
||||||
|
httpPrefix: str, domainFull: str,
|
||||||
|
dfcIds: {} = None) -> str:
|
||||||
"""Attempts to obtain a DFC Id for the shared item,
|
"""Attempts to obtain a DFC Id for the shared item,
|
||||||
based upon productTypes ontology.
|
based upon productTypes ontology.
|
||||||
See https://github.com/datafoodconsortium/ontology
|
See https://github.com/datafoodconsortium/ontology
|
||||||
|
|
@ -207,7 +216,8 @@ def _getshareDfcId(baseDir: str, systemLanguage: str,
|
||||||
itemType = itemType.replace('.', '')
|
itemType = itemType.replace('.', '')
|
||||||
return 'epicyon#' + itemType
|
return 'epicyon#' + itemType
|
||||||
if not dfcIds:
|
if not dfcIds:
|
||||||
dfcIds = _loadDfcIds(baseDir, systemLanguage, matchedProductType)
|
dfcIds = _loadDfcIds(baseDir, systemLanguage, matchedProductType,
|
||||||
|
httpPrefix, domainFull)
|
||||||
if not dfcIds:
|
if not dfcIds:
|
||||||
return ''
|
return ''
|
||||||
itemTypeLower = itemType.lower()
|
itemTypeLower = itemType.lower()
|
||||||
|
|
@ -316,7 +326,8 @@ def addShare(baseDir: str,
|
||||||
actor = localActorUrl(httpPrefix, nickname, domainFull)
|
actor = localActorUrl(httpPrefix, nickname, domainFull)
|
||||||
itemID = _getValidSharedItemID(actor, displayName)
|
itemID = _getValidSharedItemID(actor, displayName)
|
||||||
dfcId = _getshareDfcId(baseDir, systemLanguage,
|
dfcId = _getshareDfcId(baseDir, systemLanguage,
|
||||||
itemType, itemCategory, translate)
|
itemType, itemCategory, translate,
|
||||||
|
httpPrefix, domainFull)
|
||||||
|
|
||||||
# has an image for this share been uploaded?
|
# has an image for this share been uploaded?
|
||||||
imageUrl = None
|
imageUrl = None
|
||||||
|
|
@ -350,7 +361,10 @@ def addShare(baseDir: str,
|
||||||
imageFilename, itemIDfile + '.' + ext,
|
imageFilename, itemIDfile + '.' + ext,
|
||||||
city)
|
city)
|
||||||
if moveImage:
|
if moveImage:
|
||||||
|
try:
|
||||||
os.remove(imageFilename)
|
os.remove(imageFilename)
|
||||||
|
except BaseException:
|
||||||
|
pass
|
||||||
imageUrl = \
|
imageUrl = \
|
||||||
httpPrefix + '://' + domainFull + \
|
httpPrefix + '://' + domainFull + \
|
||||||
'/sharefiles/' + nickname + '/' + itemID + '.' + ext
|
'/sharefiles/' + nickname + '/' + itemID + '.' + ext
|
||||||
|
|
@ -419,7 +433,10 @@ def _expireSharesForAccount(baseDir: str, nickname: str, domain: str,
|
||||||
formats = getImageExtensions()
|
formats = getImageExtensions()
|
||||||
for ext in formats:
|
for ext in formats:
|
||||||
if os.path.isfile(itemIDfile + '.' + ext):
|
if os.path.isfile(itemIDfile + '.' + ext):
|
||||||
|
try:
|
||||||
os.remove(itemIDfile + '.' + ext)
|
os.remove(itemIDfile + '.' + ext)
|
||||||
|
except BaseException:
|
||||||
|
pass
|
||||||
saveJson(sharesJson, sharesFilename)
|
saveJson(sharesJson, sharesFilename)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -535,7 +552,8 @@ def sendShareViaServer(baseDir, session,
|
||||||
location: str, duration: str,
|
location: str, duration: str,
|
||||||
cachedWebfingers: {}, personCache: {},
|
cachedWebfingers: {}, personCache: {},
|
||||||
debug: bool, projectVersion: str,
|
debug: bool, projectVersion: str,
|
||||||
itemPrice: str, itemCurrency: str) -> {}:
|
itemPrice: str, itemCurrency: str,
|
||||||
|
signingPrivateKeyPem: str) -> {}:
|
||||||
"""Creates an item share via c2s
|
"""Creates an item share via c2s
|
||||||
"""
|
"""
|
||||||
if not session:
|
if not session:
|
||||||
|
|
@ -585,7 +603,8 @@ def sendShareViaServer(baseDir, session,
|
||||||
wfRequest = \
|
wfRequest = \
|
||||||
webfingerHandle(session, handle, httpPrefix,
|
webfingerHandle(session, handle, httpPrefix,
|
||||||
cachedWebfingers,
|
cachedWebfingers,
|
||||||
fromDomain, projectVersion, debug, False)
|
fromDomain, projectVersion, debug, False,
|
||||||
|
signingPrivateKeyPem)
|
||||||
if not wfRequest:
|
if not wfRequest:
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: share webfinger failed for ' + handle)
|
print('DEBUG: share webfinger failed for ' + handle)
|
||||||
|
|
@ -598,9 +617,11 @@ def sendShareViaServer(baseDir, session,
|
||||||
postToBox = 'outbox'
|
postToBox = 'outbox'
|
||||||
|
|
||||||
# get the actor inbox for the To handle
|
# get the actor inbox for the To handle
|
||||||
(inboxUrl, pubKeyId, pubKey,
|
originDomain = fromDomain
|
||||||
fromPersonId, sharedInbox,
|
(inboxUrl, pubKeyId, pubKey, fromPersonId, sharedInbox, avatarUrl,
|
||||||
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
displayName, _) = getPersonBox(signingPrivateKeyPem,
|
||||||
|
originDomain,
|
||||||
|
baseDir, session, wfRequest,
|
||||||
personCache, projectVersion,
|
personCache, projectVersion,
|
||||||
httpPrefix, fromNickname,
|
httpPrefix, fromNickname,
|
||||||
fromDomain, postToBox,
|
fromDomain, postToBox,
|
||||||
|
|
@ -652,7 +673,8 @@ def sendUndoShareViaServer(baseDir: str, session,
|
||||||
fromDomain: str, fromPort: int,
|
fromDomain: str, fromPort: int,
|
||||||
httpPrefix: str, displayName: str,
|
httpPrefix: str, displayName: str,
|
||||||
cachedWebfingers: {}, personCache: {},
|
cachedWebfingers: {}, personCache: {},
|
||||||
debug: bool, projectVersion: str) -> {}:
|
debug: bool, projectVersion: str,
|
||||||
|
signingPrivateKeyPem: str) -> {}:
|
||||||
"""Undoes a share via c2s
|
"""Undoes a share via c2s
|
||||||
"""
|
"""
|
||||||
if not session:
|
if not session:
|
||||||
|
|
@ -685,7 +707,8 @@ def sendUndoShareViaServer(baseDir: str, session,
|
||||||
# lookup the inbox for the To handle
|
# lookup the inbox for the To handle
|
||||||
wfRequest = \
|
wfRequest = \
|
||||||
webfingerHandle(session, handle, httpPrefix, cachedWebfingers,
|
webfingerHandle(session, handle, httpPrefix, cachedWebfingers,
|
||||||
fromDomain, projectVersion, debug, False)
|
fromDomain, projectVersion, debug, False,
|
||||||
|
signingPrivateKeyPem)
|
||||||
if not wfRequest:
|
if not wfRequest:
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: unshare webfinger failed for ' + handle)
|
print('DEBUG: unshare webfinger failed for ' + handle)
|
||||||
|
|
@ -698,9 +721,11 @@ def sendUndoShareViaServer(baseDir: str, session,
|
||||||
postToBox = 'outbox'
|
postToBox = 'outbox'
|
||||||
|
|
||||||
# get the actor inbox for the To handle
|
# get the actor inbox for the To handle
|
||||||
(inboxUrl, pubKeyId, pubKey,
|
originDomain = fromDomain
|
||||||
fromPersonId, sharedInbox,
|
(inboxUrl, pubKeyId, pubKey, fromPersonId, sharedInbox, avatarUrl,
|
||||||
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
displayName, _) = getPersonBox(signingPrivateKeyPem,
|
||||||
|
originDomain,
|
||||||
|
baseDir, session, wfRequest,
|
||||||
personCache, projectVersion,
|
personCache, projectVersion,
|
||||||
httpPrefix, fromNickname,
|
httpPrefix, fromNickname,
|
||||||
fromDomain, postToBox,
|
fromDomain, postToBox,
|
||||||
|
|
@ -747,7 +772,8 @@ def sendWantedViaServer(baseDir, session,
|
||||||
location: str, duration: str,
|
location: str, duration: str,
|
||||||
cachedWebfingers: {}, personCache: {},
|
cachedWebfingers: {}, personCache: {},
|
||||||
debug: bool, projectVersion: str,
|
debug: bool, projectVersion: str,
|
||||||
itemMaxPrice: str, itemCurrency: str) -> {}:
|
itemMaxPrice: str, itemCurrency: str,
|
||||||
|
signingPrivateKeyPem: str) -> {}:
|
||||||
"""Creates a wanted item via c2s
|
"""Creates a wanted item via c2s
|
||||||
"""
|
"""
|
||||||
if not session:
|
if not session:
|
||||||
|
|
@ -797,7 +823,8 @@ def sendWantedViaServer(baseDir, session,
|
||||||
wfRequest = \
|
wfRequest = \
|
||||||
webfingerHandle(session, handle, httpPrefix,
|
webfingerHandle(session, handle, httpPrefix,
|
||||||
cachedWebfingers,
|
cachedWebfingers,
|
||||||
fromDomain, projectVersion, debug, False)
|
fromDomain, projectVersion, debug, False,
|
||||||
|
signingPrivateKeyPem)
|
||||||
if not wfRequest:
|
if not wfRequest:
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: share webfinger failed for ' + handle)
|
print('DEBUG: share webfinger failed for ' + handle)
|
||||||
|
|
@ -810,13 +837,15 @@ def sendWantedViaServer(baseDir, session,
|
||||||
postToBox = 'outbox'
|
postToBox = 'outbox'
|
||||||
|
|
||||||
# get the actor inbox for the To handle
|
# get the actor inbox for the To handle
|
||||||
(inboxUrl, pubKeyId, pubKey,
|
originDomain = fromDomain
|
||||||
fromPersonId, sharedInbox,
|
(inboxUrl, pubKeyId, pubKey, fromPersonId, sharedInbox, avatarUrl,
|
||||||
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
displayName, _) = getPersonBox(signingPrivateKeyPem,
|
||||||
|
originDomain,
|
||||||
|
baseDir, session, wfRequest,
|
||||||
personCache, projectVersion,
|
personCache, projectVersion,
|
||||||
httpPrefix, fromNickname,
|
httpPrefix, fromNickname,
|
||||||
fromDomain, postToBox,
|
fromDomain, postToBox,
|
||||||
83653)
|
23653)
|
||||||
|
|
||||||
if not inboxUrl:
|
if not inboxUrl:
|
||||||
if debug:
|
if debug:
|
||||||
|
|
@ -864,7 +893,8 @@ def sendUndoWantedViaServer(baseDir: str, session,
|
||||||
fromDomain: str, fromPort: int,
|
fromDomain: str, fromPort: int,
|
||||||
httpPrefix: str, displayName: str,
|
httpPrefix: str, displayName: str,
|
||||||
cachedWebfingers: {}, personCache: {},
|
cachedWebfingers: {}, personCache: {},
|
||||||
debug: bool, projectVersion: str) -> {}:
|
debug: bool, projectVersion: str,
|
||||||
|
signingPrivateKeyPem: str) -> {}:
|
||||||
"""Undoes a wanted item via c2s
|
"""Undoes a wanted item via c2s
|
||||||
"""
|
"""
|
||||||
if not session:
|
if not session:
|
||||||
|
|
@ -897,7 +927,8 @@ def sendUndoWantedViaServer(baseDir: str, session,
|
||||||
# lookup the inbox for the To handle
|
# lookup the inbox for the To handle
|
||||||
wfRequest = \
|
wfRequest = \
|
||||||
webfingerHandle(session, handle, httpPrefix, cachedWebfingers,
|
webfingerHandle(session, handle, httpPrefix, cachedWebfingers,
|
||||||
fromDomain, projectVersion, debug, False)
|
fromDomain, projectVersion, debug, False,
|
||||||
|
signingPrivateKeyPem)
|
||||||
if not wfRequest:
|
if not wfRequest:
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: unwant webfinger failed for ' + handle)
|
print('DEBUG: unwant webfinger failed for ' + handle)
|
||||||
|
|
@ -910,13 +941,15 @@ def sendUndoWantedViaServer(baseDir: str, session,
|
||||||
postToBox = 'outbox'
|
postToBox = 'outbox'
|
||||||
|
|
||||||
# get the actor inbox for the To handle
|
# get the actor inbox for the To handle
|
||||||
(inboxUrl, pubKeyId, pubKey,
|
originDomain = fromDomain
|
||||||
fromPersonId, sharedInbox,
|
(inboxUrl, pubKeyId, pubKey, fromPersonId, sharedInbox, avatarUrl,
|
||||||
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
displayName, _) = getPersonBox(signingPrivateKeyPem,
|
||||||
|
originDomain,
|
||||||
|
baseDir, session, wfRequest,
|
||||||
personCache, projectVersion,
|
personCache, projectVersion,
|
||||||
httpPrefix, fromNickname,
|
httpPrefix, fromNickname,
|
||||||
fromDomain, postToBox,
|
fromDomain, postToBox,
|
||||||
12663)
|
12693)
|
||||||
|
|
||||||
if not inboxUrl:
|
if not inboxUrl:
|
||||||
if debug:
|
if debug:
|
||||||
|
|
@ -953,7 +986,8 @@ def sendUndoWantedViaServer(baseDir: str, session,
|
||||||
def getSharedItemsCatalogViaServer(baseDir, session,
|
def getSharedItemsCatalogViaServer(baseDir, session,
|
||||||
nickname: str, password: str,
|
nickname: str, password: str,
|
||||||
domain: str, port: int,
|
domain: str, port: int,
|
||||||
httpPrefix: str, debug: bool) -> {}:
|
httpPrefix: str, debug: bool,
|
||||||
|
signingPrivateKeyPem: str) -> {}:
|
||||||
"""Returns the shared items catalog via c2s
|
"""Returns the shared items catalog via c2s
|
||||||
"""
|
"""
|
||||||
if not session:
|
if not session:
|
||||||
|
|
@ -972,8 +1006,8 @@ def getSharedItemsCatalogViaServer(baseDir, session,
|
||||||
url = localActorUrl(httpPrefix, nickname, domainFull) + '/catalog'
|
url = localActorUrl(httpPrefix, nickname, domainFull) + '/catalog'
|
||||||
if debug:
|
if debug:
|
||||||
print('Shared items catalog request to: ' + url)
|
print('Shared items catalog request to: ' + url)
|
||||||
catalogJson = getJson(session, url, headers, None, debug,
|
catalogJson = getJson(signingPrivateKeyPem, session, url, headers, None,
|
||||||
__version__, httpPrefix, None)
|
debug, __version__, httpPrefix, None)
|
||||||
if not catalogJson:
|
if not catalogJson:
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: GET shared items catalog failed for c2s to ' + url)
|
print('DEBUG: GET shared items catalog failed for c2s to ' + url)
|
||||||
|
|
@ -1129,12 +1163,14 @@ def sharesCatalogAccountEndpoint(baseDir: str, httpPrefix: str,
|
||||||
sharesFileType: str) -> {}:
|
sharesFileType: str) -> {}:
|
||||||
"""Returns the endpoint for the shares catalog of a particular account
|
"""Returns the endpoint for the shares catalog of a particular account
|
||||||
See https://github.com/datafoodconsortium/ontology
|
See https://github.com/datafoodconsortium/ontology
|
||||||
|
Also the subdirectory ontology/DFC
|
||||||
"""
|
"""
|
||||||
today, minPrice, maxPrice, matchPattern = _sharesCatalogParams(path)
|
today, minPrice, maxPrice, matchPattern = _sharesCatalogParams(path)
|
||||||
dfcUrl = \
|
dfcUrl = \
|
||||||
"http://static.datafoodconsortium.org/ontologies/DFC_FullModel.owl#"
|
httpPrefix + '://' + domainFull + '/ontologies/DFC_FullModel.owl#'
|
||||||
dfcPtUrl = \
|
dfcPtUrl = \
|
||||||
"http://static.datafoodconsortium.org/data/productTypes.rdf#"
|
httpPrefix + '://' + domainFull + \
|
||||||
|
'/ontologies/DFC_ProductGlossary.rdf#'
|
||||||
owner = localActorUrl(httpPrefix, nickname, domainFull)
|
owner = localActorUrl(httpPrefix, nickname, domainFull)
|
||||||
if sharesFileType == 'shares':
|
if sharesFileType == 'shares':
|
||||||
dfcInstanceId = owner + '/catalog'
|
dfcInstanceId = owner + '/catalog'
|
||||||
|
|
@ -1217,12 +1253,14 @@ def sharesCatalogEndpoint(baseDir: str, httpPrefix: str,
|
||||||
path: str, sharesFileType: str) -> {}:
|
path: str, sharesFileType: str) -> {}:
|
||||||
"""Returns the endpoint for the shares catalog for the instance
|
"""Returns the endpoint for the shares catalog for the instance
|
||||||
See https://github.com/datafoodconsortium/ontology
|
See https://github.com/datafoodconsortium/ontology
|
||||||
|
Also the subdirectory ontology/DFC
|
||||||
"""
|
"""
|
||||||
today, minPrice, maxPrice, matchPattern = _sharesCatalogParams(path)
|
today, minPrice, maxPrice, matchPattern = _sharesCatalogParams(path)
|
||||||
dfcUrl = \
|
dfcUrl = \
|
||||||
"http://static.datafoodconsortium.org/ontologies/DFC_FullModel.owl#"
|
httpPrefix + '://' + domainFull + '/ontologies/DFC_FullModel.owl#'
|
||||||
dfcPtUrl = \
|
dfcPtUrl = \
|
||||||
"http://static.datafoodconsortium.org/data/productTypes.rdf#"
|
httpPrefix + '://' + domainFull + \
|
||||||
|
'/ontologies/DFC_ProductGlossary.rdf#'
|
||||||
dfcInstanceId = httpPrefix + '://' + domainFull + '/catalog'
|
dfcInstanceId = httpPrefix + '://' + domainFull + '/catalog'
|
||||||
endpoint = {
|
endpoint = {
|
||||||
"@context": {
|
"@context": {
|
||||||
|
|
@ -1323,6 +1361,7 @@ def sharesCatalogCSVEndpoint(baseDir: str, httpPrefix: str,
|
||||||
csvStr += str(item['DFC:quantity']) + ','
|
csvStr += str(item['DFC:quantity']) + ','
|
||||||
csvStr += item['DFC:price'].split(' ')[0] + ','
|
csvStr += item['DFC:price'].split(' ')[0] + ','
|
||||||
csvStr += '"' + item['DFC:price'].split(' ')[1] + '",'
|
csvStr += '"' + item['DFC:price'].split(' ')[1] + '",'
|
||||||
|
if item.get('DFC:Image'):
|
||||||
csvStr += '"' + item['DFC:Image'] + '",'
|
csvStr += '"' + item['DFC:Image'] + '",'
|
||||||
description = item['DFC:description'].replace('"', "'")
|
description = item['DFC:description'].replace('"', "'")
|
||||||
csvStr += '"' + description + '",\n'
|
csvStr += '"' + description + '",\n'
|
||||||
|
|
@ -1550,7 +1589,8 @@ def _updateFederatedSharesCache(session, sharedItemsFederatedDomains: [],
|
||||||
if saveJson(catalogJson, catalogFilename):
|
if saveJson(catalogJson, catalogFilename):
|
||||||
print('Downloaded shared items catalog for ' + federatedDomainFull)
|
print('Downloaded shared items catalog for ' + federatedDomainFull)
|
||||||
sharesJson = _dfcToSharesFormat(catalogJson,
|
sharesJson = _dfcToSharesFormat(catalogJson,
|
||||||
baseDir, systemLanguage)
|
baseDir, systemLanguage,
|
||||||
|
httpPrefix, domainFull)
|
||||||
if sharesJson:
|
if sharesJson:
|
||||||
sharesFilename = \
|
sharesFilename = \
|
||||||
catalogsDir + '/' + federatedDomainFull + '.' + \
|
catalogsDir + '/' + federatedDomainFull + '.' + \
|
||||||
|
|
@ -1709,7 +1749,8 @@ def runFederatedSharesDaemon(baseDir: str, httpd, httpPrefix: str,
|
||||||
|
|
||||||
|
|
||||||
def _dfcToSharesFormat(catalogJson: {},
|
def _dfcToSharesFormat(catalogJson: {},
|
||||||
baseDir: str, systemLanguage: str) -> {}:
|
baseDir: str, systemLanguage: str,
|
||||||
|
httpPrefix: str, domainFull: str) -> {}:
|
||||||
"""Converts DFC format into the internal formal used to store shared items.
|
"""Converts DFC format into the internal formal used to store shared items.
|
||||||
This simplifies subsequent search and display
|
This simplifies subsequent search and display
|
||||||
"""
|
"""
|
||||||
|
|
@ -1720,7 +1761,8 @@ def _dfcToSharesFormat(catalogJson: {},
|
||||||
dfcIds = {}
|
dfcIds = {}
|
||||||
productTypesList = getCategoryTypes(baseDir)
|
productTypesList = getCategoryTypes(baseDir)
|
||||||
for productType in productTypesList:
|
for productType in productTypesList:
|
||||||
dfcIds[productType] = _loadDfcIds(baseDir, systemLanguage, productType)
|
dfcIds[productType] = _loadDfcIds(baseDir, systemLanguage, productType,
|
||||||
|
httpPrefix, domainFull)
|
||||||
|
|
||||||
currTime = int(time.time())
|
currTime = int(time.time())
|
||||||
for item in catalogJson['DFC:supplies']:
|
for item in catalogJson['DFC:supplies']:
|
||||||
|
|
@ -1731,7 +1773,6 @@ def _dfcToSharesFormat(catalogJson: {},
|
||||||
not item.get('DFC:expiryDate') or \
|
not item.get('DFC:expiryDate') or \
|
||||||
not item.get('DFC:quantity') or \
|
not item.get('DFC:quantity') or \
|
||||||
not item.get('DFC:price') or \
|
not item.get('DFC:price') or \
|
||||||
not item.get('DFC:Image') or \
|
|
||||||
not item.get('DFC:description'):
|
not item.get('DFC:description'):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
@ -1780,10 +1821,13 @@ def _dfcToSharesFormat(catalogJson: {},
|
||||||
itemID = item['@id']
|
itemID = item['@id']
|
||||||
description = item['DFC:description'].split(':', 1)[1].strip()
|
description = item['DFC:description'].split(':', 1)[1].strip()
|
||||||
|
|
||||||
|
imageUrl = ''
|
||||||
|
if item.get('DFC:Image'):
|
||||||
|
imageUrl = item['DFC:Image']
|
||||||
sharesJson[itemID] = {
|
sharesJson[itemID] = {
|
||||||
"displayName": item['DFC:description'].split(':')[0],
|
"displayName": item['DFC:description'].split(':')[0],
|
||||||
"summary": description,
|
"summary": description,
|
||||||
"imageUrl": item['DFC:Image'],
|
"imageUrl": imageUrl,
|
||||||
"itemQty": float(item['DFC:quantity']),
|
"itemQty": float(item['DFC:quantity']),
|
||||||
"dfcId": dfcId,
|
"dfcId": dfcId,
|
||||||
"itemType": itemType,
|
"itemType": itemType,
|
||||||
|
|
@ -1795,3 +1839,17 @@ def _dfcToSharesFormat(catalogJson: {},
|
||||||
"itemCurrency": item['DFC:price'].split(' ')[1]
|
"itemCurrency": item['DFC:price'].split(' ')[1]
|
||||||
}
|
}
|
||||||
return sharesJson
|
return sharesJson
|
||||||
|
|
||||||
|
|
||||||
|
def shareCategoryIcon(category: str) -> str:
|
||||||
|
"""Returns unicode icon for the given category
|
||||||
|
"""
|
||||||
|
categoryIcons = {
|
||||||
|
'accommodation': '🏠',
|
||||||
|
'clothes': '👚',
|
||||||
|
'tools': '🔧',
|
||||||
|
'food': '🍏'
|
||||||
|
}
|
||||||
|
if categoryIcons.get(category):
|
||||||
|
return categoryIcons[category]
|
||||||
|
return ''
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ __credits__ = ["webchk"]
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Core"
|
__module_group__ = "Core"
|
||||||
|
|
||||||
|
|
|
||||||
18
skills.py
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Profile Metadata"
|
__module_group__ = "Profile Metadata"
|
||||||
|
|
||||||
|
|
@ -177,7 +177,8 @@ def sendSkillViaServer(baseDir: str, session, nickname: str, password: str,
|
||||||
httpPrefix: str,
|
httpPrefix: str,
|
||||||
skill: str, skillLevelPercent: int,
|
skill: str, skillLevelPercent: int,
|
||||||
cachedWebfingers: {}, personCache: {},
|
cachedWebfingers: {}, personCache: {},
|
||||||
debug: bool, projectVersion: str) -> {}:
|
debug: bool, projectVersion: str,
|
||||||
|
signingPrivateKeyPem: str) -> {}:
|
||||||
"""Sets a skill for a person via c2s
|
"""Sets a skill for a person via c2s
|
||||||
"""
|
"""
|
||||||
if not session:
|
if not session:
|
||||||
|
|
@ -209,7 +210,8 @@ def sendSkillViaServer(baseDir: str, session, nickname: str, password: str,
|
||||||
wfRequest = \
|
wfRequest = \
|
||||||
webfingerHandle(session, handle, httpPrefix,
|
webfingerHandle(session, handle, httpPrefix,
|
||||||
cachedWebfingers,
|
cachedWebfingers,
|
||||||
domain, projectVersion, debug, False)
|
domain, projectVersion, debug, False,
|
||||||
|
signingPrivateKeyPem)
|
||||||
if not wfRequest:
|
if not wfRequest:
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: skill webfinger failed for ' + handle)
|
print('DEBUG: skill webfinger failed for ' + handle)
|
||||||
|
|
@ -222,12 +224,14 @@ def sendSkillViaServer(baseDir: str, session, nickname: str, password: str,
|
||||||
postToBox = 'outbox'
|
postToBox = 'outbox'
|
||||||
|
|
||||||
# get the actor inbox for the To handle
|
# get the actor inbox for the To handle
|
||||||
(inboxUrl, pubKeyId, pubKey,
|
originDomain = domain
|
||||||
fromPersonId, sharedInbox,
|
(inboxUrl, pubKeyId, pubKey, fromPersonId, sharedInbox, avatarUrl,
|
||||||
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
displayName, _) = getPersonBox(signingPrivateKeyPem,
|
||||||
|
originDomain,
|
||||||
|
baseDir, session, wfRequest,
|
||||||
personCache, projectVersion,
|
personCache, projectVersion,
|
||||||
httpPrefix, nickname, domain,
|
httpPrefix, nickname, domain,
|
||||||
postToBox, 86725)
|
postToBox, 76121)
|
||||||
|
|
||||||
if not inboxUrl:
|
if not inboxUrl:
|
||||||
if debug:
|
if debug:
|
||||||
|
|
|
||||||
18
socnet.py
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Moderation"
|
__module_group__ = "Moderation"
|
||||||
|
|
||||||
|
|
@ -18,7 +18,7 @@ def instancesGraph(baseDir: str, handles: str,
|
||||||
proxyType: str,
|
proxyType: str,
|
||||||
port: int, httpPrefix: str,
|
port: int, httpPrefix: str,
|
||||||
debug: bool, projectVersion: str,
|
debug: bool, projectVersion: str,
|
||||||
systemLanguage: str) -> str:
|
systemLanguage: str, signingPrivateKeyPem: str) -> str:
|
||||||
""" Returns a dot graph of federating instances
|
""" Returns a dot graph of federating instances
|
||||||
based upon a few sample handles.
|
based upon a few sample handles.
|
||||||
The handles argument should contain a comma separated list
|
The handles argument should contain a comma separated list
|
||||||
|
|
@ -54,7 +54,8 @@ def instancesGraph(baseDir: str, handles: str,
|
||||||
wfRequest = \
|
wfRequest = \
|
||||||
webfingerHandle(session, handle, httpPrefix,
|
webfingerHandle(session, handle, httpPrefix,
|
||||||
cachedWebfingers,
|
cachedWebfingers,
|
||||||
domain, projectVersion, debug, False)
|
domain, projectVersion, debug, False,
|
||||||
|
signingPrivateKeyPem)
|
||||||
if not wfRequest:
|
if not wfRequest:
|
||||||
return dotGraphStr + '}\n'
|
return dotGraphStr + '}\n'
|
||||||
if not isinstance(wfRequest, dict):
|
if not isinstance(wfRequest, dict):
|
||||||
|
|
@ -62,9 +63,11 @@ def instancesGraph(baseDir: str, handles: str,
|
||||||
str(wfRequest))
|
str(wfRequest))
|
||||||
return dotGraphStr + '}\n'
|
return dotGraphStr + '}\n'
|
||||||
|
|
||||||
(personUrl, pubKeyId, pubKey,
|
originDomain = None
|
||||||
personId, shaedInbox,
|
(personUrl, pubKeyId, pubKey, personId, shaedInbox, avatarUrl,
|
||||||
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
displayName, _) = getPersonBox(signingPrivateKeyPem,
|
||||||
|
originDomain,
|
||||||
|
baseDir, session, wfRequest,
|
||||||
personCache,
|
personCache,
|
||||||
projectVersion, httpPrefix,
|
projectVersion, httpPrefix,
|
||||||
nickname, domain, 'outbox',
|
nickname, domain, 'outbox',
|
||||||
|
|
@ -75,7 +78,8 @@ def instancesGraph(baseDir: str, handles: str,
|
||||||
maxAttachments, federationList,
|
maxAttachments, federationList,
|
||||||
personCache, debug,
|
personCache, debug,
|
||||||
projectVersion, httpPrefix, domain,
|
projectVersion, httpPrefix, domain,
|
||||||
wordFrequency, [], systemLanguage)
|
wordFrequency, [], systemLanguage,
|
||||||
|
signingPrivateKeyPem)
|
||||||
postDomains.sort()
|
postDomains.sort()
|
||||||
for fedDomain in postDomains:
|
for fedDomain in postDomains:
|
||||||
dotLineStr = ' "' + domain + '" -> "' + fedDomain + '";\n'
|
dotLineStr = ' "' + domain + '" -> "' + fedDomain + '";\n'
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ __author__ = "Bob Mottram"
|
||||||
__license__ = "AGPL3+"
|
__license__ = "AGPL3+"
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.0"
|
||||||
__maintainer__ = "Bob Mottram"
|
__maintainer__ = "Bob Mottram"
|
||||||
__email__ = "bob@freedombone.net"
|
__email__ = "bob@libreserver.org"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
__module_group__ = "Accessibility"
|
__module_group__ = "Accessibility"
|
||||||
|
|
||||||
|
|
@ -11,6 +11,7 @@ import os
|
||||||
import html
|
import html
|
||||||
import random
|
import random
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
|
from utils import removeIdEnding
|
||||||
from utils import isDM
|
from utils import isDM
|
||||||
from utils import isReply
|
from utils import isReply
|
||||||
from utils import camelCaseSplit
|
from utils import camelCaseSplit
|
||||||
|
|
@ -489,7 +490,7 @@ def _postToSpeakerJson(baseDir: str, httpPrefix: str,
|
||||||
announcedHandle + '. ' + content
|
announcedHandle + '. ' + content
|
||||||
postId = None
|
postId = None
|
||||||
if postJsonObject['object'].get('id'):
|
if postJsonObject['object'].get('id'):
|
||||||
postId = postJsonObject['object']['id']
|
postId = removeIdEnding(postJsonObject['object']['id'])
|
||||||
|
|
||||||
followRequestsExist = False
|
followRequestsExist = False
|
||||||
followRequestsList = []
|
followRequestsList = []
|
||||||
|
|
|
||||||