parsav  Diff

Differences From Artifact [4494d99300]:

To Artifact [09fa445b20]:


    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')