parsav  Diff

Differences From Artifact [6e4ba75dd2]:

To Artifact [4494d99300]:


1
2
3

4
5
6
7
8
9

































10
11
12

13

14



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
-- vim: ft=terra
local pstr = lib.mem.ptr(int8)
local pref = lib.mem.ref(int8)


local terra cs(s: rawstring)
	return pstr { ptr = s, ct = lib.str.sz(s) }
end

local terra 

































render_conf_users(co: &lib.srv.convo, path: lib.mem.ptr(pref)): pstr
	if path.ct == 2 then
		var uid, ok = lib.math.shorthand.parse(path(1).ptr,path(1).ct)

		var user = co.srv:actor_fetch_uid(uid)

		if not user then goto e404 end



		var islinkct = false
		var cinp: lib.str.acc
		var clnk: lib.str.acc clnk:compose('<hr>')





























































		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 pg = data.view.conf_user_ctl {
			name = cs(user(0).handle);

			inputcontent = cinpp;
			linkcontent = clnkp;
		}
		var ret = pg:tostr()

		if islinkct then clnkp:free() end
		return ret
	else









	end










































	do return pstr.null() end
	::e404:: co:complain(404, 'not found', 'there is no user or resource by that identifier on this server')


	do return pstr.null() end
end

return render_conf_users



>






>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

|
|
>

>

>
>
>

|

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>






>
>
>
>
>
>
>
>
>

<
>




>



<
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

|
>

|



1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
-- vim: ft=terra
local pstr = lib.mem.ptr(int8)
local pref = lib.mem.ref(int8)
local P = lib.str.plit

local terra cs(s: rawstring)
	return pstr { ptr = s, ct = lib.str.sz(s) }
end

local terra 
regalia(acc: &lib.str.acc, rank: uint16)
	switch rank do -- TODO customizability
		case [uint16](1) then acc:lpush('๐Ÿ‘‘') end
		case [uint16](2) then acc:lpush('๐Ÿ”ฑ') end
		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)
			unym:ppush(sanxid)
			sanxid:free() end
		unym:lpush('" class="id">')
		lib.render.nym(user.ptr,0,&unym)
		unym:lpush('</a>')
		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')
		ulst:lpush('<div style="text-align: right"><em>showing ')
		for i=0,[modes.type.N] do
			if modestr:ref() and modes[i]:cmp(modestr) then mode = i end
		end
		for i=0,[modes.type.N] do
			if i > 0 then ulst:lpush(' ยท ') end
			if mode == i then
				ulst:lpush('<strong>'):ppush(modes[i]):lpush('</strong>')
			else
				ulst:lpush('<a href="?show='):ppush(modes[i]):lpush('">')
					:ppush(modes[i]):lpush('</a>')
			end
		end
		var users: lib.mem.lstptr(lib.store.actor)
		if mode == mode_local then
			users = co.srv:actor_enum_local()
		else
			users = co.srv:actor_enum()
		end
		ulst:lpush('</em></div>')
		ulst:lpush('<ul class="user-list">')
		for i=0,users.ct do var usr = users(i).ptr
			if mode == mode_staff and usr.rights.rank == 0 then goto skip
			elseif mode == mode_peons and usr.rights.rank ~= 0 then goto skip
			elseif mode == mode_remote and usr.origin == 0 then goto skip 
			elseif mode == mode_peers and usr.epithet == nil then goto skip end
			var idlen = lib.math.shorthand.gen(usr.id, &idbuf[0])
			ulst:lpush('<li>')
			if usr.rights.rank ~= 0 then
				ulst:lpush('<span class="regalia">')
				regalia(&ulst, usr.rights.rank)
				ulst:lpush('</span>')
			end
			if co.who:overpowers(usr) then
				ulst:lpush('<a class="id" href="users/'):push(&idbuf[0],idlen):lpush('">')
				lib.render.nym(usr, 0, &ulst)
				ulst:lpush('</a></li>')
			else
				ulst:lpush('<span class="id">')
				lib.render.nym(usr, 0, &ulst)
				ulst:lpush('</span></li>')
			end
		::skip::end
		ulst:lpush('</ul>')
		return ulst:finalize()
	end
	do return pstr.null() end
	::e404:: co:complain(404, 'not found', 'there is no user or resource by that identifier on this server') goto quit
	::e403:: co:complain(403, 'forbidden', 'you do not have sufficient authority to control that resource')

	::quit:: return pstr.null()
end

return render_conf_users