forked from extern/egroupware
W.I.P. collab editor: First implementation for syncing operation
This commit is contained in:
parent
00ce2295be
commit
99b8c5773f
144
filemanager/inc/class.filemanager_collab.inc.php
Normal file
144
filemanager/inc/class.filemanager_collab.inc.php
Normal file
@ -0,0 +1,144 @@
|
||||
<?php
|
||||
/**
|
||||
* EGroupware - Filemanager Collab
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @package filemanager
|
||||
* @author Hadi Nategh <hn-AT-stylite.de>
|
||||
* @copyright (c) 2016 by Stylite AG
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
use EGroupware\Api;
|
||||
|
||||
class filemanager_collab extends filemanager_collab_bo {
|
||||
|
||||
/**
|
||||
* Methods callable via menuaction
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
var $public_functions = array(
|
||||
'poll' => true
|
||||
);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
*/
|
||||
function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Join session, initialises edit session for opened file by user
|
||||
*
|
||||
* @param type $es_id session id
|
||||
* @return array returns an array consists of session data
|
||||
*/
|
||||
function join_session ($es_id)
|
||||
{
|
||||
$response = $this->initSession($es_id);
|
||||
$response += array (
|
||||
'id' => $GLOBALS['egw_info']['user']['account_id'],
|
||||
'full_name' => $GLOBALS['egw_info']['user']['account_fullname'],
|
||||
'success' => true
|
||||
);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Polling mechanisim to sysncronise data
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
function poll ()
|
||||
{
|
||||
// Get POST request payload
|
||||
$payload = file_get_contents('php://input');
|
||||
$params = $payload? json_decode ($payload, true): null;
|
||||
$response = array();
|
||||
if (is_array($params))
|
||||
{
|
||||
switch ($params['command'])
|
||||
{
|
||||
case 'join_session':
|
||||
$response = $this->join_session($params['args']['es_id'],$params['args']['user_id']);
|
||||
break;
|
||||
case 'sync_ops':
|
||||
try
|
||||
{
|
||||
$memberid = $params['args']['member_id']? $params['args']['member_id']: '';
|
||||
$es_id = $params['args']['es_id'];
|
||||
$seq_head = (string) isset($params['args']['seq_head'])? $params['args']['seq_head']: null;
|
||||
if(!is_null($seq_head))
|
||||
{
|
||||
$client_ops = $params['args']['client_ops']? $params['args']['client_ops']: [];
|
||||
$current_seq_head = $this->OP_getHeadSeq($es_id);
|
||||
if ($seq_head == $current_seq_head) {
|
||||
|
||||
if (count($client_ops)>0)
|
||||
{
|
||||
$newHead = $this->get_newHead($es_id, $memberid, $client_ops);
|
||||
$response = array(
|
||||
'result' => 'added',
|
||||
'head_seq' => $newHead ? $newHead : $current_seq_head
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
$response = array(
|
||||
'result' => 'new_ops',
|
||||
'ops' => array(),
|
||||
'head_seq' => $current_seq_head
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$response = array(
|
||||
'result' => count($client_ops)>0 ? 'conflict' : 'new_ops',
|
||||
'ops' => $this->OP_getOPSECS($es_id, $seq_head),
|
||||
'head_seq' => $current_seq_head,
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception('Invalid seq head!');
|
||||
}
|
||||
} catch (Exception $ex) {
|
||||
error_log($ex->getMessage());
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
//
|
||||
}
|
||||
}
|
||||
header('content-type: application/json; charset=utf-8');
|
||||
echo json_encode($response);
|
||||
exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to get a new head sequence
|
||||
*
|
||||
* @param string $es_id session id
|
||||
* @param string $member_id member id
|
||||
* @param array $client_ops opspec from client side
|
||||
*
|
||||
* @return string return a seq head number
|
||||
*/
|
||||
function get_newHead ($es_id, $member_id, $client_ops)
|
||||
{
|
||||
$this->OP_addOPS($es_id, $member_id, $client_ops);
|
||||
|
||||
return $this->OP_getHeadSeq($es_id);
|
||||
}
|
||||
|
||||
}
|
@ -58,22 +58,28 @@ class filemanager_collab_bo
|
||||
*/
|
||||
protected function initSession ($es_id)
|
||||
{
|
||||
$session = $this->db->select(self::SESSION_TABLE,'*', array('collab_es_id' => $es_id));
|
||||
$query = $this->db->select(self::SESSION_TABLE,'*', array('collab_es_id' => $es_id),__LINE__,__FILE__);
|
||||
$full_name = $GLOBALS['egw_info']['user']['account_fullname'];
|
||||
$color = $GLOBALS['egw_info']['user']['prefs']['collab_user_color'];
|
||||
$color = $GLOBALS['egw_info']['user']['preferences']['filemanager']['collab_user_color'];
|
||||
$user_id = $GLOBALS['egw_info']['user']['account_id'];
|
||||
|
||||
$imageUrl = $GLOBALS['egw_info']['server']['webserver_url'].'/index.php?menuaction=addressbook.addressbook_ui.photo&account_id='.$user_id;
|
||||
|
||||
if (!($result = self::db2id($session->fields)) && $es_id)
|
||||
if (!($result = self::db2id($query->fetchRow())) && $es_id)
|
||||
{
|
||||
$result = self::db2id($this->SESSION_add2Db($es_id));
|
||||
}
|
||||
|
||||
$this->MEMBER_add2Db($es_id, $user_id, $color);
|
||||
if (is_null($result['member_id'] = $this->MEMBER_getUserMemberId($es_id, $user_id)))
|
||||
{
|
||||
$this->MEMBER_add2Db($es_id, $user_id, $color);
|
||||
|
||||
$member_id = $this->MEMBER_getLastMember();
|
||||
$result['member_id'] = $this->MEMBER_getLastMember();
|
||||
|
||||
$this->OP_addMember($es_id, $member_id, $full_name, $user_id, $color);
|
||||
$this->OP_addMember($es_id, $result['member_id'], $full_name, $user_id, $color, $imageUrl);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -99,7 +105,6 @@ class filemanager_collab_bo
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* OP addMember function is backend equivalent to addMember from frontend
|
||||
*
|
||||
@ -110,12 +115,12 @@ class filemanager_collab_bo
|
||||
* @param string $color
|
||||
* @param string $imageUrl
|
||||
*/
|
||||
protected function OP_addMember($es_id, $member_id, $full_name, $user_id, $color, $imageUrl)
|
||||
protected function OP_addMember($es_id, $member_id, $full_name, $user_id, $color='', $imageUrl='')
|
||||
{
|
||||
$date = new DateTime();
|
||||
$op = array(
|
||||
'optype' => 'AddMember',
|
||||
'member' => (string) $member_id,
|
||||
'memberid' => (string) $member_id,
|
||||
'timestamp' => $date->getTimestamp(),
|
||||
'setProperties' => array(
|
||||
'fullName' => $full_name,
|
||||
@ -139,7 +144,7 @@ class filemanager_collab_bo
|
||||
{
|
||||
if (!$es_id) throw new Exception ('Session id must be given, none given!');
|
||||
|
||||
$headSeq = $this->db->select(
|
||||
$query = $this->db->select(
|
||||
self::OP_TABLE,
|
||||
'collab_seq',
|
||||
array('collab_es_id' => $es_id),
|
||||
@ -149,8 +154,58 @@ class filemanager_collab_bo
|
||||
'ORDER BY collab_seq DESC LIMIT 1',
|
||||
'filemanager'
|
||||
);
|
||||
$head_seq = $query->fetchRow();
|
||||
return is_array($head_seq)? $head_seq['collab_seq']: '';
|
||||
}
|
||||
|
||||
return $headSeq->fields? $headSeq->fields['collab_seq']: '';
|
||||
/**
|
||||
* Function to get opsepcs of session base on seq head
|
||||
*
|
||||
* @param string $es_id session id
|
||||
* @param string $seq_head sequence head
|
||||
*
|
||||
* @return array returns array of opspecs
|
||||
*/
|
||||
protected function OP_getOPSECS($es_id, $seq_head)
|
||||
{
|
||||
if ($seq_head == "")
|
||||
{
|
||||
$seq_head = -1;
|
||||
}
|
||||
$ops = array();
|
||||
$query = $this->db->select(
|
||||
self::OP_TABLE,
|
||||
'collab_opspec',
|
||||
'collab_es_id ="'. $es_id.'" AND collab_seq >'.$seq_head,
|
||||
__LINE__,
|
||||
__FILE__,
|
||||
false, 'ORDER BY collab_seq ASC','filemanager');
|
||||
|
||||
foreach ($query as $spec)
|
||||
{
|
||||
$op = json_decode($spec['collab_opspec'], true);
|
||||
$op['memberid'] = strval($op['memberid']);
|
||||
$ops [] = $op;
|
||||
}
|
||||
return $ops;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to ops data array into op table
|
||||
*
|
||||
* @param string $es_id session id
|
||||
* @param string $member_id member id
|
||||
* @param array $client_ops array of ops
|
||||
* @throws Exception if no array of ops given
|
||||
*/
|
||||
protected function OP_addOPS ($es_id, $member_id, $client_ops)
|
||||
{
|
||||
if (count($client_ops)<= 0) throw new Exception ('ops need to be an array of op data, none array given!');
|
||||
|
||||
foreach ($client_ops as $op)
|
||||
{
|
||||
$this->OP_add2Db($op, $es_id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -163,7 +218,7 @@ class filemanager_collab_bo
|
||||
{
|
||||
$data = array (
|
||||
'collab_es_id' => $es_id,
|
||||
'collab_member' => $op['member'],
|
||||
'collab_member' => $op['memberid'],
|
||||
'collab_optype' => $op['optype'],
|
||||
'collab_opspec' => json_encode($op)
|
||||
);
|
||||
@ -192,21 +247,21 @@ class filemanager_collab_bo
|
||||
*
|
||||
* @param string $member_id member id
|
||||
*
|
||||
* @return array returns an array consist of member record
|
||||
* @return string member id or null
|
||||
* @throws Exception throws exception if no member id is given
|
||||
*/
|
||||
protected function MEMBER_getMember ($member_id)
|
||||
protected function MEMBER_getUserMemberId ($es_id, $user_id)
|
||||
{
|
||||
if (!$member_id) throw new Exception ('Member id must be given, none given!');
|
||||
$member = $this->db->select(
|
||||
if (!$es_id || !$user_id) throw new Exception ('Member id must be given, none given!');
|
||||
$query = $this->db->select(
|
||||
self::MEMBER_TABLE,
|
||||
'*',
|
||||
array('collab_member_id' => $member_id),
|
||||
'collab_member_id',
|
||||
array('collab_es_id' => $es_id, 'collab_uid' => $user_id),
|
||||
__LINE__,
|
||||
__FILE__
|
||||
);
|
||||
|
||||
return $member->fields? self::db2id($member->fileds): [];
|
||||
$member = $query->fetchRow();
|
||||
return is_array($member)? $member['collab_member_id']: null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -230,7 +285,7 @@ class filemanager_collab_bo
|
||||
*/
|
||||
protected function MEMBER_getLastMember()
|
||||
{
|
||||
$last_row = $this->db->select(
|
||||
$query = $this->db->select(
|
||||
self::MEMBER_TABLE,
|
||||
'collab_member_id',
|
||||
'',
|
||||
@ -239,7 +294,7 @@ class filemanager_collab_bo
|
||||
false,
|
||||
"ORDER BY `collab_member_id` DESC LIMIT 1;"
|
||||
);
|
||||
|
||||
return $last_row->fields? $last_row->fields['collab_member_id']: 0;
|
||||
$last_row = $query->fetchRow();
|
||||
return is_array($last_row)? $last_row['collab_member_id']: 0;
|
||||
}
|
||||
}
|
@ -124,6 +124,13 @@ class filemanager_hooks
|
||||
);
|
||||
|
||||
$settings = array(
|
||||
'sections.1' => array(
|
||||
'type' => 'section',
|
||||
'title' => lang('General settings'),
|
||||
'no_lang'=> true,
|
||||
'xmlrpc' => False,
|
||||
'admin' => False
|
||||
),
|
||||
'startfolder' => array(
|
||||
'type' => 'input',
|
||||
'name' => 'startfolder',
|
||||
@ -227,6 +234,26 @@ class filemanager_hooks
|
||||
'admin' => False,
|
||||
);
|
||||
}
|
||||
|
||||
$settings += array (
|
||||
'sections.2' => array(
|
||||
'type' => 'section',
|
||||
'title' => lang('Collab Editor settings'),
|
||||
'no_lang'=> true,
|
||||
'xmlrpc' => False,
|
||||
'admin' => False
|
||||
),
|
||||
'collab_user_color' => array(
|
||||
'type' => 'color',
|
||||
'label' => lang('User color indicator'),
|
||||
'name' => 'collab_user_color',
|
||||
'help' => lang('Use eg. %1 or %2','#FF0000','orange'),
|
||||
'no_lang'=> true,
|
||||
'xmlrpc' => True,
|
||||
'admin' => False,
|
||||
)
|
||||
);
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
|
@ -10,8 +10,9 @@
|
||||
*/
|
||||
|
||||
/*egw:uses
|
||||
/api/js/webodf/wodotexteditor/wodotexteditor/wodotexteditor.js;
|
||||
/api/js/webodf/wodotexteditor/wodotexteditor/webodf.js;
|
||||
/api/js/webodf/collab/webodf.js;
|
||||
/api/js/webodf/collab/wodocollabtexteditor.js;
|
||||
/api/js/webodf/collab/dojo-amalgamation.js;
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -119,7 +120,7 @@ app.classes.filemanager = AppJS.extend(
|
||||
{
|
||||
// need to make body rock solid to avoid extra scrollbars
|
||||
jQuery('body').css({overflow:'hidden'});
|
||||
this._init_odf_editor ();
|
||||
this._init_odf_collab_editor ();
|
||||
}
|
||||
},
|
||||
|
||||
@ -1082,10 +1083,12 @@ app.classes.filemanager = AppJS.extend(
|
||||
|
||||
var serverOptions = {
|
||||
"serverParams": {
|
||||
url:egw.webserverUrl+'/api/js/webodf/poll.php?action=poll',
|
||||
url:egw.link('/index.php?', {
|
||||
menuaction: 'filemanager.filemanager_collab.poll'
|
||||
}),
|
||||
genesisUrl:egw.webserverUrl+file_path
|
||||
},
|
||||
"sessionId": base64.toBase64(egw.webserverUrl+file_path),
|
||||
"sessionId": egw.webserverUrl+file_path,
|
||||
editorOptions: {
|
||||
allFeaturesEnabled: true,
|
||||
userData: {
|
||||
@ -1332,7 +1335,7 @@ app.classes.filemanager = AppJS.extend(
|
||||
serverParams = _args.serverParams,
|
||||
sessionId = _args.sessionId,
|
||||
editorOptions = jQuery.extend(_args.editorOptions,{networkSecurityToken:'', closeCallback:this.editor_close}),
|
||||
userId = egw.user('account_lid'),
|
||||
userId = egw.user('account_id'),
|
||||
memberId,
|
||||
self = this;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user