| Comment: | continued iteration |
|---|---|
| Downloads: | Tarball | ZIP archive | SQL archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
0324d625467b68d51407a9ab6432c30e |
| User & Date: | lexi on 2020-12-30 00:43:11 |
| Other Links: | manifest | tags |
|
2020-12-30
| ||
| 02:44 | enable profile editing check-in: ac4a630ad5 user: lexi tags: trunk | |
| 00:43 | continued iteration check-in: 0324d62546 user: lexi tags: trunk | |
|
2020-12-29
| ||
| 15:48 | enable remote control of running instances check-in: f8816b0ab5 user: lexi tags: trunk | |
Modified backend/pgsql.t from [0f1425913d] to [30de1dd276].
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 ... 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 ... 685 686 687 688 689 690 691 692 693 694 695 696 697 698 ... 905 906 907 908 909 910 911 912 913 914 915 916 |
select relatee as user from parsav_rels where relator = $1::bigint and kind = <follow> ), followers as ( select relator as user from parsav_rels where relatee = $1::bigint and kind = <follow> ), mutuals as (select * from follows intersect select * from followers) select count(tweets.*)::bigint, count(follows.*)::bigint, count(followers.*)::bigint, count(mutuals.*)::bigint from tweets, follows, followers, mutuals ]]):gsub('<(%w+)>',function(r) return tostring(lib.store.relation[r]) end) }; actor_auth_how = { params = {rawstring, lib.store.inet}, sql = [[ with mts as (select a.kind from parsav_auth as a left join parsav_actors as u on u.id = a.uid ................................................................................ (a.origin is null) order by (p.posted, p.discovered) desc limit case when $3::bigint = 0 then null else $3::bigint end offset $4::bigint ]] }; } --($5::bool = false or p.parent is null) and local struct pqr { sz: intptr res: &lib.pq.PGresult } terra pqr:free() if self.sz > 0 then lib.pq.PQclear(self.res) end end terra pqr:null(row: intptr, col: intptr) ................................................................................ lib.report('successfully wiped out everything parsav-related in database') return true else lib.warn('backend pgsql - failed to obliterate database: \n', lib.pq.PQresultErrorMessage(res)) return false end end]; conf_get = [terra(src: &lib.store.source, key: rawstring) var r = queries.conf_get.exec(src, key) if r.sz == 0 then return [lib.mem.ptr(int8)] { ptr = nil, ct = 0 } else defer r:free() return r:String(0,0) end ................................................................................ queries.auth_purge_type.exec(src, handle, uid, 'otp-%') end]; auth_purge_trust = [terra(src: &lib.store.source, uid: uint64, handle: rawstring): {} queries.auth_purge_type.exec(src, handle, uid, 'trust') end]; actor_auth_register_uid = nil; -- not necessary for view-based auth } return b |
| > | > > | | | | < > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > |
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 ... 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 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 ... 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 .... 1000 1001 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 |
select relatee as user from parsav_rels where relator = $1::bigint and kind = <follow> ), followers as ( select relator as user from parsav_rels where relatee = $1::bigint and kind = <follow> ), mutuals as ( select * from follows intersect select * from followers ) values ( (select count(tweets.*)::bigint from tweets), (select count(follows.*)::bigint from follows), (select count(followers.*)::bigint from followers), (select count(mutuals.*)::bigint from mutuals) ) ]]):gsub('<(%w+)>',function(r) return tostring(lib.store.relation[r]) end) }; actor_auth_how = { params = {rawstring, lib.store.inet}, sql = [[ with mts as (select a.kind from parsav_auth as a left join parsav_actors as u on u.id = a.uid ................................................................................ (a.origin is null) order by (p.posted, p.discovered) desc limit case when $3::bigint = 0 then null else $3::bigint end offset $4::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 ]]; }; artifact_disclaim = { params = {uint64, uint64}, cmd = true, sql = [[ delete from parsav_artifact_claims where uid = $1::bigint and rid = $2::bigint ]]; }; artifact_excise_forget = { -- delete the blasted thing and pretend it never existed params = {uint64}, cmd=true, sql = [[ delete from parsav_artifacts where id = $1::bigint ]]; }; artifact_excise_suppress_nullify = { -- banish the thing into the outer darkness, preventing -- it from ever being admitted into our databases, and -- tabulate a -- list of the degenerates who befouled -- their accounts with such wanton and execrable filth, -- the better to ensure their long-overdue punishment params = {uint64}, cmd=true, sql = [[ update parsav_artifacts set content = null where id = $1::bigint; ]]; }; artifact_excise_suppress_breaklinks = { -- "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] ]]; }; post_attach_ctl_del = { params = {uint64, uint64}, cmd=true, sql = [[ update parsav_posts set artifacts = array_remove(artifacts, $2::bigint) where id = $1::bigint and artifacts @> array[$2::bigint] ]]; }; } local struct pqr { sz: intptr res: &lib.pq.PGresult } terra pqr:free() if self.sz > 0 then lib.pq.PQclear(self.res) end end terra pqr:null(row: intptr, col: intptr) ................................................................................ lib.report('successfully wiped out everything parsav-related in database') return true else lib.warn('backend pgsql - failed to obliterate database: \n', lib.pq.PQresultErrorMessage(res)) return false end end]; tx_enter = [terra(src: &lib.store.source) var res = lib.pq.PQexec([&lib.pq.PGconn](src.handle), 'begin') if lib.pq.PQresultStatus(res) == lib.pq.PGRES_COMMAND_OK then lib.dbg('beginning pgsql transaction') return true else lib.warn('backend pgsql - failed to begin transaction: \n', lib.pq.PQresultErrorMessage(res)) return false end end]; tx_complete = [terra(src: &lib.store.source) var res = lib.pq.PQexec([&lib.pq.PGconn](src.handle), 'end') if lib.pq.PQresultStatus(res) == lib.pq.PGRES_COMMAND_OK then lib.dbg('completing pgsql transaction') return true else lib.warn('backend pgsql - failed to complete transaction: \n', lib.pq.PQresultErrorMessage(res)) return false end end]; conf_get = [terra(src: &lib.store.source, key: rawstring) var r = queries.conf_get.exec(src, key) if r.sz == 0 then return [lib.mem.ptr(int8)] { ptr = nil, ct = 0 } else defer r:free() return r:String(0,0) end ................................................................................ queries.auth_purge_type.exec(src, handle, uid, 'otp-%') end]; auth_purge_trust = [terra(src: &lib.store.source, uid: uint64, handle: rawstring): {} queries.auth_purge_type.exec(src, handle, uid, 'trust') end]; artifact_quicksearch = [terra( src: &lib.store.source, hash: binblob ): {uint64, bool} var srec = queries.artifact_quicksearch.exec(src, hash) if srec.sz > 0 then defer srec:free() var id = srec:int(uint64,0,0) var ban = srec:bool(0,1) return id, ban else return 0, false end end]; artifact_instantiate = [terra( src: &lib.store.source, artifact: binblob, mime: pstring ): uint64 var arthash: uint8[lib.crypt.algsz.sha256] if lib.md.mbedtls_md(lib.md.mbedtls_md_info_from_type(lib.crypt.alg.sha256.id), artifact.ptr, artifact.ct, &arthash[0]) ~= 0 then lib.bail('could not hash artifact to be instantiated') end var hashb = binblob{ptr=&arthash[0],ct=[arthash.type.N]} var srec = queries.artifact_quicksearch.exec(src, hashb) if srec.sz > 0 then defer srec:free() var ban = srec:bool(0,1) 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 ): {} if detach then queries.post_attach_ctl_del.exec(src,post,artifact) else queries.post_attach_ctl_ins.exec(src,post,artifact) end end]; actor_auth_register_uid = nil; -- TODO better support non-view based auth } return b |
Modified backend/schema/pgsql-drop.sql from [e1fb43be2e] to [17a37aa5f6].
5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
drop table if exists parsav_actors cascade; drop table if exists parsav_rights cascade; drop table if exists parsav_posts cascade; drop table if exists parsav_conversations cascade; drop table if exists parsav_rels cascade; drop table if exists parsav_acts cascade; drop table if exists parsav_log cascade; drop table if exists parsav_attach cascade; drop table if exists parsav_circles cascade; drop table if exists parsav_rooms cascade; drop table if exists parsav_room_members cascade; drop table if exists parsav_invites cascade; drop table if exists parsav_interventions cascade; drop table if exists parsav_auth cascade; |
| > | |
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
drop table if exists parsav_actors cascade; drop table if exists parsav_rights cascade; drop table if exists parsav_posts cascade; drop table if exists parsav_conversations cascade; drop table if exists parsav_rels cascade; drop table if exists parsav_acts cascade; drop table if exists parsav_log cascade; drop table if exists parsav_artifacts cascade; drop table if exists parsav_artifact_claims cascade; drop table if exists parsav_circles cascade; drop table if exists parsav_rooms cascade; drop table if exists parsav_room_members cascade; drop table if exists parsav_invites cascade; drop table if exists parsav_sanctions cascade; drop table if exists parsav_auth cascade; |
Modified backend/schema/pgsql.sql from [0ef43163b5] to [cb277a93b1].
26 27 28 29 30 31 32 33 34 35 36 37 38 39 .. 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 .. 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 |
id bigint primary key default (1+random()*(2^63-1))::bigint, nym text, handle text not null, -- nym [@handle@origin] origin bigint references parsav_servers(id) on delete cascade, -- null origin = local actor knownsince timestamp, bio text, avataruri text, -- null if local rank smallint not null default 0, quota integer not null default 1000, key bytea, -- private if localactor; public if remote epithet text, authtime timestamp not null default now(), -- cookies earlier than this timepoint will not be accepted ................................................................................ author bigint references parsav_actors(id) on delete cascade, subject text, acl text not null default 'all', -- just store the script raw 🤷 body text, posted timestamp not null, discovered timestamp not null, parent bigint not null default 0, circles bigint[], -- TODO at edit or creation, iterate through each circle mentions bigint[], -- a user has, check if it can see her post, and if so add convoheaduri text -- only used for tracking foreign conversations and tying them to post heads; -- local conversations are tracked directly and mapped to URIs based on the -- head's ID. null if native tweet or not the first tweet in convo ); ................................................................................ id bigint primary key default (1+random()*(2^63-1))::bigint, time timestamp not null default now(), actor bigint references parsav_actors(id) on delete cascade, post bigint not null ); create table parsav_attach ( id bigint primary key default (1+random()*(2^63-1))::bigint, birth timestamp not null default now(), content bytea not null, mime text, -- null if unknown, will be reported as x-octet-stream description text, parent bigint -- post id, or userid for avatars ); create table parsav_circles ( id bigint primary key default (1+random()*(2^63-1))::bigint, owner bigint not null references parsav_actors(id), name text not null, members bigint[] not null default array[]::bigint[], unique (owner,name) ); create table parsav_rooms ( id bigint primary key default (1+random()*(2^63-1))::bigint, origin bigint references parsav_servers(id), name text not null, description text not null, policy smallint not null ); create table parsav_room_members ( room bigint references parsav_rooms(id), member bigint references parsav_actors(id), rank smallint not null default 0, admin boolean not null default false, -- non-admins with rank can only moderate + invite title text, -- admin-granted title like reddit flair vouchedby bigint references parsav_actors(id) ); create table parsav_invites ( id bigint primary key default (1+random()*(2^63-1))::bigint, -- when a user is created from an invite, the invite is deleted and the invite -- ID becomes the user ID. privileges granted on the invite ID during the invite -- process are thus inherited by the user issuer bigint references parsav_actors(id), handle text, -- admin can lock invite to specific handle rank smallint not null default 0, quota integer not null default 1000 ); create table parsav_interventions ( id bigint primary key default (1+random()*(2^63-1))::bigint, issuer bigint references parsav_actors(id) not null, scope bigint, -- can be null or room for local actions nature smallint not null, -- silence, suspend, disemvowel, etc victim bigint not null, -- could potentially target group as well expire timestamp -- auto-expires if set ); -- create a temporary managed auth table; we can delete this later -- if it ends up being replaced with a view %include pgsql-auth.sql% |
> | > | | > > > | > > > > > > > < > > > > | | | | | | | | | | > > > |
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 .. 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 .. 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 |
id bigint primary key default (1+random()*(2^63-1))::bigint, nym text, handle text not null, -- nym [@handle@origin] origin bigint references parsav_servers(id) on delete cascade, -- null origin = local actor knownsince timestamp, bio text, avatarid bigint, -- artifact id, null if remote avataruri text, -- null if local rank smallint not null default 0, quota integer not null default 1000, key bytea, -- private if localactor; public if remote epithet text, authtime timestamp not null default now(), -- cookies earlier than this timepoint will not be accepted ................................................................................ author bigint references parsav_actors(id) on delete cascade, subject text, acl text not null default 'all', -- just store the script raw 🤷 body text, posted timestamp not null, discovered timestamp not null, parent bigint not null default 0, -- if post: part of conversation; if chatroom: top-level post circles bigint[], -- TODO at edit or creation, iterate through each circle mentions bigint[], -- a user has, check if it can see her post, and if so add artifacts bigint[], convoheaduri text -- only used for tracking foreign conversations and tying them to post heads; -- local conversations are tracked directly and mapped to URIs based on the -- head's ID. null if native tweet or not the first tweet in convo ); ................................................................................ id bigint primary key default (1+random()*(2^63-1))::bigint, time timestamp not null default now(), actor bigint references parsav_actors(id) on delete cascade, post bigint not null ); create table parsav_artifacts ( id bigint primary key default (1+random()*(2^63-1))::bigint, birth timestamp not null default now(), content bytea, -- if null, this is a "ban record" preventing content matching the hash from being re-uploaded hash bytea unique not null, -- sha256 hash of content -- it would be cool to use a computed column for this, but i don't want -- to lock people into PG12 or drag in the pgcrypto extension just for this mime text -- null if unknown, will be reported as x-octet-stream ); create index on parsav_artifacts (mime); create table parsav_artifact_claims ( birth timestamp not null default now(), uid bigint references parsav_actors(id) on delete cascade, rid bigint references parsav_artifacts(id) on delete cascade, description text, folder text, unique (uid,rid) ); create index on parsav_artifact_claims (uid); create table parsav_circles ( id bigint primary key default (1+random()*(2^63-1))::bigint, owner bigint not null references parsav_actors(id) on delete cascade, name text not null, members bigint[] not null default array[]::bigint[], unique (owner,name) ); create table parsav_rooms ( id bigint primary key default (1+random()*(2^63-1))::bigint, origin bigint references parsav_servers(id) on delete cascade, name text not null, description text not null, policy smallint not null ); create table parsav_room_members ( room bigint not null references parsav_rooms(id) on delete cascade, member bigint not null references parsav_actors(id) on delete cascade, rank smallint not null default 0, admin boolean not null default false, -- non-admins with rank can only moderate + invite title text, -- admin-granted title like reddit flair vouchedby bigint references parsav_actors(id) ); create table parsav_invites ( id bigint primary key default (1+random()*(2^63-1))::bigint, -- when a user is created from an invite, the invite is deleted and the invite -- ID becomes the user ID. privileges granted on the invite ID during the invite -- process are thus inherited by the user issuer bigint references parsav_actors(id) on delete set null, handle text, -- admin can lock invite to specific handle rank smallint not null default 0, quota integer not null default 1000 ); create table parsav_sanctions ( id bigint primary key default (1+random()*(2^63-1))::bigint, issuer bigint references parsav_actors(id) on delete set null, scope bigint, -- can be null or room for local actions nature smallint not null, -- silence, suspend, disemvowel, censor, noreply, etc victim bigint not null, -- can be user, room, or post expire timestamp, -- auto-expires if set review timestamp, -- brings up for review at given time if set reason text, -- visible to victim if set context text -- admin-only note ); -- create a temporary managed auth table; we can delete this later -- if it ends up being replaced with a view %include pgsql-auth.sql% |
Modified mgtool.t from [c623f2c8c5] to [03b0c72484].
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
...
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
|
local fn = f.field or f[1]
local ft = f.type or f[2]
if fn == meth then rt = ft.type.returntype break end
end
return quote
var r: rt
if self.all
then r=self.srv:[meth]([expr])
elseif self.src ~= nil then r=self.src:[meth]([expr])
else lib.bail('no data source specified')
end
in r end
end)
................................................................................
return 1
end
if dbmode.arglist.ct < 1 then goto cmderr end
srv:setup(cnf)
if lib.str.cmp(dbmode.arglist(0),'init') == 0 and dbmode.arglist.ct == 2 then
lib.report('initializing new database structure for domain ', dbmode.arglist(1))
dlg:dbsetup()
srv:conprep(lib.store.prepmode.conf)
dlg:conf_set('instance-name', dbmode.arglist(1))
do var sec: int8[65] gensec(&sec[0])
dlg:conf_set('server-secret', &sec[0])
end
lib.report('database setup complete; use mkroot to create an administrative user')
elseif lib.str.cmp(dbmode.arglist(0),'obliterate') == 0 then
var confirmstrs = array(
'alpha', 'beta', 'gamma', 'delta', 'epsilon', 'eta', 'nu', 'kappa'
)
var cfmstr: int8[64] cfmstr[0] = 0
var tdx = lib.osclock.time(nil) / 60
for i=0,3 do
if i ~= 0 then lib.str.cat(&cfmstr[0], '-') end
lib.str.cat(&cfmstr[0], confirmstrs[(tdx ^ (173*i)) % [confirmstrs.type.N]])
end
|
|
|
|
|
|
|
|
|
>
|
>
|
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
...
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
|
local fn = f.field or f[1] local ft = f.type or f[2] if fn == meth then rt = ft.type.returntype break end end return quote var r: rt if self.all or (self.srv ~= nil and self.srv.sources.ct == 1) then r=self.srv:[meth]([expr]) elseif self.src ~= nil then r=self.src:[meth]([expr]) else lib.bail('no data source specified') end in r end end) ................................................................................ return 1 end if dbmode.arglist.ct < 1 then goto cmderr end srv:setup(cnf) if lib.str.cmp(dbmode.arglist(0),'init') == 0 and dbmode.arglist.ct == 2 then lib.report('initializing new database structure for domain ', dbmode.arglist(1)) if dlg:dbsetup() then srv:conprep(lib.store.prepmode.conf) dlg:conf_set('instance-name', dbmode.arglist(1)) do var sec: int8[65] gensec(&sec[0]) dlg:conf_set('server-secret', &sec[0]) end lib.report('database setup complete; use mkroot to create an administrative user') else lib.bail('initialization process interrupted') end elseif lib.str.cmp(dbmode.arglist(0),'obliterate') == 0 then var confirmstrs = array( 'alpha', 'beta', 'gamma', 'delta', 'epsilon', 'eta', 'nu', 'kappa', 'emerald', 'carnelian', 'sapphire', 'ruby', 'amethyst' ) var cfmstr: int8[64] cfmstr[0] = 0 var tdx = lib.osclock.time(nil) / 60 for i=0,3 do if i ~= 0 then lib.str.cat(&cfmstr[0], '-') end lib.str.cat(&cfmstr[0], confirmstrs[(tdx ^ (173*i)) % [confirmstrs.type.N]]) end |
Modified render/conf.t from [6e08f785f6] to [79b6da76d7].
62 63 64 65 66 67 68 69 70 71 72 73 74 |
panel = panel;
}
var pgt = pg:tostr() defer pgt:free()
co:stdpage([lib.srv.convo.page] {
title = 'configure'; body = pgt;
class = lib.str.plit 'conf';
})
if panel.ct ~= 0 then panel:free() end
end
return render_conf
|
> |
62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
panel = panel;
}
var pgt = pg:tostr() defer pgt:free()
co:stdpage([lib.srv.convo.page] {
title = 'configure'; body = pgt;
class = lib.str.plit 'conf';
cache = false;
})
if panel.ct ~= 0 then panel:free() end
end
return render_conf
|
Modified render/docpage.t from [7e1168b387] to [3eda6110a6].
44
45
46
47
48
49
50
51
52
53
54
55
56
57
...
107
108
109
110
111
112
113
114
115
116
117
118
119
|
parent = par;
priv = restrict;
title = R(t.meta.title);
content = page {
title = ['documentation :: ' .. t.meta.title];
body = [ t.text ];
class = P'doc article';
};
} end
end
local terra
showpage(co: &lib.srv.convo, id: pref)
var [pages] = array([allpages])
................................................................................
list:lpush('</ul>')
var bp = list:finalize()
co:stdpage(page {
title = 'documentation';
body = bp;
class = P'doc listing';
})
bp:free()
else showpage(co, pg) end
end
return render_docpage
|
>
>
|
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
...
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
parent = par;
priv = restrict;
title = R(t.meta.title);
content = page {
title = ['documentation :: ' .. t.meta.title];
body = [ t.text ];
class = P'doc article';
cache = true;
};
} end
end
local terra
showpage(co: &lib.srv.convo, id: pref)
var [pages] = array([allpages])
................................................................................
list:lpush('</ul>')
var bp = list:finalize()
co:stdpage(page {
title = 'documentation';
body = bp;
class = P'doc listing';
cache = false;
})
bp:free()
else showpage(co, pg) end
end
return render_docpage
|
Modified render/login.t from [dd5c50c3e9] to [7ea4ccf2b4].
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
..
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
-- vim: ft=terra local pstr = lib.mem.ptr(int8) local P = lib.str.plit local terra login_form(co: &lib.srv.convo, user: &lib.store.actor, creds: &lib.store.credset, msg: pstr) var doc = data.view.docskel { instance = co.srv.cfg.instance; title = lib.str.plit 'instance logon'; class = lib.str.plit 'login'; navlinks = co.navbar; } if user == nil then var form = data.view.login_username { loginmsg = msg; } if form.loginmsg.ptr == nil then ................................................................................ end doc.body = ch:tostr() else -- pick a method end var hdrs = array( lib.http.header { 'Content-Type', 'text/html; charset=UTF-8' } ) doc:send(co.con,200,[lib.mem.ptr(lib.http.header)] {ct = 1, ptr = &hdrs[0]}) doc.body:free() end return login_form |
|
<
<
>
|
<
<
<
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
..
51
52
53
54
55
56
57
58
59
60
61
62
|
-- vim: ft=terra local pstr = lib.mem.ptr(int8) local P = lib.str.plit local terra login_form(co: &lib.srv.convo, user: &lib.store.actor, creds: &lib.store.credset, msg: pstr) var doc = [lib.srv.convo.page] { title = lib.str.plit 'instance logon'; class = lib.str.plit 'login'; cache = false; } if user == nil then var form = data.view.login_username { loginmsg = msg; } if form.loginmsg.ptr == nil then ................................................................................ end doc.body = ch:tostr() else -- pick a method end co:stdpage(doc) doc.body:free() end return login_form |
Modified render/nav.t from [27572ae99b] to [4a737bb7ff].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
-- vim: ft=terra
local terra
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 href="/">timeline</a>')
end
if co.who ~= nil then
t:lpush('<a href="/compose">compose</a> <a href="/'):push(co.who.xid,0)
t:lpush('">profile</a> <a href="/conf">configure</a> <a href="/doc">docs</a> <a href="/logout">log out</a>')
else
t:lpush('<a href="/doc">docs</a> <a href="/login">log in</a>')
end
return t:finalize()
end
return render_nav
|
| | | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
-- vim: ft=terra
local terra
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 href="/">timeline</a>')
end
if co.who ~= nil then
t:lpush(' <a href="/compose">compose</a> <a href="/'):push(co.who.xid,0)
t:lpush('">profile</a> <a href="/conf">configure</a> <a href="/doc">docs</a> <a href="/logout">log out</a>')
else
t:lpush(' <a href="/doc">docs</a> <a href="/login">log in</a>')
end
return t:finalize()
end
return render_nav
|
Modified render/nym.t from [89e574dd98] to [0d2437aadd].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
-- vim: ft=terra
local pstr = lib.mem.ptr(int8)
local terra
render_nym(who: &lib.store.actor, scope: uint64)
var n: lib.str.acc n:init(128)
if who.nym ~= nil and who.nym[0] ~= 0 then
n:compose('<span class="nym">',who.nym,'</span> [<span class="handle">',
who.xid,'</span>]')
else n:compose('<span class="handle">',who.xid,'</span>') end
if who.epithet ~= nil then
n:lpush(' <span class="epithet">'):push(who.epithet,0):lpush('</span>')
end
-- TODO: if scope == chat room then lookup titles in room member db
return n:finalize()
end
return render_nym
|
> > > > > | | > | > > | > < |
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 |
-- vim: ft=terra local pstr = lib.mem.ptr(int8) local terra cs(s: rawstring) return pstr { ptr = s, ct = lib.str.sz(s) } end local terra render_nym(who: &lib.store.actor, scope: uint64) var n: lib.str.acc n:init(128) var xidsan = lib.html.sanitize(cs(who.xid),false) if who.nym ~= nil and who.nym[0] ~= 0 then var nymsan = lib.html.sanitize(cs(who.nym),false) n:compose('<span class="nym">',nymsan,'</span> [<span class="handle">', xidsan,'</span>]') nymsan:free() else n:compose('<span class="handle">',xidsan,'</span>') end xidsan:free() if who.epithet ~= nil then var episan = lib.html.sanitize(cs(who.epithet),false) n:lpush(' <span class="epithet">'):ppush(episan):lpush('</span>') episan:free() end -- TODO: if scope == chat room then lookup titles in room member db return n:finalize() end return render_nym |
Modified render/timeline.t from [873aeea861] to [2afba48373].
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
var acc: lib.str.acc acc:init(1024) for i = 0, posts.sz do lib.render.tweet(co, posts(i).ptr, &acc) posts(i):free() end posts:free() var doc = data.view.docskel { instance = co.srv.cfg.instance; title = lib.str.plit'timeline'; body = acc:finalize(); class = lib.str.plit'timeline'; navlinks = co.navbar; } var hdrs = array( lib.http.header { 'Content-Type', 'text/html; charset=UTF-8' } ) doc:send(co.con,200,[lib.mem.ptr(lib.http.header)] {ct = 1, ptr = &hdrs[0]}) doc.body:free() end return render_timeline |
| < | | < < < |
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
var acc: lib.str.acc acc:init(1024) for i = 0, posts.sz do lib.render.tweet(co, posts(i).ptr, &acc) posts(i):free() end posts:free() var doc = [lib.srv.convo.page] { title = lib.str.plit'timeline'; body = acc:finalize(); class = lib.str.plit'timeline'; cache = false; } co:stdpage(doc) doc.body:free() end return render_timeline |
Modified render/userpage.t from [edce0da550] to [8e478d7a95].
26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
end
posts:free()
var bdf = acc:finalize()
co:stdpage([lib.srv.convo.page] {
title = tiptr; body = bdf;
class = lib.str.plit 'profile';
})
tiptr:free()
bdf:free()
end
return render_userpage
|
> |
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
end
posts:free()
var bdf = acc:finalize()
co:stdpage([lib.srv.convo.page] {
title = tiptr; body = bdf;
class = lib.str.plit 'profile';
cache = false;
})
tiptr:free()
bdf:free()
end
return render_userpage
|
Modified route.t from [4ebb6db558] to [5e16c3f22b].
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
if aid == 0 then
lib.render.login(co, nil, nil, lib.str.plit 'authentication failure')
else
var sesskey: int8[lib.session.maxlen + #lib.session.cookiename + #"=; Path=/" + 1]
do var p = &sesskey[0]
p = lib.str.ncpy(p, [lib.session.cookiename .. '='], [#lib.session.cookiename + 1])
p = p + lib.session.cookie_gen(co.srv.cfg.secret, aid, lib.osclock.time(nil), p)
lib.dbg('sending cookie',&sesskey[0])
p = lib.str.ncpy(p, '; Path=/', 9)
end
co:reroute_cookie('/', &sesskey[0])
end
end
if act.ptr ~= nil and fakeact == false then act:free() end
else
|
| |
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
if aid == 0 then
lib.render.login(co, nil, nil, lib.str.plit 'authentication failure')
else
var sesskey: int8[lib.session.maxlen + #lib.session.cookiename + #"=; Path=/" + 1]
do var p = &sesskey[0]
p = lib.str.ncpy(p, [lib.session.cookiename .. '='], [#lib.session.cookiename + 1])
p = p + lib.session.cookie_gen(co.srv.cfg.secret, aid, lib.osclock.time(nil), p)
lib.dbg('sending cookie ',{&sesskey[0],15})
p = lib.str.ncpy(p, '; Path=/', 9)
end
co:reroute_cookie('/', &sesskey[0])
end
end
if act.ptr ~= nil and fakeact == false then act:free() end
else
|
Modified srv.t from [7727a773dd] to [4721bcd333].
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
...
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
|
ptr = &hdrs[0], ct = [hdrs.type.N] - lib.trn(cookie == nil,1,0) }) end terra convo:reroute(dest: rawstring) self:reroute_cookie(dest,nil) end terra convo:complain(code: uint16, title: rawstring, msg: rawstring) var hdrs = array(lib.http.header { key = 'Content-Type', value = 'text/html; charset=UTF-8' }) var ti: lib.str.acc ti:compose('error :: ', title) var bo: lib.str.acc bo:compose('<div class="message"><img class="icon" src="/s/warn.webp"><h1>',title,'</h1><p>',msg,'</p></div>') var body = data.view.docskel { instance = self.srv.cfg.instance; title = ti:finalize(); body = bo:finalize(); ................................................................................ in ok end end) struct convo.page { title: pstring body: pstring class: pstring } terra convo:stdpage(pg: convo.page) var doc = data.view.docskel { instance = self.srv.cfg.instance; title = pg.title; body = pg.body; class = pg.class; navlinks = self.navbar; } var hdrs = array( lib.http.header { 'Content-Type', 'text/html; charset=UTF-8' } ) doc:send(self.con,200,[lib.mem.ptr(lib.http.header)] {ct = [hdrs.type.N], ptr = &hdrs[0]}) end -- CALL ONLY ONCE PER VAR terra convo:postv(name: rawstring) if self.varbuf.ptr == nil then self.varbuf = lib.mem.heapa(int8, self.msg.body.len + self.msg.query.len) self.vbofs = self.varbuf.ptr |
>
|
>
>
>
|
>
|
|
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
...
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
|
ptr = &hdrs[0], ct = [hdrs.type.N] - lib.trn(cookie == nil,1,0) }) end terra convo:reroute(dest: rawstring) self:reroute_cookie(dest,nil) end terra convo:complain(code: uint16, title: rawstring, msg: rawstring) var hdrs = array( lib.http.header { key = 'Content-Type', value = 'text/html; charset=UTF-8' }, lib.http.header { key = 'Cache-Control', value = 'no-store' } ) var ti: lib.str.acc ti:compose('error :: ', title) var bo: lib.str.acc bo:compose('<div class="message"><img class="icon" src="/s/warn.webp"><h1>',title,'</h1><p>',msg,'</p></div>') var body = data.view.docskel { instance = self.srv.cfg.instance; title = ti:finalize(); body = bo:finalize(); ................................................................................ in ok end end) struct convo.page { title: pstring body: pstring class: pstring cache: bool } terra convo:stdpage(pg: convo.page) var doc = data.view.docskel { instance = self.srv.cfg.instance; title = pg.title; body = pg.body; class = pg.class; navlinks = self.navbar; } var hdrs = array( lib.http.header { key = 'Content-Type', value = 'text/html; charset=UTF-8' }, lib.http.header { key = 'Cache-Control', value = 'no-store' } ) doc:send(self.con,200,[lib.mem.ptr(lib.http.header)] {ct = [hdrs.type.N] - lib.trn(pg.cache,1,0), ptr = &hdrs[0]}) end -- CALL ONLY ONCE PER VAR terra convo:postv(name: rawstring) if self.varbuf.ptr == nil then self.varbuf = lib.mem.heapa(int8, self.msg.body.len + self.msg.query.len) self.vbofs = self.varbuf.ptr |
Modified static/style.scss from [1f479ddac7] to [a08d589c48].
127 128 129 130 131 132 133 134 135 136 137 138 139 140 ... 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 ... 541 542 543 544 545 546 547 548 |
tone(-50%),
tone(-35%)
);
input[type='text'], input[type='password'], textarea {
@extend %serif;
padding: 0.08in 0.1in;
border: 1px solid black;
background: linear-gradient(to bottom, tone(-55%), tone(-40%));
font-size: 16pt;
color: tone(25%);
box-shadow: inset 0 0 20px -3px tone(-55%);
&:focus {
color: white;
................................................................................
> a { @extend %button; grid-column: 1 / 2; grid-row: 3/4; }
}
}
form.compose {
@extend %box;
display: grid;
grid-template-columns: 1.1in 2fr min-content 1fr;
grid-template-rows: 1fr min-content;
grid-gap: 2px;
padding: 0.1in;
> img { grid-column: 1/2; grid-row: 1/3; width: 1in; height: 1in;}
> textarea {
grid-column: 2/5; grid-row: 1/2; height: 3in;
resize: vertical;
margin-bottom: 0.08in;
}
> input[name="acl"] { grid-column: 2/3; grid-row: 2/3; }
> button { grid-column: 4/5; grid-row: 2/3; }
a.help[href] { margin-right: 0.05in }
}
a.help[href] {
display: block;
text-align: center;
padding: 0.09in 0.2in;
................................................................................
padding-top: 0.12in;
background: linear-gradient(to right, tone(-50%), tone(-50%,-0.7));
border: 1px solid tone(-55%);
border-left: none;
text-shadow: 1px 1px 0 black;
}
}
}
|
> | | > | | > > > > > > > > > > > > > > > > > > > > |
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 ... 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 ... 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 |
tone(-50%),
tone(-35%)
);
input[type='text'], input[type='password'], textarea {
@extend %serif;
padding: 0.08in 0.1in;
box-sizing: border-box;
border: 1px solid black;
background: linear-gradient(to bottom, tone(-55%), tone(-40%));
font-size: 16pt;
color: tone(25%);
box-shadow: inset 0 0 20px -3px tone(-55%);
&:focus {
color: white;
................................................................................
> a { @extend %button; grid-column: 1 / 2; grid-row: 3/4; }
}
}
form.compose {
@extend %box;
display: grid;
grid-template-columns: 1.1in 2fr min-content 1fr 1.5fr;
grid-template-rows: 1fr min-content;
grid-gap: 2px;
padding: 0.1in;
> img { grid-column: 1/2; grid-row: 1/3; width: 1in; height: 1in;}
> textarea {
grid-column: 2/6; grid-row: 1/2; height: 3in;
resize: vertical;
margin-bottom: 0.08in;
}
> input[name="acl"] { grid-column: 2/3; grid-row: 2/3; }
> button[value="post"] { grid-column: 5/6; grid-row: 2/3; }
> button[value="attach"] { grid-column: 4/5; grid-row: 2/3; }
a.help[href] { margin-right: 0.05in }
}
a.help[href] {
display: block;
text-align: center;
padding: 0.09in 0.2in;
................................................................................
padding-top: 0.12in;
background: linear-gradient(to right, tone(-50%), tone(-50%,-0.7));
border: 1px solid tone(-55%);
border-left: none;
text-shadow: 1px 1px 0 black;
}
}
}
form {
.elem {
margin: 0.1in 0;
label { display:block; font-weight: bold; padding: 0.03in 0; }
.txtbox {
@extend %serif;
box-sizing: border-box;
padding: 0.08in 0.1in;
border: 1px solid black;
background: tone(-55%);
}
input, textarea, .txtbox {
display: block;
width: 100%;
}
button { float: right; width: 50%; }
}
}
|
Modified store.t from [763fd9ba8a] to [69369cc5c2].
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 .. 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 ... 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 ... 209 210 211 212 213 214 215 216 217 218 219 220 221 222 ... 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 |
relation = lib.enum {
'follow', 'mute', 'block'
};
credset = lib.set {
'pw', 'otp', 'challenge', 'trust'
};
privset = lib.set {
'post', 'edit', 'acct', 'upload', 'censor', 'admin'
};
powerset = lib.set {
-- user powers -- default on
'login', 'visible', 'post', 'shout',
'propagate', 'upload', 'acct', 'edit';
-- admin powers -- default off
'purge', 'config', 'censor', 'suspend',
'cred', 'elevate', 'demote', 'rebrand', -- modify site's brand identity
'herald' -- grant serverwide epithets
};
prepmode = lib.enum {
'full','conf','admin'
}
}
m.privmap = {}
................................................................................
struct m.source
struct m.rights {
rank: uint16 -- lower = more powerful except 0 = regular user
-- creating staff automatically assigns rank immediately below you
quota: uint32 -- # of allowed tweets per day; 0 = no limit
powers: m.powerset
}
terra m.rights_default()
var pow: m.powerset pow:fill()
(pow.purge << false)
(pow.config << false)
(pow.censor << false)
(pow.suspend << false)
(pow.elevate << false)
(pow.demote << false)
(pow.cred << false)
(pow.rebrand << false)
return m.rights { rank = 0, quota = 1000, powers = pow; }
end
struct m.actor {
id: uint64
nym: str
handle: str
origin: uint64
................................................................................
var bytes = bits / 8
var hexchs = bytes * 2
var segs = hexchs / 4
var seps = segs - 1
var maxsz = hexchs + seps + 1
else return nil end
end
struct m.auth {
aid: uint64
uid: uint64
aname: str
netmask: m.inet
privs: m.privset
blacklist: bool
}
................................................................................
struct m.backend { id: rawstring
open: &m.source -> &opaque
close: &m.source -> {}
dbsetup: &m.source -> bool -- creates the schema needed to call conprep (called only once per database e.g. with `parsav db init`)
conprep: {&m.source, m.prepmode.t} -> {} -- prepares queries and similar tasks that require the schema to already be in place
obliterate_everything: &m.source -> bool -- wipes everything parsav-related out of the database
conf_get: {&m.source, rawstring} -> lib.mem.ptr(int8)
conf_set: {&m.source, rawstring, rawstring} -> {}
conf_reset: {&m.source, rawstring} -> {}
actor_create: {&m.source, &m.actor} -> uint64
actor_save_privs: {&m.source, &m.actor} -> {}
actor_fetch_xid: {&m.source, lib.mem.ptr(int8)} -> lib.mem.ptr(m.actor)
................................................................................
auth_purge_pw: {&m.source, uint64, rawstring} -> {}
auth_purge_otp: {&m.source, uint64, rawstring} -> {}
auth_purge_trust: {&m.source, uint64, rawstring} -> {}
post_save: {&m.source, &m.post} -> {}
post_create: {&m.source, &m.post} -> uint64
post_enum_author_uid: {&m.source, uint64, m.range} -> lib.mem.ptr(lib.mem.ptr(m.post))
convo_fetch_xid: {&m.source,rawstring} -> lib.mem.ptr(m.post)
convo_fetch_uid: {&m.source,uint64} -> lib.mem.ptr(m.post)
timeline_actor_fetch_uid: {&m.source, uint64, m.range} -> lib.mem.ptr(lib.mem.ptr(m.post))
timeline_instance_fetch: {&m.source, m.range} -> lib.mem.ptr(lib.mem.ptr(m.post))
}
struct m.source {
backend: &m.backend
|
| | > > | | | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | |
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 .. 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 ... 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 ... 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 ... 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 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 |
relation = lib.enum {
'follow', 'mute', 'block'
};
credset = lib.set {
'pw', 'otp', 'challenge', 'trust'
};
privset = lib.set {
'post', 'edit', 'acct', 'upload', 'censor', 'admin', 'invite'
};
powerset = lib.set {
-- user powers -- default on
'login', 'visible', 'post', 'shout',
'propagate', 'upload', 'acct', 'edit';
-- admin powers -- default off
'purge', 'config', 'censor', 'suspend',
'cred', 'elevate', 'demote', 'rebrand', -- modify site's brand identity
'herald', -- grant serverwide epithets
'invite' -- *unlimited* invites
};
prepmode = lib.enum {
'full','conf','admin'
}
}
m.privmap = {}
................................................................................
struct m.source
struct m.rights {
rank: uint16 -- lower = more powerful except 0 = regular user
-- creating staff automatically assigns rank immediately below you
quota: uint32 -- # of allowed tweets per day; 0 = no limit
invites: intptr -- # of people left this user can invite
powers: m.powerset
}
terra m.rights_default()
var pow: m.powerset pow:clear()
(pow.login << true)
(pow.visible << true)
(pow.post << true)
(pow.shout << true)
(pow.propagate << true)
(pow.upload << true)
(pow.acct << true)
(pow.edit << true)
return m.rights { rank = 0, quota = 1000, invites = 0, powers = pow; }
end
struct m.actor {
id: uint64
nym: str
handle: str
origin: uint64
................................................................................
var bytes = bits / 8
var hexchs = bytes * 2
var segs = hexchs / 4
var seps = segs - 1
var maxsz = hexchs + seps + 1
else return nil end
end
struct m.kompromat {
-- The Evidence
id: uint64
perp: uint64 -- whodunnit
desc: str
post: uint64 -- the post in question, if any
reporter: uint64 -- 0 = originated automatically by the System itself
resolution: str -- null for unresolved
-- as proto: set resolution to empty string to search for resolved incidents
}
struct m.sanction {
id: uint64
issuer: uint64
scope: uint64
nature: uint16
victim: uint64
autoexpire: bool expire: m.timepoint
timedreview: bool review: m.timepoint
reason: str
context: str
}
struct m.auth {
-- a credential record
aid: uint64
uid: uint64
aname: str
netmask: m.inet
privs: m.privset
blacklist: bool
}
................................................................................
struct m.backend { id: rawstring
open: &m.source -> &opaque
close: &m.source -> {}
dbsetup: &m.source -> bool -- creates the schema needed to call conprep (called only once per database e.g. with `parsav db init`)
conprep: {&m.source, m.prepmode.t} -> {} -- prepares queries and similar tasks that require the schema to already be in place
obliterate_everything: &m.source -> bool -- wipes everything parsav-related out of the database
tx_enter: &m.source -> bool
tx_complete: &m.source -> bool
-- these two functions are special, in that they should be called
-- directly on a specific backend, rather than passed down to the
-- backends by the server; that is pathological behavior that will
-- not have the desired effect
conf_get: {&m.source, rawstring} -> lib.mem.ptr(int8)
conf_set: {&m.source, rawstring, rawstring} -> {}
conf_reset: {&m.source, rawstring} -> {}
actor_create: {&m.source, &m.actor} -> uint64
actor_save_privs: {&m.source, &m.actor} -> {}
actor_fetch_xid: {&m.source, lib.mem.ptr(int8)} -> lib.mem.ptr(m.actor)
................................................................................
auth_purge_pw: {&m.source, uint64, rawstring} -> {}
auth_purge_otp: {&m.source, uint64, rawstring} -> {}
auth_purge_trust: {&m.source, uint64, rawstring} -> {}
post_save: {&m.source, &m.post} -> {}
post_create: {&m.source, &m.post} -> uint64
post_enum_author_uid: {&m.source, uint64, m.range} -> lib.mem.ptr(lib.mem.ptr(m.post))
post_attach_ctl: {&m.source, uint64, uint64, bool} -> {}
-- attaches or detaches an existing database artifact
-- post id: uint64
-- artifact id: uint64
-- detach: bool
artifact_instantiate: {&m.source, lib.mem.ptr(uint8), lib.mem.ptr(int8)} -> uint64
-- instantiate an artifact in the database, either installing a new
-- artifact or returning the id of an existing artifact with the same hash
-- 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)
nkvd_sanction_issue: {&m.source, &m.sanction} -> uint64
nkvd_sanction_vacate: {&m.source, uint64} -> {}
nkvd_sanction_enum_target: {&m.source, uint64} -> {}
nkvd_sanction_enum_issuer: {&m.source, uint64} -> {}
nkvd_sanction_review: {&m.source, m.timepoint} -> {}
convo_fetch_xid: {&m.source,rawstring} -> lib.mem.ptr(m.post)
convo_fetch_cid: {&m.source,uint64} -> lib.mem.ptr(m.post)
timeline_actor_fetch_uid: {&m.source, uint64, m.range} -> lib.mem.ptr(lib.mem.ptr(m.post))
timeline_instance_fetch: {&m.source, m.range} -> lib.mem.ptr(lib.mem.ptr(m.post))
}
struct m.source {
backend: &m.backend
|
Modified view/compose.tpl from [5ccb8d92d6] to [a602850007].
1 2 3 4 5 6 7 8 9 10 11 12 |
<form class="compose" method="post"> <img src="/avi/@handle"> <textarea autofocus name="post" placeholder="it was a dark and stormy night…">@!content</textarea> <input required autocomplete="on" type="text" name="acl" class="acl" value="@acl" list="scopes" placeholder="access control"> @?acl <button type="submit">commit</button> </form> <datalist id="scopes"> <option>all</option> <option>mentioned</option> <option>local</option> <option>mutual</option> |
| > |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<form class="compose" method="post"> <img src="/avi/@handle"> <textarea autofocus name="post" placeholder="it was a dark and stormy night…">@!content</textarea> <input required autocomplete="on" type="text" name="acl" class="acl" value="@acl" list="scopes" placeholder="access control"> @?acl <button type="submit" name="act" value="post">commit</button> <button type="submit" name="act" value="attach">attach</button> </form> <datalist id="scopes"> <option>all</option> <option>mentioned</option> <option>local</option> <option>mutual</option> |
Modified view/conf-profile.tpl from [746111dd26] to [f1f77d7014].
1 2 3 4 5 6 |
<form method="post"> <label>handle <div class="txtbox">@!handle</div></label> <label>display name <input type="text" name="nym" value="@:nym"></label> <label>bio <textarea name="bio">@!bio</textarea></label> <input type="submit" value="commit"> </form> |
| | | | |
1 2 3 4 5 6 |
<form method="post"> <div class="elem"><label>handle</label> <div class="txtbox">@!handle</div> <div class="elem"><label for="nym">display name</label> <input type="text" name="nym" id="nym" placeholder="j. random poster" value="@:nym"></div> <div class="elem"><label for="bio">bio</label><textarea name="bio" id="bio" placeholder="tall, dark, and mysterious">@!bio</textarea></div> <button>commit</button> </form> |