Index: backend/pgsql.t
==================================================================
--- backend/pgsql.t
+++ backend/pgsql.t
@@ -60,10 +60,36 @@
(a.origin is null and
$1::text = a.handle or
$1::text = ('@' || a.handle))
]];
};
+
+ actor_save = {
+ params = {
+ uint64, --id
+ rawstring, --nym
+ rawstring, --handle
+ rawstring, --bio
+ rawstring, --epithet
+ rawstring, --avataruri
+ uint64, --avatarid
+ uint16, --rank
+ uint32 --quota
+ }, cmd = true, sql = [[
+ update parsav_actors set
+ nym = $2::text,
+ handle = $3::text,
+ bio = $4::text,
+ epithet = $5::text,
+ avataruri = $6::text,
+ avatarid = $7::bigint,
+ rank = $8::smallint,
+ quota = $9::integer
+ --invites are controlled by their own specialized routines
+ where id = $1::bigint
+ ]];
+ };
actor_create = {
params = {
rawstring, rawstring, uint64, lib.store.timepoint,
rawstring, rawstring, lib.mem.ptr(uint8),
@@ -825,11 +851,14 @@
var r = queries.actor_enum.exec(src)
if r.sz == 0 then
return [lib.mem.ptr(&lib.store.actor)] { ct = 0, ptr = nil }
else defer r:free()
var mem = lib.mem.heapa([&lib.store.actor], r.sz)
- for i=0,r.sz do mem.ptr[i] = row_to_actor(&r, i).ptr end
+ for i=0,r.sz do
+ mem.ptr[i] = row_to_actor(&r, i).ptr
+ mem.ptr[i].source = src
+ end
return [lib.mem.ptr(&lib.store.actor)] { ct = r.sz, ptr = mem.ptr }
end
end];
actor_enum_local = [terra(src: &lib.store.source)
@@ -836,11 +865,14 @@
var r = queries.actor_enum_local.exec(src)
if r.sz == 0 then
return [lib.mem.ptr(&lib.store.actor)] { ct = 0, ptr = nil }
else defer r:free()
var mem = lib.mem.heapa([&lib.store.actor], r.sz)
- for i=0,r.sz do mem.ptr[i] = row_to_actor(&r, i).ptr end
+ for i=0,r.sz do
+ mem.ptr[i] = row_to_actor(&r, i).ptr
+ mem.ptr[i].source = src
+ end
return [lib.mem.ptr(&lib.store.actor)] { ct = r.sz, ptr = mem.ptr }
end
end];
actor_auth_how = [terra(
@@ -936,11 +968,14 @@
var r = pqr { sz = 0 }
var A,B,C,D = rg:matrix() -- :/
r = queries.timeline_instance_fetch.exec(src,A,B,C,D)
var ret: lib.mem.ptr(lib.mem.ptr(lib.store.post)) ret:init(r.sz)
- for i=0,r.sz do ret.ptr[i] = row_to_post(&r, i) end -- MUST FREE ALL
+ for i=0,r.sz do
+ ret.ptr[i] = row_to_post(&r, i) -- MUST FREE ALL
+ ret.ptr[i].ptr.source = src
+ end
return ret
end];
post_enum_author_uid = [terra(
@@ -951,16 +986,29 @@
var r = pqr { sz = 0 }
var A,B,C,D = rg:matrix() -- :/
r = queries.post_enum_author_uid.exec(src,A,B,C,D,uid)
var ret: lib.mem.ptr(lib.mem.ptr(lib.store.post)) ret:init(r.sz)
- for i=0,r.sz do ret.ptr[i] = row_to_post(&r, i) end -- MUST FREE ALL
+ for i=0,r.sz do
+ ret.ptr[i] = row_to_post(&r, i) -- MUST FREE ALL
+ ret.ptr[i].ptr.source = src
+ end
return ret
end];
actor_powers_fetch = getpow;
+ actor_save = [terra(
+ src: &lib.store.source,
+ ac: &lib.store.actor
+ ): {}
+ queries.actor_save.exec(src,
+ ac.id, ac.nym, ac.handle,
+ ac.bio, ac.epithet, ac.avatar,
+ ac.avatarid, ac.rights.rank, ac.rights.quota)
+ end];
+
actor_save_privs = privupdate;
actor_create = [terra(
src: &lib.store.source,
ac: &lib.store.actor
Index: parsav.t
==================================================================
--- parsav.t
+++ parsav.t
@@ -560,11 +560,11 @@
end
local holler = print
local suffix = config.exe and '' or ('.'..config.outform)
local out = 'parsavd' .. suffix
-local linkargs = {}
+local linkargs = {'-O4'}
local target = config.tgttrip and terralib.newtarget {
Triple = config.tgttrip;
CPU = config.tgtcpu;
FloatABIHard = config.tgthf;
} or nil
Index: render/conf.t
==================================================================
--- render/conf.t
+++ render/conf.t
@@ -37,11 +37,11 @@
end
end
end
local terra
-render_conf([co], [path])
+render_conf([co], [path], notify: pstr)
var menu: lib.str.acc menu:init(64):lpush('
') defer menu:free()
-- build menu
do var p = co.who.rights.powers
if p.config() then menu:lpush 'server settings' end
@@ -60,11 +60,19 @@
var pg = data.view.conf {
menu = mptr;
panel = panel;
}
- var pgt = pg:tostr() defer pgt:free()
+ var pgt: pstr
+ if notify:ref() then
+ var fnpg: lib.str.acc
+ fnpg:compose('', notify, '
')
+ pg:append(&fnpg)
+ pgt = fnpg:finalize()
+ else pgt = pg:tostr() end
+ defer pgt:free()
+
co:stdpage([lib.srv.convo.page] {
title = 'configure'; body = pgt;
class = lib.str.plit 'conf';
cache = false;
})
Index: render/profile.t
==================================================================
--- render/profile.t
+++ render/profile.t
@@ -5,24 +5,22 @@
end
local terra
render_profile(co: &lib.srv.convo, actor: &lib.store.actor)
var aux: lib.str.acc
- var auxp: pstr
if co.aid ~= 0 and co.who.id == actor.id then
- auxp = lib.str.plit 'alter'
+ aux:compose('alter')
elseif co.aid ~= 0 then
aux:compose('followchat')
if co.who.rights.powers:affect_users() then
aux:lpush('control')
end
- auxp = aux:finalize()
else
aux:compose('remote follow')
- auxp = aux:finalize()
end
+ var auxp = aux:finalize()
var avistr: lib.str.acc if actor.origin == 0 then
avistr:compose('/avi/',actor.handle)
end
var timestr: int8[26] lib.osclock.ctime_r(&actor.knownsince, ×tr[0])
@@ -32,11 +30,11 @@
var sn_follows = cs(lib.math.decstr_friendly(stats.follows, sn_posts.ptr - 1))
var sn_followers = cs(lib.math.decstr_friendly(stats.followers, sn_follows.ptr - 1))
var sn_mutuals = cs(lib.math.decstr_friendly(stats.mutuals, sn_followers.ptr - 1))
var bio = lib.str.plit "tall, dark, and mysterious"
if actor.bio ~= nil then
- bio = lib.html.sanitize(cs(actor.bio), false)
+ bio = lib.smackdown.html(cs(actor.bio))
end
var fullname = lib.render.nym(actor,0) defer fullname:free()
var profile = data.view.profile {
nym = fullname;
bio = bio;
@@ -52,11 +50,11 @@
auxbtn = auxp;
}
var ret = profile:tostr()
if actor.origin == 0 then avistr:free() end
- if not (co.aid ~= 0 and co.who.id == actor.id) then auxp:free() end
+ auxp:free()
if actor.bio ~= nil then bio:free() end
return ret
end
return render_profile
Index: route.t
==================================================================
--- route.t
+++ route.t
@@ -174,12 +174,39 @@
else
co:complain(404, 'no such documentation', 'invalid documentation URL')
end
end
-terra http.configure(co: &lib.srv.convo, path: hpath)
- lib.render.conf(co,path)
+terra http.configure(co: &lib.srv.convo, path: hpath, meth: method.t)
+ var msg = pstring.null()
+ if meth == method.post and path.ct >= 1 then
+ var user_refresh = false var fail = false
+ if path(1):cmp(lib.str.lit 'profile') then
+ co.who.bio = co:postv('bio')._0
+ co.who.nym = co:postv('nym')._0
+ if co.who.bio ~= nil and @co.who.bio == 0 then co.who.bio = nil end
+ if co.who.nym ~= nil and @co.who.nym == 0 then co.who.nym = nil end
+ co.who.source:actor_save(co.who)
+ msg = lib.str.plit 'profile changes saved'
+ --user_refresh = true -- not really necessary here, actually
+ elseif path(1):cmp(lib.str.lit 'srv') then
+ elseif path(1):cmp(lib.str.lit 'users') then
+
+ end
+
+ if user_refresh then -- refresh the user info for the renderer
+ var usr = co.srv:actor_fetch_uid(co.who.id)
+ lib.mem.heapf(co.who)
+ co.who = usr.ptr
+ end
+ var go,golen = co:getv('go')
+ if not fail and go ~= nil then
+ co:reroute(go)
+ return
+ end
+ end
+ lib.render.conf(co,path,msg)
end
do local branches = quote end
local filename, flen = symbol(&int8), symbol(intptr)
local page = symbol(lib.http.page)
@@ -272,14 +299,14 @@
elseif path.ptr[0]:cmp(lib.str.lit('doc')) then
if meth ~= method.get and meth ~= method.head then goto wrongmeth end
http.documentation(co, path)
elseif path.ptr[0]:cmp(lib.str.lit('conf')) then
if co.aid == 0 then goto unauth end
- http.configure(co,path)
+ http.configure(co,path,meth)
else goto notfound end
return
end
::wrongmeth:: co:complain(405, 'method not allowed', 'that method is not meaningful for this endpoint') do return end
::notfound:: co:complain(404, 'not found', 'no such resource available') do return end
::unauth:: co:complain(401, 'unauthorized', 'this content is not available at your clearance level') do return end
end
Index: static/style.scss
==================================================================
--- static/style.scss
+++ static/style.scss
@@ -559,12 +559,39 @@
box-sizing: border-box;
padding: 0.08in 0.1in;
border: 1px solid black;
background: tone(-55%);
}
+ textarea { resize: vertical; min-height: 2in; }
input, textarea, .txtbox {
display: block;
width: 100%;
}
button { float: right; width: 50%; }
}
}
+
+@keyframes flashup {
+ 0% { opacity: 0; transform: scale(0.8); }
+ 10% { opacity: 1; transform: scale(1.1); }
+ 80% { opacity: 1; transform: scale(1); }
+ 100% { opacity: 0; transform: scale(0.9) translateY(-0.12in); display: none; }
+}
+.flashmsg {
+ display: block;
+ position: fixed;
+ top: 1.3in;
+ max-width: 3in;
+ padding: 0.5in 0.2in;
+ left: 0; right: 0;
+ text-align: center;
+ text-shadow: 0 0 15px tone(10%);
+ margin: auto;
+ background: linear-gradient(to bottom, tone(-49%), tone(-43%,-0.1));
+ border: 1px solid tone(0%);
+ border-radius: 3px;
+ box-shadow: 0 0 50px tone(-55%);
+ color: white;
+ animation: ease forwards flashup;
+ //cubic-bezier(0.4, 0.63, 0.6, 0.31)
+ animation-duration: 3s;
+}
Index: store.t
==================================================================
--- store.t
+++ store.t
@@ -55,11 +55,11 @@
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
+ invites: uint32 -- # of people left this user can invite
powers: m.powerset
}
terra m.rights_default()
@@ -81,10 +81,11 @@
handle: str
origin: uint64
bio: str
epithet: str
avatar: str
+ avatarid: uint64
knownsince: m.timepoint
rights: m.rights
key: lib.mem.ptr(uint8)
-- ephemera
@@ -249,10 +250,11 @@
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: {&m.source, &m.actor} -> {}
actor_save_privs: {&m.source, &m.actor} -> {}
actor_fetch_xid: {&m.source, lib.mem.ptr(int8)} -> lib.mem.ptr(m.actor)
actor_fetch_uid: {&m.source, uint64} -> lib.mem.ptr(m.actor)
actor_notif_fetch_uid: {&m.source, uint64} -> lib.mem.ptr(m.notif)
actor_enum: {&m.source} -> lib.mem.ptr(&m.actor)