diff --git a/daemon.py b/daemon.py
index b54fd2b07..888c363b0 100644
--- a/daemon.py
+++ b/daemon.py
@@ -123,6 +123,7 @@ from blocking import removeGlobalBlock
from blocking import isBlockedHashtag
from blocking import isBlockedDomain
from blocking import getDomainBlocklist
+from roles import getActorRolesList
from roles import setRole
from roles import clearModeratorStatus
from roles import clearEditorStatus
@@ -200,6 +201,8 @@ from shares import addShare
from shares import removeShare
from shares import expireShares
from categories import setHashtagCategory
+from utils import getOccupationName
+from utils import setOccupationName
from utils import loadTranslationsFromFile
from utils import getLocalNetworkAddresses
from utils import decodedHost
@@ -4581,21 +4584,18 @@ class PubServer(BaseHTTPRequestHandler):
actorChanged = True
# Other accounts (alsoKnownAs)
- occupationName = ""
- if actorJson.get('hasOccupation'):
- if actorJson['hasOccupation'].get('name'):
- occupationName = actorJson['hasOccupation']['name']
+ occupationName = getOccupationName(actorJson)
if fields.get('occupationName'):
fields['occupationName'] = \
removeHtml(fields['occupationName'])
if occupationName != \
fields['occupationName']:
- actorJson['hasOccupation']['name'] = \
- fields['occupationName']
+ setOccupationName(actorJson,
+ fields['occupationName'])
actorChanged = True
else:
if occupationName:
- actorJson['hasOccupation']['name'] = ''
+ setOccupationName(actorJson, '')
actorChanged = True
# Other accounts (alsoKnownAs)
@@ -7373,7 +7373,7 @@ class PubServer(BaseHTTPRequestHandler):
if not actorJson:
return False
- if actorJson.get('affiliation'):
+ if actorJson.get('hasOccupation'):
if self._requestHTTP():
getPerson = \
personLookup(domain, path.replace('/roles', ''),
@@ -7394,11 +7394,7 @@ class PubServer(BaseHTTPRequestHandler):
if self.server.keyShortcuts.get(nickname):
accessKeys = self.server.keyShortcuts[nickname]
- rolesList = []
- if actorJson.get('affiliation'):
- if isinstance(actorJson['affiliation']['roleName'],
- list):
- rolesList = actorJson['affiliation']['roleName']
+ rolesList = getActorRolesList(actorJson)
city = self._getSpoofedCity(baseDir, nickname, domain)
msg = \
htmlProfile(self.server.rssIconAtTop,
@@ -7435,12 +7431,7 @@ class PubServer(BaseHTTPRequestHandler):
'show roles')
else:
if self._fetchAuthenticated():
- rolesList = []
- if actorJson.get('affiliation'):
- if isinstance(actorJson['affiliation']['roleName'],
- list):
- rolesList = actorJson['affiliation']['roleName']
-
+ rolesList = getActorRolesList(actorJson)
msg = json.dumps(rolesList,
ensure_ascii=False)
msg = msg.encode('utf-8')
diff --git a/person.py b/person.py
index 747847787..ea7b228b2 100644
--- a/person.py
+++ b/person.py
@@ -34,6 +34,8 @@ from posts import createModeration
from auth import storeBasicCredentials
from auth import removePassword
from roles import setRole
+from roles import setRolesFromList
+from roles import getActorRolesList
from media import processMetaData
from utils import getStatusNumber
from utils import getFullDomain
@@ -201,10 +203,12 @@ def getDefaultPersonContext() -> str:
'toot': 'http://joinmastodon.org/ns#',
'value': 'schema:value',
'hasOccupation': 'schema:hasOccupation',
- 'affiliation': 'schema:affiliation',
'Occupation': 'schema:Occupation',
- 'OrganizationRole': 'schema:OrganizationRole',
- 'WebSite': 'schema:Project'
+ 'occupationalCategory': 'schema:occupationalCategory',
+ 'Role': 'schema:Role',
+ 'WebSite': 'schema:Project',
+ 'CategoryCode': 'schema:CategoryCode',
+ 'CategoryCodeSet': 'schema:CategoryCodeSet'
}
@@ -280,20 +284,13 @@ def _createPersonBase(baseDir: str, nickname: str, domain: str, port: int,
'following': personId + '/following',
'tts': personId + '/speaker',
'shares': personId + '/shares',
- 'hasOccupation': {
- '@type': 'Occupation',
- 'name': "",
- 'skills': []
- },
- "affiliation": {
- "@type": "OrganizationRole",
- "roleName": [],
- "affiliation": {
- "@type": "WebSite",
- "url": httpPrefix + '://' + domain
- },
- "startDate": published
- },
+ 'hasOccupation': [
+ {
+ '@type': 'Occupation',
+ 'name': "",
+ 'skills': []
+ }
+ ],
'availability': None,
'icon': {
'mediaType': 'image/png',
@@ -587,16 +584,13 @@ def personUpgradeActor(baseDir: str, personJson: {},
# if the older skills format is being used then switch
# to the new one
if not personJson.get('hasOccupation'):
- personJson['hasOccupation'] = {
- '@type': 'Occupation',
- 'name': occupationName,
- 'skills': []
- }
- updateActor = True
-
- if isinstance(personJson['hasOccupation']['skills'], str):
- skillsList = personJson['hasOccupation']['skills'].split(', ')
- personJson['hasOccupation']['skills'] = skillsList
+ personJson['hasOccupation'] = [
+ {
+ '@type': 'Occupation',
+ 'name': occupationName,
+ 'skills': []
+ }
+ ]
updateActor = True
# remove the old skills format
@@ -606,36 +600,29 @@ def personUpgradeActor(baseDir: str, personJson: {},
# if the older roles format is being used then switch
# to the new one
- if not personJson.get('affiliation'):
- rolesList = []
- adminName = getConfigParam(baseDir, 'admin')
- if personJson['id'].endswith('/users/' + adminName):
- rolesList = ["admin", "moderator", "editor"]
- statusNumber, published = getStatusNumber()
- personJson['affiliation'] = {
- "@type": "OrganizationRole",
- "roleName": rolesList,
- "affiliation": {
- "@type": "WebSite",
- "url": personJson['id'].split('/users/')[0]
- },
- "startDate": published
- }
+ if personJson.get('affiliation'):
+ del personJson['affiliation']
updateActor = True
- if isinstance(personJson['affiliation']['roleName'], str):
- rolesList = personJson['affiliation']['roleName'].split(', ')
- personJson['affiliation']['roleName'] = rolesList
+ if not isinstance(personJson['hasOccupation'], list):
+ personJson['hasOccupation'] = [
+ {
+ '@type': 'Occupation',
+ 'name': occupationName,
+ 'skills': []
+ }
+ ]
updateActor = True
# if no roles are defined then ensure that the admin
# roles are configured
- if not personJson['affiliation']['roleName']:
+ rolesList = getActorRolesList(personJson)
+ if not rolesList:
adminName = getConfigParam(baseDir, 'admin')
if personJson['id'].endswith('/users/' + adminName):
- personJson['affiliation']['roleName'] = \
- ["admin", "moderator", "editor"]
- updateActor = True
+ rolesList = ["admin", "moderator", "editor"]
+ setRolesFromList(personJson, rolesList)
+ updateActor = True
# remove the old roles format
if personJson.get('roles'):
diff --git a/roles.py b/roles.py
index 3a59d21c3..3655c99e9 100644
--- a/roles.py
+++ b/roles.py
@@ -9,6 +9,7 @@ __status__ = "Production"
import os
from utils import loadJson
from utils import saveJson
+from utils import getStatusNumber
def _clearRoleStatus(baseDir: str, role: str) -> None:
@@ -30,12 +31,10 @@ def _clearRoleStatus(baseDir: str, role: str) -> None:
actorJson = loadJson(filename)
if not actorJson:
continue
- if not actorJson.get('affiliation'):
- continue
- rolesList = \
- getRolesFromList(actorJson['affiliation']['roleName'])
+ rolesList = getActorRolesList(actorJson)
if role in rolesList:
rolesList.remove(role)
+ setRolesFromList(actorJson, rolesList)
saveJson(actorJson, filename)
@@ -65,7 +64,8 @@ def clearModeratorStatus(baseDir: str) -> None:
def _addRole(baseDir: str, nickname: str, domain: str,
roleFilename: str) -> None:
- """Adds a role nickname to the file
+ """Adds a role nickname to the file.
+ This is a file containing the nicknames of accounts having this role
"""
if ':' in domain:
domain = domain.split(':')[0]
@@ -94,7 +94,8 @@ def _addRole(baseDir: str, nickname: str, domain: str,
def _removeRole(baseDir: str, nickname: str, roleFilename: str) -> None:
- """Removes a role nickname from the file
+ """Removes a role nickname from the file.
+ This is a file containing the nicknames of accounts having this role
"""
roleFile = baseDir + '/accounts/' + roleFilename
if not os.path.isfile(roleFile):
@@ -108,24 +109,99 @@ def _removeRole(baseDir: str, nickname: str, roleFilename: str) -> None:
f.write(roleNickname + '\n')
+def _setActorRole(actorJson: {}, roleName: str) -> bool:
+ """Sets a role for an actor
+ """
+ if not actorJson.get('hasOccupation'):
+ return False
+ if not isinstance(actorJson['hasOccupation'], list):
+ return False
+
+ category = None
+ if 'admin' in roleName:
+ category = '15-1299.01'
+ elif 'moderator' in roleName:
+ category = '11-9199.02'
+ elif 'editor' in roleName:
+ category = '27-3041.00'
+ elif 'counselor' in roleName:
+ category = '23-1022.00'
+ if not category:
+ return False
+
+ for index in range(len(actorJson['hasOccupation'])):
+ occupationItem = actorJson['hasOccupation'][index]
+ if not isinstance(occupationItem, dict):
+ continue
+ if not occupationItem.get('@type'):
+ continue
+ if occupationItem['@type'] != 'Role':
+ continue
+ if occupationItem['hasOccupation']['name'] == roleName:
+ return True
+ statusNumber, published = getStatusNumber()
+ newRole = {
+ "@type": "Role",
+ "hasOccupation": {
+ "@type": "Occupation",
+ "name": roleName,
+ "occupationalCategory": {
+ "@type": "CategoryCode",
+ "inCodeSet": {
+ "@type": "CategoryCodeSet",
+ "name": "O*Net-SOC",
+ "dateModified": "2019",
+ "url": "https://www.onetonline.org/"
+ },
+ "codeValue": category,
+ "url": "https://www.onetonline.org/link/summary/" + category
+ }
+ },
+ "startDate": published
+ }
+ actorJson['hasOccupation'].append(newRole)
+ return True
+
+
def setRolesFromList(actorJson: {}, rolesList: []) -> None:
"""Sets roles from a list
"""
- if actorJson.get('affiliation'):
- actorJson['affiliation']['roleName'] = rolesList.copy()
+ # clear Roles from the occupation list
+ emptyRolesList = []
+ for occupationItem in actorJson['hasOccupation']:
+ if not isinstance(occupationItem, dict):
+ continue
+ if not occupationItem.get('@type'):
+ continue
+ if occupationItem['@type'] == 'Role':
+ continue
+ emptyRolesList.append(occupationItem)
+ actorJson['hasOccupation'] = emptyRolesList
+
+ # create the new list
+ for roleName in rolesList:
+ _setActorRole(actorJson, roleName)
-def getRolesFromList(rolesList: []) -> []:
- """Returns a list of roles from a list
+def getActorRolesList(actorJson: {}) -> []:
+ """Gets a list of role names from an actor
"""
- if isinstance(rolesList, list):
- rolesList2 = rolesList
- else:
- rolesList2 = rolesList.split(',')
- rolesResult = []
- for roleName in rolesList2:
- rolesResult.append(roleName.strip().lower())
- return rolesResult
+ if not actorJson.get('hasOccupation'):
+ return []
+ if not isinstance(actorJson['hasOccupation'], list):
+ return []
+ rolesList = []
+ for occupationItem in actorJson['hasOccupation']:
+ if not isinstance(occupationItem, dict):
+ continue
+ if not occupationItem.get('@type'):
+ continue
+ if occupationItem['@type'] != 'Role':
+ continue
+ roleName = occupationItem['hasOccupation']['name']
+ if roleName not in rolesList:
+ rolesList.append(roleName)
+ return rolesList
def setRole(baseDir: str, nickname: str, domain: str,
@@ -149,10 +225,9 @@ def setRole(baseDir: str, nickname: str, domain: str,
actorJson = loadJson(actorFilename)
if actorJson:
- if not actorJson.get('affiliation'):
+ if not actorJson.get('hasOccupation'):
return False
- rolesList = \
- getRolesFromList(actorJson['affiliation']['roleName'])
+ rolesList = getActorRolesList(actorJson)
actorChanged = False
if role:
# add the role
@@ -174,3 +249,10 @@ def setRole(baseDir: str, nickname: str, domain: str,
if actorChanged:
saveJson(actorJson, actorFilename)
return True
+
+
+def actorHasRole(actorJson: {}, roleName: str) -> bool:
+ """Returns true if the given actor has the given role
+ """
+ rolesList = getActorRolesList(actorJson)
+ return roleName in rolesList
diff --git a/skills.py b/skills.py
index 8105cc5c0..c97c678fd 100644
--- a/skills.py
+++ b/skills.py
@@ -15,16 +15,18 @@ from utils import getFullDomain
from utils import getNicknameFromActor
from utils import getDomainFromActor
from utils import loadJson
+from utils import getOccupationSkills
+from utils import setOccupationSkillsList
def setSkillsFromDict(actorJson: {}, skillsDict: {}) -> []:
- """Converts a dict containing skills to a string
+ """Converts a dict containing skills to a list
Returns the string version of the dictionary
"""
skillsList = []
for name, value in skillsDict.items():
skillsList.append(name + ':' + str(value))
- actorJson['hasOccupation']['skills'] = skillsList
+ setOccupationSkillsList(actorJson, skillsList)
return skillsList
@@ -47,21 +49,11 @@ def getSkillsFromList(skillsList: []) -> {}:
return skillsDict
-def actorHasSkill(actorJson: {}, skillName: str) -> bool:
- """Returns true if the actor has the given skill
- """
- skillsDict = \
- getSkillsFromList(actorJson['hasOccupation']['skills'])
- if not skillsDict:
- return False
- return skillsDict.get(skillName.lower())
-
-
def actorSkillValue(actorJson: {}, skillName: str) -> int:
"""Returns The skill level from an actor
"""
- skillsDict = \
- getSkillsFromList(actorJson['hasOccupation']['skills'])
+ ocSkillsList = getOccupationSkills(actorJson)
+ skillsDict = getSkillsFromList(ocSkillsList)
if not skillsDict:
return 0
skillName = skillName.lower()
@@ -74,13 +66,8 @@ def noOfActorSkills(actorJson: {}) -> int:
"""Returns the number of skills that an actor has
"""
if actorJson.get('hasOccupation'):
- skillsStr = actorJson['hasOccupation']['skills']
- if isinstance(skillsStr, list):
- skillsList = skillsStr
- else:
- skillsList = skillsStr.split(',')
- if skillsList:
- return len(skillsList)
+ skillsList = getOccupationSkills(actorJson)
+ return len(skillsList)
return 0
@@ -95,13 +82,15 @@ def setActorSkillLevel(actorJson: {},
if not actorJson:
return True
if not actorJson.get('hasOccupation'):
- actorJson['hasOccupation'] = {
- '@type': 'Occupation',
- 'name': '',
- 'skills': ''
- }
- skillsDict = \
- getSkillsFromList(actorJson['hasOccupation']['skills'])
+ actorJson['hasOccupation'] = [
+ {
+ '@type': 'Occupation',
+ 'name': '',
+ 'skills': []
+ }
+ ]
+ ocSkillsList = getOccupationSkills(actorJson)
+ skillsDict = getSkillsFromList(ocSkillsList)
if skillLevelPercent > 0:
skillsDict[skill] = skillLevelPercent
else:
@@ -138,7 +127,8 @@ def getSkills(baseDir: str, nickname: str, domain: str) -> []:
if actorJson:
if not actorJson.get('hasOccupation'):
return None
- return getSkillsFromList(actorJson['hasOccupation']['skills'])
+ ocSkillsList = getOccupationSkills(actorJson)
+ return getSkillsFromList(ocSkillsList)
return None
@@ -258,3 +248,13 @@ def sendSkillViaServer(baseDir: str, session, nickname: str, password: str,
print('DEBUG: c2s POST skill success')
return newSkillJson
+
+
+def actorHasSkill(actorJson: {}, skillName: str) -> bool:
+ """Returns true if the given actor has the given skill
+ """
+ ocSkillsList = getOccupationSkills(actorJson)
+ for skillStr in ocSkillsList:
+ if skillName + ':' in skillStr:
+ return True
+ return False
diff --git a/tests.py b/tests.py
index 4a3d84fe3..5b22e7860 100644
--- a/tests.py
+++ b/tests.py
@@ -67,11 +67,12 @@ from person import setDisplayNickname
from person import setBio
# from person import generateRSAKey
from skills import setSkillLevel
+from skills import actorSkillValue
from skills import setSkillsFromDict
-from skills import getSkillsFromList
+from skills import actorHasSkill
from roles import setRolesFromList
-from roles import getRolesFromList
from roles import setRole
+from roles import actorHasRole
from auth import constantTimeStringCheck
from auth import createBasicAuthHeader
from auth import authorizeBasic
@@ -3661,44 +3662,42 @@ def testSpoofGeolocation() -> None:
def testSkills() -> None:
print('testSkills')
actorJson = {
- 'hasOccupation': {
- '@type': 'Occupation',
- 'name': "",
- 'skills': []
- }
+ 'hasOccupation': [
+ {
+ '@type': 'Occupation',
+ 'name': "Sysop",
+ 'skills': []
+ }
+ ]
}
skillsDict = {
'bakery': 40,
'gardening': 70
}
setSkillsFromDict(actorJson, skillsDict)
- assert actorJson['hasOccupation']['skills']
- skillsDict = getSkillsFromList(actorJson['hasOccupation']['skills'])
- assert skillsDict.get('bakery')
- assert skillsDict.get('gardening')
- assert skillsDict['bakery'] == 40
- assert skillsDict['gardening'] == 70
+ assert actorHasSkill(actorJson, 'bakery')
+ assert actorHasSkill(actorJson, 'gardening')
+ assert actorSkillValue(actorJson, 'bakery') == 40
+ assert actorSkillValue(actorJson, 'gardening') == 70
def testRoles() -> None:
print('testRoles')
actorJson = {
- 'affiliation': {
- "@type": "OrganizationRole",
- "roleName": [],
- "affiliation": {
- "@type": "WebSite",
- "url": "https://testinstance.org"
- },
- "startDate": "date goes here"
- }
+ 'hasOccupation': [
+ {
+ '@type': 'Occupation',
+ 'name': "Sysop",
+ 'skills': []
+ }
+ ]
}
testRolesList = ["admin", "moderator"]
setRolesFromList(actorJson, testRolesList)
- assert actorJson['affiliation']['roleName']
- rolesList = getRolesFromList(actorJson['affiliation']['roleName'])
- assert 'admin' in rolesList
- assert 'moderator' in rolesList
+ assert actorHasRole(actorJson, "admin")
+ assert actorHasRole(actorJson, "moderator")
+ assert not actorHasRole(actorJson, "editor")
+ assert not actorHasRole(actorJson, "counselor")
def runAllTests():
diff --git a/utils.py b/utils.py
index 5b4ef6bd9..c478158d7 100644
--- a/utils.py
+++ b/utils.py
@@ -2279,3 +2279,89 @@ def dmAllowedFromDomain(baseDir: str,
if sendingActorDomain + '\n' in open(dmAllowedInstancesFilename).read():
return True
return False
+
+
+def getOccupationSkills(actorJson: {}) -> []:
+ """Returns the list of skills for an actor
+ """
+ if 'hasOccupation' not in actorJson:
+ return []
+ if not isinstance(actorJson['hasOccupation'], list):
+ return []
+ for occupationItem in actorJson['hasOccupation']:
+ if not isinstance(occupationItem, dict):
+ continue
+ if not occupationItem.get('@type'):
+ continue
+ if not occupationItem['@type'] == 'Occupation':
+ continue
+ if not occupationItem.get('skills'):
+ continue
+ if isinstance(occupationItem['skills'], list):
+ return occupationItem['skills']
+ elif isinstance(occupationItem['skills'], str):
+ return [occupationItem['skills']]
+ break
+ return []
+
+
+def getOccupationName(actorJson: {}) -> str:
+ """Returns the occupation name an actor
+ """
+ if not actorJson.get('hasOccupation'):
+ return ""
+ if not isinstance(actorJson['hasOccupation'], list):
+ return ""
+ for occupationItem in actorJson['hasOccupation']:
+ if not isinstance(occupationItem, dict):
+ continue
+ if not occupationItem.get('@type'):
+ continue
+ if occupationItem['@type'] != 'Occupation':
+ continue
+ if not occupationItem.get('name'):
+ continue
+ if isinstance(occupationItem['name'], str):
+ return occupationItem['name']
+ break
+ return ""
+
+
+def setOccupationName(actorJson: {}, name: str) -> bool:
+ """Sets the occupation name of an actor
+ """
+ if not actorJson.get('hasOccupation'):
+ return False
+ if not isinstance(actorJson['hasOccupation'], list):
+ return False
+ for index in range(len(actorJson['hasOccupation'])):
+ occupationItem = actorJson['hasOccupation'][index]
+ if not isinstance(occupationItem, dict):
+ continue
+ if not occupationItem.get('@type'):
+ continue
+ if occupationItem['@type'] != 'Occupation':
+ continue
+ occupationItem['name'] = name
+ return True
+ return False
+
+
+def setOccupationSkillsList(actorJson: {}, skillsList: []) -> bool:
+ """Sets the occupation skills for an actor
+ """
+ if 'hasOccupation' not in actorJson:
+ return False
+ if not isinstance(actorJson['hasOccupation'], list):
+ return False
+ for index in range(len(actorJson['hasOccupation'])):
+ occupationItem = actorJson['hasOccupation'][index]
+ if not isinstance(occupationItem, dict):
+ continue
+ if not occupationItem.get('@type'):
+ continue
+ if occupationItem['@type'] != 'Occupation':
+ continue
+ occupationItem['skills'] = skillsList
+ return True
+ return False
diff --git a/webapp_profile.py b/webapp_profile.py
index 5a8baffa4..5ec33c1c9 100644
--- a/webapp_profile.py
+++ b/webapp_profile.py
@@ -8,6 +8,7 @@ __status__ = "Production"
import os
from pprint import pprint
+from utils import getOccupationName
from utils import getLockedAccount
from utils import hasUsersPath
from utils import getFullDomain
@@ -741,8 +742,7 @@ def htmlProfile(rssIconAtTop: bool,
joinedDate = profileJson['published']
occupationName = None
if profileJson.get('hasOccupation'):
- if profileJson['hasOccupation'].get('name'):
- occupationName = profileJson['hasOccupation']['name']
+ occupationName = getOccupationName(profileJson)
avatarUrl = profileJson['icon']['url']
@@ -1602,8 +1602,7 @@ def htmlEditProfile(cssCache: {}, translate: {}, baseDir: str, path: str,
occupationName = ''
if actorJson.get('hasOccupation'):
- if actorJson['hasOccupation'].get('name'):
- occupationName = actorJson['hasOccupation']['name']
+ occupationName = getOccupationName(actorJson)
editProfileForm += '
\n'