| Comment: | tentative beginnings of upload + media management system |
|---|---|
| Downloads: | Tarball | ZIP archive | SQL archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
f4c6e72a22221e80abe7e4088cf97cb9 |
| User & Date: | lexi on 2021-01-07 07:35:14 |
| Other Links: | manifest | tags |
|
2021-01-07
| ||
| 09:39 | further iteration on media check-in: af5ed65b68 user: lexi tags: trunk | |
| 07:35 | tentative beginnings of upload + media management system check-in: f4c6e72a22 user: lexi tags: trunk | |
|
2021-01-06
| ||
| 22:31 | unfuck last commit check-in: 8d8ab01573 user: lexi tags: trunk | |
Modified backend/pgsql.t from [80ca2205e4] to [5d4cebec04].
477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 ... 529 530 531 532 533 534 535 536 537 538 539 540 541 542 .... 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 |
limit case when $4::bigint = 0 then null
else $4::bigint end
offset $5::bigint
]];
};
artifact_instantiate = {
params = {binblob, binblob, pstring}, sql = [[
insert into parsav_artifacts (content,hash,mime) values (
$1::bytea, $2::bytea, $3::text
) on conflict do nothing returning id
]];
};
artifact_expropriate = {
params = {uint64, uint64, pstring}, cmd = true, sql = [[
insert into parsav_artifact_claims (uid,rid,description,folder) values (
$1::bigint, $2::bigint, $3::text, 'new'
) on conflict do nothing
]];
};
artifact_quicksearch = {
params = {binblob}, sql = [[
select id, (content is null) from parsav_artifacts where hash = $1::bytea
limit 1
................................................................................
-- "ERROR: cannot insert multiple commands into a prepared
-- statement" are you fucking shitting me with this shit
params = {uint64}, sql = [[
delete from parsav_artifact_claims where
rid = $1::bigint
returning uid, description, birth, folder;
]];
};
post_attach_ctl_ins = {
params = {uint64, uint64}, cmd=true, sql = [[
update parsav_posts set
artifacts = artifacts || $2::bigint
where id = $1::bigint and not
artifacts @> array[$2::bigint] -- prevent duplication
................................................................................
if ban then
lib.report('user attempted to instantiate forsaken artifact')
return 0
end
var oldid = srec:int(uint64,0,0)
return oldid
else -- not in db, insert
var nrec = queries.artifact_instantiate.exec(src, artifact, hashb, mime)
if nrec.sz == 0 then
lib.warn('failed to instantiate artifact -- are you running out of storage?')
return 0
else defer nrec:free()
var newid = nrec:int(uint64,0,0)
return newid
end
end
end];
post_attach_ctl = [terra(
src: &lib.store.source,
post: uint64,
artifact: uint64,
detach: bool
): {}
|
| | | | | | > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > |
477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 ... 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 .... 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 |
limit case when $4::bigint = 0 then null
else $4::bigint end
offset $5::bigint
]];
};
artifact_instantiate = {
params = {binblob, binblob, pstring, int64}, sql = [[
insert into parsav_artifacts (content,hash,mime,birth) values (
$1::bytea, $2::bytea, $3::text,$4::bigint
) on conflict do nothing returning id
]];
};
artifact_expropriate = {
params = {uint64, uint64, pstring, pstring, int64}, cmd = true, sql = [[
insert into parsav_artifact_claims (uid,rid,description,folder,birth) values (
$1::bigint, $2::bigint, $3::text, $4::text, $5::bigint
) on conflict do nothing
]];
};
artifact_quicksearch = {
params = {binblob}, sql = [[
select id, (content is null) from parsav_artifacts where hash = $1::bytea
limit 1
................................................................................
-- "ERROR: cannot insert multiple commands into a prepared
-- statement" are you fucking shitting me with this shit
params = {uint64}, sql = [[
delete from parsav_artifact_claims where
rid = $1::bigint
returning uid, description, birth, folder;
]];
};
artifact_enum_uid = {
params = {uint64, pstring}, sql = [[
select (pg_temp.parsavpg_translate_artifact(a)).*
from parsav_artifact_claims as a where uid = $1::bigint and
($2::text is null or
($2::text = '' and folder is null) or
$2::text = folder)
order by birth desc
]];
};
artifact_fetch = {
params = {uint64, uint64}, sql = [[
select (pg_temp.parsavpg_translate_artifact(a)).*
from parsav_artifact_claims as a where uid = $1::bigint and rid = $2::bigint
]];
};
artifact_load = {
params = {uint64}, sql = [[
select content, mime from parsav_artifacts where id = $1::bigint
]];
};
post_attach_ctl_ins = {
params = {uint64, uint64}, cmd=true, sql = [[
update parsav_posts set
artifacts = artifacts || $2::bigint
where id = $1::bigint and not
artifacts @> array[$2::bigint] -- prevent duplication
................................................................................
if ban then
lib.report('user attempted to instantiate forsaken artifact')
return 0
end
var oldid = srec:int(uint64,0,0)
return oldid
else -- not in db, insert
var nrec = queries.artifact_instantiate.exec(src, artifact, hashb, mime, lib.osclock.time(nil))
if nrec.sz == 0 then
lib.warn('failed to instantiate artifact -- are you running out of storage?')
return 0
else defer nrec:free()
var newid = nrec:int(uint64,0,0)
return newid
end
end
end];
artifact_expropriate = [terra(
src: &lib.store.source,
uid: uint64,
artifact: uint64,
desc: pstring,
folder: pstring
): {}
queries.artifact_expropriate.exec(src,uid,artifact,desc,folder, lib.osclock.time(nil))
end];
artifact_enum_uid = [terra(
src: &lib.store.source,
uid: uint64,
folder: pstring
)
var res = queries.artifact_enum_uid.exec(src,uid,folder)
if res.sz > 0 then
var m = lib.mem.heapa([lib.mem.ptr(lib.store.artifact)], res.sz)
for i=0,res.sz do
var id = res:int(uint64,i,0)
var idbuf: int8[lib.math.shorthand.maxlen]
var idlen = lib.math.shorthand.gen(id, &idbuf[0])
var desc = res:_string(i,2)
var folder = res:_string(i,3)
var mime = res:_string(i,4)
var url = lib.str.acc{}:init(48):lpush('/media/a/'):push(&idbuf[0],idlen):finalize() defer url:free()
m.ptr[i] = [ lib.str.encapsulate(lib.store.artifact, {
desc = {`desc.ptr, `desc.ct + 1};
folder = {`folder.ptr, `folder.ct + 1};
mime = {`mime.ptr, `mime.ct + 1};
url = {`url.ptr, `url.ct + 1};
}) ]
m(i).ptr.rid = id
m(i).ptr.owner = uid
end
return m
else return [lib.mem.lstptr(lib.store.artifact)].null() end
end];
post_attach_ctl = [terra(
src: &lib.store.source,
post: uint64,
artifact: uint64,
detach: bool
): {}
|
Modified backend/schema/pgsql-views.sql from [d567971842] to [ca832d14af].
15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
select p.id as post, coalesce((select counts.ct from counts where counts.subject = p.id and counts.kind = 'like'),0)::integer as likes, coalesce((select counts.ct from counts where counts.subject = p.id and counts.kind = 'rt' ),0)::integer as rts from parsav_posts as p ); create type pg_temp.parsavpg_intern_notice as ( kind smallint, "when" bigint, who bigint, what bigint, reply bigint, |
> > > > > > > > > > > > > > > > |
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 |
select p.id as post, coalesce((select counts.ct from counts where counts.subject = p.id and counts.kind = 'like'),0)::integer as likes, coalesce((select counts.ct from counts where counts.subject = p.id and counts.kind = 'rt' ),0)::integer as rts from parsav_posts as p ); create type pg_temp.parsavpg_intern_artifact as ( rid bigint, owner bigint, "desc" text, folder text, mime text ); create or replace function pg_temp.parsavpg_translate_artifact(parsav_artifact_claims) returns pg_temp.parsavpg_intern_artifact as $$ select ($1).rid, ($1).uid, ($1).description, ($1).folder, a.mime from parsav_artifacts a where a.id = ($1).rid limit 1 $$ language sql; create type pg_temp.parsavpg_intern_notice as ( kind smallint, "when" bigint, who bigint, what bigint, reply bigint, |
Modified config.lua from [eb323f3b45] to [6cff716428].
57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
{'bell.svg', 'image/svg+xml'};
{'heart.webp', 'image/webp'};
{'retweet.webp', 'image/webp'};
{'padlock.svg', 'image/svg+xml'};
{'warn.svg', 'image/svg+xml'};
{'query.webp', 'image/webp'};
{'reply.webp', 'image/webp'};
-- keep in mind before you add anything to this list: these are not
-- just files parsav can access, they are files that are *kept in
-- memory* for fast access the entire time parsav is running, and
-- which need to be loaded into memory before the program can even
-- start. it's imperative to keep these as small and few in number
-- as is realistically possible.
};
|
> |
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
{'bell.svg', 'image/svg+xml'};
{'heart.webp', 'image/webp'};
{'retweet.webp', 'image/webp'};
{'padlock.svg', 'image/svg+xml'};
{'warn.svg', 'image/svg+xml'};
{'query.webp', 'image/webp'};
{'reply.webp', 'image/webp'};
{'file.webp', 'image/webp'};
-- keep in mind before you add anything to this list: these are not
-- just files parsav can access, they are files that are *kept in
-- memory* for fast access the entire time parsav is running, and
-- which need to be loaded into memory before the program can even
-- start. it's imperative to keep these as small and few in number
-- as is realistically possible.
};
|
Modified http.t from [7092b409fb] to [4c9f723184].
1
2
3
4
5
6
7
8
9
10
11
12
..
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
-- vim: ft=terra
local m = {}
local util = lib.util
m.method = lib.enum { 'get', 'post', 'head', 'options', 'put', 'delete' }
m.mime = lib.enum {
'html'; -- default
'json';
'mkdown';
'text';
'ansi';
'none';
................................................................................
key: rawstring
value: rawstring
}
struct m.page {
respcode: uint16
body: lib.mem.ptr(int8)
headers: lib.mem.ptr(m.header)
}
local resps = {
[200] = 'OK';
[201] = 'Created';
[301] = 'Moved Permanently';
[302] = 'Found';
|
|
>
>
>
>
>
>
|
1
2
3
4
5
6
7
8
9
10
11
12
..
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
-- vim: ft=terra
local m = {}
local util = lib.util
m.method = lib.enum { 'get', 'post', 'post_file', 'head', 'options', 'put', 'delete' }
m.mime = lib.enum {
'html'; -- default
'json';
'mkdown';
'text';
'ansi';
'none';
................................................................................
key: rawstring
value: rawstring
}
struct m.page {
respcode: uint16
body: lib.mem.ptr(int8)
headers: lib.mem.ptr(m.header)
}
struct m.upload {
ctype: lib.str.t;
filename: lib.str.t;
field: lib.str.t;
body: lib.str.t;
}
local resps = {
[200] = 'OK';
[201] = 'Created';
[301] = 'Moved Permanently';
[302] = 'Found';
|
Modified makefile from [0e9ec3efb8] to [8559ac7b2c].
1 2 3 4 5 6 7 8 9 10 11 |
dl = git dbg-flags = $(if $(dbg),-g) images = static/default-avatar.webp static/query.webp static/heart.webp static/retweet.webp static/reply.webp #$(addsuffix .webp, $(basename $(wildcard static/*.svg))) styles = $(addsuffix .css, $(basename $(wildcard static/*.scss))) parsav parsavd: parsav.t config.lua pkgdata.lua $(images) $(styles) terra $(dbg-flags) $< parsav.o parsavd.o: parsav.t config.lua pkgdata.lua $(images) $(styles) env parsav_link=no terra $(dbg-flags) $< |
| |
1 2 3 4 5 6 7 8 9 10 11 |
dl = git
dbg-flags = $(if $(dbg),-g)
images = static/default-avatar.webp static/query.webp static/heart.webp static/retweet.webp static/reply.webp static/file.webp
#$(addsuffix .webp, $(basename $(wildcard static/*.svg)))
styles = $(addsuffix .css, $(basename $(wildcard static/*.scss)))
parsav parsavd: parsav.t config.lua pkgdata.lua $(images) $(styles)
terra $(dbg-flags) $<
parsav.o parsavd.o: parsav.t config.lua pkgdata.lua $(images) $(styles)
env parsav_link=no terra $(dbg-flags) $<
|
Modified parsav.t from [8bdefbaeb6] to [7b59e1e979].
434 435 436 437 438 439 440 441 442 443 444 445 446 447 |
'render:profile'; 'render:compose'; 'render:tweet'; 'render:tweet-page'; 'render:user-page'; 'render:timeline'; 'render:notices'; 'render:docpage'; 'render:conf:profile'; 'render:conf:sec'; 'render:conf:users'; 'render:conf'; |
> > |
434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 |
'render:profile';
'render:compose';
'render:tweet';
'render:tweet-page';
'render:user-page';
'render:timeline';
'render:notices';
'render:media-gallery';
'render:docpage';
'render:conf:profile';
'render:conf:sec';
'render:conf:users';
'render:conf';
|
Added render/media-gallery.t version [79b3557b2e].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > |
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 |
-- vim: ft=terra local pstr = lib.str.t local P = lib.str.plit local terra cs(s: rawstring) return pstr { ptr = s, ct = lib.str.sz(s) } end local show_all,show_new,show_files,show_vid,show_img=1,2,3,4,5 local terra render_media_gallery(co: &lib.srv.convo, path: lib.mem.ptr(lib.mem.ref(int8)), uid: uint64, acc: &lib.str.acc) -- note that when calling this function, path must be adjusted so that path(0) -- eq "media" var owner = false if co.aid ~= 0 and co.who.id == uid then owner = true end var ou = co.srv:actor_fetch_uid(uid) if not ou then goto e404 end var view = data.view.media_gallery { menu = pstr{'',0}; folders = pstr{'',0}; directory = pstr{'',0}; images = pstr{'',0}; } if owner then view.menu = P'<a class="pos" href="/media/upload">upload</a><hr>' end var mode: uint8 = show_new var folder: pstr if mode == show_new then folder = lib.str.plit'' elseif mode == show_all then folder = pstr.null() -- else get folder from query str end var md = co.srv:artifact_enum_uid(uid, folder) var gallery: lib.str.acc gallery:init(256) var files: lib.str.acc files:init(256) for i=0,md.ct do if lib.str.ncmp(md(i)(0).mime, 'image/', 6) == 0 then gallery:lpush('<a class="thumb" href="') if not owner then gallery:lpush('/') if ou(0).origin ~= 0 then gallery:lpush('@') end gallery:push(ou(0).xid,0):lpush('/') end gallery:push(md(i)(0).url,0) :lpush('"><img src="') :push(md(i)(0).url,0) :lpush('/raw"><div class="caption">') :push(md(i)(0).desc,0) :lpush('</div></a>') else files:lpush('<a class="file" href="') if not owner then gallery:lpush('/') if ou(0).origin ~= 0 then gallery:lpush('@') end gallery:push(ou(0).xid,0):lpush('/') end files:push(md(i)(0).url,0) :lpush('"><span class="label">'):push(md(i)(0).desc,0) :lpush('</span> <span class="mime">'):push(md(i)(0).mime,0) :lpush('</span></a>') end md(i):free() end view.images = gallery:finalize() view.directory = files:finalize() if acc ~= nil then view:append(acc) else var pg = view:tostr() defer pg:free() co:stdpage([lib.srv.convo.page] { title = P'media'; class = P'media manager'; cache = false; body = pg; }) end view.images:free() view.directory:free() if md:ref() then md:free() end do return end ::e404:: co:complain(404,'media not found','no such media exists on this server') end return render_media_gallery |
Modified render/nav.t from [62959bc993] to [5194b2263f].
3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
render_nav(co: &lib.srv.convo)
var t: lib.str.acc t:init(64)
if co.who ~= nil or co.srv.cfg.pol_sec == lib.srv.secmode.public then
t:lpush(' <a accesskey="t" href="/">timeline</a>')
end
if co.who ~= nil then
t:lpush(' <a accesskey="c" href="/compose">compose</a> <a accesskey="p" href="/'):push(co.who.xid,0)
t:lpush('">profile</a> <a accesskey="o" href="/conf">configure</a> <a accesskey="d" href="/doc">docs</a> <a accesskey="g" href="/logout">log out</a> <a class="bell" href="/notices">notices</a>')
else
t:lpush(' <a accesskey="d" href="/doc">docs</a> <a accesskey="g" href="/login">log in</a>')
end
return t:finalize()
end
return render_nav
|
| |
3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
render_nav(co: &lib.srv.convo)
var t: lib.str.acc t:init(64)
if co.who ~= nil or co.srv.cfg.pol_sec == lib.srv.secmode.public then
t:lpush(' <a accesskey="t" href="/">timeline</a>')
end
if co.who ~= nil then
t:lpush(' <a accesskey="c" href="/compose">compose</a> <a accesskey="p" href="/'):push(co.who.xid,0)
t:lpush('">profile</a> <a accesskey="m" href="/media">media</a> <a accesskey="o" href="/conf">configure</a> <a accesskey="d" href="/doc">docs</a> <a accesskey="g" href="/logout">log out</a> <a class="bell" href="/notices">notices</a>')
else
t:lpush(' <a accesskey="d" href="/doc">docs</a> <a accesskey="g" href="/login">log in</a>')
end
return t:finalize()
end
return render_nav
|
Modified route.t from [e8c2143a0c] to [af3d41e739].
1 2 3 4 5 6 7 8 9 10 11 12 ... 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 ... 483 484 485 486 487 488 489 490 491 492 493 494 495 496 |
-- vim: ft=terra
local r = lib.srv.route
local method = lib.http.method
local pstring = lib.mem.ptr(int8)
local rstring = lib.mem.ref(int8)
local hpath = lib.mem.ptr(rstring)
local http = {}
terra meth_get(meth: method.t) return (meth == method.get) or (meth == method.head) end
terra http.actor_profile(co: &lib.srv.convo, actor: &lib.store.actor, meth: method.t)
var rel: lib.store.relationship
................................................................................
return
else goto badop end
end
lib.render.notices(co)
do return end
::badop :: do co:complain(405, 'invalid operation', 'the operation you have attempted on this post is not meaningful') return end
end
do local branches = quote end
local filename, flen = symbol(&int8), symbol(intptr)
local page = symbol(lib.http.page)
local send = label()
local storage = data.stmap
................................................................................
var path = lib.http.hier(uri) defer path:free()
if path.ct > 1 and path(0):cmp(lib.str.lit('user')) then
http.actor_profile_uid(co, path, meth)
elseif path.ct > 1 and path(0):cmp(lib.str.lit('post')) then
http.tweet_page(co, path, meth)
elseif path(0):cmp(lib.str.lit('tl')) then
http.timeline(co, path)
elseif path(0):cmp(lib.str.lit('doc')) then
if not meth_get(meth) then goto wrongmeth end
http.documentation(co, path)
elseif path(0):cmp(lib.str.lit('conf')) then
if co.aid == 0 then goto unauth end
http.configure(co,path,meth)
else goto notfound end
|
> | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > |
1 2 3 4 5 6 7 8 9 10 11 12 13 ... 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 ... 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 |
-- vim: ft=terra local r = lib.srv.route local method = lib.http.method local pstring = lib.mem.ptr(int8) local rstring = lib.mem.ref(int8) local binblob = lib.mem.ptr(uint8) local hpath = lib.mem.ptr(rstring) local http = {} terra meth_get(meth: method.t) return (meth == method.get) or (meth == method.head) end terra http.actor_profile(co: &lib.srv.convo, actor: &lib.store.actor, meth: method.t) var rel: lib.store.relationship ................................................................................ return else goto badop end end lib.render.notices(co) do return end ::badop:: do co:complain(405, 'invalid operation', 'the operation you have attempted on this post is not meaningful') return end end terra http.media_manager(co: &lib.srv.convo, path: hpath, meth: method.t) if meth == method.post then goto badop end if path.ct == 1 or (path.ct >= 3 and path(1):cmp(lib.str.lit'a')) then if meth == method.post then goto badop end lib.render.media_gallery(co,path,co.who.id,nil) elseif path.ct == 2 then if path(1):cmp(lib.str.lit'upload') and co.who.rights.powers.artifact() then if meth == method.get then var view = data.view.media_upload { folders = '' } var pg = view:tostr() defer pg:free() co:stdpage([lib.srv.convo.page] { title = lib.str.plit'media :: upload'; class = lib.str.plit'media upload'; cache = false; body = pg; }) elseif meth == method.post_file then var desc = pstring.null() var folder = pstring.null() var mime = pstring.null() var name = pstring.null() var body = binblob.null() for i=0, co.uploads.sz do var up = co.uploads.storage.ptr + i if up.body.ct > 0 then if up.field:cmp(lib.str.plit'desc') then desc = up.body elseif up.field:cmp(lib.str.plit'folder') then folder = up.body elseif up.field:cmp(lib.str.plit'file') then mime = up.ctype body = binblob {ptr = [&uint8](up.body.ptr), ct = up.body.ct} name = up.filename end end end if not body then goto badop end if body.ct > co.srv.cfg.maxupsz then co:complain(403, 'file too long', "the file you have attempted to upload exceeds the maximum length permitted by this server's upload policy. if it is an image or video, try compressing it at a lower quality setting or resolution") return end var id = co.srv:artifact_instantiate(body,mime) if id == 0 then co:complain(500,'upload failed','artifact rejected. either the server is running out of space or this file is banned from the server') return end co.srv:artifact_expropriate(co.who.id,id,desc,folder) var idbuf: int8[lib.math.shorthand.maxlen] var idlen = lib.math.shorthand.gen(id,&idbuf[0]) var url = lib.str.acc{}:compose('/media/a/',pstring{&idbuf[0],idlen}):finalize() co:reroute(url.ptr) url:free() else goto badop end end else goto e404 end do return end ::badop:: do co:complain(405, 'invalid operation', 'the operation you have attempted on this post is not meaningful') return end ::e404:: do co:complain(404, 'artifact not found', 'no such artifact has been uploaded by this user') return end end do local branches = quote end local filename, flen = symbol(&int8), symbol(intptr) local page = symbol(lib.http.page) local send = label() local storage = data.stmap ................................................................................ var path = lib.http.hier(uri) defer path:free() if path.ct > 1 and path(0):cmp(lib.str.lit('user')) then http.actor_profile_uid(co, path, meth) elseif path.ct > 1 and path(0):cmp(lib.str.lit('post')) then http.tweet_page(co, path, meth) elseif path(0):cmp(lib.str.lit('tl')) then http.timeline(co, path) elseif path(0):cmp(lib.str.lit('media')) then http.media_manager(co, path, meth) elseif path(0):cmp(lib.str.lit('doc')) then if not meth_get(meth) then goto wrongmeth end http.documentation(co, path) elseif path(0):cmp(lib.str.lit('conf')) then if co.aid == 0 then goto unauth end http.configure(co,path,meth) else goto notfound end |
Modified srv.t from [d4dcecb4e5] to [a1d0408148].
134 135 136 137 138 139 140 141 142 143 144 145 146 147 ... 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 ... 391 392 393 394 395 396 397 398 399 400 401 402 403 404 ... 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 |
aid: uint64 -- 0 if logged out aid_issue: lib.store.timepoint who: &lib.store.actor -- who we're logged in as, if aid ~= 0 peer: lib.store.inet reqtype: lib.http.mime.t -- negotiated content type method: lib.http.method.t live_last: lib.store.timepoint -- cache ui_hue: uint16 navbar: lib.mem.ptr(int8) actorcache: lib.mem.cache(lib.mem.ptr(lib.store.actor),32) -- naive cache to avoid unnecessary queries -- private varbuf: lib.mem.ptr(int8) vbofs: &int8 ................................................................................ else return nil, 0 end end terra convo:pgetv(name: rawstring) var s,l = self:getv(name) return pstring { ptr = s, ct = l } end local urimatch = macro(function(uri, ptn) return `lib.net.mg_globmatch(ptn, [#ptn], uri.ptr, uri.ct+1) end) local route = {} -- these are defined in route.t, as they need access to renderers terra route.dispatch_http :: {&convo, lib.mem.ptr(int8), lib.http.method.t} -> {} local mimetypes = { {'html', 'text/html'}; {'json', 'application/json'}; {'mkdown', 'text/markdown'}; ................................................................................ reqtype = lib.http.mime.none; peer = peer, live_last = 0; } co.varbuf.ptr = nil co.navbar.ptr = nil co.actorcache.top = 0 co.actorcache.cur = 0 co.ui_hue = server.cfg.ui_hue -- first, check for an accept header. if it's there, we need to -- iterate over the values and pick the highest-priority one do var acc = lib.http.findheader(msg, 'Accept') -- TODO handle q-value if acc ~= nil and acc.ptr ~= nil then var [mimevar] = [lib.mem.ref(int8)] { ptr = acc.ptr } ................................................................................ end uri.ct = msg.uri.len else uri.ct = urideclen end lib.dbg('routing URI ', {uri.ptr, uri.ct}) if lib.str.ncmp('GET', msg.method.ptr, msg.method.len) == 0 then co.method = [lib.http.method.get] route.dispatch_http(&co, uri, [lib.http.method.get]) elseif lib.str.ncmp('POST', msg.method.ptr, msg.method.len) == 0 then co.method = [lib.http.method.get] route.dispatch_http(&co, uri, [lib.http.method.post]) elseif lib.str.ncmp('HEAD', msg.method.ptr, msg.method.len) == 0 then co.method = [lib.http.method.head] route.dispatch_http(&co, uri, [lib.http.method.head]) elseif lib.str.ncmp('OPTIONS', msg.method.ptr, msg.method.len) == 0 then co.method = [lib.http.method.options] route.dispatch_http(&co, uri, [lib.http.method.options]) else co:complain(400,'unknown method','you have submitted an invalid http request') end if co.aid ~= 0 then lib.mem.heapf(co.who) end if co.varbuf.ptr ~= nil then co.varbuf:free() end if co.navbar.ptr ~= nil then co.navbar:free() end co.actorcache:free() end end end; |
> > < < < < > < | < < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > |
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 ... 330 331 332 333 334 335 336 337 338 339 340 341 342 343 ... 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 ... 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 |
aid: uint64 -- 0 if logged out aid_issue: lib.store.timepoint who: &lib.store.actor -- who we're logged in as, if aid ~= 0 peer: lib.store.inet reqtype: lib.http.mime.t -- negotiated content type method: lib.http.method.t live_last: lib.store.timepoint uploads: lib.mem.vec(lib.http.upload) body: lib.str.t -- cache ui_hue: uint16 navbar: lib.mem.ptr(int8) actorcache: lib.mem.cache(lib.mem.ptr(lib.store.actor),32) -- naive cache to avoid unnecessary queries -- private varbuf: lib.mem.ptr(int8) vbofs: &int8 ................................................................................ else return nil, 0 end end terra convo:pgetv(name: rawstring) var s,l = self:getv(name) return pstring { ptr = s, ct = l } end local route = {} -- these are defined in route.t, as they need access to renderers terra route.dispatch_http :: {&convo, lib.mem.ptr(int8), lib.http.method.t} -> {} local mimetypes = { {'html', 'text/html'}; {'json', 'application/json'}; {'mkdown', 'text/markdown'}; ................................................................................ reqtype = lib.http.mime.none; peer = peer, live_last = 0; } co.varbuf.ptr = nil co.navbar.ptr = nil co.actorcache.top = 0 co.actorcache.cur = 0 co.ui_hue = server.cfg.ui_hue co.body.ptr = msg.body.ptr co.body.ct = msg.body.len -- first, check for an accept header. if it's there, we need to -- iterate over the values and pick the highest-priority one do var acc = lib.http.findheader(msg, 'Accept') -- TODO handle q-value if acc ~= nil and acc.ptr ~= nil then var [mimevar] = [lib.mem.ref(int8)] { ptr = acc.ptr } ................................................................................ end uri.ct = msg.uri.len else uri.ct = urideclen end lib.dbg('routing URI ', {uri.ptr, uri.ct}) if lib.str.ncmp('GET', msg.method.ptr, msg.method.len) == 0 then co.method = [lib.http.method.get] elseif lib.str.ncmp('POST', msg.method.ptr, msg.method.len) == 0 then co.method = [lib.http.method.post] elseif lib.str.ncmp('HEAD', msg.method.ptr, msg.method.len) == 0 then co.method = [lib.http.method.head] elseif lib.str.ncmp('OPTIONS', msg.method.ptr, msg.method.len) == 0 then co.method = [lib.http.method.options] else co:complain(400,'unknown method','you have submitted an invalid http request') goto fail end -- check for a content-type header, and see if it's a multipart/ -- form-data encoded POST request so we can handle file uploads co.uploads.sz = 0 co.uploads.run = 0 if co.method == [lib.http.method.post] then var ctt = lib.http.findheader(msg, 'Content-Type') if ctt ~= nil then lib.dbg('found content type', {ctt.ptr,ctt.ct}) if lib.str.ncmp(ctt.ptr,'multipart/form-data;',20) == 0 then var p = lib.str.ffw(ctt.ptr + 20,ctt.ct-20) if lib.str.ncmp(p,'boundary=',9) ~= 0 then co:complain(400,'bad request','unrecognized content-type') goto fail end var boundary = pstring {ptr=p+9,ct=ctt.ct - ((p - ctt.ptr) + 9)} lib.dbg('got boundary ',{boundary.ptr,boundary.ct}) co.method = lib.http.method.post_file co.uploads:init(8) var bsr = (lib.str.acc{}):compose('\r\n--',boundary,'\r\n'):finalize() var upmap = lib.str.splitmap(co.body,bsr,8) -- first entry may not be preceded by header-break if lib.str.find(upmap(0), pstring { ptr = bsr.ptr + 2, ct = bsr.ct - 2 }):ref() then upmap(0).ptr = upmap(0).ptr + (bsr.ct - 2) upmap(0).ct = upmap(0).ct - (bsr.ct - 2) end -- last entry is weird do var lsr = (lib.str.acc{}):compose('\r\n--',boundary,'--\r\n'):finalize() var lsent = upmap.ptr + (upmap.ct - 1) var halt = lib.str.find(@lsent, lsr) if halt:ref() then lsent.ct = halt.ptr - lsent.ptr end lsr:free() end for i=0,upmap.ct do var hdrbrk = lib.str.find(upmap(i), lib.str.plit'\r\n\r\n') if hdrbrk:ref() then lib.dbg('got new entry') var hdrtxt = pstring {upmap(i).ptr,upmap(i).ct - hdrbrk.ct} var hdrs = lib.str.splitmap(hdrtxt, '\r\n',6) var ctt = pstring.null() var ctd = pstring.null() for j=0, hdrs.ct do var brk = lib.str.find(hdrs(j),lib.str.plit':') if brk:ref() then var hdr = pstring{hdrs(j).ptr,hdrs(j).ct - brk.ct} var val = pstring{brk.ptr+1, brk.ct-1}:ffw() if hdr:cmp(lib.str.plit'Content-Type') then ctt = val elseif hdr:cmp(lib.str.plit'Content-Disposition') then ctd = val end end end if ctd:ref() then var ctdvals = lib.str.splitmap(ctd, ';', 4) defer ctdvals:free() if ctdvals(0):cmp(lib.str.plit'form-data') and ctdvals.ct > 1 then lib.dbg('found form data') var fld = pstring.null() var file = pstring.null() for j=1, ctdvals.ct do var v = ctdvals(j):ffw() var x = lib.str.find(v,lib.str.plit'=') if x:ref() then var key = pstring{v.ptr, v.ct - x.ct} var val = pstring{x.ptr + 1, x.ct - 1} var decval, ofs, sp = lib.str.toknext(val,@';',true) if key:cmp(lib.str.plit'name') then fld = decval elseif key:cmp(lib.str.plit'filename') then file = decval else decval:free() end end end if fld:ref() then var nextup = co.uploads:new() if ctt:ref() then nextup.ctype = ctt else nextup.ctype = pstring.null() end nextup.body = pstring { ptr = hdrbrk.ptr + 4; ct = hdrbrk.ct - 4; } nextup.ctype = ctt nextup.field = fld nextup.filename = file end end end end end bsr:free() upmap:free() end end end route.dispatch_http(&co, uri, co.method) if co.uploads.run > 0 then for i=0,co.uploads.sz do co.uploads(i).filename:free() co.uploads(i).field:free() end co.uploads:free() end ::fail:: if co.aid ~= 0 then lib.mem.heapf(co.who) end if co.varbuf.ptr ~= nil then co.varbuf:free() end if co.navbar.ptr ~= nil then co.navbar:free() end co.actorcache:free() end end end; |
Added static/file.svg version [c89d070bea].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > |
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 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 |
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!-- Created with Inkscape (http://www.inkscape.org/) --> <svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="20" height="20" viewBox="0 0 5.2916664 5.2916665" version="1.1" id="svg8" inkscape:version="0.92.4 (5da689c313, 2019-01-14)" sodipodi:docname="file.svg"> <defs id="defs2"> <linearGradient inkscape:collect="always" id="linearGradient935"> <stop style="stop-color:#39104b;stop-opacity:1;" offset="0" id="stop931" /> <stop style="stop-color:#39104b;stop-opacity:0;" offset="1" id="stop933" /> </linearGradient> <linearGradient id="linearGradient923" inkscape:collect="always"> <stop id="stop919" offset="0" style="stop-color:#f0cfff;stop-opacity:1" /> <stop id="stop921" offset="1" style="stop-color:#eabcff;stop-opacity:0;" /> </linearGradient> <linearGradient inkscape:collect="always" id="linearGradient904"> <stop style="stop-color:#df9aff;stop-opacity:1;" offset="0" id="stop900" /> <stop style="stop-color:#df9aff;stop-opacity:0;" offset="1" id="stop902" /> </linearGradient> <linearGradient inkscape:collect="always" id="linearGradient896"> <stop style="stop-color:#eabcff;stop-opacity:1;" offset="0" id="stop892" /> <stop style="stop-color:#eabcff;stop-opacity:0;" offset="1" id="stop894" /> </linearGradient> <linearGradient inkscape:collect="always" id="linearGradient954"> <stop style="stop-color:#ffffff;stop-opacity:1;" offset="0" id="stop950" /> <stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop952" /> </linearGradient> <linearGradient inkscape:collect="always" id="linearGradient938"> <stop style="stop-color:#d9fff6;stop-opacity:1;" offset="0" id="stop934" /> <stop style="stop-color:#d9fff6;stop-opacity:0;" offset="1" id="stop936" /> </linearGradient> <linearGradient inkscape:collect="always" id="linearGradient1403"> <stop style="stop-color:#ccaaff;stop-opacity:1;" offset="0" id="stop1399" /> <stop style="stop-color:#ccaaff;stop-opacity:0;" offset="1" id="stop1401" /> </linearGradient> <linearGradient id="linearGradient1395" inkscape:collect="always"> <stop id="stop1391" offset="0" style="stop-color:#ff1616;stop-opacity:1" /> <stop id="stop1393" offset="1" style="stop-color:#ff1d1d;stop-opacity:0" /> </linearGradient> <linearGradient inkscape:collect="always" id="linearGradient1383"> <stop style="stop-color:#980000;stop-opacity:1;" offset="0" id="stop1379" /> <stop style="stop-color:#980000;stop-opacity:0;" offset="1" id="stop1381" /> </linearGradient> <linearGradient inkscape:collect="always" id="linearGradient832"> <stop style="stop-color:#ffcfcf;stop-opacity:1;" offset="0" id="stop828" /> <stop style="stop-color:#ffcfcf;stop-opacity:0;" offset="1" id="stop830" /> </linearGradient> <radialGradient inkscape:collect="always" xlink:href="#linearGradient832" id="radialGradient834" cx="3.2286437" cy="286.62921" fx="3.2286437" fy="286.62921" r="1.0866126" gradientTransform="matrix(1.8608797,0.8147617,-0.38242057,0.87343168,106.71446,33.692223)" gradientUnits="userSpaceOnUse" /> <radialGradient inkscape:collect="always" xlink:href="#linearGradient1383" id="radialGradient1385" cx="4.1787109" cy="286.89261" fx="4.1787109" fy="286.89261" r="1.2260786" gradientTransform="matrix(1.7016464,0,0,1.6348586,-2.9319775,-182.10895)" gradientUnits="userSpaceOnUse" /> <radialGradient inkscape:collect="always" xlink:href="#linearGradient1395" id="radialGradient1389" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.66230313,-1.6430738,1.0154487,0.40931507,-290.06307,177.39489)" cx="4.02069" cy="287.79269" fx="4.02069" fy="287.79269" r="1.0866126" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient1403" id="linearGradient1405" x1="8.3939333" y1="288.1091" x2="7.0158253" y2="287.32819" gradientUnits="userSpaceOnUse" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient938" id="linearGradient940" x1="7.609839" y1="288.73215" x2="7.609839" y2="283.78305" gradientUnits="userSpaceOnUse" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient954" id="linearGradient956" x1="3.0150654" y1="285.94464" x2="3.0150654" y2="282.40109" gradientUnits="userSpaceOnUse" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient954" id="linearGradient1138" gradientUnits="userSpaceOnUse" x1="3.0150654" y1="285.94464" x2="3.0150654" y2="284.62277" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient896" id="linearGradient898" x1="2.6224887" y1="20" x2="2.6224887" y2="-0.44642866" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.26458333,0,0,0.26458333,2.6134662,283.36966)" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient904" id="linearGradient906" x1="5.1028705" y1="285.45639" x2="6.1422977" y2="284.41696" gradientUnits="userSpaceOnUse" gradientTransform="translate(1.4605056e-7,1.403324e-5)" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient923" id="linearGradient915" gradientUnits="userSpaceOnUse" x1="2.6224887" y1="-7.0215807" x2="2.6224887" y2="19.346249" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient904" id="linearGradient927" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.1002873,0,0,1.1002873,-0.68825328,-28.478577)" x1="5.2755661" y1="285.28369" x2="5.7849226" y2="284.77432" /> <radialGradient inkscape:collect="always" xlink:href="#linearGradient935" id="radialGradient939" cx="6.3029079" cy="284.65445" fx="6.3029079" fy="284.65445" r="1.6035197" gradientTransform="matrix(1.3125186,0,0,1.1401099,-1.643629,-40.275795)" gradientUnits="userSpaceOnUse" /> </defs> <sodipodi:namedview id="base" pagecolor="#181818" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:zoom="2.8" inkscape:cx="-104.22073" inkscape:cy="-48.222179" inkscape:document-units="mm" inkscape:current-layer="layer1" showgrid="false" units="px" inkscape:window-width="1920" inkscape:window-height="1042" inkscape:window-x="0" inkscape:window-y="38" inkscape:window-maximized="0" showguides="false" fit-margin-top="0" fit-margin-left="0" fit-margin-right="0" fit-margin-bottom="0" /> <metadata id="metadata5"> <rdf:RDF> <cc:Work rdf:about=""> <dc:format>image/svg+xml</dc:format> <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> <dc:title></dc:title> </cc:Work> </rdf:RDF> </metadata> <g inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1" transform="translate(-2.6134661,-283.36966)"> <path sodipodi:type="inkscape:offset" inkscape:radius="1.2412" inkscape:original="M 5.9453125 2.2695312 C 4.8334737 2.2695312 3.9394531 3.1635518 3.9394531 4.2753906 L 3.9394531 15.724609 C 3.9394531 16.836448 4.8334737 17.730469 5.9453125 17.730469 L 14.054688 17.730469 C 15.166526 17.730469 16.060547 16.836448 16.060547 15.724609 L 16.060547 7.6113281 L 10.71875 2.2695312 L 5.9453125 2.2695312 z " style="opacity:0.223;vector-effect:none;fill:url(#linearGradient915);fill-opacity:1;stroke:none;stroke-width:0.62362206;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" id="path913" d="m 5.9453125,1.0292969 c -1.777198,0 -3.2460937,1.4688957 -3.2460937,3.2460937 V 15.724609 c -1e-7,1.777199 1.4688954,3.246094 3.2460937,3.246094 h 8.1093755 c 1.777198,0 3.246093,-1.468895 3.246093,-3.246094 V 7.6113281 A 1.2413241,1.2413241 0 0 0 16.9375,6.734375 L 11.595703,1.3925781 A 1.2413241,1.2413241 0 0 0 10.71875,1.0292969 Z" transform="matrix(0.26458333,0,0,0.26458333,2.6134662,283.36966)" /> <path style="opacity:1;vector-effect:none;fill:url(#linearGradient898);fill-opacity:1;stroke:none;stroke-width:0.16500001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" d="m 4.1864967,283.97014 c -0.294174,0 -0.5307169,0.23654 -0.5307169,0.53072 v 3.02927 c 0,0.29417 0.2365429,0.53072 0.5307169,0.53072 h 2.1456056 c 0.2941738,0 0.5307169,-0.23655 0.5307169,-0.53072 v -2.14664 l -1.4133505,-1.41335 z" id="rect882" inkscape:connector-curvature="0" /> <path inkscape:connector-curvature="0" id="path929" d="m 4.1864967,283.97014 c -0.294174,0 -0.5307169,0.23654 -0.5307169,0.53072 v 3.02927 c 0,0.29417 0.2365429,0.53072 0.5307169,0.53072 h 2.1456056 c 0.2941738,0 0.5307169,-0.23655 0.5307169,-0.53072 v -2.14664 l -1.4133505,-1.41335 z" style="opacity:0.71;vector-effect:none;fill:url(#radialGradient939);fill-opacity:1;stroke:none;stroke-width:0.16500001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> <path inkscape:connector-curvature="0" id="path925" d="m 5.3077278,283.97015 v 0.97114 c 0,0.32367 0.2602653,0.58395 0.583941,0.58395 h 0.9711506 z" style="fill:url(#linearGradient927);fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;opacity:0.449" /> <path style="fill:url(#linearGradient906);fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="m 5.4494687,283.97014 v 0.88263 c 0,0.29417 0.2365431,0.53072 0.5307169,0.53072 h 0.8826336 z" id="path890" inkscape:connector-curvature="0" /> </g> </svg> |
Modified static/style.scss from [37c2876b01] to [7f55f7d5d1].
1002 1003 1004 1005 1006 1007 1008 |
}
> article.post {
margin: 0.1in 0.2in;
margin-left: 0.4in;
}
}
}
|
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > |
1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 |
}
> article.post {
margin: 0.1in 0.2in;
margin-left: 0.4in;
}
}
}
.media.manager main, .media.gallery {
display: grid;
grid-template-columns: 2in 1fr;
grid-template-rows: max-content 1fr;
menu {
@extend %navmenu;
}
.gallery, .dir {
background: tone(-55%,-0.5);
border: 1px solid tone(-60%);
padding: 0.2in;
display: flex;
flex-wrap: wrap;
}
.gallery {
grid-row: 1/2; grid-column: 2/3;
margin-left: 0.1in;
flex-flow: row;
> a[href].thumb {
display: block;
width: 1.5in;
padding: 0.1in;
height: max-content;
> img {
width: 1.5in; height: 1.5in;
}
> .caption {
text-align: center;
font-size: 80%;
}
}
}
.dir {
grid-row: 2/3; grid-column: 1/3;
margin-top: 0.1in;
flex-flow: column;
flex-grow: 1;
> a[href].file {
padding: 0.1in 0.15in;
text-decoration: none;
height: max-content;
background-image: url(/s/file.webp); //TODO different icons for different mime types
background-repeat: no-repeat;
background-position: left;
padding-left: 0.4in;
> .label {
text-decoration: underline;
}
> .mime {
font-style: italic;
opacity: 60%;
margin-left: 0.5ex;
}
}
}
}
.media.upload form {
padding: 0.1in 0.2in;
@extend %box;
}
|
Modified store.t from [54fed43947] to [fdc1c1d9e2].
226 227 228 229 230 231 232 233 234 235 236 237 238 239 ... 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 ... 466 467 468 469 470 471 472 473 474 475 476 477 478 479 |
rtdby: uint64 -- 0 if not rt
rtact: uint64 -- 0 if not rt, id of rt action otherwise
isreply: bool
source: &m.source
-- save :: bool -> {} (defined in acl.t due to dep. hell)
}
m.user_conf_funcs = function(be,n,ty,rty,rty2)
rty = rty or ty
local gt
if not rty2 -- what the fuck?
then gt = {&m.source, uint64, rawstring} -> rty;
else gt = {&m.source, uint64, rawstring} -> {rty, rty2};
................................................................................
-- artifact: bytea
-- mime: pstring
artifact_quicksearch: {&m.source, lib.mem.ptr(uint8)} -> {uint64,bool}
-- checks whether a hash is already in the database without uploading
-- the entire file to the database server
-- hash: bytea
--> artifact id (0 if null), suppressed?
artifact_expropriate: {&m.source, uint64, uint64, lib.mem.ptr(int8)} -> {}
-- claims an existing artifact for the user's own collection
-- uid: uint64
-- artifact id: uint64
-- description: pstring
artifact_disclaim: {&m.source, uint64, uint64} -> {}
-- a user disclaims their ownership stake in an artifact, removing it from
-- the database entirely if they were the only owner, and removing their
-- description of it either way
-- uid: uint64
-- artifact id: uint64
artifact_excise: {&m.source, uint64, bool} -> {}
................................................................................
-- (admin action) forcibly excise an artifact from the database, deleting
-- all links to it and removing it from users' collections. if "blacklist,"
-- the artifact will be banned and attempts to upload it in the future
-- will fail, triggering a report. mainly intended for dealing with spam,
-- IP violations, That Which Shall Not Be Named, and various other infohazards.
-- artifact id: uint64
-- blacklist: bool
nkvd_report_issue: {&m.source, &m.kompromat} -> {}
-- an incidence of Badthink has been detected. report it immediately
-- to the Supreme Soviet
nkvd_reports_enum: {&m.source, &m.kompromat} -> lib.mem.ptr(m.kompromat)
-- search through the Archives
-- proto: kompromat (null for all records, or a prototype describing the records to return)
|
> > > > > > > > > | > > > > > > > > > > > > > |
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 ... 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 ... 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 |
rtdby: uint64 -- 0 if not rt
rtact: uint64 -- 0 if not rt, id of rt action otherwise
isreply: bool
source: &m.source
-- save :: bool -> {} (defined in acl.t due to dep. hell)
}
struct m.artifact {
rid: uint64
owner: uint64
desc: str
folder: str
mime: str
url: str
}
m.user_conf_funcs = function(be,n,ty,rty,rty2)
rty = rty or ty
local gt
if not rty2 -- what the fuck?
then gt = {&m.source, uint64, rawstring} -> rty;
else gt = {&m.source, uint64, rawstring} -> {rty, rty2};
................................................................................
-- artifact: bytea
-- mime: pstring
artifact_quicksearch: {&m.source, lib.mem.ptr(uint8)} -> {uint64,bool}
-- checks whether a hash is already in the database without uploading
-- the entire file to the database server
-- hash: bytea
--> artifact id (0 if null), suppressed?
artifact_expropriate: {&m.source, uint64, uint64, lib.str.t, lib.str.t} -> {}
-- claims an existing artifact for the user's own collection
-- uid: uint64
-- artifact id: uint64
-- description: pstring
-- folder: pstring
artifact_claim_alter: {&m.source, uint64, uint64, lib.str.t, lib.str.t} -> {}
-- edits an existing claim to an artifact
-- ibid
artifact_disclaim: {&m.source, uint64, uint64} -> {}
-- a user disclaims their ownership stake in an artifact, removing it from
-- the database entirely if they were the only owner, and removing their
-- description of it either way
-- uid: uint64
-- artifact id: uint64
artifact_excise: {&m.source, uint64, bool} -> {}
................................................................................
-- (admin action) forcibly excise an artifact from the database, deleting
-- all links to it and removing it from users' collections. if "blacklist,"
-- the artifact will be banned and attempts to upload it in the future
-- will fail, triggering a report. mainly intended for dealing with spam,
-- IP violations, That Which Shall Not Be Named, and various other infohazards.
-- artifact id: uint64
-- blacklist: bool
artifact_enum_uid: {&m.source, uint64, lib.str.t} -> lib.mem.lstptr(m.artifact)
-- produces a list of artifacts claimed by a user, optionally
-- restricted by folder (empty string = new only)
artifact_fetch: {&m.source, uint64, uint64} -> lib.mem.ptr(m.artifact)
-- fetch a user's view of an artifact
-- uid: uint64
-- rid: uint64
artifact_load: {&m.source, uint64} -> {lib.mem.ptr(uint8),lib.str.t}
-- load the body of an artifact into memory (also returns mime)
nkvd_report_issue: {&m.source, &m.kompromat} -> {}
-- an incidence of Badthink has been detected. report it immediately
-- to the Supreme Soviet
nkvd_reports_enum: {&m.source, &m.kompromat} -> lib.mem.ptr(m.kompromat)
-- search through the Archives
-- proto: kompromat (null for all records, or a prototype describing the records to return)
|
Modified str.t from [004fceba8a] to [d98a573fe7].
17 18 19 20 21 22 23 24 25 26 27 28 29 30 .. 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 ... 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 |
ndup = terralib.externfunction('strndup',{rawstring, intptr} -> rawstring);
fmt = terralib.externfunction('asprintf',
terralib.types.funcpointer({&rawstring,rawstring},{int},true));
bfmt = terralib.externfunction('sprintf',
terralib.types.funcpointer({rawstring,rawstring},{int},true));
span = terralib.externfunction('strspn',{rawstring, rawstring} -> rawstring);
}
do local strptr = (lib.mem.ptr(int8))
local strref = (lib.mem.ref(int8))
local byteptr = (lib.mem.ptr(uint8))
strptr.metamethods.__cast = function(from,to,e)
if from == &int8 then
return `strptr {ptr = e, ct = m.sz(e)}
................................................................................
var sz = lib.math.biggest(self.ct, other.ct)
for i = 0, sz do
if self.ptr[i] == 0 and other.ptr[i] == 0 then return true end
if self.ptr[i] ~= other.ptr[i] then return false end
end
return true
end
strptr.methods.cmpl = macro(function(self,other)
return `self:cmp(strptr { ptr = [other:asvalue()], ct = [#(other:asvalue())] })
end)
strref.methods.cmpl = macro(function(self,other)
return `self:cmp(strref { ptr = [other:asvalue()], ct = [#(other:asvalue())] })
end)
................................................................................
for j=0, reject.ct do
if str.ptr[i] == reject.ptr[j] then return i end
end
end
return maxlen
end
terra m.ffw(str: &int8, maxlen: intptr)
while maxlen > 0 and @str ~= 0 and
(@str == @' ' or @str == @'\t' or @str == @'\n') do
str = str + 1
maxlen = maxlen - 1
end
return str
end
terra m.ffw_unsafe(str: &int8)
while @str ~= 0 and
(@str == @' ' or @str == @'\t' or @str == @'\n') do
str = str + 1
end
return str
end
return m
|
> > > > > > > > > > > < > > > > > | | < > | > > > > > > > > > > > > > > | < < > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > |
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 .. 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 ... 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 |
ndup = terralib.externfunction('strndup',{rawstring, intptr} -> rawstring);
fmt = terralib.externfunction('asprintf',
terralib.types.funcpointer({&rawstring,rawstring},{int},true));
bfmt = terralib.externfunction('sprintf',
terralib.types.funcpointer({rawstring,rawstring},{int},true));
span = terralib.externfunction('strspn',{rawstring, rawstring} -> rawstring);
}
terra m.ffw(str: &int8, maxlen: intptr)
if maxlen == 0 then maxlen = m.sz(str) end
while maxlen > 0 and @str ~= 0 and
(@str == @' ' or @str == @'\t' or @str == @'\n') do
str = str + 1
maxlen = maxlen - 1
end
return str
end
do local strptr = (lib.mem.ptr(int8))
local strref = (lib.mem.ref(int8))
local byteptr = (lib.mem.ptr(uint8))
strptr.metamethods.__cast = function(from,to,e)
if from == &int8 then
return `strptr {ptr = e, ct = m.sz(e)}
................................................................................
var sz = lib.math.biggest(self.ct, other.ct)
for i = 0, sz do
if self.ptr[i] == 0 and other.ptr[i] == 0 then return true end
if self.ptr[i] ~= other.ptr[i] then return false end
end
return true
end
terra strptr:ffw()
var newp = m.ffw(self.ptr,self.ct)
var newct = self.ct - (newp - self.ptr)
return strptr { ptr = newp, ct = newct }
end
strptr.methods.cmpl = macro(function(self,other)
return `self:cmp(strptr { ptr = [other:asvalue()], ct = [#(other:asvalue())] })
end)
strref.methods.cmpl = macro(function(self,other)
return `self:cmp(strref { ptr = [other:asvalue()], ct = [#(other:asvalue())] })
end)
................................................................................
for j=0, reject.ct do
if str.ptr[i] == reject.ptr[j] then return i end
end
end
return maxlen
end
terra m.ffw_unsafe(str: &int8)
while @str ~= 0 and
(@str == @' ' or @str == @'\t' or @str == @'\n') do
str = str + 1
end
return str
end
terra m.find(haystack: pstr, needle: pstr): pstr
for i=0,haystack.ct do
for j=0, needle.ct do
if haystack(i + j) ~= needle(j) then goto nomatch end
end
do return pstr {
ptr = haystack.ptr + i;
ct = haystack.ct - i;
} end
::nomatch::end
return pstr.null()
end
terra m.splitmap(str: pstr, delim: pstr, expect: uint16)
var vec: lib.mem.vec(pstr) vec:init(expect)
var start = pstr{str.ptr, str.ct}
while true do
var n = m.find(start, delim)
if not n then break end
vec:push(pstr {ptr = start.ptr, ct = start.ct - n.ct})
n.ptr = n.ptr + delim.ct
n.ct = n.ct - delim.ct
start = n
end
vec:push(start)
return vec:crush()
end
terra m.toknext(str: m.t, delim: int8, brkspace: bool): {pstr,intptr,bool}
var b: m.acc b:init(48)
var mode: int8 = 0
var esc = false
var spacebroke = false
var max = 0
for i=0, str.ct do
max = i
if str(i) == 0 then break
elseif esc == true then b:push(str.ptr + i,1) esc = false
elseif str(i) == @'\\' then esc = true
elseif mode == 0 and str(i) == delim then break
elseif mode ~= 2 and str(i) == @'"' then
if mode == 1
then mode = 0
else mode = 1
end
elseif mode ~= 1 and str(i) == @"'" then
if mode == 2
then mode = 0
else mode = 2
end
elseif brkspace and mode == 0 and (
str(i) == @' ' or str(i) == @'\t' or
str(i) == @'\r' or str(i) == @'\n') then
spacebroke = true
break
else b:push(str.ptr + i,1) end
end
if mode ~= 0 then return m.t.null(), 0, false end
return b:finalize(), max, spacebroke
end
return m
|
Modified view/load.lua from [1dbf5e584d] to [fbf23a2927].
6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
local sources = {
'docskel';
'confirm';
'tweet';
'profile';
'compose';
'notice';
'login-username';
'login-challenge';
'conf';
'conf-profile';
'conf-sec';
|
> > > |
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
local sources = {
'docskel';
'confirm';
'tweet';
'profile';
'compose';
'notice';
'media-gallery';
'media-upload';
'login-username';
'login-challenge';
'conf';
'conf-profile';
'conf-sec';
|
Added view/media-gallery.tpl version [d752c55f41].
> > > > > > > > > > > > > > > > > > > |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<menu>@menu <a href="/media">new uploads</a> <a href="/media/unfiled">unfiled</a> <hr> @folders <a href="/media/all">all uploads</a> <a href="/media/kind/img">all images</a> <a href="/media/kind/vid">all videos</a> <a href="/media/kind/txt">all text files</a> <a href="/media/king/misc">all others</a> </menu> <div class="dir"> @directory </div> <div class="gallery"> @images </div> |
Added view/media-upload.tpl version [687485d89c].
> > > > > > > > > > > > > > > > > > > > > > |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<form method="post" enctype="multipart/form-data"> <div class="elem"> <label for="file">file</label> <input type="file" name="file" id="file" required> </div> <div class="elem"> <label for="desc">description</label> <textarea name="desc" id="desc" placeholder="soviet troops planting the red flag on olympus mons after the battle of tharsis (1969)"></textarea> </div> <div class="elem"> <label for="folder">folder</label> <input type="text" name="folder" id="folder" list="folders"> </div> <menu class="choice horizontal"> <button>upload</button> <a class="button" href="/media">cancel</a> </menu> </form> <datalist id="folders"> @folders </datalist> |
Deleted view/media.tpl version [5a68c18a8e].
1 2 3 4 5 6 7 8 9 10 11 12 |
<menu> <a href="/user/@:xid/media">new uploads</a> @folders </menu> <div name="gallery"> @images </div> <div name="files"> @files </div> |
< < < < < < < < < < < < |