$ git clone http://socialnetwork.ion.nu/socialnetwork-web.git
commit effc5d880218b170d351f63cd8b5bf4924eab968
Author: Alicia <...>
Date: Thu Aug 17 05:34:02 2017 +0000
Implemented support for fields.
diff --git a/Makefile b/Makefile
index 2b9da73..8ff756a 100644
--- a/Makefile
+++ b/Makefile
@@ -4,11 +4,11 @@ EMSCRIPTVERSION=1.37.12
GMPVERSION=6.1.2
NETTLEVERSION=3.3
GNUTLSVERSION=3.5.12
-SOCIALNETWORKREVISION=f5e92db17a617d4777df4b7a1107d67114d3b6f9
+SOCIALNETWORKREVISION=b3f54256b676bbca6805fd5c27d4270f6994f31d
REVISION=$(shell git log | sed -n -e 's/^commit //p;q')
JSLIBS=$(shell PKG_CONFIG_PATH=toolchain/usr/lib/pkgconfig pkg-config --libs gnutls nettle hogweed) -lgmp
JSCFLAGS=$(shell PKG_CONFIG_PATH=toolchain/usr/lib/pkgconfig pkg-config --cflags gnutls)
-JSSYMBOLS='_social_init','_peer_handlesocket','_peer_new_unique','_websockproxy_read','_websockproxy_setwrite','_getcirclecount','_circle_getcount','_circle_getname','_circle_getprivacyptr','_social_addfriend','_circle_getid','_social_finduser','_self_getid','_user_getupdatecount','_user_getupdateptr','_update_gettype','_update_gettimestamp','_update_post_getmessage','_setcircle','_privacy_getflags','_privacy_getcirclecount','_privacy_getcircle','_createpost'
+JSSYMBOLS='_social_init','_peer_handlesocket','_peer_new_unique','_websockproxy_read','_websockproxy_setwrite','_getcirclecount','_circle_getcount','_circle_getname','_circle_getprivacyptr','_social_addfriend','_circle_getid','_social_finduser','_self_getid','_user_getupdatecount','_user_getupdateptr','_update_gettype','_update_gettimestamp','_update_getprivacy','_update_post_getmessage','_update_field_getname','_update_field_getvalue','_setcircle','_privacy_getflags','_privacy_getcirclecount','_privacy_getcircle','_createpost','_setfield'
all: webpeer libsocial.js
diff --git a/jsglue.c b/jsglue.c
index 0e59ac7..37e06ef 100644
--- a/jsglue.c
+++ b/jsglue.c
@@ -94,7 +94,10 @@ const char* update_gettype(struct update* update)
return "Unknown";
}
uint64_t update_gettimestamp(struct update* update){return update->timestamp;}
+struct privacy* update_getprivacy(struct update* update){return &update->privacy;}
const char* update_post_getmessage(struct update* update){return update->post.message;}
+const char* update_field_getname(struct update* update){return update->field.name;}
+const char* update_field_getvalue(struct update* update){return update->field.value;}
const char* self_getid(void)
{
unsigned char* bin=social_self->id;
@@ -114,3 +117,12 @@ void createpost(const char* msg, uint8_t flags, void* circles, uint32_t circleco
};
social_createpost(msg, &priv);
}
+void setfield(const char* name, const char* value, uint8_t flags, void* circles, uint32_t circlecount)
+{
+ struct privacy priv={
+ .flags=flags,
+ .circles=circles,
+ .circlecount=circlecount
+ };
+ social_updatefield(name, value, &priv);
+}
diff --git a/libsocialjs.js b/libsocialjs.js
index c934ef4..e0bd206 100644
--- a/libsocialjs.js
+++ b/libsocialjs.js
@@ -37,12 +37,16 @@ var user_getupdatecount;
var user_getupdateptr;
var update_gettype;
var update_gettimestamp;
+var update_getprivacy;
var update_post_getmessage;
+var update_field_getname;
+var update_field_getvalue;
var self_getid;
var privacy_getflags;
var privacy_getcirclecount;
var privacy_getcircle;
var createpost;
+var setfield;
var websockproxy_to=false;
var firstpacket=true;
@@ -75,8 +79,8 @@ function handlenet(data)
}
function init(privkey)
{
- websockproxy_read=Module.cwrap('websockproxy_read', null, ['array', 'number', 'array', 'number']);
- peer_new_unique=Module.cwrap('peer_new_unique', 'array', ['number', 'array', 'number']);
+ websockproxy_read=Module.cwrap('websockproxy_read', null, ['array','number','array','number']);
+ peer_new_unique=Module.cwrap('peer_new_unique', 'array', ['number','array','number']);
// Low level access functions
getcirclecount=Module.cwrap('getcirclecount', 'number', []);
circle_getcount=Module.cwrap('circle_getcount', 'number', ['number']);
@@ -90,12 +94,16 @@ function init(privkey)
user_getupdateptr=Module.cwrap('user_getupdateptr', 'number', ['number','number']);
update_gettype=Module.cwrap('update_gettype', 'string', ['number']);
update_gettimestamp=Module.cwrap('update_gettimestamp', 'number', ['number']);
+ update_getprivacy=Module.cwrap('update_getprivacy', 'number', ['number']);
update_post_getmessage=Module.cwrap('update_post_getmessage', 'string', ['number']);
+ update_field_getname=Module.cwrap('update_field_getname', 'string', ['number']);
+ update_field_getvalue=Module.cwrap('update_field_getvalue', 'string', ['number']);
self_getid=Module.cwrap('self_getid', 'string', []);
privacy_getflags=Module.cwrap('privacy_getflags', 'number', ['number']);
privacy_getcirclecount=Module.cwrap('privacy_getcirclecount', 'number', ['number']);
- privacy_getcircle=Module.cwrap('privacy_getcircle', 'number', ['number', 'number']);
- createpost=Module.cwrap('createpost', null, ['string', 'number', 'array', 'number']);
+ privacy_getcircle=Module.cwrap('privacy_getcircle', 'number', ['number','number']);
+ createpost=Module.cwrap('createpost', null, ['string','number','array','number']);
+ setfield=Module.cwrap('setfield', null, ['string','string','number','array','number']);
_websockproxy_setwrite(Runtime.addFunction(websockwrite));
FS.writeFile('privkey.pem', privkey, {});
@@ -160,8 +168,17 @@ function getuser(id)
var user=new Object();
user.ptr=userptr;
user.id=id;
-// TODO: Gather more user data? No need to store updates themselves in user objects though
+// TODO: Gather more user data? No need to store updates themselves in user objects though, except for fields
user.updatecount=user_getupdatecount(userptr);
+ user.fields={};
+ for(var i=0; i<user.updatecount; ++i)
+ {
+ var update=user_getupdate(user, i);
+ if(update.type=='Field')
+ {
+ user.fields[update.name]=update;
+ }
+ }
return user;
}
function user_getupdate(user, index)
@@ -170,12 +187,17 @@ function user_getupdate(user, index)
var ptr=user_getupdateptr(user.ptr, index);
update.type=update_gettype(ptr);
update.timestamp=update_gettimestamp(ptr);
+ update.privacy=getprivacy(update_getprivacy(ptr));
// Get type-specific data
switch(update.type)
{
case 'Post':
update.message=update_post_getmessage(ptr);
break;
+ case 'Field':
+ update.name=update_field_getname(ptr);
+ update.value=update_field_getvalue(ptr);
+ break;
}
return update;
}
diff --git a/websocial.css b/websocial.css
index d2b6278..4105a9e 100644
--- a/websocial.css
+++ b/websocial.css
@@ -62,3 +62,17 @@ div.update
box-shadow:0px 0px 2px #c0c0c0;
background-color:#ffffff;
}
+div.updatebox
+{
+ border-style:solid;
+ border-color:#000000;
+ border-width:1px;
+ border-radius:6px;
+ padding:4px;
+ margin:5px;
+ min-width:40%;
+ max-width:96%;
+ display:inline-block;
+ box-shadow:0px 0px 4px #0080ff;
+ background-color:#ffffff;
+}
diff --git a/websocial.js b/websocial.js
index 795a7ad..8360a8f 100644
--- a/websocial.js
+++ b/websocial.js
@@ -135,8 +135,19 @@ function page_friends()
var count=circle_getcount(item.index);
for(var i=0; i<count; ++i)
{
- var user=circle_getid(item.index, i);
- display.appendChild(document.createTextNode(user));
+ var id=circle_getid(item.index, i);
+ // Get user and get their name field, TODO: maybe a 'picture' field for main profile picture?
+ var user=getuser(id);
+ if(!user){continue;}
+ var name=(user.fields['name']?user.fields['name'].value:id);
+ if(!name){name=id;}
+ // Link to profile
+ var link=document.createElement('a');
+ link.href='#';
+ link.dataset.id=id;
+ link.onclick=function(){page_user(this.dataset.id); return false;};
+ link.appendChild(document.createTextNode(name));
+ display.appendChild(link);
display.appendChild(document.createElement('br'));
}
}
@@ -144,19 +155,54 @@ function page_friends()
function page_user(id)
{
- if(!id){id=self_getid();} // No ID = show our own page
+ var userself=self_getid();
+ if(!id){id=userself;} // No ID = show our own page
var display=document.getElementById('display');
dom_clear(display);
- // TODO: Get and present fields
var user=getuser(id);
- display.appendChild(document.createTextNode(id+':'));
- display.appendChild(document.createElement('br'));
- var button=document.createElement('button');
- button.name='postbutton';
- button.onclick=postwidget;
- button.appendChild(document.createTextNode('Create update'));
- display.appendChild(button);
- display.appendChild(document.createElement('br'));
+ // Placeholder for common fields
+ if(!user.fields['name']){user.fields['name']={'value':''};}
+ // List fields and their values
+ var fields=document.createElement('p');
+ for(field in user.fields)
+ {
+ var span=document.createElement('span');
+ span.appendChild(document.createTextNode(field+': '+user.fields[field].value));
+ if(id==userself) // If self, enable editing
+ {
+ span.dataset.name=field;
+ span.dataset.value=user.fields[field].value;
+ if(user.fields[field].privacy)
+ {
+ span.dataset.privacyflags=user.fields[field].privacy.flags;
+ span.dataset.privacycircles=JSON.stringify(user.fields[field].privacy.circles);
+ }
+ span.className='updatebutton';
+ span.onclick=fieldwidget;
+ var button=document.createElement('button');
+ button.appendChild(document.createTextNode('Edit'));
+ span.appendChild(button);
+ }
+ fields.appendChild(span);
+ fields.appendChild(document.createElement('br'));
+ }
+ if(id==userself) // If self, enable editing
+ {
+ // Field button
+ var button=document.createElement('button');
+ button.className='updatebutton';
+ button.onclick=fieldwidget;
+ button.appendChild(document.createTextNode('Add field'));
+ fields.appendChild(button);
+ display.appendChild(fields);
+ // Post button
+ button=document.createElement('button');
+ button.className='updatebutton';
+ button.onclick=postwidget;
+ button.appendChild(document.createTextNode('Create post'));
+ display.appendChild(button);
+ display.appendChild(document.createElement('br'));
+ }
display.appendChild(document.createTextNode(user.updatecount+' updates'));
for(var i=1; i<=user.updatecount && i<=20; ++i)
{
@@ -272,55 +318,94 @@ function circle_save()
chdisplay('circle_window',false);
}
-var postwidgetbox=false;
-var postprivacy=new privacy(0,[]);
-function postwidget()
+var updatewidgetbox=false;
+var updateprivacy=new privacy(0,[]);
+function updatewidget(updatebutton, title)
{
-// TODO: Differences in widgets for posts on others walls or in response to other posts?
- if(postwidgetbox && postwidgetbox.parentNode)
+ if(updatewidgetbox && updatewidgetbox.parentNode)
{
- postwidgetbox.parentNode.removeChild(postwidgetbox);
+ updatewidgetbox.parentNode.removeChild(updatewidgetbox);
}
- postwidgetbox=document.createElement('div');
+ updatewidgetbox=document.createElement('div');
+ updatewidgetbox.className='updatebox';
// TODO: Configurable default privacy?
- var privtext=document.createTextNode('Privacy: '+postprivacy.toString());
- postwidgetbox.appendChild(privtext);
+ var bold=document.createElement('strong');
+ bold.appendChild(document.createTextNode(title));
+ updatewidgetbox.appendChild(bold);
+ updatewidgetbox.appendChild(document.createElement('br'));
+ var privtext=document.createTextNode('Privacy: '+updateprivacy.toString());
+ updatewidgetbox.appendChild(privtext);
button=document.createElement('button');
button.appendChild(document.createTextNode('Change'));
button.onclick=function()
{
- privacy_openconfig('generic', postprivacy);
+ privacy_openconfig('generic', updateprivacy);
document.getElementById('privacy_button').onclick=function()
{
- postprivacy=privacy_save('generic');
+ updateprivacy=privacy_save('generic');
chdisplay('privacy_window', false);
- privtext.textContent='Privacy: '+postprivacy.toString();
+ privtext.textContent='Privacy: '+updateprivacy.toString();
};
chdisplay(false, 'privacy_window');
};
- postwidgetbox.appendChild(button);
- postwidgetbox.appendChild(document.createElement('br'));
+ updatewidgetbox.appendChild(button);
+ updatewidgetbox.appendChild(document.createElement('br'));
+ // Re-show all updatebuttons
+ var buttons=document.getElementsByClassName('updatebutton');
+ for(button of buttons)
+ {
+ button.style.display='inline';
+ }
+ // Hide this one and insert updatewidget
+ updatebutton.style.display='none';
+ updatebutton.parentNode.insertBefore(updatewidgetbox, updatebutton);
+ return updatewidgetbox;
+}
+function postwidget()
+{
+// TODO: Differences in widgets for posts on others walls or in response to other posts?
+ var box=updatewidget(this, 'New post');
// TODO: Non-text posts, maybe media for starters
var text=document.createElement('textarea');
- postwidgetbox.appendChild(text);
- postwidgetbox.appendChild(document.createElement('br'));
+ box.appendChild(text);
+ box.appendChild(document.createElement('br'));
// Submit button
button=document.createElement('button');
button.appendChild(document.createTextNode('Post'));
button.onclick=function()
{
- createpost(text.value, postprivacy.flags, postprivacy.bincircles(), postprivacy.circles.length);
-// TODO: Instead of reloading the user page, insert the update and hide the postwidget (and re-show postbutton)
+ createpost(text.value, updateprivacy.flags, updateprivacy.bincircles(), updateprivacy.circles.length);
+// TODO: Instead of reloading the user page, insert the update and hide the updatewidget (and re-show postbutton)
page_user(false);
};
- postwidgetbox.appendChild(button);
- // Re-show all postbuttons
- var buttons=document.getElementsByName('postbutton');
- for(button of buttons)
+ box.appendChild(button);
+}
+function fieldwidget()
+{
+ if(this.dataset.privacyflags!==undefined && this.dataset.privacycircles)
{
- button.style.display='inline';
+ updateprivacy.flags=this.dataset.privacyflags;
+ updateprivacy.circles=JSON.parse(this.dataset.privacycircles);
}
- // Hide this one and insert postwidget
- this.style.display='none';
- this.parentNode.insertBefore(postwidgetbox, this);
+ var box=updatewidget(this, this.dataset.name?'Edit field':'New field');
+ var name=document.createElement('input');
+ name.type='text';
+ box.appendChild(name);
+ box.appendChild(document.createTextNode(': '));
+ var value=document.createElement('input');
+ value.type='text';
+ // Use existing values if provided
+ if(this.dataset.name){name.value=this.dataset.name; name.readOnly=true;}
+ if(this.dataset.value){value.value=this.dataset.value;}
+ box.appendChild(value);
+ // Save button
+ button=document.createElement('button');
+ button.appendChild(document.createTextNode('Save'));
+ button.onclick=function()
+ {
+ setfield(name.value, value.value, updateprivacy.flags, updateprivacy.bincircles(), updateprivacy.circles.length);
+// TODO: Instead of reloading the user page, insert the field and hide the updatewidget (and re-show field button)
+ page_user(false);
+ };
+ box.appendChild(button);
}