| 
									
										
										
										
											2020-04-04 11:35:55 +00:00
										 |  |  | __filename__ = "skills.py" | 
					
						
							|  |  |  | __author__ = "Bob Mottram" | 
					
						
							|  |  |  | __license__ = "AGPL3+" | 
					
						
							|  |  |  | __version__ = "1.1.0" | 
					
						
							|  |  |  | __maintainer__ = "Bob Mottram" | 
					
						
							|  |  |  | __email__ = "bob@freedombone.net" | 
					
						
							|  |  |  | __status__ = "Production" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-19 10:01:24 +00:00
										 |  |  | import os | 
					
						
							|  |  |  | from webfinger import webfingerHandle | 
					
						
							|  |  |  | from auth import createBasicAuthHeader | 
					
						
							|  |  |  | from posts import getPersonBox | 
					
						
							|  |  |  | from session import postJson | 
					
						
							|  |  |  | from utils import getNicknameFromActor | 
					
						
							|  |  |  | from utils import getDomainFromActor | 
					
						
							| 
									
										
										
										
											2019-10-22 11:55:06 +00:00
										 |  |  | from utils import loadJson | 
					
						
							|  |  |  | from utils import saveJson | 
					
						
							| 
									
										
										
										
											2019-07-19 10:01:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 11:35:55 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def setSkillLevel(baseDir: str, nickname: str, domain: str, | 
					
						
							|  |  |  |                   skill: str, skillLevelPercent: int) -> bool: | 
					
						
							| 
									
										
										
										
											2019-07-19 10:01:24 +00:00
										 |  |  |     """Set a skill level for a person
 | 
					
						
							|  |  |  |     Setting skill level to zero removes it | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-04 11:35:55 +00:00
										 |  |  |     if skillLevelPercent < 0 or skillLevelPercent > 100: | 
					
						
							| 
									
										
										
										
											2019-07-19 10:01:24 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2020-04-04 11:35:55 +00:00
										 |  |  |     actorFilename = baseDir + '/accounts/' + nickname + '@' + domain + '.json' | 
					
						
							| 
									
										
										
										
											2019-07-19 10:01:24 +00:00
										 |  |  |     if not os.path.isfile(actorFilename): | 
					
						
							|  |  |  |         return False | 
					
						
							| 
									
										
										
										
											2019-09-30 22:39:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 11:35:55 +00:00
										 |  |  |     actorJson = loadJson(actorFilename) | 
					
						
							| 
									
										
										
										
											2019-09-30 22:39:02 +00:00
										 |  |  |     if actorJson: | 
					
						
							| 
									
										
										
										
											2019-07-19 10:01:24 +00:00
										 |  |  |         if not actorJson.get('skills'): | 
					
						
							| 
									
										
										
										
											2020-04-04 11:35:55 +00:00
										 |  |  |             actorJson['skills'] = {} | 
					
						
							|  |  |  |         if skillLevelPercent > 0: | 
					
						
							|  |  |  |             actorJson['skills'][skill] = skillLevelPercent | 
					
						
							| 
									
										
										
										
											2019-07-19 10:01:24 +00:00
										 |  |  |         else: | 
					
						
							|  |  |  |             del actorJson['skills'][skill] | 
					
						
							| 
									
										
										
										
											2020-04-04 11:35:55 +00:00
										 |  |  |         saveJson(actorJson, actorFilename) | 
					
						
							| 
									
										
										
										
											2019-07-19 10:01:24 +00:00
										 |  |  |     return True | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 11:35:55 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def setSkills(baseDir: str, nickname: str, domain: str, skills: {}) -> None: | 
					
						
							|  |  |  |     actorFilename = baseDir + '/accounts/' + nickname + '@' + domain + '.json' | 
					
						
							| 
									
										
										
										
											2019-08-09 08:46:38 +00:00
										 |  |  |     if not os.path.isfile(actorFilename): | 
					
						
							|  |  |  |         return False | 
					
						
							| 
									
										
										
										
											2019-09-30 22:39:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 11:35:55 +00:00
										 |  |  |     actorJson = loadJson(actorFilename) | 
					
						
							| 
									
										
										
										
											2019-09-30 22:39:02 +00:00
										 |  |  |     if actorJson: | 
					
						
							| 
									
										
										
										
											2020-04-04 11:35:55 +00:00
										 |  |  |         actorJson['skills'] = skills | 
					
						
							|  |  |  |         saveJson(actorJson, actorFilename) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-09 08:46:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 11:35:55 +00:00
										 |  |  | def getSkills(baseDir: str, nickname: str, domain: str) -> []: | 
					
						
							| 
									
										
										
										
											2019-07-19 10:01:24 +00:00
										 |  |  |     """Returns the skills for a given person
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-04 11:35:55 +00:00
										 |  |  |     actorFilename = baseDir + '/accounts/' + nickname + '@' + domain + '.json' | 
					
						
							| 
									
										
										
										
											2019-07-19 10:01:24 +00:00
										 |  |  |     if not os.path.isfile(actorFilename): | 
					
						
							|  |  |  |         return False | 
					
						
							| 
									
										
										
										
											2019-09-30 22:39:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 11:35:55 +00:00
										 |  |  |     actorJson = loadJson(actorFilename) | 
					
						
							| 
									
										
										
										
											2019-09-30 22:39:02 +00:00
										 |  |  |     if actorJson: | 
					
						
							| 
									
										
										
										
											2019-07-19 10:01:24 +00:00
										 |  |  |         if not actorJson.get('skills'): | 
					
						
							|  |  |  |             return None | 
					
						
							|  |  |  |         return actorJson['skills'] | 
					
						
							|  |  |  |     return None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 11:35:55 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def outboxSkills(baseDir: str, nickname: str, messageJson: {}, | 
					
						
							|  |  |  |                  debug: bool) -> bool: | 
					
						
							| 
									
										
										
										
											2019-07-19 10:01:24 +00:00
										 |  |  |     """Handles receiving a skills update
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if not messageJson.get('type'): | 
					
						
							|  |  |  |         return False | 
					
						
							| 
									
										
										
										
											2020-04-04 11:35:55 +00:00
										 |  |  |     if not messageJson['type'] == 'Skill': | 
					
						
							| 
									
										
										
										
											2019-07-19 10:01:24 +00:00
										 |  |  |         return False | 
					
						
							|  |  |  |     if not messageJson.get('actor'): | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |     if not messageJson.get('object'): | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |     if not isinstance(messageJson['object'], str): | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 11:35:55 +00:00
										 |  |  |     actorNickname = getNicknameFromActor(messageJson['actor']) | 
					
						
							|  |  |  |     if actorNickname != nickname: | 
					
						
							| 
									
										
										
										
											2019-07-19 10:01:24 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2020-04-04 11:35:55 +00:00
										 |  |  |     domain, port = getDomainFromActor(messageJson['actor']) | 
					
						
							|  |  |  |     skill = messageJson['object'].replace('"', '').split(';')[0].strip() | 
					
						
							|  |  |  |     skillLevelPercentStr = \ | 
					
						
							|  |  |  |         messageJson['object'].replace('"', '').split(';')[1].strip() | 
					
						
							|  |  |  |     skillLevelPercent = 50 | 
					
						
							| 
									
										
										
										
											2020-03-01 10:18:08 +00:00
										 |  |  |     if skillLevelPercentStr.isdigit(): | 
					
						
							| 
									
										
										
										
											2020-04-04 11:35:55 +00:00
										 |  |  |         skillLevelPercent = int(skillLevelPercentStr) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return setSkillLevel(baseDir, nickname, domain, | 
					
						
							|  |  |  |                          skill, skillLevelPercent) | 
					
						
							| 
									
										
										
										
											2019-07-19 10:01:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 11:35:55 +00:00
										 |  |  | def sendSkillViaServer(baseDir: str, session, nickname: str, password: str, | 
					
						
							|  |  |  |                        domain: str, port: int, | 
					
						
							|  |  |  |                        httpPrefix: str, | 
					
						
							|  |  |  |                        skill: str, skillLevelPercent: int, | 
					
						
							|  |  |  |                        cachedWebfingers: {}, personCache: {}, | 
					
						
							|  |  |  |                        debug: bool, projectVersion: str) -> {}: | 
					
						
							| 
									
										
										
										
											2019-07-19 10:01:24 +00:00
										 |  |  |     """Sets a skill for a person via c2s
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if not session: | 
					
						
							|  |  |  |         print('WARN: No session for sendSkillViaServer') | 
					
						
							|  |  |  |         return 6 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 11:35:55 +00:00
										 |  |  |     domainFull = domain | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  |     if port: | 
					
						
							| 
									
										
										
										
											2020-04-04 11:35:55 +00:00
										 |  |  |         if port != 80 and port != 443: | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  |             if ':' not in domain: | 
					
						
							| 
									
										
										
										
											2020-04-04 11:35:55 +00:00
										 |  |  |                 domainFull = domain + ':' + str(port) | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 11:35:55 +00:00
										 |  |  |     actor = httpPrefix + '://' + domainFull + '/users/' + nickname | 
					
						
							|  |  |  |     toUrl = actor | 
					
						
							|  |  |  |     ccUrl = actor + '/followers' | 
					
						
							| 
									
										
										
										
											2019-07-19 10:01:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if skillLevelPercent: | 
					
						
							| 
									
										
										
										
											2020-04-04 11:35:55 +00:00
										 |  |  |         skillStr = skill + ';' + str(skillLevelPercent) | 
					
						
							| 
									
										
										
										
											2019-07-19 10:01:24 +00:00
										 |  |  |     else: | 
					
						
							| 
									
										
										
										
											2020-04-04 11:35:55 +00:00
										 |  |  |         skillStr = skill + ';0' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     newSkillJson = { | 
					
						
							| 
									
										
										
										
											2019-07-19 10:01:24 +00:00
										 |  |  |         'type': 'Skill', | 
					
						
							| 
									
										
										
										
											2020-04-04 11:35:55 +00:00
										 |  |  |         'actor': actor, | 
					
						
							| 
									
										
										
										
											2019-07-19 11:38:37 +00:00
										 |  |  |         'object': '"'+skillStr+'"', | 
					
						
							| 
									
										
										
										
											2019-07-19 10:01:24 +00:00
										 |  |  |         'to': [toUrl], | 
					
						
							|  |  |  |         'cc': [ccUrl] | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 11:35:55 +00:00
										 |  |  |     handle = httpPrefix + '://' + domainFull + '/@' + nickname | 
					
						
							| 
									
										
										
										
											2019-07-19 10:01:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # lookup the inbox for the To handle | 
					
						
							| 
									
										
										
										
											2020-04-04 11:35:55 +00:00
										 |  |  |     wfRequest = \ | 
					
						
							|  |  |  |         webfingerHandle(session, handle, httpPrefix, | 
					
						
							|  |  |  |                         cachedWebfingers, | 
					
						
							|  |  |  |                         domain, projectVersion) | 
					
						
							| 
									
										
										
										
											2019-07-19 10:01:24 +00:00
										 |  |  |     if not wfRequest: | 
					
						
							|  |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-04 11:35:55 +00:00
										 |  |  |             print('DEBUG: announce webfinger failed for ' + handle) | 
					
						
							| 
									
										
										
										
											2019-07-19 10:01:24 +00:00
										 |  |  |         return 1 | 
					
						
							| 
									
										
										
										
											2020-06-23 10:41:12 +00:00
										 |  |  |     if not isinstance(wfRequest, dict): | 
					
						
							|  |  |  |         print('WARN: Webfinger for ' + handle + ' did not return a dict. ' + | 
					
						
							|  |  |  |               str(wfRequest)) | 
					
						
							|  |  |  |         return 1 | 
					
						
							| 
									
										
										
										
											2019-07-19 10:01:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 11:35:55 +00:00
										 |  |  |     postToBox = 'outbox' | 
					
						
							| 
									
										
										
										
											2019-07-19 10:01:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # get the actor inbox for the To handle | 
					
						
							| 
									
										
										
										
											2020-04-04 11:35:55 +00:00
										 |  |  |     (inboxUrl, pubKeyId, pubKey, | 
					
						
							|  |  |  |      fromPersonId, sharedInbox, | 
					
						
							|  |  |  |      avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest, | 
					
						
							|  |  |  |                                             personCache, projectVersion, | 
					
						
							|  |  |  |                                             httpPrefix, nickname, domain, | 
					
						
							|  |  |  |                                             postToBox) | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-19 10:01:24 +00:00
										 |  |  |     if not inboxUrl: | 
					
						
							|  |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-04 11:35:55 +00:00
										 |  |  |             print('DEBUG: No ' + postToBox + ' was found for ' + handle) | 
					
						
							| 
									
										
										
										
											2019-07-19 10:01:24 +00:00
										 |  |  |         return 3 | 
					
						
							|  |  |  |     if not fromPersonId: | 
					
						
							|  |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-04 11:35:55 +00:00
										 |  |  |             print('DEBUG: No actor was found for ' + handle) | 
					
						
							| 
									
										
										
										
											2019-07-19 10:01:24 +00:00
										 |  |  |         return 4 | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 11:35:55 +00:00
										 |  |  |     authHeader = createBasicAuthHeader(nickname, password) | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 11:35:55 +00:00
										 |  |  |     headers = { | 
					
						
							|  |  |  |         'host': domain, | 
					
						
							|  |  |  |         'Content-type': 'application/json', | 
					
						
							| 
									
										
										
										
											2020-03-22 20:36:19 +00:00
										 |  |  |         'Authorization': authHeader | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-04-04 11:35:55 +00:00
										 |  |  |     postResult = \ | 
					
						
							| 
									
										
										
										
											2020-09-27 19:27:24 +00:00
										 |  |  |         postJson(session, newSkillJson, [], inboxUrl, headers) | 
					
						
							| 
									
										
										
										
											2020-04-04 11:35:55 +00:00
										 |  |  |     if not postResult: | 
					
						
							|  |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: POST announce failed for c2s to ' + inboxUrl) | 
					
						
							|  |  |  | #        return 5 | 
					
						
							| 
									
										
										
										
											2019-07-19 10:01:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if debug: | 
					
						
							|  |  |  |         print('DEBUG: c2s POST skill success') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return newSkillJson |