parsav  Diff

Differences From Artifact [6e4ba75dd2]:

To Artifact [4494d99300]:


     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