2020-04-04 10:28:58 +00:00
|
|
|
__filename__ = "roles.py"
|
|
|
|
__author__ = "Bob Mottram"
|
|
|
|
__license__ = "AGPL3+"
|
2021-01-26 10:07:42 +00:00
|
|
|
__version__ = "1.2.0"
|
2020-04-04 10:28:58 +00:00
|
|
|
__maintainer__ = "Bob Mottram"
|
2021-09-10 16:14:50 +00:00
|
|
|
__email__ = "bob@libreserver.org"
|
2020-04-04 10:28:58 +00:00
|
|
|
__status__ = "Production"
|
2021-06-26 11:16:41 +00:00
|
|
|
__module_group__ = "Profile Metadata"
|
2020-04-04 10:28:58 +00:00
|
|
|
|
2019-07-18 15:09:23 +00:00
|
|
|
import os
|
2021-12-26 15:13:34 +00:00
|
|
|
from utils import load_json
|
2021-12-26 14:47:21 +00:00
|
|
|
from utils import save_json
|
2021-12-27 17:42:35 +00:00
|
|
|
from utils import get_status_number
|
2021-12-26 18:17:37 +00:00
|
|
|
from utils import remove_domain_port
|
2021-12-26 12:02:29 +00:00
|
|
|
from utils import acct_dir
|
2019-07-18 15:09:23 +00:00
|
|
|
|
2020-04-04 10:28:58 +00:00
|
|
|
|
2021-12-25 16:17:53 +00:00
|
|
|
def _clearRoleStatus(base_dir: str, role: str) -> None:
|
2021-03-08 21:07:28 +00:00
|
|
|
"""Removes role status from all accounts
|
2020-10-11 19:42:21 +00:00
|
|
|
This could be slow if there are many users, but only happens
|
2021-03-08 21:07:28 +00:00
|
|
|
rarely when roles are appointed or removed
|
2020-10-11 19:42:21 +00:00
|
|
|
"""
|
2021-12-25 16:17:53 +00:00
|
|
|
directory = os.fsencode(base_dir + '/accounts/')
|
2020-10-11 19:42:21 +00:00
|
|
|
for f in os.scandir(directory):
|
|
|
|
f = f.name
|
|
|
|
filename = os.fsdecode(f)
|
2020-11-24 14:06:42 +00:00
|
|
|
if '@' not in filename:
|
|
|
|
continue
|
|
|
|
if not filename.endswith(".json"):
|
|
|
|
continue
|
2021-12-25 16:17:53 +00:00
|
|
|
filename = os.path.join(base_dir + '/accounts/', filename)
|
2021-03-08 21:07:28 +00:00
|
|
|
if '"' + role + '"' not in open(filename).read():
|
2020-11-24 14:06:42 +00:00
|
|
|
continue
|
2021-12-26 15:13:34 +00:00
|
|
|
actor_json = load_json(filename)
|
2021-12-26 10:29:52 +00:00
|
|
|
if not actor_json:
|
2020-11-24 14:06:42 +00:00
|
|
|
continue
|
2021-12-26 10:29:52 +00:00
|
|
|
rolesList = getActorRolesList(actor_json)
|
2021-05-13 19:58:16 +00:00
|
|
|
if role in rolesList:
|
|
|
|
rolesList.remove(role)
|
2021-12-26 10:29:52 +00:00
|
|
|
setRolesFromList(actor_json, rolesList)
|
2021-12-26 14:47:21 +00:00
|
|
|
save_json(actor_json, filename)
|
2020-10-11 19:42:21 +00:00
|
|
|
|
|
|
|
|
2021-12-25 16:17:53 +00:00
|
|
|
def clearEditorStatus(base_dir: str) -> None:
|
2021-03-08 21:07:28 +00:00
|
|
|
"""Removes editor status from all accounts
|
|
|
|
This could be slow if there are many users, but only happens
|
|
|
|
rarely when editors are appointed or removed
|
|
|
|
"""
|
2021-12-25 16:17:53 +00:00
|
|
|
_clearRoleStatus(base_dir, 'editor')
|
2021-03-08 21:07:28 +00:00
|
|
|
|
|
|
|
|
2021-12-25 16:17:53 +00:00
|
|
|
def clearCounselorStatus(base_dir: str) -> None:
|
2021-03-08 23:03:02 +00:00
|
|
|
"""Removes counselor status from all accounts
|
|
|
|
This could be slow if there are many users, but only happens
|
|
|
|
rarely when counselors are appointed or removed
|
|
|
|
"""
|
2021-12-25 16:17:53 +00:00
|
|
|
_clearRoleStatus(base_dir, 'editor')
|
2021-03-08 23:03:02 +00:00
|
|
|
|
|
|
|
|
2021-12-25 16:17:53 +00:00
|
|
|
def clearArtistStatus(base_dir: str) -> None:
|
2021-05-17 16:13:56 +00:00
|
|
|
"""Removes artist status from all accounts
|
|
|
|
This could be slow if there are many users, but only happens
|
|
|
|
rarely when artists are appointed or removed
|
|
|
|
"""
|
2021-12-25 16:17:53 +00:00
|
|
|
_clearRoleStatus(base_dir, 'artist')
|
2021-05-17 16:13:56 +00:00
|
|
|
|
|
|
|
|
2021-12-25 16:17:53 +00:00
|
|
|
def clearModeratorStatus(base_dir: str) -> None:
|
2021-03-08 21:07:28 +00:00
|
|
|
"""Removes moderator status from all accounts
|
|
|
|
This could be slow if there are many users, but only happens
|
|
|
|
rarely when moderators are appointed or removed
|
|
|
|
"""
|
2021-12-25 16:17:53 +00:00
|
|
|
_clearRoleStatus(base_dir, 'moderator')
|
2021-03-08 21:07:28 +00:00
|
|
|
|
|
|
|
|
2021-12-25 16:17:53 +00:00
|
|
|
def _addRole(base_dir: str, nickname: str, domain: str,
|
2021-03-08 21:07:28 +00:00
|
|
|
roleFilename: str) -> None:
|
2021-05-16 15:10:39 +00:00
|
|
|
"""Adds a role nickname to the file.
|
|
|
|
This is a file containing the nicknames of accounts having this role
|
2019-08-11 11:25:27 +00:00
|
|
|
"""
|
2021-12-26 18:17:37 +00:00
|
|
|
domain = remove_domain_port(domain)
|
2021-12-25 16:17:53 +00:00
|
|
|
roleFile = base_dir + '/accounts/' + roleFilename
|
2021-03-08 21:07:28 +00:00
|
|
|
if os.path.isfile(roleFile):
|
2019-08-11 11:25:27 +00:00
|
|
|
# is this nickname already in the file?
|
2021-07-13 14:40:49 +00:00
|
|
|
with open(roleFile, 'r') as f:
|
2020-04-04 10:28:58 +00:00
|
|
|
lines = f.readlines()
|
2021-03-08 21:07:28 +00:00
|
|
|
for roleNickname in lines:
|
|
|
|
roleNickname = roleNickname.strip('\n').strip('\r')
|
|
|
|
if roleNickname == nickname:
|
2019-08-11 11:25:27 +00:00
|
|
|
return
|
|
|
|
lines.append(nickname)
|
2021-03-08 21:07:28 +00:00
|
|
|
with open(roleFile, 'w+') as f:
|
|
|
|
for roleNickname in lines:
|
|
|
|
roleNickname = roleNickname.strip('\n').strip('\r')
|
2021-07-04 17:14:18 +00:00
|
|
|
if len(roleNickname) < 2:
|
|
|
|
continue
|
2021-12-25 16:17:53 +00:00
|
|
|
if os.path.isdir(base_dir + '/accounts/' +
|
2021-07-04 17:14:18 +00:00
|
|
|
roleNickname + '@' + domain):
|
|
|
|
f.write(roleNickname + '\n')
|
2019-08-11 11:27:29 +00:00
|
|
|
else:
|
2021-07-13 14:40:49 +00:00
|
|
|
with open(roleFile, 'w+') as f:
|
2021-12-26 12:02:29 +00:00
|
|
|
accountDir = acct_dir(base_dir, nickname, domain)
|
2021-07-13 21:59:53 +00:00
|
|
|
if os.path.isdir(accountDir):
|
2020-04-04 10:28:58 +00:00
|
|
|
f.write(nickname + '\n')
|
2020-03-22 21:16:02 +00:00
|
|
|
|
2020-04-04 10:28:58 +00:00
|
|
|
|
2021-12-25 16:17:53 +00:00
|
|
|
def _removeRole(base_dir: str, nickname: str, roleFilename: str) -> None:
|
2021-05-16 15:10:39 +00:00
|
|
|
"""Removes a role nickname from the file.
|
|
|
|
This is a file containing the nicknames of accounts having this role
|
2019-08-11 11:25:27 +00:00
|
|
|
"""
|
2021-12-25 16:17:53 +00:00
|
|
|
roleFile = base_dir + '/accounts/' + roleFilename
|
2021-03-08 21:07:28 +00:00
|
|
|
if not os.path.isfile(roleFile):
|
2019-08-11 11:25:27 +00:00
|
|
|
return
|
2021-07-13 14:40:49 +00:00
|
|
|
with open(roleFile, 'r') as f:
|
2020-04-04 10:28:58 +00:00
|
|
|
lines = f.readlines()
|
2021-03-08 21:07:28 +00:00
|
|
|
with open(roleFile, 'w+') as f:
|
|
|
|
for roleNickname in lines:
|
|
|
|
roleNickname = roleNickname.strip('\n').strip('\r')
|
|
|
|
if len(roleNickname) > 1 and roleNickname != nickname:
|
|
|
|
f.write(roleNickname + '\n')
|
|
|
|
|
|
|
|
|
2021-12-26 10:29:52 +00:00
|
|
|
def _setActorRole(actor_json: {}, roleName: str) -> bool:
|
2021-05-16 15:10:39 +00:00
|
|
|
"""Sets a role for an actor
|
|
|
|
"""
|
2021-12-26 10:29:52 +00:00
|
|
|
if not actor_json.get('hasOccupation'):
|
2021-05-16 15:10:39 +00:00
|
|
|
return False
|
2021-12-26 10:29:52 +00:00
|
|
|
if not isinstance(actor_json['hasOccupation'], list):
|
2021-05-16 15:10:39 +00:00
|
|
|
return False
|
|
|
|
|
2021-07-04 17:14:18 +00:00
|
|
|
# occupation category from www.onetonline.org
|
2021-05-16 15:10:39 +00:00
|
|
|
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'
|
2021-05-17 16:13:56 +00:00
|
|
|
elif 'artist' in roleName:
|
|
|
|
category = '27-1024.00'
|
2021-05-16 15:10:39 +00:00
|
|
|
if not category:
|
|
|
|
return False
|
|
|
|
|
2021-12-26 10:29:52 +00:00
|
|
|
for index in range(len(actor_json['hasOccupation'])):
|
|
|
|
occupationItem = actor_json['hasOccupation'][index]
|
2021-05-16 15:10:39 +00:00
|
|
|
if not isinstance(occupationItem, dict):
|
|
|
|
continue
|
|
|
|
if not occupationItem.get('@type'):
|
|
|
|
continue
|
|
|
|
if occupationItem['@type'] != 'Role':
|
|
|
|
continue
|
|
|
|
if occupationItem['hasOccupation']['name'] == roleName:
|
|
|
|
return True
|
2021-12-27 17:42:35 +00:00
|
|
|
statusNumber, published = get_status_number()
|
2021-05-16 15:10:39 +00:00
|
|
|
newRole = {
|
|
|
|
"@type": "Role",
|
|
|
|
"hasOccupation": {
|
|
|
|
"@type": "Occupation",
|
|
|
|
"name": roleName,
|
2021-05-17 11:33:59 +00:00
|
|
|
"description": "Fediverse instance role",
|
2021-05-17 10:04:26 +00:00
|
|
|
"occupationLocation": {
|
2021-05-17 10:27:14 +00:00
|
|
|
"@type": "City",
|
|
|
|
"url": "Fediverse"
|
2021-05-17 09:28:15 +00:00
|
|
|
},
|
2021-05-16 15:10:39 +00:00
|
|
|
"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
|
|
|
|
}
|
2021-12-26 10:29:52 +00:00
|
|
|
actor_json['hasOccupation'].append(newRole)
|
2021-05-16 15:10:39 +00:00
|
|
|
return True
|
|
|
|
|
|
|
|
|
2021-12-26 10:29:52 +00:00
|
|
|
def setRolesFromList(actor_json: {}, rolesList: []) -> None:
|
2021-05-13 19:58:16 +00:00
|
|
|
"""Sets roles from a list
|
|
|
|
"""
|
2021-05-16 15:10:39 +00:00
|
|
|
# clear Roles from the occupation list
|
|
|
|
emptyRolesList = []
|
2021-12-26 10:29:52 +00:00
|
|
|
for occupationItem in actor_json['hasOccupation']:
|
2021-05-16 15:10:39 +00:00
|
|
|
if not isinstance(occupationItem, dict):
|
|
|
|
continue
|
|
|
|
if not occupationItem.get('@type'):
|
|
|
|
continue
|
|
|
|
if occupationItem['@type'] == 'Role':
|
|
|
|
continue
|
|
|
|
emptyRolesList.append(occupationItem)
|
2021-12-26 10:29:52 +00:00
|
|
|
actor_json['hasOccupation'] = emptyRolesList
|
2021-05-16 15:10:39 +00:00
|
|
|
|
|
|
|
# create the new list
|
|
|
|
for roleName in rolesList:
|
2021-12-26 10:29:52 +00:00
|
|
|
_setActorRole(actor_json, roleName)
|
2021-05-13 19:58:16 +00:00
|
|
|
|
|
|
|
|
2021-12-26 10:29:52 +00:00
|
|
|
def getActorRolesList(actor_json: {}) -> []:
|
2021-05-16 15:10:39 +00:00
|
|
|
"""Gets a list of role names from an actor
|
2021-05-13 19:58:16 +00:00
|
|
|
"""
|
2021-12-26 10:29:52 +00:00
|
|
|
if not actor_json.get('hasOccupation'):
|
2021-05-16 15:10:39 +00:00
|
|
|
return []
|
2021-12-26 10:29:52 +00:00
|
|
|
if not isinstance(actor_json['hasOccupation'], list):
|
2021-05-16 15:10:39 +00:00
|
|
|
return []
|
|
|
|
rolesList = []
|
2021-12-26 10:29:52 +00:00
|
|
|
for occupationItem in actor_json['hasOccupation']:
|
2021-05-16 15:10:39 +00:00
|
|
|
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
|
2021-05-13 19:58:16 +00:00
|
|
|
|
|
|
|
|
2021-12-25 16:17:53 +00:00
|
|
|
def setRole(base_dir: str, nickname: str, domain: str,
|
2021-05-13 19:58:16 +00:00
|
|
|
role: str) -> bool:
|
|
|
|
"""Set a person's role
|
2019-07-18 15:09:23 +00:00
|
|
|
Setting the role to an empty string or None will remove it
|
|
|
|
"""
|
|
|
|
# avoid giant strings
|
2021-05-13 19:58:16 +00:00
|
|
|
if len(role) > 128:
|
2019-07-18 15:09:23 +00:00
|
|
|
return False
|
2021-12-26 12:02:29 +00:00
|
|
|
actorFilename = acct_dir(base_dir, nickname, domain) + '.json'
|
2019-07-18 15:09:23 +00:00
|
|
|
if not os.path.isfile(actorFilename):
|
|
|
|
return False
|
2019-09-30 22:39:02 +00:00
|
|
|
|
2021-03-08 21:18:20 +00:00
|
|
|
roleFiles = {
|
|
|
|
"moderator": "moderators.txt",
|
2021-03-08 23:03:02 +00:00
|
|
|
"editor": "editors.txt",
|
2021-05-17 16:13:56 +00:00
|
|
|
"counselor": "counselors.txt",
|
|
|
|
"artist": "artists.txt"
|
2021-03-08 21:18:20 +00:00
|
|
|
}
|
|
|
|
|
2021-12-26 15:13:34 +00:00
|
|
|
actor_json = load_json(actorFilename)
|
2021-12-26 10:29:52 +00:00
|
|
|
if actor_json:
|
|
|
|
if not actor_json.get('hasOccupation'):
|
2021-05-13 19:58:16 +00:00
|
|
|
return False
|
2021-12-26 10:29:52 +00:00
|
|
|
rolesList = getActorRolesList(actor_json)
|
2021-05-13 19:58:16 +00:00
|
|
|
actorChanged = False
|
2019-07-18 15:09:23 +00:00
|
|
|
if role:
|
2019-08-11 11:25:27 +00:00
|
|
|
# add the role
|
2021-05-13 19:58:16 +00:00
|
|
|
if roleFiles.get(role):
|
2021-12-25 16:17:53 +00:00
|
|
|
_addRole(base_dir, nickname, domain, roleFiles[role])
|
2021-05-13 19:58:16 +00:00
|
|
|
if role not in rolesList:
|
|
|
|
rolesList.append(role)
|
|
|
|
rolesList.sort()
|
2021-12-26 10:29:52 +00:00
|
|
|
setRolesFromList(actor_json, rolesList)
|
2021-05-13 19:58:16 +00:00
|
|
|
actorChanged = True
|
2019-07-18 15:09:23 +00:00
|
|
|
else:
|
2019-08-11 11:25:27 +00:00
|
|
|
# remove the role
|
2021-05-13 19:58:16 +00:00
|
|
|
if roleFiles.get(role):
|
2021-12-25 16:17:53 +00:00
|
|
|
_removeRole(base_dir, nickname, roleFiles[role])
|
2021-05-13 19:58:16 +00:00
|
|
|
if role in rolesList:
|
|
|
|
rolesList.remove(role)
|
2021-12-26 10:29:52 +00:00
|
|
|
setRolesFromList(actor_json, rolesList)
|
2021-05-13 19:58:16 +00:00
|
|
|
actorChanged = True
|
|
|
|
if actorChanged:
|
2021-12-26 14:47:21 +00:00
|
|
|
save_json(actor_json, actorFilename)
|
2019-07-18 16:21:26 +00:00
|
|
|
return True
|
2021-05-16 15:10:39 +00:00
|
|
|
|
|
|
|
|
2021-12-26 10:29:52 +00:00
|
|
|
def actorHasRole(actor_json: {}, roleName: str) -> bool:
|
2021-05-16 15:10:39 +00:00
|
|
|
"""Returns true if the given actor has the given role
|
|
|
|
"""
|
2021-12-26 10:29:52 +00:00
|
|
|
rolesList = getActorRolesList(actor_json)
|
2021-05-16 15:10:39 +00:00
|
|
|
return roleName in rolesList
|