skills.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. __filename__ = "skills.py"
  2. __author__ = "Bob Mottram"
  3. __license__ = "AGPL3+"
  4. __version__ = "1.1.0"
  5. __maintainer__ = "Bob Mottram"
  6. __email__ = "bob@freedombone.net"
  7. __status__ = "Production"
  8. import os
  9. from webfinger import webfingerHandle
  10. from auth import createBasicAuthHeader
  11. from posts import getPersonBox
  12. from session import postJson
  13. from utils import getNicknameFromActor
  14. from utils import getDomainFromActor
  15. from utils import loadJson
  16. from utils import saveJson
  17. def setSkillLevel(baseDir: str, nickname: str, domain: str,
  18. skill: str, skillLevelPercent: int) -> bool:
  19. """Set a skill level for a person
  20. Setting skill level to zero removes it
  21. """
  22. if skillLevelPercent < 0 or skillLevelPercent > 100:
  23. return False
  24. actorFilename = baseDir + '/accounts/' + nickname + '@' + domain + '.json'
  25. if not os.path.isfile(actorFilename):
  26. return False
  27. actorJson = loadJson(actorFilename)
  28. if actorJson:
  29. if not actorJson.get('skills'):
  30. actorJson['skills'] = {}
  31. if skillLevelPercent > 0:
  32. actorJson['skills'][skill] = skillLevelPercent
  33. else:
  34. del actorJson['skills'][skill]
  35. saveJson(actorJson, actorFilename)
  36. return True
  37. def setSkills(baseDir: str, nickname: str, domain: str, skills: {}) -> None:
  38. actorFilename = baseDir + '/accounts/' + nickname + '@' + domain + '.json'
  39. if not os.path.isfile(actorFilename):
  40. return False
  41. actorJson = loadJson(actorFilename)
  42. if actorJson:
  43. actorJson['skills'] = skills
  44. saveJson(actorJson, actorFilename)
  45. def getSkills(baseDir: str, nickname: str, domain: str) -> []:
  46. """Returns the skills for a given person
  47. """
  48. actorFilename = baseDir + '/accounts/' + nickname + '@' + domain + '.json'
  49. if not os.path.isfile(actorFilename):
  50. return False
  51. actorJson = loadJson(actorFilename)
  52. if actorJson:
  53. if not actorJson.get('skills'):
  54. return None
  55. return actorJson['skills']
  56. return None
  57. def outboxSkills(baseDir: str, nickname: str, messageJson: {},
  58. debug: bool) -> bool:
  59. """Handles receiving a skills update
  60. """
  61. if not messageJson.get('type'):
  62. return False
  63. if not messageJson['type'] == 'Skill':
  64. return False
  65. if not messageJson.get('actor'):
  66. return False
  67. if not messageJson.get('object'):
  68. return False
  69. if not isinstance(messageJson['object'], str):
  70. return False
  71. actorNickname = getNicknameFromActor(messageJson['actor'])
  72. if actorNickname != nickname:
  73. return False
  74. domain, port = getDomainFromActor(messageJson['actor'])
  75. skill = messageJson['object'].replace('"', '').split(';')[0].strip()
  76. skillLevelPercentStr = \
  77. messageJson['object'].replace('"', '').split(';')[1].strip()
  78. skillLevelPercent = 50
  79. if skillLevelPercentStr.isdigit():
  80. skillLevelPercent = int(skillLevelPercentStr)
  81. return setSkillLevel(baseDir, nickname, domain,
  82. skill, skillLevelPercent)
  83. def sendSkillViaServer(baseDir: str, session, nickname: str, password: str,
  84. domain: str, port: int,
  85. httpPrefix: str,
  86. skill: str, skillLevelPercent: int,
  87. cachedWebfingers: {}, personCache: {},
  88. debug: bool, projectVersion: str) -> {}:
  89. """Sets a skill for a person via c2s
  90. """
  91. if not session:
  92. print('WARN: No session for sendSkillViaServer')
  93. return 6
  94. domainFull = domain
  95. if port:
  96. if port != 80 and port != 443:
  97. if ':' not in domain:
  98. domainFull = domain + ':' + str(port)
  99. actor = httpPrefix + '://' + domainFull + '/users/' + nickname
  100. toUrl = actor
  101. ccUrl = actor + '/followers'
  102. if skillLevelPercent:
  103. skillStr = skill + ';' + str(skillLevelPercent)
  104. else:
  105. skillStr = skill + ';0'
  106. newSkillJson = {
  107. 'type': 'Skill',
  108. 'actor': actor,
  109. 'object': '"'+skillStr+'"',
  110. 'to': [toUrl],
  111. 'cc': [ccUrl]
  112. }
  113. handle = httpPrefix + '://' + domainFull + '/@' + nickname
  114. # lookup the inbox for the To handle
  115. wfRequest = \
  116. webfingerHandle(session, handle, httpPrefix,
  117. cachedWebfingers,
  118. domain, projectVersion)
  119. if not wfRequest:
  120. if debug:
  121. print('DEBUG: announce webfinger failed for ' + handle)
  122. return 1
  123. if not isinstance(wfRequest, dict):
  124. print('WARN: Webfinger for ' + handle + ' did not return a dict. ' +
  125. str(wfRequest))
  126. return 1
  127. postToBox = 'outbox'
  128. # get the actor inbox for the To handle
  129. (inboxUrl, pubKeyId, pubKey,
  130. fromPersonId, sharedInbox,
  131. capabilityAcquisition,
  132. avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
  133. personCache, projectVersion,
  134. httpPrefix, nickname, domain,
  135. postToBox)
  136. if not inboxUrl:
  137. if debug:
  138. print('DEBUG: No ' + postToBox + ' was found for ' + handle)
  139. return 3
  140. if not fromPersonId:
  141. if debug:
  142. print('DEBUG: No actor was found for ' + handle)
  143. return 4
  144. authHeader = createBasicAuthHeader(nickname, password)
  145. headers = {
  146. 'host': domain,
  147. 'Content-type': 'application/json',
  148. 'Authorization': authHeader
  149. }
  150. postResult = \
  151. postJson(session, newSkillJson, [], inboxUrl, headers, "inbox:write")
  152. if not postResult:
  153. if debug:
  154. print('DEBUG: POST announce failed for c2s to ' + inboxUrl)
  155. # return 5
  156. if debug:
  157. print('DEBUG: c2s POST skill success')
  158. return newSkillJson