epicyon/roles.py

278 lines
9.0 KiB
Python
Raw Normal View History

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)
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')
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:
"""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-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-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-12-25 16:17:53 +00:00
def setRole(base_dir: str, nickname: str, domain: str,
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
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'):
return False
2021-12-26 10:29:52 +00:00
rolesList = getActorRolesList(actor_json)
actorChanged = False
2019-07-18 15:09:23 +00:00
if role:
2019-08-11 11:25:27 +00:00
# add the role
if roleFiles.get(role):
2021-12-25 16:17:53 +00:00
_addRole(base_dir, nickname, domain, roleFiles[role])
if role not in rolesList:
rolesList.append(role)
rolesList.sort()
2021-12-26 10:29:52 +00:00
setRolesFromList(actor_json, rolesList)
actorChanged = True
2019-07-18 15:09:23 +00:00
else:
2019-08-11 11:25:27 +00:00
# remove the role
if roleFiles.get(role):
2021-12-25 16:17:53 +00:00
_removeRole(base_dir, nickname, roleFiles[role])
if role in rolesList:
rolesList.remove(role)
2021-12-26 10:29:52 +00:00
setRolesFromList(actor_json, rolesList)
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