Differences From
Artifact [4494d99300]:
15 15 case [uint16](3) then acc:lpush('⚜️') end
16 16 case [uint16](4) then acc:lpush('🗡') end
17 17 case [uint16](5) then acc:lpush('🗝') end
18 18 else acc:lpush('🕴')
19 19 end
20 20 end
21 21
22 -local num_field = macro(function(acc,name,lbl,min,max,value)
22 +local push_num_field = macro(function(acc,name,lbl,min,max,value,disable)
23 23 name = name:asvalue()
24 24 lbl = lbl:asvalue()
25 + local start = '<div class="elem small">'
26 + local enabled = start .. string.format('<label for="%s">%s</label><input type="number" id="%s" name="%s" min="', name, lbl, name, name)
27 + local disabled = start .. string.format('<label>%s</label><div class="txtbox">', lbl)
25 28 return quote
26 29 var decbuf: int8[21]
27 - 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)])
28 - :push(lib.math.decstr(min, &decbuf[20]),0)
29 - :lpush('" max="'):push(lib.math.decstr(max, &decbuf[20]),0)
30 - :lpush('" value="'):push(lib.math.decstr(value, &decbuf[20]),0):lpush('"></div>')
30 + if disable then
31 + acc:lpush([disabled])
32 + :push(lib.math.decstr(value, &decbuf[20]),0):lpush('</div></div>')
33 + else
34 + acc:lpush([enabled]):push(lib.math.decstr(min, &decbuf[20]),0)
35 + :lpush('" max="'):push(lib.math.decstr(max, &decbuf[20]),0)
36 + :lpush('" value="'):push(lib.math.decstr(value, &decbuf[20]),0):lpush('"></div>')
37 + end
31 38 end
32 39 end)
33 40
34 -local terra
35 -push_checkbox(acc: &lib.str.acc, name: pstr, lbl: pstr, on: bool, enabled: bool)
36 - acc:lpush('<label><input type="checkbox" name="'):ppush(name):lpush('"')
37 - if on then acc:lpush(' checked') end
38 - if not enabled then acc:lpush(' disabled') end
39 - acc:lpush('> '):ppush(lbl):lpush('</label>')
41 +local input_pusher = function(kind,wrap,uniq)
42 + local fn = terra(acc: &lib.str.acc, name: pstr, val: pstr, lbl: pstr, on: bool, enabled: bool, class: pstr)
43 + if wrap then acc:lpush('<label>') end
44 + acc:lpush(['<input type="'..kind..'" name="']):ppush(name)
45 + if not wrap then
46 + acc:lpush('" id="'):ppush(name)
47 + if uniq then acc:lpush('-'):ppush(val) end
48 + end
49 + if val:ref() then acc:lpush('" value="'):ppush(val) end
50 + if class:ref() then acc:lpush('" class="'):ppush(class) end
51 + acc:lpush('"')
52 + if on then acc:lpush(' checked') end
53 + if not enabled then acc:lpush(' disabled') end
54 + acc:lpush('>')
55 + if not wrap then acc:lpush('<label for="'):ppush(name)
56 + if uniq then acc:lpush('-'):ppush(val) end
57 + acc:lpush('">')
58 + else acc:lpush(' ') end
59 + acc:ppush(lbl):lpush('</label>')
60 + end
61 + fn.name = string.format('push-input-element<%q>',kind)
62 + return fn
40 63 end
64 +
65 +local push_checkbox = input_pusher('checkbox',true,false)
66 +local push_pickbox = input_pusher('checkbox',false,false)
67 +local push_radio = input_pusher('radio',false,true)
41 68
42 69 local mode_local, mode_remote, mode_staff, mode_peers, mode_peons, mode_all = 0,1,2,3,4,5
43 70 local terra
44 71 render_conf_users(co: &lib.srv.convo, path: lib.mem.ptr(pref)): pstr
45 72 if path.ct == 3 then
46 73 var uid, ok = lib.math.shorthand.parse(path(2).ptr,path(2).ct)
47 74 if not ok then goto e404 end
48 75 var user = co.srv:actor_fetch_uid(uid)
49 76 -- FIXME allow xids as well, for manual queries
50 77 if not user then goto e404 end
51 78 defer user:free()
52 79 if not co.who:overpowers(user.ptr) then goto e403 end
53 80
54 - var islinkct = false
55 - var cinp: lib.str.acc cinp:init(128)
56 - var clnk: lib.str.acc clnk:compose('<hr>')
81 + var cinp: lib.str.acc cinp:init(256)
82 + var clnk: lib.str.acc clnk:init(512)
57 83 cinp:lpush('<div class="elem-group">')
84 + if user.ptr.rights.rank > 0 and (co.who.rights.powers.elevate() or co.who.rights.powers.demote()) then
85 + var max = co.who.rights.rank
86 + if not co.who.rights.powers.elevate() then max = user.ptr.rights.rank end
87 + var min = co.srv.cfg.nranks
88 + if not co.who.rights.powers.demote() then min = user.ptr.rights.rank end
89 +
90 + push_num_field(cinp, 'rank', 'rank', max, min, user.ptr.rights.rank, user.ptr.id == co.who.id)
91 + end
58 92 if co.who.rights.powers.herald() then
59 93 var sanitized: pstr
60 94 if user.ptr.epithet == nil
61 95 then sanitized = pstr {ptr='', ct=0}
62 96 else sanitized = lib.html.sanitize(cs(user.ptr.epithet),true)
63 97 end
64 98 cinp:lpush('<div class="elem"><label for="epithet">epithet</label><input type="text" id="epithet" name="epithet" value="'):ppush(sanitized):lpush('"></div>')
65 99 if user.ptr.epithet ~= nil then sanitized:free() end
66 100 end
67 - if user.ptr.rights.rank > 0 and (co.who.rights.powers.elevate() or co.who.rights.powers.demote()) then
68 - var max = co.who.rights.rank
69 - if not co.who.rights.powers.elevate() then max = user.ptr.rights.rank end
70 - var min = co.srv.cfg.nranks
71 - if not co.who.rights.powers.demote() then min = user.ptr.rights.rank end
72 -
73 - num_field(cinp, 'rank', 'rank', max, min, user.ptr.rights.rank)
74 - end
75 101 if co.who.rights.powers.invite() or co.who.rights.powers.discipline() then
76 102 var min = 0
77 103 if not (co.who.rights.powers.discipline() or
78 104 co.who.rights.powers.demote() and co.who.rights.powers.invite())
79 105 then min = user.ptr.rights.invites end
80 106 var max = co.srv.cfg.maxinvites
81 107 if not co.who.rights.powers.invite() then max = user.ptr.rights.invites end
82 108
83 - num_field(cinp, 'invites', 'invites', min, max, user.ptr.rights.invites)
109 + push_num_field(cinp, 'invites', 'invites', min, max, user.ptr.rights.invites, false)
84 110 end
85 - cinp:lpush('</div><div class="check-panel">')
111 + cinp:lpush('</div><div class="elem"><div class="check-panel">')
86 112
87 - if (user.ptr.rights.rank == 0 and co.who.rights.powers.elevate()) or
88 - (user.ptr.rights.rank > 0 and co.who.rights.powers.demote()) then
89 - push_checkbox(&cinp, 'staff', 'site staff member', user.ptr.rights.rank > 0, true)
113 + if user.ptr.id ~= co.who.id and
114 + ((user.ptr.rights.rank == 0 and co.who.rights.powers.elevate()) or
115 + (user.ptr.rights.rank > 0 and co.who.rights.powers.demote())) then
116 + push_checkbox(&cinp, 'staff', pstr.null(), 'site staff member', user.ptr.rights.rank > 0, true, pstr.null())
90 117 end
91 118
92 - cinp:lpush('</div>')
119 + cinp:lpush('</div></div>')
93 120
94 - if co.who.rights.powers.elevate() or
95 - co.who.rights.powers.demote() then
121 + if (co.who.rights.powers.elevate() or
122 + co.who.rights.powers.demote()) and user.ptr.id ~= co.who.id then
96 123 var map = array([lib.store.privmap])
97 - cinp:lpush('<label>powers</label><div class="check-panel">')
124 + cinp:lpush('<details><summary>powers</summary><div class="pick-list">')
98 125 for i=0, [map.type.N] do
99 - if (co.who.rights.powers and map[i].priv) == map[i].priv then
100 - var name: int8[64]
101 - var on = (user.ptr.rights.powers and map[i].priv) == map[i].priv
102 - var enabled = (on and co.who.rights.powers.demote()) or
126 + if (co.who.rights.powers and map[i].priv):sz() > 0 then
127 + var on = (user.ptr.rights.powers and map[i].priv):sz() > 0
128 + var enabled = ( on and co.who.rights.powers.demote() ) or
103 129 ((not on) and co.who.rights.powers.elevate())
104 - lib.str.cpy(&name[0], 'allow-')
105 - lib.str.ncpy(&name[6], map[i].name.ptr, map[i].name.ct)
106 - push_checkbox(&cinp, pstr{ptr=&name[0],ct=map[i].name.ct+6},
107 - map[i].name, on, enabled)
130 + var namea: lib.str.acc namea:compose('power-', map[i].name)
131 + var name = namea:finalize()
132 + push_pickbox(&cinp, name, pstr.null(), map[i].name, on, enabled, pstr.null())
133 + name:free()
108 134 end
109 135 end
110 - cinp:lpush('</div>')
136 + cinp:lpush('</div></details>')
111 137 end
112 138
113 139 -- TODO black mark system? e.g. resolution option for badthink reports
114 140 -- adds a black mark to the offending user; they can be automatically banned
115 141 -- or brought up for review after a certain number of offenses; possibly lower
116 142 -- set of default privs for marked users
117 143
118 144 var cinpp = cinp:finalize() defer cinpp:free()
119 145 var clnkp: pstr
120 - if islinkct then clnkp = clnk:finalize() else
146 + if clnk.sz > 0 then clnkp = clnk:finalize() else
121 147 clnk:free()
122 148 clnkp = pstr { ptr='', ct=0 }
123 149 end
124 150 var unym: lib.str.acc unym:init(64)
125 151 unym:lpush('<a href="/')
126 152 if user(0).origin ~= 0 then unym:lpush('@') end
127 153 do var sanxid = lib.html.sanitize(user(0).xid, true)
................................................................................
133 159 var pg = data.view.conf_user_ctl {
134 160 name = unym:finalize();
135 161 inputcontent = cinpp;
136 162 linkcontent = clnkp;
137 163 }
138 164 var ret = pg:tostr()
139 165 pg.name:free()
140 - if islinkct then clnkp:free() end
166 + if clnkp.ct > 0 then clnkp:free() end
141 167 return ret
142 168 else
143 169 var modes = array(P'local', P'remote', P'staff', P'titled', P'peons', P'all')
144 170 var idbuf: int8[lib.math.shorthand.maxlen]
145 171 var ulst: lib.str.acc ulst:init(256)
146 172 var mode: uint8 = mode_local
147 173 var modestr = co:pgetv('show')