forked from wijnen/supernovel
-
Notifications
You must be signed in to change notification settings - Fork 0
/
user.py
141 lines (128 loc) · 4.45 KB
/
user.py
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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#!/usr/bin/python3
# Imports and config. {{{
import os
import re
import json
import traceback
from websocketd import log
from __main__ import config
from debug import debug
# }}}
users = {} # including admins.
admins = {}
# Keys which are never saved.
unsaved = ['connection', 'text_buffer', 'full_section', 'run_stack', 'section', 'answers', 'variables', 'last_path', 'characters', 'cookie', 'python']
default_user = lambda group, name: {'filename': name.lower(), 'name': name, 'group': group.lower(), 'connection': None, 'password': None, 'nosave': False, 'sandbox': False, 'score': 0, 'answers': {}}
def load(name, group): # {{{
# Set default user data; can be replaced (or not returned) below.
ret = default_user(group, name)
if not os.path.exists(os.path.join(config['data'], 'users', group.lower())):
debug(0, 'user.load called for nonexistent group {}:{}'.format(name, group))
return None
if not os.path.exists(os.path.join(config['data'], 'users', group.lower(), name.lower())):
if os.path.exists(os.path.join(config['data'], 'users', group.lower(), 'Open')):
# Create new user.
save(ret)
else:
debug(0, 'user.load called for nonexistent user {}:{}'.format(name, group))
return None
if (name.lower(), group.lower()) in users:
ret = users[(name.lower(), group.lower())]
for ln in open(os.path.join(config['data'], 'users', group.lower(), name.lower()), errors = 'replace'):
if ln.strip() == '':
continue
try:
key, value = ln.strip().split('=', 1)
except ValueError:
log('Failed to parse line from user config for %s:%s: %s' % (name, group, ln.strip()))
continue
if key in unsaved:
# This key should not have been in the file.
continue
if key in ('nosave', 'sandbox'):
ret[key] = value == 'True'
continue
if key.startswith('answer:'):
try:
a, c, s, q = key.split(':', 3)
except:
log('Failed to parse answer key {}; ignoring'.format(key))
continue
if (c, s) not in ret['answers']:
ret['answers'][(c, s)] = {}
try:
ret['answers'][(c, s)][q] = [json.loads(a) for a in value.split(';')]
assert all('raw' in x for x in ret['answers'][(c, s)][q])
assert all('style' in x for x in ret['answers'][(c, s)][q])
except:
ret['answers'][(c, s)][q] = [{'raw': a, 'style': []} for a in value.split(';')]
continue
ret[key] = value.rstrip('\n')
# Make sure name and group match file location.
if ret['filename'] != name.lower():
ret['filename'] = name.lower()
if ret['group'].casefold() != group.casefold():
ret['group'] = group
return ret
# }}}
def list_groups(): # {{{
path = os.path.join(config['data'], 'users')
ret = [p for p in os.listdir(path) if os.path.isdir(os.path.join(path, p)) and p.lower() == p and p != 'admin']
ret.sort()
return ret
# }}}
def new_group(name): # {{{
path = os.path.join(config['data'], 'users')
target = os.path.join(path, name)
assert not os.path.exists(target)
os.mkdir(target)
# }}}
def del_group(name): # {{{
os.rmdir(os.path.join(config['data'], 'users', name))
# }}}
def new_user(group, name): # {{{
path = os.path.join(config['data'], 'users', group.lower())
assert os.path.exists(path)
target = os.path.join(path, name.lower())
assert not os.path.exists(target)
ret = default_user(group, name)
save(ret)
# }}}
def del_user(group, name): # {{{
path = os.path.join(config['data'], 'users', group.lower(), name)
assert os.path.exists(target)
os.unlink(target)
# }}}
def list_group(group): # {{{
path = os.path.join(config['data'], 'users', group.lower())
if not os.path.exists(path):
debug(0, 'list_group called for nonexistent group {}'.format(group))
return []
return [p for p in os.listdir(path) if p == p.lower() and not os.path.isdir(os.path.join(path, p))]
# }}}
def save(user): # {{{
'''Save user information to disk.'''
with open(os.path.join(config['data'], 'users', user['group'].lower(), user['filename']), 'w', errors = 'replace') as f:
for key in user:
if user[key] is None or key in unsaved:
continue
f.write('{}={}\n'.format(key, user[key]))
# Record answers.
if not user['nosave'] and 'answers' in user:
for s in user['answers']:
if s[0] == 'sandbox':
continue
section = user['answers'][s]
for q in section:
question = section[q]
f.write('answer:{}:{}:{}={}\n'.format(s[0], s[1], q, ';'.join(json.dumps(a) for a in question)))
# }}}
def save_all(): # {{{
for user in users:
save(user)
# }}}
def refresh_admins(): # {{{
for a in admins:
admins[a].refresh()
# }}}
# vim: set foldmethod=marker :