parsav  Diff

Differences From Artifact [4494d99300]:

To Artifact [09fa445b20]:


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