Differences From
Artifact [6e4ba75dd2]:
1 1 -- vim: ft=terra
2 2 local pstr = lib.mem.ptr(int8)
3 3 local pref = lib.mem.ref(int8)
4 +local P = lib.str.plit
4 5
5 6 local terra cs(s: rawstring)
6 7 return pstr { ptr = s, ct = lib.str.sz(s) }
7 8 end
8 9
9 10 local terra
11 +regalia(acc: &lib.str.acc, rank: uint16)
12 + switch rank do -- TODO customizability
13 + case [uint16](1) then acc:lpush('๐') end
14 + case [uint16](2) then acc:lpush('๐ฑ') end
15 + case [uint16](3) then acc:lpush('โ๏ธ') end
16 + case [uint16](4) then acc:lpush('๐ก') end
17 + case [uint16](5) then acc:lpush('๐') end
18 + else acc:lpush('๐ด')
19 + end
20 +end
21 +
22 +local num_field = macro(function(acc,name,lbl,min,max,value)
23 + name = name:asvalue()
24 + lbl = lbl:asvalue()
25 + return quote
26 + 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>')
31 + end
32 +end)
33 +
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>')
40 +end
41 +
42 +local mode_local, mode_remote, mode_staff, mode_peers, mode_peons, mode_all = 0,1,2,3,4,5
43 +local terra
10 44 render_conf_users(co: &lib.srv.convo, path: lib.mem.ptr(pref)): pstr
11 - if path.ct == 2 then
12 - var uid, ok = lib.math.shorthand.parse(path(1).ptr,path(1).ct)
45 + if path.ct == 3 then
46 + var uid, ok = lib.math.shorthand.parse(path(2).ptr,path(2).ct)
47 + if not ok then goto e404 end
13 48 var user = co.srv:actor_fetch_uid(uid)
49 + -- FIXME allow xids as well, for manual queries
14 50 if not user then goto e404 end
51 + defer user:free()
52 + if not co.who:overpowers(user.ptr) then goto e403 end
53 +
15 54 var islinkct = false
16 - var cinp: lib.str.acc
55 + var cinp: lib.str.acc cinp:init(128)
17 56 var clnk: lib.str.acc clnk:compose('<hr>')
57 + cinp:lpush('<div class="elem-group">')
58 + if co.who.rights.powers.herald() then
59 + var sanitized: pstr
60 + if user.ptr.epithet == nil
61 + then sanitized = pstr {ptr='', ct=0}
62 + else sanitized = lib.html.sanitize(cs(user.ptr.epithet),true)
63 + end
64 + cinp:lpush('<div class="elem"><label for="epithet">epithet</label><input type="text" id="epithet" name="epithet" value="'):ppush(sanitized):lpush('"></div>')
65 + if user.ptr.epithet ~= nil then sanitized:free() end
66 + 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 + if co.who.rights.powers.invite() or co.who.rights.powers.discipline() then
76 + var min = 0
77 + if not (co.who.rights.powers.discipline() or
78 + co.who.rights.powers.demote() and co.who.rights.powers.invite())
79 + then min = user.ptr.rights.invites end
80 + var max = co.srv.cfg.maxinvites
81 + if not co.who.rights.powers.invite() then max = user.ptr.rights.invites end
82 +
83 + num_field(cinp, 'invites', 'invites', min, max, user.ptr.rights.invites)
84 + end
85 + cinp:lpush('</div><div class="check-panel">')
86 +
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)
90 + end
91 +
92 + cinp:lpush('</div>')
93 +
94 + if co.who.rights.powers.elevate() or
95 + co.who.rights.powers.demote() then
96 + var map = array([lib.store.privmap])
97 + cinp:lpush('<label>powers</label><div class="check-panel">')
98 + 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
103 + ((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)
108 + end
109 + end
110 + cinp:lpush('</div>')
111 + end
112 +
113 + -- TODO black mark system? e.g. resolution option for badthink reports
114 + -- adds a black mark to the offending user; they can be automatically banned
115 + -- or brought up for review after a certain number of offenses; possibly lower
116 + -- set of default privs for marked users
18 117
19 118 var cinpp = cinp:finalize() defer cinpp:free()
20 119 var clnkp: pstr
21 120 if islinkct then clnkp = clnk:finalize() else
22 121 clnk:free()
23 122 clnkp = pstr { ptr='', ct=0 }
24 123 end
124 + var unym: lib.str.acc unym:init(64)
125 + unym:lpush('<a href="/')
126 + if user(0).origin ~= 0 then unym:lpush('@') end
127 + do var sanxid = lib.html.sanitize(user(0).xid, true)
128 + unym:ppush(sanxid)
129 + sanxid:free() end
130 + unym:lpush('" class="id">')
131 + lib.render.nym(user.ptr,0,&unym)
132 + unym:lpush('</a>')
25 133 var pg = data.view.conf_user_ctl {
26 - name = cs(user(0).handle);
134 + name = unym:finalize();
27 135 inputcontent = cinpp;
28 136 linkcontent = clnkp;
29 137 }
30 138 var ret = pg:tostr()
139 + pg.name:free()
31 140 if islinkct then clnkp:free() end
32 141 return ret
33 142 else
34 -
143 + var modes = array(P'local', P'remote', P'staff', P'titled', P'peons', P'all')
144 + var idbuf: int8[lib.math.shorthand.maxlen]
145 + var ulst: lib.str.acc ulst:init(256)
146 + var mode: uint8 = mode_local
147 + var modestr = co:pgetv('show')
148 + ulst:lpush('<div style="text-align: right"><em>showing ')
149 + for i=0,[modes.type.N] do
150 + if modestr:ref() and modes[i]:cmp(modestr) then mode = i end
151 + end
152 + for i=0,[modes.type.N] do
153 + if i > 0 then ulst:lpush(' ยท ') end
154 + if mode == i then
155 + ulst:lpush('<strong>'):ppush(modes[i]):lpush('</strong>')
156 + else
157 + ulst:lpush('<a href="?show='):ppush(modes[i]):lpush('">')
158 + :ppush(modes[i]):lpush('</a>')
159 + end
160 + end
161 + var users: lib.mem.lstptr(lib.store.actor)
162 + if mode == mode_local then
163 + users = co.srv:actor_enum_local()
164 + else
165 + users = co.srv:actor_enum()
166 + end
167 + ulst:lpush('</em></div>')
168 + ulst:lpush('<ul class="user-list">')
169 + for i=0,users.ct do var usr = users(i).ptr
170 + if mode == mode_staff and usr.rights.rank == 0 then goto skip
171 + elseif mode == mode_peons and usr.rights.rank ~= 0 then goto skip
172 + elseif mode == mode_remote and usr.origin == 0 then goto skip
173 + elseif mode == mode_peers and usr.epithet == nil then goto skip end
174 + var idlen = lib.math.shorthand.gen(usr.id, &idbuf[0])
175 + ulst:lpush('<li>')
176 + if usr.rights.rank ~= 0 then
177 + ulst:lpush('<span class="regalia">')
178 + regalia(&ulst, usr.rights.rank)
179 + ulst:lpush('</span>')
180 + end
181 + if co.who:overpowers(usr) then
182 + ulst:lpush('<a class="id" href="users/'):push(&idbuf[0],idlen):lpush('">')
183 + lib.render.nym(usr, 0, &ulst)
184 + ulst:lpush('</a></li>')
185 + else
186 + ulst:lpush('<span class="id">')
187 + lib.render.nym(usr, 0, &ulst)
188 + ulst:lpush('</span></li>')
189 + end
190 + ::skip::end
191 + ulst:lpush('</ul>')
192 + return ulst:finalize()
35 193 end
36 194 do return pstr.null() end
37 - ::e404:: co:complain(404, 'not found', 'there is no user or resource by that identifier on this server')
195 + ::e404:: co:complain(404, 'not found', 'there is no user or resource by that identifier on this server') goto quit
196 + ::e403:: co:complain(403, 'forbidden', 'you do not have sufficient authority to control that resource')
38 197
39 - do return pstr.null() end
198 + ::quit:: return pstr.null()
40 199 end
41 200
42 201 return render_conf_users