Merge pull request #133 from owncloud/member-management

Member management
pull/1/head
VicDeo 11 years ago
commit 5bdad7be17

@ -50,50 +50,6 @@ try{
$command = $request->getParam('command');
switch ($command){
case 'query_memberdata_list':
$ids = $request->getParam('args/member_ids');
$member = new Db_Member();
$members = $member->getCollectionBy('member_id', $ids);
$response["memberdata_list"] = array_map(
function($x){
$x['display_name'] = \OCP\User::getDisplayName($x['uid']);
// Do we have OC_Avatar in out disposal?
if (!class_exists('\OC_Avatar') || \OC_Config::getValue('enable_avatars', true) !== true){
//$x['avatar_url'] = \OCP\Util::linkToRoute('documents_user_avatar');
$x['avatar_url'] = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAAAAACH5BAAAAAAALAAAAAABAAEAAAICTAEAOw==';
} else {
// https://github.com/owncloud/documents/issues/51
// Temporary stub
$x['avatar_url'] = $x['uid'];
/*
$avatar = new \OC_Avatar($x['uid']);
$image = $avatar->get(64);
// User has an avatar
if ($image instanceof \OC_Image) {
$x['avatar_url'] = \OC_Helper::linkToRoute(
'core_avatar_get',
array( 'user' => $x['uid'], 'size' => 64)
) . '?requesttoken=' . \OC::$session->get('requesttoken');
} else {
//shortcircuit if it's not an image
$x['avatar_url'] = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAAAAACH5BAAAAAAALAAAAAABAAEAAAICTAEAOw==';
}
*/
}
return $x;
},
$members
);
break;
case 'sync_ops':
$seqHead = (string) $request->getParam('args/seq_head');
if (!is_null($seqHead)){

@ -32,6 +32,8 @@ class UserController extends Controller{
$memberData = $member->getData();
if ($memberData['es_id']===$esId){
$member->deactivate(array($args['member_id']));
$op = new Db_Op();
$op->removeMember($esId, $args['member_id']);
}
}
\OCP\JSON::success();

@ -124,7 +124,20 @@ define("webodf/editor/Editor", [
* @return {undefined}
*/
this.openDocument = function (docUrl, memberId, editorReadyCallback) {
initDocLoading(docUrl, memberId, editorReadyCallback);
initDocLoading(docUrl, memberId, function () {
runtime.loadClass("ops.OpAddMember");
var op = new ops.OpAddMember();
op.init({
memberid: memberId,
setProperties: {
fullName: runtime.tr("Unknown Author"),
color: "black",
imageUrl: "avatar-joe.png"
}
});
session.enqueue([op]);
editorReadyCallback();
});
};
/**
@ -134,6 +147,14 @@ define("webodf/editor/Editor", [
*/
this.closeDocument = function (callback) {
runtime.assert(session, "session should exist here.");
runtime.loadClass("ops.OpRemoveMember");
var op = new ops.OpRemoveMember();
op.init({
memberid: editorSession.sessionController.getInputMemberId()
});
session.enqueue([op]);
session.close(function (err) {
if (err) {
callback(err);
@ -195,16 +216,12 @@ define("webodf/editor/Editor", [
*/
this.openSession = function (sessionId, memberId, editorReadyCallback) {
initDocLoading(server.getGenesisUrl(sessionId), memberId, function () {
var opRouter, memberModel;
// overwrite router and member model
// overwrite router
// TODO: serverFactory should be a backendFactory,
// and there should be a backendFactory for local editing
opRouter = serverFactory.createOperationRouter(sessionId, memberId, server, odfCanvas.odfContainer());
var opRouter = serverFactory.createOperationRouter(sessionId, memberId, server, odfCanvas.odfContainer());
session.setOperationRouter(opRouter);
memberModel = serverFactory.createMemberModel(sessionId, server);
session.setMemberModel(memberModel);
opRouter.requestReplay(function done() {
editorReadyCallback();
});

@ -82,8 +82,11 @@ define("webodf/editor/EditorSession", [
domUtils = new core.DomUtils(),
eventNotifier = new core.EventNotifier([
EditorSession.signalMemberAdded,
EditorSession.signalMemberUpdated,
EditorSession.signalMemberRemoved,
EditorSession.signalCursorAdded,
EditorSession.signalCursorMoved,
EditorSession.signalCursorRemoved,
EditorSession.signalParagraphChanged,
EditorSession.signalCommonStyleCreated,
EditorSession.signalCommonStyleDeleted,
@ -211,13 +214,25 @@ define("webodf/editor/EditorSession", [
paragraphRange.detach();
}
function onMemberAdded(member) {
self.emit(EditorSession.signalMemberAdded, member.getMemberId());
}
function onMemberUpdated(member) {
self.emit(EditorSession.signalMemberUpdated, member.getMemberId());
}
function onMemberRemoved(memberId) {
self.emit(EditorSession.signalMemberRemoved, memberId);
}
function onCursorAdded(cursor) {
self.emit(EditorSession.signalMemberAdded, cursor.getMemberId());
self.emit(EditorSession.signalCursorAdded, cursor.getMemberId());
trackCursor(cursor);
}
function onCursorRemoved(memberId) {
self.emit(EditorSession.signalMemberRemoved, memberId);
self.emit(EditorSession.signalCursorRemoved, memberId);
}
function onCursorMoved(cursor) {
@ -267,14 +282,6 @@ define("webodf/editor/EditorSession", [
eventNotifier.unsubscribe(eventid, cb);
};
this.getMemberDetailsAndUpdates = function (memberId, subscriber) {
return session.getMemberModel().getMemberDetailsAndUpdates(memberId, subscriber);
};
this.unsubscribeMemberDetailsUpdates = function (memberId, subscriber) {
return session.getMemberModel().unsubscribeMemberDetailsUpdates(memberId, subscriber);
};
this.getCursorPosition = function () {
return odtDocument.getCursorPosition(localMemberId);
};
@ -513,6 +520,14 @@ define("webodf/editor/EditorSession", [
self.sessionController.getImageManager().insertImage(mimetype, content, width, height);
};
/**
* @param {!string} memberId
* @return {?ops.Member}
*/
this.getMember = function (memberId) {
return odtDocument.getMember(memberId);
};
/**
* @param {!function(!Object=)} callback, passing an error object in case of error
* @return {undefined}
@ -522,6 +537,9 @@ define("webodf/editor/EditorSession", [
head.removeChild(fontStyles);
odtDocument.unsubscribe(ops.OdtDocument.signalMemberAdded, onMemberAdded);
odtDocument.unsubscribe(ops.OdtDocument.signalMemberUpdated, onMemberUpdated);
odtDocument.unsubscribe(ops.OdtDocument.signalMemberRemoved, onMemberRemoved);
odtDocument.unsubscribe(ops.OdtDocument.signalCursorAdded, onCursorAdded);
odtDocument.unsubscribe(ops.OdtDocument.signalCursorRemoved, onCursorRemoved);
odtDocument.unsubscribe(ops.OdtDocument.signalCursorMoved, onCursorMoved);
@ -578,6 +596,9 @@ define("webodf/editor/EditorSession", [
self.availableFonts = getAvailableFonts();
selectionViewManager.registerCursor(shadowCursor, true);
// Custom signals, that make sense in the Editor context. We do not want to expose webodf's ops signals to random bits of the editor UI.
odtDocument.subscribe(ops.OdtDocument.signalMemberAdded, onMemberAdded);
odtDocument.subscribe(ops.OdtDocument.signalMemberUpdated, onMemberUpdated);
odtDocument.subscribe(ops.OdtDocument.signalMemberRemoved, onMemberRemoved);
odtDocument.subscribe(ops.OdtDocument.signalCursorAdded, onCursorAdded);
odtDocument.subscribe(ops.OdtDocument.signalCursorRemoved, onCursorRemoved);
odtDocument.subscribe(ops.OdtDocument.signalCursorMoved, onCursorMoved);
@ -592,7 +613,10 @@ define("webodf/editor/EditorSession", [
};
/**@const*/EditorSession.signalMemberAdded = "memberAdded";
/**@const*/EditorSession.signalMemberUpdated = "memberUpdated";
/**@const*/EditorSession.signalMemberRemoved = "memberRemoved";
/**@const*/EditorSession.signalCursorAdded = "cursorAdded";
/**@const*/EditorSession.signalCursorRemoved = "cursorRemoved";
/**@const*/EditorSession.signalCursorMoved = "cursorMoved";
/**@const*/EditorSession.signalParagraphChanged = "paragraphChanged";
/**@const*/EditorSession.signalCommonStyleCreated = "styleCreated";

@ -73,14 +73,14 @@ define("webodf/editor/MemberListView",
while (node) {
if (node.localName === "img") {
// update avatar image
node.src = memberDetails.imageurl;
node.src = memberDetails.imageUrl;
// update border color
node.style.borderColor = memberDetails.color;
} else if (node.localName === "span" && memberDetails.imageurl){
$(node).avatar(memberDetails.imageurl, 60);
} else if (node.localName === "span" && memberDetails.imageUrl){
$(node).avatar(memberDetails.imageUrl, 60);
node.style.borderColor = memberDetails.color;
} else if (node.localName === "div") {
node.setAttribute('fullname', memberDetails.fullname);
node.setAttribute('fullname', memberDetails.fullName);
}
node = node.nextSibling;
}
@ -142,8 +142,21 @@ define("webodf/editor/MemberListView",
* @return {undefined}
*/
function addMember(memberId) {
var member = editorSession.getMember(memberId),
properties = member.getProperties();
createAvatarButton(memberId);
editorSession.getMemberDetailsAndUpdates(memberId, updateAvatarButton);
updateAvatarButton(memberId, properties);
}
/**
* @param {!string} memberId
* @return {undefined}
*/
function updateMember(memberId) {
var member = editorSession.getMember(memberId),
properties = member.getProperties();
updateAvatarButton(memberId, properties);
}
/**
@ -151,7 +164,6 @@ define("webodf/editor/MemberListView",
* @return {undefined}
*/
function removeMember(memberId) {
editorSession.unsubscribeMemberDetailsUpdates(memberId, updateAvatarButton);
removeAvatarButton(memberId);
}
@ -161,14 +173,12 @@ define("webodf/editor/MemberListView",
if (editorSession) {
// unsubscribe from editorSession
editorSession.unsubscribe(EditorSession.signalMemberAdded, addMember);
editorSession.unsubscribe(EditorSession.signalMemberUpdated, updateMember);
editorSession.unsubscribe(EditorSession.signalMemberRemoved, removeMember);
// remove all current avatars
node = memberListDiv.firstChild;
while (node) {
nextNode = node.nextSibling;
if (node.memberId) {
editorSession.unsubscribeMemberDetailsUpdates(node.memberId, updateAvatarButton);
}
memberListDiv.removeChild(node);
node = nextNode;
}
@ -185,6 +195,7 @@ define("webodf/editor/MemberListView",
editorSession = session;
if (editorSession) {
editorSession.subscribe(EditorSession.signalMemberAdded, addMember);
editorSession.subscribe(EditorSession.signalMemberUpdated, updateMember);
editorSession.subscribe(EditorSession.signalMemberRemoved, removeMember);
}
};

@ -57,13 +57,6 @@ ServerFactory.prototype.createServer = function () {"use strict"; };
*/
ServerFactory.prototype.createOperationRouter = function (sessionId, memberId, server, odfContainer) {"use strict"; };
/**
* @param {!string} sessionId
* @param {!ops.Server} server
* @return {!ops.MemberModel}
*/
ServerFactory.prototype.createMemberModel = function (sessionId, server) {"use strict"; };
/**
* @param {!ops.Server} server
* @return {!SessionList}

@ -27,10 +27,9 @@
define("webodf/editor/server/owncloud/ServerFactory", [
"webodf/editor/server/pullbox/Server",
"webodf/editor/server/pullbox/MemberModel",
"webodf/editor/server/pullbox/OperationRouter",
"webodf/editor/server/pullbox/SessionList"],
function (PullBoxServer, PullBoxMemberModel, PullBoxOperationRouter, PullBoxSessionList) {
function (PullBoxServer, PullBoxOperationRouter, PullBoxSessionList) {
"use strict";
/**
@ -54,9 +53,6 @@ define("webodf/editor/server/owncloud/ServerFactory", [
this.createOperationRouter = function (sid, mid, server, odfContainer) {
return new PullBoxOperationRouter(sid, mid, server, odfContainer);
};
this.createMemberModel = function (sid, server) {
return new PullBoxMemberModel(sid, server);
};
this.createSessionList = function (server) {
return new PullBoxSessionList(server);
};

@ -1,279 +0,0 @@
/**
* @license
* Copyright (C) 2013 KO GmbH <copyright@kogmbh.com>
*
* @licstart
* This file is part of WebODF.
*
* WebODF is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License (GNU AGPL)
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* WebODF is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with WebODF. If not, see <http://www.gnu.org/licenses/>.
* @licend
*
* @source: http://www.webodf.org/
* @source: https://github.com/kogmbh/WebODF/
*/
/*global runtime, ops*/
define("webodf/editor/server/pullbox/MemberModel", [], function () {
"use strict";
/**
* @constructor
* @implements ops.MemberModel
*/
return function PullBoxMemberModel(sessionId, server) {
var cachedMemberData = {},
memberDataSubscribers = {},
isServerPullingActivated = false,
isServerPullingOpen = true,
serverPullingTimeoutId = null,
isInstantPullingRequested = false,
isPulling = false,
/**@const*/pullingIntervall = 20000;
/**
* @param {!Object} memberData
*/
function cacheMemberDatum(memberData) {
var subscribers,
i;
// notify all subscribers who are interested in this data
subscribers = memberDataSubscribers[memberData.memberid];
if (subscribers) {
// cache
cachedMemberData[memberData.memberid] = memberData;
for (i = 0; i < subscribers.length; i += 1) {
subscribers[i](memberData.memberid, memberData);
}
}
}
function pullMemberData() {
var i,
memberIds = Object.keys(memberDataSubscribers);
if (!isServerPullingOpen || isPulling) {
return;
}
// no more timeout or instant pull request in any case
serverPullingTimeoutId = null;
isInstantPullingRequested = false;
// set lock
isPulling = true;
runtime.log("member-list request for : " + memberIds.join(","));
server.call({
command: 'query_memberdata_list',
args: {
es_id: sessionId,
member_ids: memberIds
}
}, function(responseData) {
var response = /**@type {{memberdata_list:Array.<{uid,member_id,display_name,avatar_url,color}>}}*/(runtime.fromJson(responseData)),
memberDataList,
newMemberData, oldMemberData;
// unlock
isPulling = false;
// meanwhile closed/disactivated?
if (!isServerPullingOpen || !isServerPullingActivated) {
return;
}
runtime.log("member-list reply: " + responseData);
if (response.hasOwnProperty("memberdata_list")) {
// add/update with all delivered memberdata
memberDataList = response.memberdata_list;
for (i = 0; i < memberDataList.length; i+=1) {
newMemberData = {
memberid: memberDataList[i].member_id,
fullname: memberDataList[i].display_name,
imageurl: memberDataList[i].avatar_url,
color: memberDataList[i].color
};
oldMemberData = cachedMemberData.hasOwnProperty(newMemberData.memberid) ? cachedMemberData[newMemberData.memberid] : null;
if (!oldMemberData ||
oldMemberData.fullname !== newMemberData.fullname ||
oldMemberData.imageurl !== newMemberData.imageurl ||
oldMemberData.color !== newMemberData.color) {
cacheMemberDatum(newMemberData);
}
}
} else {
runtime.log("Meh, memberdata list broken: " + responseData);
}
// trigger the next pulling
if (isInstantPullingRequested) {
pullMemberData();
} else {
serverPullingTimeoutId = runtime.setTimeout(pullMemberData, pullingIntervall);
}
});
}
/**
* Activates the pulling
* @return {undefined}
*/
function pullNewMemberData() {
// cancel any running pulling timeout
if (serverPullingTimeoutId !== null) {
runtime.clearTimeout(serverPullingTimeoutId);
}
isInstantPullingRequested = true;
isServerPullingActivated = true;
pullMemberData();
}
/**
* Deactivates the pulling if there are no more subscribers
* @return {undefined}
*/
function deactivatePeriodicMemberDataPulling() {
var key;
if (!isServerPullingActivated) {
return;
}
// check if there is no more subscription
for(key in memberDataSubscribers) {
if (memberDataSubscribers.hasOwnProperty(key)) {
// still subscribers, cannot deactivate yet
return;
}
}
isServerPullingActivated = false;
// cancel any running pulling timeout
if (serverPullingTimeoutId !== null) {
runtime.clearTimeout(serverPullingTimeoutId);
}
}
/**
* callback is called as soon as the memberdata is available and after that
* on every memberdata update.
* a parameter `null` passed to the callback means that the member is finally
* not known.
*
* @param {!string} memberId
* @param {!function(!string, ?Object)} subscriber
* @return {undefined}
*/
this.getMemberDetailsAndUpdates = function (memberId, subscriber) {
var /**@type{Object}*/
memberData = cachedMemberData[memberId],
subscribers = memberDataSubscribers[memberId] || [],
i;
memberDataSubscribers[memberId] = subscribers;
runtime.assert(subscriber !== undefined, "missing callback");
// detect double subscription
for (i=0; i<subscribers.length; i+=1) {
if (subscribers[i] === subscriber) {
break;
}
}
if (i < subscribers.length) {
// already subscribed
runtime.log("double subscription request for "+memberId+" in PullBoxMemberModel::getMemberDetailsAndUpdates");
} else {
// subscribe
subscribers.push(subscriber);
// query data from server, if not done yet
if (subscribers.length === 1) {
// TODO: only fetch data for memberId here
pullNewMemberData();
}
}
if (memberData) {
// data available from cache
subscriber(memberId, memberData);
} else {
// pass temporary data
subscriber(memberId, {
memberid: memberId,
fullname: "Unknown",
color: "black",
imageurl: ""
});
}
};
/**
* getMemberDetailsAndUpdates subscribes a callback for updates on member details.
* this function undoes this subscription.
*
* @param {!string} memberId
* @param {!function(!string, ?Object)} subscriber
* @return {undefined}
*/
this.unsubscribeMemberDetailsUpdates = function (memberId, subscriber) {
var i,
subscribers = memberDataSubscribers[memberId];
runtime.assert(subscriber!==undefined, "missing subscriber parameter or null");
runtime.assert(subscribers,
"tried to unsubscribe when no one is subscribed ('" + memberId + "')");
if (subscribers) {
for (i=0; i<subscribers.length; i+=1) {
if (subscribers[i] === subscriber) {
break;
}
}
runtime.assert((i < subscribers.length),
"tried to unsubscribe when not subscribed for memberId '" + memberId + "'");
subscribers.splice(i,1);
// clean up
if (subscribers.length === 0) {
runtime.log("no more subscribers for: "+memberId);
delete memberDataSubscribers[memberId];
delete cachedMemberData[memberId];
deactivatePeriodicMemberDataPulling();
}
}
};
/**
* Requests a gracefull shutdown of the Member Model
* No more network activity is necessary.
*/
this.close = function (cb) {
isServerPullingOpen = false;
cb();
};
runtime.assert(server.networkStatus() === "ready", "network not ready");
};
});

@ -410,8 +410,8 @@ runtime.log("OperationRouter: instant opsSync requested");
var timedOp,
opspec = op.spec();
// note if any local ops modified TODO: find less fragile way, perhaps have the operationFactory check it?
hasPushedModificationOps = hasPushedModificationOps || !/^(AddCursor|MoveCursor|RemoveCursor)$/.test(opspec.optype);
// note if any local ops modified
hasPushedModificationOps = hasPushedModificationOps || op.isEdit;
// apply locally
opspec.timestamp = (new Date()).getTime();

@ -57,9 +57,7 @@ define("webodf/editor/server/pullbox/Server", [], function () {
*/
function call(message, cb) {
var xhr = new XMLHttpRequest(),
byteArrayWriter = new core.ByteArrayWriter("utf8"),
messageString = JSON.stringify(message),
data;
messageString = JSON.stringify(message);
function handleResult() {
if (xhr.readyState === 4) {
@ -73,9 +71,6 @@ define("webodf/editor/server/pullbox/Server", [], function () {
}
runtime.log("Sending message to server: "+messageString);
// create body data for request from metadata and payload
byteArrayWriter.appendString(messageString);
// byteArrayWriter.appendByteArray(zipData);
data = byteArrayWriter.getByteArray();
// do the request
xhr.open('POST', args.url, true);
@ -83,20 +78,8 @@ runtime.log("Sending message to server: "+messageString);
xhr.setRequestHeader("requesttoken", token);
}
xhr.onreadystatechange = handleResult;
// ArrayBufferView will have an ArrayBuffer property, in WebKit, XHR can send()
// an ArrayBuffer, In Firefox, one must use sendAsBinary with a string
if (data.buffer && !xhr.sendAsBinary) {
data = data.buffer; // webkit supports sending an ArrayBuffer
} else {
// encode into a string, this works in FireFox >= 3
data = runtime.byteArrayToString(data, "binary");
}
try {
if (xhr.sendAsBinary) {
xhr.sendAsBinary(data);
} else {
xhr.send(data);
}
xhr.send(messageString);
} catch (e) {
runtime.log("Problem with calling server: " + e + " " + data);
cb(e.message);

@ -27,10 +27,9 @@
define("webodf/editor/server/pullbox/ServerFactory", [
"webodf/editor/server/pullbox/Server",
"webodf/editor/server/pullbox/MemberModel",
"webodf/editor/server/pullbox/OperationRouter",
"webodf/editor/server/pullbox/SessionList"],
function (PullBoxServer, PullBoxMemberModel, PullBoxOperationRouter, PullBoxSessionList) {
function (PullBoxServer, PullBoxOperationRouter, PullBoxSessionList) {
"use strict";
/**
@ -44,9 +43,6 @@ define("webodf/editor/server/pullbox/ServerFactory", [
this.createOperationRouter = function (sid, mid, server, odfContainer) {
return new PullBoxOperationRouter(sid, mid, server, odfContainer);
};
this.createMemberModel = function (sid, server) {
return new PullBoxMemberModel(sid, server);
};
this.createSessionList = function (server) {
return new PullBoxSessionList(server);
};

@ -48,7 +48,7 @@ define("webodf/editor/widgets/annotation", [
var self = this,
widget = {},
addAnnotationButton,
annotationManager;
annotationController;
addAnnotationButton = new Button({
@ -57,8 +57,8 @@ define("webodf/editor/widgets/annotation", [
showLabel: false,
iconClass: 'dijitIconBookmark',
onClick: function () {
if (annotationManager) {
annotationManager.addAnnotation();
if (annotationController) {
annotationController.addAnnotation();
self.onToolDone();
}
}
@ -83,14 +83,14 @@ define("webodf/editor/widgets/annotation", [
}
this.setEditorSession = function (session) {
if (annotationManager) {
annotationManager.unsubscribe(gui.AnnotationManager.annotatableChanged, onAnnotatableChanged);
if (annotationController) {
annotationController.unsubscribe(gui.AnnotationController.annotatableChanged, onAnnotatableChanged);
}
annotationManager = session && session.sessionController.getAnnotationManager();
if (annotationManager) {
annotationManager.subscribe(gui.AnnotationManager.annotatableChanged, onAnnotatableChanged);
annotationController = session && session.sessionController.getAnnotationController();
if (annotationController) {
annotationController.subscribe(gui.AnnotationController.annotatableChanged, onAnnotatableChanged);
}
onAnnotatableChanged(annotationManager && annotationManager.isAnnotatable());
onAnnotatableChanged(annotationController && annotationController.isAnnotatable());
};
this.onToolDone = function () {};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -84,11 +84,34 @@ class Db_Op extends Db {
}
public function removeCursor($esId, $memberId){
$op = '{"optype":"RemoveCursor","memberid":"'. $memberId .'","reason":"server-idle","timestamp":'. time() .'}';
$this->insertOp($esId, $op);
}
public function addMember($esId, $memberId, $fullName, $color, $imageUrl){
$op = '{"optype":"AddMember","memberid":"'. $memberId .'","timestamp":"'. time() .'", "setProperties":{"fullName":"'. $fullName .'","color":"'. $color .'","imageUrl":"'. $imageUrl .'"}}';
$this->insertOp($esId, $op);
}
public function removeMember($esId, $memberId){
$op ='{"optype":"RemoveMember","memberid":"'. $memberId .'","timestamp":'. time() .'}';
$this->insertOp($esId, $op);
}
public function updateMember($esId, $memberId, $fullName, $color, $imageUrl){
//TODO: Follow the spec https://github.com/kogmbh/WebODF/blob/master/webodf/lib/ops/OpUpdateMember.js#L95
$op = '{"optype":"UpdateMember","memberid":"'. $memberId .'","fullName":"'. $fullName .'","color":"'. $color .'","imageUrl":"'. $imageUrl .'","timestamp":'. time() .'}'
;
$this->insertOp($esId, $op);
}
protected function insertOp($esId, $op){
$op = new Db_Op(array(
$esId,
0,
'{"optype":"RemoveCursor","memberid":"'. $memberId .'","reason":"server-idle","timestamp":'. time() .'}'
$op
));
$op->insert();
}
}

@ -64,14 +64,52 @@ class Db_Session extends \OCA\Documents\Db {
->getData()
;
$memberColor = Helper::getRandomColor();
$member = new Db_Member(array(
$session['es_id'],
$uid,
Helper::getRandomColor(),
$uid,
$memberColor,
time()
));
if ($member->insert()){
// Do we have OC_Avatar in out disposal?
if (!class_exists('\OC_Avatar') || \OC_Config::getValue('enable_avatars', true) !== true){
//$x['avatar_url'] = \OCP\Util::linkToRoute('documents_user_avatar');
$imageUrl = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAAAAACH5BAAAAAAALAAAAAABAAEAAAICTAEAOw==';
} else {
// https://github.com/owncloud/documents/issues/51
// Temporary stub
$imageUrl = $uid;
/*
$avatar = new \OC_Avatar($uid);
$image = $avatar->get(64);
// User has an avatar
if ($image instanceof \OC_Image) {
$imageUrl = \OC_Helper::linkToRoute(
'core_avatar_get',
array( 'user' => $uid, 'size' => 64)
) . '?requesttoken=' . \OC::$session->get('requesttoken');
} else {
//shortcircuit if it's not an image
$imageUrl = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAAAAACH5BAAAAAAALAAAAAABAAEAAAICTAEAOw==';
}
*/
}
$session['member_id'] = (string) $member->getLastInsertId();
$op = new Db_Op();
$op->addMember(
$session['es_id'],
$session['member_id'],
\OCP\User::getDisplayName($uid),
$memberColor,
$imageUrl
);
} else {
throw new \Exception('Failed to add member into database');
}

Loading…
Cancel
Save