diff --git a/daemon.py b/daemon.py index a91879a98..05c9eb297 100644 --- a/daemon.py +++ b/daemon.py @@ -98,6 +98,11 @@ from follow import getFollowingFeed from follow import sendFollowRequest from follow import unfollowAccount from follow import createInitialLastSeen +from skills import getSkillsFromString +from skills import noOfActorSkills +from skills import actorHasSkill +from skills import actorSkillValue +from skills import setActorSkillLevel from auth import authorize from auth import createPassword from auth import createBasicAuthHeader @@ -4191,7 +4196,7 @@ class PubServer(BaseHTTPRequestHandler): # set skill levels skillCtr = 1 - newSkills = {} + actorSkillsCtr = noOfActorSkills(actorJson) while skillCtr < 10: skillName = \ fields.get('skillName' + str(skillCtr)) @@ -4206,21 +4211,20 @@ class PubServer(BaseHTTPRequestHandler): if not skillValue: skillCtr += 1 continue - if not actorJson['skills'].get(skillName): + if not actorHasSkill(actorJson, skillName): actorChanged = True else: - if actorJson['skills'][skillName] != \ + if actorSkillValue(actorJson, skillName) != \ int(skillValue): actorChanged = True - newSkills[skillName] = int(skillValue) + setActorSkillLevel(actorJson, skillName, skillValue) skillsStr = self.server.translate['Skills'] setHashtagCategory(baseDir, skillName, skillsStr.lower()) skillCtr += 1 - if len(actorJson['skills'].items()) != \ - len(newSkills.items()): + if noOfActorSkills(actorJson) != \ + actorSkillsCtr: actorChanged = True - actorJson['skills'] = newSkills # change password if fields.get('password'): @@ -7461,7 +7465,7 @@ class PubServer(BaseHTTPRequestHandler): if os.path.isfile(actorFilename): actorJson = loadJson(actorFilename) if actorJson: - if actorJson.get('skills'): + if noOfActorSkills(actorJson) > 0: if self._requestHTTP(): getPerson = \ personLookup(domain, @@ -7486,6 +7490,9 @@ class PubServer(BaseHTTPRequestHandler): if self.server.keyShortcuts.get(nickname): accessKeys = \ self.server.keyShortcuts[nickname] + actorSkillsStr = \ + actorJson['hasOccupation']['skills'] + skills = getSkillsFromString(actorSkillsStr) msg = \ htmlProfile(self.server.rssIconAtTop, self.server.cssCache, @@ -7509,8 +7516,7 @@ class PubServer(BaseHTTPRequestHandler): allowLocalNetworkAccess, self.server.textModeBanner, self.server.debug, - accessKeys, - actorJson['skills'], + accessKeys, skills, None, None) msg = msg.encode('utf-8') msglen = len(msg) @@ -7523,7 +7529,10 @@ class PubServer(BaseHTTPRequestHandler): 'show skills') else: if self._fetchAuthenticated(): - msg = json.dumps(actorJson['skills'], + actorSkillsStr = \ + actorJson['hasOccupation']['skills'] + skills = getSkillsFromString(actorSkillsStr) + msg = json.dumps(skills, ensure_ascii=False) msg = msg.encode('utf-8') msglen = len(msg) diff --git a/person.py b/person.py index 60c064ae6..c029a81ec 100644 --- a/person.py +++ b/person.py @@ -279,9 +279,8 @@ def _createPersonBase(baseDir: str, nickname: str, domain: str, port: int, 'hasOccupation': { '@type': 'Occupation', 'name': "", - 'skills': "", + 'skills': "" }, - 'skills': {}, 'roles': {}, 'availability': None, 'icon': { @@ -317,7 +316,8 @@ def _createPersonBase(baseDir: str, nickname: str, domain: str, port: int, del newPerson['outbox'] del newPerson['icon'] del newPerson['image'] - del newPerson['skills'] + if newPerson.get('skills'): + del newPerson['skills'] del newPerson['shares'] del newPerson['roles'] del newPerson['tag'] @@ -574,10 +574,14 @@ def personUpgradeActor(baseDir: str, personJson: {}, personJson['hasOccupation'] = { '@type': 'Occupation', 'name': occupationName, - 'skills': "", + 'skills': "" } updateActor = True + if personJson.get('skills'): + del personJson['skills'] + updateActor = True + if updateActor: personJson['@context'] = [ 'https://www.w3.org/ns/activitystreams', diff --git a/skills.py b/skills.py index 0609bfd5a..00d258d09 100644 --- a/skills.py +++ b/skills.py @@ -15,7 +15,89 @@ from utils import getFullDomain from utils import getNicknameFromActor from utils import getDomainFromActor from utils import loadJson -from utils import saveJson + + +def _setSkillsFromDict(actorJson: {}, skills: {}) -> None: + """Converts a dict containing skills to a string + """ + skillsStr = '' + for name, value in skills.items(): + if skillsStr: + skillsStr += ', ' + skillsStr += name + ':' + str(value) + return skillsStr + + +def getSkillsFromString(skillsStr: str) -> {}: + """Returns a dict of skills from a string + """ + skillsList = skillsStr.split(',') + skills = {} + for skill in skillsList: + if ':' not in skill: + continue + name = skill.split(':')[0].strip().lower() + valueStr = skill.split(':')[1] + if not valueStr.isdigit(): + continue + skills[name] = int(valueStr) + return skills + + +def actorHasSkill(actorJson: {}, skillName: str) -> bool: + """Returns true if the actor has the given skill + """ + skills = getSkillsFromString(actorJson['hasOccupation']['skills']) + if not skills: + return False + return skills.get(skillName.lower()) + + +def actorSkillValue(actorJson: {}, skillName: str) -> int: + """Returns The skill level from an actor + """ + skills = getSkillsFromString(actorJson['hasOccupation']['skills']) + if not skills: + return 0 + skillName = skillName.lower() + if skills.get(skillName): + return skills[skillName] + return 0 + + +def noOfActorSkills(actorJson: {}) -> int: + """Returns the number of skills that an actor has + """ + if actorJson.get('hasOccupation'): + skillsList = actorJson['hasOccupation']['skills'].split(',') + if skillsList: + return int(skillsList) + return 0 + + +def setActorSkillLevel(actorJson: {}, + skill: str, skillLevelPercent: int) -> bool: + """Set a skill level for a person + Setting skill level to zero removes it + """ + if skillLevelPercent < 0 or skillLevelPercent > 100: + return False + + if actorJson: + if not actorJson.get('hasOccupation'): + actorJson['hasOccupation'] = { + '@type': 'Occupation', + 'name': '', + 'skills': '' + } + skills = getSkillsFromString(actorJson['hasOccupation']['skills']) + if skillLevelPercent > 0: + skills[skill] = skillLevelPercent + else: + if skills.get(skill): + del skills[skill] + _setSkillsFromDict(actorJson, skills) + return True def setSkillLevel(baseDir: str, nickname: str, domain: str, @@ -30,15 +112,8 @@ def setSkillLevel(baseDir: str, nickname: str, domain: str, return False actorJson = loadJson(actorFilename) - if actorJson: - if not actorJson.get('skills'): - actorJson['skills'] = {} - if skillLevelPercent > 0: - actorJson['skills'][skill] = skillLevelPercent - else: - del actorJson['skills'][skill] - saveJson(actorJson, actorFilename) - return True + return setActorSkillLevel(actorJson, + skill, skillLevelPercent) def getSkills(baseDir: str, nickname: str, domain: str) -> []: @@ -50,9 +125,9 @@ def getSkills(baseDir: str, nickname: str, domain: str) -> []: actorJson = loadJson(actorFilename) if actorJson: - if not actorJson.get('skills'): + if not actorJson.get('hasOccupation'): return None - return actorJson['skills'] + return getSkillsFromString(actorJson['hasOccupation']['skills']) return None @@ -112,7 +187,7 @@ def sendSkillViaServer(baseDir: str, session, nickname: str, password: str, newSkillJson = { 'type': 'Skill', 'actor': actor, - 'object': '"'+skillStr+'"', + 'object': '"' + skillStr + '"', 'to': [toUrl], 'cc': [ccUrl] } diff --git a/webapp_search.py b/webapp_search.py index 7148e57d2..131d019a3 100644 --- a/webapp_search.py +++ b/webapp_search.py @@ -20,6 +20,8 @@ from utils import locatePost from utils import isPublicPost from utils import firstParagraphFromString from utils import searchBoxPosts +from skills import noOfActorSkills +from skills import getSkillsFromString from categories import getHashtagCategory from feeds import rss2TagHeader from feeds import rss2TagFooter @@ -414,11 +416,13 @@ def htmlSkillsSearch(actor: str, actorJson = loadJson(actorFilename) if actorJson: if actorJson.get('id') and \ - actorJson.get('skills') and \ + noOfActorSkills(actorJson) > 0 and \ actorJson.get('name') and \ actorJson.get('icon'): actor = actorJson['id'] - for skillName, skillLevel in actorJson['skills'].items(): + actorSkillsStr = actorJson['hasOccupation']['skills'] + skills = getSkillsFromString(actorSkillsStr) + for skillName, skillLevel in skills.items(): skillName = skillName.lower() if not (skillName in skillsearch or skillsearch in skillName): @@ -453,12 +457,14 @@ def htmlSkillsSearch(actor: str, if cachedActorJson.get('actor'): actorJson = cachedActorJson['actor'] if actorJson.get('id') and \ - actorJson.get('skills') and \ + noOfActorSkills(actorJson) > 0 and \ actorJson.get('name') and \ actorJson.get('icon'): actor = actorJson['id'] - for skillName, skillLevel in \ - actorJson['skills'].items(): + actorSkillsStr = \ + actorJson['hasOccupation']['skills'] + skills = getSkillsFromString(actorSkillsStr) + for skillName, skillLevel in skills.items(): skillName = skillName.lower() if not (skillName in skillsearch or skillsearch in skillName): diff --git a/webapp_utils.py b/webapp_utils.py index 65c68b87f..ba812dccb 100644 --- a/webapp_utils.py +++ b/webapp_utils.py @@ -720,18 +720,11 @@ def htmlHeaderWithPersonMarkup(cssFilename: str, instanceTitle: str, return htmlStr skillsMarkup = '' - if actorJson.get('skills'): - skillsStr = '' - for skillName, skillValue in actorJson['skills'].items(): - if skillsStr: - skillsStr += ', ' + skillName - else: - skillsStr += skillName - if skillsStr: - occupationStr = '' - if actorJson.get('occupationName'): - occupationName = actorJson['occupationName'] - occupationStr = ' "name": "' + occupationName + '",\n' + if actorJson.get('hasOccupation'): + skillsStr = actorJson['hasOccupation']['skills'] + if actorJson['hasOccupation'].get('name'): + occupationName = actorJson['hasOccupation']['name'] + occupationStr = ' "name": "' + occupationName + '",\n' skillsMarkup = \ ' "hasOccupation": {\n' + \ ' "@type": "Occupation",\n' + \