Differences From
Artifact [a9eb70a00e]:
2 2 local r = lib.srv.route
3 3 local method = lib.http.method
4 4 local pstring = lib.mem.ptr(int8)
5 5 local rstring = lib.mem.ref(int8)
6 6 local hpath = lib.mem.ptr(rstring)
7 7 local http = {}
8 8
9 +terra meth_get(meth: method.t) return (meth == method.get) or (meth == method.head) end
9 10 terra http.actor_profile_xid(co: &lib.srv.convo, uri: lib.mem.ptr(int8), meth: method.t)
10 11 var handle = [lib.mem.ptr(int8)] { ptr = &uri.ptr[2], ct = 0 }
11 12 for i=2,uri.ct do
12 13 if uri.ptr[i] == @'/' or uri.ptr[i] == 0 then handle.ct = i - 2 break end
13 14 end
14 15 if handle.ct == 0 then
15 16 handle.ct = uri.ct - 2
................................................................................
56 57 end
57 58 defer actor:free()
58 59
59 60 lib.render.user_page(co, actor.ptr)
60 61 end
61 62
62 63 terra http.login_form(co: &lib.srv.convo, meth: method.t)
63 - if meth == method.get then
64 + if meth_get(meth) then
64 65 -- request a username
65 66 lib.render.login(co, nil, nil, lib.str.plit(nil))
66 67 elseif meth == method.post then
67 68 var usn, usnl = co:postv('user')
68 69 var am, aml = co:postv('authmethod')
69 70 var chrs, chrsl = co:postv('response')
70 71 var cs, authok = co.srv:actor_auth_how(co.peer, usn)
................................................................................
122 123 end
123 124
124 125 terra http.post_compose(co: &lib.srv.convo, meth: method.t)
125 126 if not co:assertpow('post') then return end
126 127 --if co.who.rights.powers.post() == false then
127 128 --co:complain(403,'insufficient privileges','you lack the <strong>post</strong> power and cannot perform this action')
128 129
129 - if meth == method.get then
130 + if meth_get(meth) then
130 131 lib.render.compose(co, nil, nil)
131 132 elseif meth == method.post then
132 133 var text, textlen = co:postv("post")
133 134 var acl, acllen = co:postv("acl")
134 135 var subj, subjlen = co:postv("subject")
135 136 if text == nil or acl == nil then
136 137 co:complain(405, 'invalid post', 'every post must have at least body text and an ACL')
................................................................................
138 139 end
139 140 if subj == nil then subj = '' end
140 141
141 142 var p = lib.store.post {
142 143 author = co.who.id, acl = acl;
143 144 body = text, subject = subj;
144 145 }
145 - var newid = co.srv:post_create(&p)
146 + var newid = p:publish(co.srv)
146 147
147 148 var idbuf: int8[lib.math.shorthand.maxlen]
148 149 var idlen = lib.math.shorthand.gen(newid, idbuf)
149 150 var redirto: lib.str.acc redirto:compose('/post/',{idbuf,idlen}) defer redirto:free()
150 151 co:reroute(redirto.buf)
151 152 end
152 153 end
................................................................................
181 182 if path.ct == 3 then
182 183 var lnk: lib.str.acc lnk:compose('/post/', path(1))
183 184 var lnkp = lnk:finalize() defer lnkp:free()
184 185 if post(0).author ~= co.who.id then
185 186 co:complain(403, 'forbidden', 'you cannot alter other people\'s posts')
186 187 return
187 188 elseif path(2):cmp(lib.str.lit 'edit') then
188 - if meth == method.get then
189 + if meth_get(meth) then
189 190 lib.render.compose(co, post.ptr, nil)
190 191 return
191 192 elseif meth == method.post then
192 193 var newbody = co:postv('post')._0
193 194 var newacl = co:postv('acl')._0
194 195 var newsubj = co:postv('subject')._0
195 196 if newbody ~= nil then post(0).body = newbody end
................................................................................
196 197 if newacl ~= nil then post(0).acl = newacl end
197 198 if newsubj ~= nil then post(0).subject = newsubj end
198 199 post(0):save(true)
199 200 co:reroute(lnkp.ptr)
200 201 end
201 202 return
202 203 elseif path(2):cmp(lib.str.lit 'del') then
203 - if meth == method.get then
204 + if meth_get(meth) then
204 205 var conf = data.view.confirm {
205 206 title = lib.str.plit 'delete post';
206 207 query = lib.str.plit 'are you sure you want to delete this post?';
207 208 cancel = lnkp
208 209 }
209 210 var body = conf:tostr() defer body:free()
210 211 co:stdpage([lib.srv.convo.page] {
................................................................................
220 221 co:reroute('/') -- TODO maybe return to parent or conversation if possible
221 222 return
222 223 else goto badop end
223 224 end
224 225 else goto badurl end
225 226 end
226 227
227 - if meth == method.post then goto badop end
228 + if meth == method.post then
229 + var replytext = co:ppostv('post')
230 + var acl = co:ppostv('acl')
231 + var subj = co:ppostv('subject')
232 + if not acl then acl = lib.str.plit 'all' end
233 + if not replytext then goto badop end
234 +
235 + var reply = lib.store.post {
236 + author = co.who.id, parent = pid;
237 + subject = subj.ptr, acl = acl.ptr, body = replytext.ptr;
238 + }
239 +
240 + reply:publish(co.srv)
241 + end
228 242
229 243 lib.render.tweet_page(co, path, post.ptr)
230 244 do return end
231 245
232 246 ::badurl:: do co:complain(404, 'invalid URL', 'this URL does not reference extant content or functionality') return end
233 247 ::badop :: do co:complain(405, 'invalid operation', 'the operation you have attempted on this post is not meaningful') return end
234 248 end
................................................................................
240 254 if path(1):cmp(lib.str.lit 'profile') then
241 255 lib.dbg('updating profile')
242 256 co.who.bio = co:postv('bio')._0
243 257 co.who.nym = co:postv('nym')._0
244 258 if co.who.bio ~= nil and @co.who.bio == 0 then co.who.bio = nil end
245 259 if co.who.nym ~= nil and @co.who.nym == 0 then co.who.nym = nil end
246 260 co.who.source:actor_save(co.who)
261 +
262 + var act = co:ppostv('act')
263 + var resethue = false
264 + if act:ref() then
265 + resethue = act:cmp(lib.str.plit 'reset-hue')
266 + end
267 +
268 + if not resethue then
269 + var shue = co:ppostv('hue')
270 + var nhue, okhue = lib.math.decparse(shue)
271 + if okhue and nhue ~= co.ui_hue then
272 + if nhue == co.srv.cfg.ui_hue
273 + then resethue = true
274 + else co.srv:actor_conf_int_set(co.who.id, 'ui-accent', nhue)
275 + end
276 + co.ui_hue = nhue
277 + end
278 + end
279 + if resethue then
280 + co.srv:actor_conf_int_reset(co.who.id, 'ui-accent')
281 + co.ui_hue = co.srv.cfg.ui_hue
282 + end
283 +
247 284 msg = lib.str.plit 'profile changes saved'
248 285 --user_refresh = true -- not really necessary here, actually
249 286 elseif path(1):cmp(lib.str.lit 'srv') then
250 287 if not co.who.rights.powers.config() then goto nopriv end
251 288 elseif path(1):cmp(lib.str.lit 'brand') then
252 289 if not co.who.rights.powers.rebrand() then goto nopriv end
253 290 elseif path(1):cmp(lib.str.lit 'users') then
................................................................................
322 359
323 360 -- entry points
324 361 terra r.dispatch_http(co: &lib.srv.convo, uri: lib.mem.ptr(int8), meth: method.t)
325 362 lib.dbg('handling URI of form ', {uri.ptr,uri.ct})
326 363 co.navbar = lib.render.nav(co)
327 364 -- some routes are non-hierarchical, and can be resolved with a simple strcmp
328 365 -- we run through those first before giving up and parsing the URI
329 - if uri.ptr[0] ~= @'/' then
366 + if uri.ptr == nil or uri.ptr[0] ~= @'/' then
330 367 co:complain(404, 'what the hell', 'how did you do that')
331 - return
332 368 elseif uri.ct == 1 then -- root
333 369 if (co.srv.cfg.pol_sec == lib.srv.secmode.private or
334 370 co.srv.cfg.pol_sec == lib.srv.secmode.lockdown) and co.aid == 0 then
335 371 http.login_form(co, meth)
336 - else
337 - -- FIXME display home screen
338 - http.timeline(co, hpath {ptr=nil})
339 - goto notfound
340 - end
341 - return
372 + else http.timeline(co, hpath {ptr=nil}) end
342 373 elseif uri.ptr[1] == @'@' then
343 374 http.actor_profile_xid(co, uri, meth)
344 - return
345 375 elseif uri.ptr[1] == @'s' and uri.ptr[2] == @'/' and uri.ct > 3 then
346 - if meth ~= method.get then goto wrongmeth end
376 + if not meth_get(meth) then goto wrongmeth end
347 377 if not http.static_content(co, uri.ptr + 3, uri.ct - 3) then goto notfound end
348 - return
349 378 elseif lib.str.ncmp('/avi/', uri.ptr, 5) == 0 then
350 379 http.local_avatar(co, [lib.mem.ptr(int8)] {ptr = uri.ptr + 5, ct = uri.ct - 5})
351 - return
352 380 elseif lib.str.ncmp('/compose', uri.ptr, lib.math.biggest(uri.ct,8)) == 0 then
353 381 if co.aid == 0 then co:reroute('/login') return end
354 382 http.post_compose(co,meth)
355 - return
356 383 elseif lib.str.ncmp('/login', uri.ptr, lib.math.biggest(uri.ct,6)) == 0 then
357 384 if co.aid == 0
358 385 then http.login_form(co, meth)
359 386 else co:reroute('/')
360 387 end
361 - return
362 388 elseif lib.str.ncmp('/logout', uri.ptr, lib.math.biggest(uri.ct,7)) == 0 then
363 389 if co.aid == 0
364 390 then goto notfound
365 391 else co:reroute_cookie('/','auth=; Path=/')
366 392 end
367 - return
368 393 else -- hierarchical routes
369 394 var path = lib.http.hier(uri) defer path:free()
370 395 if path.ct > 1 and path(0):cmp(lib.str.lit('user')) then
371 396 http.actor_profile_uid(co, path, meth)
372 397 elseif path.ct > 1 and path(0):cmp(lib.str.lit('post')) then
373 398 http.tweet_page(co, path, meth)
374 399 elseif path(0):cmp(lib.str.lit('tl')) then
375 400 http.timeline(co, path)
376 401 elseif path(0):cmp(lib.str.lit('doc')) then
377 - if meth ~= method.get and meth ~= method.head then goto wrongmeth end
402 + if not meth_get(meth) then goto wrongmeth end
378 403 http.documentation(co, path)
379 404 elseif path(0):cmp(lib.str.lit('conf')) then
380 405 if co.aid == 0 then goto unauth end
381 406 http.configure(co,path,meth)
382 407 else goto notfound end
383 - return
384 408 end
409 + do return end
385 410
386 411 ::wrongmeth:: co:complain(405, 'method not allowed', 'that method is not meaningful for this endpoint') do return end
387 412 ::notfound:: co:complain(404, 'not found', 'no such resource available') do return end
388 413 ::unauth:: co:complain(401, 'unauthorized', 'this content is not available at your clearance level') do return end
389 414 end