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
...
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
|
case [uint16](3) then acc:lpush('⚜️') end
case [uint16](4) then acc:lpush('🗡') end
case [uint16](5) then acc:lpush('🗝') end
else acc:lpush('🕴')
end
end
local num_field = macro(function(acc,name,lbl,min,max,value)
name = name:asvalue()
lbl = lbl:asvalue()
return quote
var decbuf: int8[21]
in acc:lpush([string.format('<div class="elem small"><label for="%s">%s</label><input type="number" id="%s" name="%s" min="', name, lbl, name, name)])
:push(lib.math.decstr(min, &decbuf[20]),0)
:lpush('" max="'):push(lib.math.decstr(max, &decbuf[20]),0)
:lpush('" value="'):push(lib.math.decstr(value, &decbuf[20]),0):lpush('"></div>')
end
end)
local terra
push_checkbox(acc: &lib.str.acc, name: pstr, lbl: pstr, on: bool, enabled: bool)
acc:lpush('<label><input type="checkbox" name="'):ppush(name):lpush('"')
if on then acc:lpush(' checked') end
if not enabled then acc:lpush(' disabled') end
acc:lpush('> '):ppush(lbl):lpush('</label>')
end
local mode_local, mode_remote, mode_staff, mode_peers, mode_peons, mode_all = 0,1,2,3,4,5
local terra
render_conf_users(co: &lib.srv.convo, path: lib.mem.ptr(pref)): pstr
if path.ct == 3 then
var uid, ok = lib.math.shorthand.parse(path(2).ptr,path(2).ct)
if not ok then goto e404 end
var user = co.srv:actor_fetch_uid(uid)
-- FIXME allow xids as well, for manual queries
if not user then goto e404 end
defer user:free()
if not co.who:overpowers(user.ptr) then goto e403 end
var islinkct = false
var cinp: lib.str.acc cinp:init(128)
var clnk: lib.str.acc clnk:compose('<hr>')
cinp:lpush('<div class="elem-group">')
if co.who.rights.powers.herald() then
var sanitized: pstr
if user.ptr.epithet == nil
then sanitized = pstr {ptr='', ct=0}
else sanitized = lib.html.sanitize(cs(user.ptr.epithet),true)
end
cinp:lpush('<div class="elem"><label for="epithet">epithet</label><input type="text" id="epithet" name="epithet" value="'):ppush(sanitized):lpush('"></div>')
if user.ptr.epithet ~= nil then sanitized:free() end
end
if user.ptr.rights.rank > 0 and (co.who.rights.powers.elevate() or co.who.rights.powers.demote()) then
var max = co.who.rights.rank
if not co.who.rights.powers.elevate() then max = user.ptr.rights.rank end
var min = co.srv.cfg.nranks
if not co.who.rights.powers.demote() then min = user.ptr.rights.rank end
num_field(cinp, 'rank', 'rank', max, min, user.ptr.rights.rank)
end
if co.who.rights.powers.invite() or co.who.rights.powers.discipline() then
var min = 0
if not (co.who.rights.powers.discipline() or
co.who.rights.powers.demote() and co.who.rights.powers.invite())
then min = user.ptr.rights.invites end
var max = co.srv.cfg.maxinvites
if not co.who.rights.powers.invite() then max = user.ptr.rights.invites end
num_field(cinp, 'invites', 'invites', min, max, user.ptr.rights.invites)
end
cinp:lpush('</div><div class="check-panel">')
if (user.ptr.rights.rank == 0 and co.who.rights.powers.elevate()) or
(user.ptr.rights.rank > 0 and co.who.rights.powers.demote()) then
push_checkbox(&cinp, 'staff', 'site staff member', user.ptr.rights.rank > 0, true)
end
cinp:lpush('</div>')
if co.who.rights.powers.elevate() or
co.who.rights.powers.demote() then
var map = array([lib.store.privmap])
cinp:lpush('<label>powers</label><div class="check-panel">')
for i=0, [map.type.N] do
if (co.who.rights.powers and map[i].priv) == map[i].priv then
var name: int8[64]
var on = (user.ptr.rights.powers and map[i].priv) == map[i].priv
var enabled = (on and co.who.rights.powers.demote()) or
((not on) and co.who.rights.powers.elevate())
lib.str.cpy(&name[0], 'allow-')
lib.str.ncpy(&name[6], map[i].name.ptr, map[i].name.ct)
push_checkbox(&cinp, pstr{ptr=&name[0],ct=map[i].name.ct+6},
map[i].name, on, enabled)
end
end
cinp:lpush('</div>')
end
-- TODO black mark system? e.g. resolution option for badthink reports
-- adds a black mark to the offending user; they can be automatically banned
-- or brought up for review after a certain number of offenses; possibly lower
-- set of default privs for marked users
var cinpp = cinp:finalize() defer cinpp:free()
var clnkp: pstr
if islinkct then clnkp = clnk:finalize() else
clnk:free()
clnkp = pstr { ptr='', ct=0 }
end
var unym: lib.str.acc unym:init(64)
unym:lpush('<a href="/')
if user(0).origin ~= 0 then unym:lpush('@') end
do var sanxid = lib.html.sanitize(user(0).xid, true)
................................................................................
var pg = data.view.conf_user_ctl {
name = unym:finalize();
inputcontent = cinpp;
linkcontent = clnkp;
}
var ret = pg:tostr()
pg.name:free()
if islinkct then clnkp:free() end
return ret
else
var modes = array(P'local', P'remote', P'staff', P'titled', P'peons', P'all')
var idbuf: int8[lib.math.shorthand.maxlen]
var ulst: lib.str.acc ulst:init(256)
var mode: uint8 = mode_local
var modestr = co:pgetv('show')
|
|
>
>
>
<
>
>
>
>
|
|
|
|
|
>
<
<
<
>
>
>
>
>
>
>
>
>
>
>
|
|
>
>
>
>
>
|
|
>
>
>
>
>
>
>
<
|
|
>
>
>
>
>
>
>
>
<
<
<
<
<
<
<
<
|
|
>
|
|
|
|
|
|
<
>
|
<
|
|
|
|
<
|
>
|
|
|
|
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
142
143
144
145
146
147
148
149
150
151
152
153
...
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
|
case [uint16](3) then acc:lpush('⚜️') end
case [uint16](4) then acc:lpush('🗡') end
case [uint16](5) then acc:lpush('🗝') end
else acc:lpush('🕴')
end
end
local push_num_field = macro(function(acc,name,lbl,min,max,value,disable)
name = name:asvalue()
lbl = lbl:asvalue()
local start = '<div class="elem small">'
local enabled = start .. string.format('<label for="%s">%s</label><input type="number" id="%s" name="%s" min="', name, lbl, name, name)
local disabled = start .. string.format('<label>%s</label><div class="txtbox">', lbl)
return quote
var decbuf: int8[21]
if disable then
acc:lpush([disabled])
:push(lib.math.decstr(value, &decbuf[20]),0):lpush('</div></div>')
else
acc:lpush([enabled]):push(lib.math.decstr(min, &decbuf[20]),0)
:lpush('" max="'):push(lib.math.decstr(max, &decbuf[20]),0)
:lpush('" value="'):push(lib.math.decstr(value, &decbuf[20]),0):lpush('"></div>')
end
end
end)
local input_pusher = function(kind,wrap,uniq)
local fn = terra(acc: &lib.str.acc, name: pstr, val: pstr, lbl: pstr, on: bool, enabled: bool, class: pstr)
if wrap then acc:lpush('<label>') end
acc:lpush(['<input type="'..kind..'" name="']):ppush(name)
if not wrap then
acc:lpush('" id="'):ppush(name)
if uniq then acc:lpush('-'):ppush(val) end
end
if val:ref() then acc:lpush('" value="'):ppush(val) end
if class:ref() then acc:lpush('" class="'):ppush(class) end
acc:lpush('"')
if on then acc:lpush(' checked') end
if not enabled then acc:lpush(' disabled') end
acc:lpush('>')
if not wrap then acc:lpush('<label for="'):ppush(name)
if uniq then acc:lpush('-'):ppush(val) end
acc:lpush('">')
else acc:lpush(' ') end
acc:ppush(lbl):lpush('</label>')
end
fn.name = string.format('push-input-element<%q>',kind)
return fn
end
local push_checkbox = input_pusher('checkbox',true,false)
local push_pickbox = input_pusher('checkbox',false,false)
local push_radio = input_pusher('radio',false,true)
local mode_local, mode_remote, mode_staff, mode_peers, mode_peons, mode_all = 0,1,2,3,4,5
local terra
render_conf_users(co: &lib.srv.convo, path: lib.mem.ptr(pref)): pstr
if path.ct == 3 then
var uid, ok = lib.math.shorthand.parse(path(2).ptr,path(2).ct)
if not ok then goto e404 end
var user = co.srv:actor_fetch_uid(uid)
-- FIXME allow xids as well, for manual queries
if not user then goto e404 end
defer user:free()
if not co.who:overpowers(user.ptr) then goto e403 end
var cinp: lib.str.acc cinp:init(256)
var clnk: lib.str.acc clnk:init(512)
cinp:lpush('<div class="elem-group">')
if user.ptr.rights.rank > 0 and (co.who.rights.powers.elevate() or co.who.rights.powers.demote()) then
var max = co.who.rights.rank
if not co.who.rights.powers.elevate() then max = user.ptr.rights.rank end
var min = co.srv.cfg.nranks
if not co.who.rights.powers.demote() then min = user.ptr.rights.rank end
push_num_field(cinp, 'rank', 'rank', max, min, user.ptr.rights.rank, user.ptr.id == co.who.id)
end
if co.who.rights.powers.herald() then
var sanitized: pstr
if user.ptr.epithet == nil
then sanitized = pstr {ptr='', ct=0}
else sanitized = lib.html.sanitize(cs(user.ptr.epithet),true)
end
cinp:lpush('<div class="elem"><label for="epithet">epithet</label><input type="text" id="epithet" name="epithet" value="'):ppush(sanitized):lpush('"></div>')
if user.ptr.epithet ~= nil then sanitized:free() end
end
if co.who.rights.powers.invite() or co.who.rights.powers.discipline() then
var min = 0
if not (co.who.rights.powers.discipline() or
co.who.rights.powers.demote() and co.who.rights.powers.invite())
then min = user.ptr.rights.invites end
var max = co.srv.cfg.maxinvites
if not co.who.rights.powers.invite() then max = user.ptr.rights.invites end
push_num_field(cinp, 'invites', 'invites', min, max, user.ptr.rights.invites, false)
end
cinp:lpush('</div><div class="elem"><div class="check-panel">')
if user.ptr.id ~= co.who.id and
((user.ptr.rights.rank == 0 and co.who.rights.powers.elevate()) or
(user.ptr.rights.rank > 0 and co.who.rights.powers.demote())) then
push_checkbox(&cinp, 'staff', pstr.null(), 'site staff member', user.ptr.rights.rank > 0, true, pstr.null())
end
cinp:lpush('</div></div>')
if (co.who.rights.powers.elevate() or
co.who.rights.powers.demote()) and user.ptr.id ~= co.who.id then
var map = array([lib.store.privmap])
cinp:lpush('<details><summary>powers</summary><div class="pick-list">')
for i=0, [map.type.N] do
if (co.who.rights.powers and map[i].priv):sz() > 0 then
var on = (user.ptr.rights.powers and map[i].priv):sz() > 0
var enabled = ( on and co.who.rights.powers.demote() ) or
((not on) and co.who.rights.powers.elevate())
var namea: lib.str.acc namea:compose('power-', map[i].name)
var name = namea:finalize()
push_pickbox(&cinp, name, pstr.null(), map[i].name, on, enabled, pstr.null())
name:free()
end
end
cinp:lpush('</div></details>')
end
-- TODO black mark system? e.g. resolution option for badthink reports
-- adds a black mark to the offending user; they can be automatically banned
-- or brought up for review after a certain number of offenses; possibly lower
-- set of default privs for marked users
var cinpp = cinp:finalize() defer cinpp:free()
var clnkp: pstr
if clnk.sz > 0 then clnkp = clnk:finalize() else
clnk:free()
clnkp = pstr { ptr='', ct=0 }
end
var unym: lib.str.acc unym:init(64)
unym:lpush('<a href="/')
if user(0).origin ~= 0 then unym:lpush('@') end
do var sanxid = lib.html.sanitize(user(0).xid, true)
................................................................................
var pg = data.view.conf_user_ctl {
name = unym:finalize();
inputcontent = cinpp;
linkcontent = clnkp;
}
var ret = pg:tostr()
pg.name:free()
if clnkp.ct > 0 then clnkp:free() end
return ret
else
var modes = array(P'local', P'remote', P'staff', P'titled', P'peons', P'all')
var idbuf: int8[lib.math.shorthand.maxlen]
var ulst: lib.str.acc ulst:init(256)
var mode: uint8 = mode_local
var modestr = co:pgetv('show')
|