skills.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. __filename__ = "skills.py"
  2. __author__ = "Bob Mottram"
  3. __license__ = "AGPL3+"
  4. __version__ = "0.0.1"
  5. __maintainer__ = "Bob Mottram"
  6. __email__ = "bob@freedombone.net"
  7. __status__ = "Production"
  8. import json
  9. import commentjson
  10. import os
  11. from webfinger import webfingerHandle
  12. from auth import createBasicAuthHeader
  13. from posts import getPersonBox
  14. from session import postJson
  15. from utils import getNicknameFromActor
  16. from utils import getDomainFromActor
  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. with open(actorFilename, 'r') as fp:
  28. actorJson=commentjson.load(fp)
  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. with open(actorFilename, 'w') as fp:
  36. commentjson.dump(actorJson, fp, indent=4, sort_keys=False)
  37. return True
  38. def setSkills(baseDir: str,nickname: str,domain: str,skills: {}) -> None:
  39. actorFilename=baseDir+'/accounts/'+nickname+'@'+domain+'.json'
  40. if not os.path.isfile(actorFilename):
  41. return False
  42. with open(actorFilename, 'r') as fp:
  43. actorJson=commentjson.load(fp)
  44. actorJson['skills']=skills
  45. with open(actorFilename, 'w') as fp:
  46. commentjson.dump(actorJson, fp, indent=4, sort_keys=False)
  47. def getSkills(baseDir: str,nickname: str,domain: str) -> []:
  48. """Returns the skills for a given person
  49. """
  50. actorFilename=baseDir+'/accounts/'+nickname+'@'+domain+'.json'
  51. if not os.path.isfile(actorFilename):
  52. return False
  53. with open(actorFilename, 'r') as fp:
  54. actorJson=commentjson.load(fp)
  55. if not actorJson.get('skills'):
  56. return None
  57. return actorJson['skills']
  58. return None
  59. def outboxSkills(baseDir: str,nickname: str,messageJson: {},debug: bool) -> bool:
  60. """Handles receiving a skills update
  61. """
  62. if not messageJson.get('type'):
  63. return False
  64. if not messageJson['type']=='Skill':
  65. return False
  66. if not messageJson.get('actor'):
  67. return False
  68. if not messageJson.get('object'):
  69. return False
  70. if not isinstance(messageJson['object'], str):
  71. return False
  72. actorNickname=getNicknameFromActor(messageJson['actor'])
  73. if actorNickname!=nickname:
  74. return False
  75. domain,port=getDomainFromActor(messageJson['actor'])
  76. skill=messageJson['object'].replace('"','').split(';')[0].strip()
  77. skillLevelPercent=int(messageJson['object'].replace('"','').split(';')[1].strip())
  78. return setSkillLevel(baseDir,nickname,domain, \
  79. skill,skillLevelPercent)
  80. def sendSkillViaServer(session,nickname: str,password: str,
  81. domain: str,port: int, \
  82. httpPrefix: str, \
  83. skill: str,skillLevelPercent: int, \
  84. cachedWebfingers: {},personCache: {}, \
  85. debug: bool,projectVersion: str) -> {}:
  86. """Sets a skill for a person via c2s
  87. """
  88. if not session:
  89. print('WARN: No session for sendSkillViaServer')
  90. return 6
  91. domainFull=domain
  92. if port:
  93. if port!=80 and port!=443:
  94. if ':' not in domain:
  95. domainFull=domain+':'+str(port)
  96. toUrl = httpPrefix+'://'+domainFull+'/users/'+nickname
  97. ccUrl = httpPrefix+'://'+domainFull+'/users/'+nickname+'/followers'
  98. if skillLevelPercent:
  99. skillStr=skill+';'+str(skillLevelPercent)
  100. else:
  101. skillStr=skill+';0'
  102. newSkillJson = {
  103. 'type': 'Skill',
  104. 'actor': httpPrefix+'://'+domainFull+'/users/'+nickname,
  105. 'object': '"'+skillStr+'"',
  106. 'to': [toUrl],
  107. 'cc': [ccUrl]
  108. }
  109. handle=httpPrefix+'://'+domainFull+'/@'+nickname
  110. # lookup the inbox for the To handle
  111. wfRequest = webfingerHandle(session,handle,httpPrefix,cachedWebfingers, \
  112. domain,projectVersion)
  113. if not wfRequest:
  114. if debug:
  115. print('DEBUG: announce webfinger failed for '+handle)
  116. return 1
  117. postToBox='outbox'
  118. # get the actor inbox for the To handle
  119. inboxUrl,pubKeyId,pubKey,fromPersonId,sharedInbox,capabilityAcquisition,avatarUrl,preferredName = \
  120. getPersonBox(session,wfRequest,personCache, \
  121. projectVersion,httpPrefix,domain,postToBox)
  122. if not inboxUrl:
  123. if debug:
  124. print('DEBUG: No '+postToBox+' was found for '+handle)
  125. return 3
  126. if not fromPersonId:
  127. if debug:
  128. print('DEBUG: No actor was found for '+handle)
  129. return 4
  130. authHeader=createBasicAuthHeader(Nickname,password)
  131. headers = {'host': domain, \
  132. 'Content-type': 'application/json', \
  133. 'Authorization': authHeader}
  134. postResult = \
  135. postJson(session,newSkillJson,[],inboxUrl,headers,"inbox:write")
  136. #if not postResult:
  137. # if debug:
  138. # print('DEBUG: POST announce failed for c2s to '+inboxUrl)
  139. # return 5
  140. if debug:
  141. print('DEBUG: c2s POST skill success')
  142. return newSkillJson