Repository navigation
Expand file tree
/
Copy pathadmin_profiles.py
More file actions
74 lines (67 loc) · 3.83 KB
/
Copy pathadmin_profiles.py
File metadata and controls
74 lines (67 loc) · 3.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
"""Bounded Workshop selections and optional config snapshots; no world settings."""
import hashlib
import json
import uuid
import admin_settings as settings
import admin_profile_configs as profile_configs
def catalog():
rows = profile_configs.read_json(settings.PENDING.with_name('mod-profiles.json'), [])
if not isinstance(rows, list):
raise ValueError('Invalid mod profile catalog.')
return {'profiles': rows, 'catalog_revision': hashlib.sha256(json.dumps(rows, sort_keys=True).encode()).hexdigest()}
def public_catalog():
state = catalog()
return {**state, 'profiles': [{**{key: value for key, value in row.items() if key != 'configs'},
'configs': [{'name': item['name']} for item in row.get('configs', [])]}
for row in state['profiles']]}
def change(payload, current):
state = catalog()
if payload.get('catalog_revision') != state['catalog_revision']:
raise ValueError('Profiles changed. Refresh before trying again.')
rows = state['profiles']
kind = payload.get('action')
if kind not in ('save', 'rename', 'delete', 'stage'):
raise ValueError('Choose a supported profile action.')
selected = next((row for row in rows if row['id'] == payload.get('id')), None)
if (kind != 'save' or payload.get('id')) and selected is None:
raise ValueError('Profile no longer exists. Refresh the list.')
if kind in ('save', 'stage') and payload.get('revision') != current['revision']:
raise ValueError('Settings changed. Refresh and review the latest selection.')
if kind == 'stage':
if not settings.web_mode():
raise ValueError('Enable web-managed settings to load a profile.')
removed = []
values = settings.clean_mod_selection(settings.validate({'TMOD_MODS': selected['mods']}), removed)
if not isinstance(payload.get('include_configs', True), bool):
raise ValueError('Choose whether to restore configuration files.')
records = profile_configs.stage(selected.get('configs', [])) if payload.get('include_configs', True) else []
profile_configs.stage_draft(records, {**current['staged'], **values})
settings.record_pending_removals(removed)
return
if kind == 'delete' or (kind == 'save' and selected):
if payload.get('confirm') is not True:
raise ValueError('Confirm deleting or replacing the profile.')
if kind in ('save', 'rename'):
name = payload.get('name')
if not isinstance(name, str) or not name.strip() or len(name) > 64 or any(ord(c) < 32 or ord(c) == 127 for c in name):
raise ValueError('Use a profile name of 1–64 characters without control characters.')
name = name.strip()
if any(row is not selected and row['name'].casefold() == name.casefold() for row in rows):
raise ValueError('That profile name already exists.')
if kind == 'save':
source = payload.get('source')
if source not in ('running', 'staged'):
raise ValueError('Choose the running or saved draft selection.')
mods = settings.validate({'TMOD_MODS': current[source].get('TMOD_MODS', '')})['TMOD_MODS']
snapshots = profile_configs.capture(payload.get('configs', []))
if selected is None:
selected = {'id': uuid.uuid4().hex}
rows.append(selected)
selected['mods'] = mods
selected['configs'] = snapshots
selected['name'] = name
else:
rows.remove(selected)
if len(rows) > 50 or len((json.dumps(rows, indent=2) + '\n').encode()) > profile_configs.STORAGE_LIMIT:
raise ValueError('Profile storage is full (50 profiles or 32 MiB). Remove an unused profile first.')
settings.atomic_json(settings.PENDING.with_name('mod-profiles.json'), rows)