From 117b559a5e5b5ebdfaad3744dc904dce8319e570 Mon Sep 17 00:00:00 2001 From: nathangray Date: Thu, 11 Oct 2018 10:09:16 -0600 Subject: [PATCH] Entry share changes - Writable share is now a checkbox - Add Sharing -> Merge entry into email template, share gets selected options - Add {{share}} placeholder which creates (by default) read only share --- .../inc/class.addressbook_merge.inc.php | 2 +- api/js/jsapi/app_base.js | 47 +++++++++-- api/src/Contacts/Merge.php | 5 +- api/src/Link/Sharing.php | 62 ++++++-------- api/src/Sharing.php | 28 ++++--- api/src/Storage/Merge.php | 80 +++++++++++++++++++ 6 files changed, 166 insertions(+), 58 deletions(-) diff --git a/addressbook/inc/class.addressbook_merge.inc.php b/addressbook/inc/class.addressbook_merge.inc.php index 3835bcc1d6..67319a3110 100644 --- a/addressbook/inc/class.addressbook_merge.inc.php +++ b/addressbook/inc/class.addressbook_merge.inc.php @@ -18,4 +18,4 @@ use EGroupware\Api\Contacts\Merge; * * @deprecated use Api\Contacts\Merge */ -class addressbook_merge extends Merge {} \ No newline at end of file +class addressbook_merge extends Merge {} diff --git a/api/js/jsapi/app_base.js b/api/js/jsapi/app_base.js index 0872cf6a06..f04abdb260 100644 --- a/api/js/jsapi/app_base.js +++ b/api/js/jsapi/app_base.js @@ -1895,18 +1895,55 @@ var AppJS = (function(){ "use strict"; return Class.extend( * @param {egwAction} _action egw actions * @param {egwActionObject[]} _senders selected nm row * @param {egwActionObject} _target Drag source. Not used here. + * @param {Boolean} _writable Allow edit access from the share. * @param {Boolean} _files Allow access to files from the share. + * @param {Function} _callback Callback with results * @returns {Boolean} returns false if not successful */ - share_link: function(_action, _senders, _target, _files){ + share_link: function(_action, _senders, _target, _writable, _files, _callback){ var path = _senders[0].id; + if(typeof _writable === 'undefined' && _action.parent && _action.parent.getActionById('shareWritable')) + { + _writable = _action.parent.getActionById('shareWritable').checked || false; + } if(typeof _files === 'undefined' && _action.parent && _action.parent.getActionById('shareFiles')) { _files = _action.parent.getActionById('shareFiles').checked || false; } - egw.json('EGroupware\\Api\\Sharing::ajax_create', [_action.id, path, _files], - this._share_link_callback, this, true, this).sendRequest(); - return true; + + return egw.json('EGroupware\\Api\\Sharing::ajax_create', [_action.id, path, _writable, _files], + _callback ? _callback : this._share_link_callback, this, true, this).sendRequest(); + }, + + share_merge: function(_action, _senders, _target) + { + var parent = _action.parent.parent; + var _writable = false; + var _files = false; + if(parent && parent.getActionById('shareWritable')) + { + _writable = parent.getActionById('shareWritable').checked || false; + } + if(parent && parent.getActionById('shareFiles')) + { + _files = parent.getActionById('shareFiles').checked || false; + } + + // Share only works on one at a time + var promises = []; + for(var i = 0; i < _senders.length; i++) + { + promises.push(new Promise(function(resolve, reject) { + this.share_link(_action, [_senders[i]], _target, _writable, _files, resolve); + }.bind(this))); + } + + // But merge into email can handle several + Promise.all(promises.map(p => p.catch(e => e))) + .then(function(values) { + // Process document after all shares created + return nm_action(_action, _senders, _target); + }); }, /** @@ -1938,7 +1975,7 @@ var AppJS = (function(){ "use strict"; return Class.extend( jQuery("body").off("click", "[name=share_link]", copy_link_to_clipboard); return true; }, - title: _data.title ? _data.title : egw.lang("%1 Share Link", _data.action ==='shareWritableLink'? egw.lang("Writable"): egw.lang("Readonly")), + title: _data.title ? _data.title : egw.lang("%1 Share Link", _data.writable ? egw.lang("Writable"): egw.lang("Readonly")), template: _data.template, width: 450, value: {content:{ "share_link": _data.share_link }} diff --git a/api/src/Contacts/Merge.php b/api/src/Contacts/Merge.php index 06b7843d01..47930ae094 100644 --- a/api/src/Contacts/Merge.php +++ b/api/src/Contacts/Merge.php @@ -218,6 +218,9 @@ class Merge extends Api\Storage\Merge echo '{{'.$name.'}}'.$label."\n"; } + echo '

'.lang('EPL Only').":

"; + echo '{{share}}'.lang('Public sharing URL')."\n"; + Api\Translation::add_app('calendar'); echo '

'.lang('Calendar fields:')." # = 1, 2, ..., 20, -1

"; foreach(array( @@ -278,7 +281,7 @@ class Merge extends Api\Storage\Merge // Change merge into email actions so we can customize them static::customise_mail_actions($actions); - + return $actions; } diff --git a/api/src/Link/Sharing.php b/api/src/Link/Sharing.php index 6bcd6aab90..746d98dd48 100644 --- a/api/src/Link/Sharing.php +++ b/api/src/Link/Sharing.php @@ -76,49 +76,33 @@ class Sharing extends \EGroupware\Api\Sharing */ public static function get_actions($appname, $group = 6) { - $actions = array( - 'share' => array( - 'caption' => lang('Share'), - 'icon' => 'api/share', - 'group' => $group, - 'allowOnMultiple' => false, - 'children' => array( - 'shareReadonlyLink' => array( - 'caption' => lang('Readonly Share'), - 'group' => 1, - 'icon' => 'view', - 'order' => 11, - 'enabled' => "javaScript:app.$appname.is_share_enabled", - 'onExecute' => "javaScript:app.$appname.share_link" - ), - 'shareWritableLink' => array( - 'caption' => lang('Writable Share'), - 'group' => 1, - 'icon' => 'edit', - 'allowOnMultiple' => false, - 'order' => 11, - 'enabled' => "javaScript:app.$appname.is_share_enabled", - 'onExecute' => "javaScript:app.$appname.share_link" - ), - 'shareFiles' => array( - 'caption' => lang('Share files'), - 'group' => 2, - 'enabled' => "javaScript:app.$appname.is_share_enabled", - 'checkbox' => true - ) - ), - )); - if(!$GLOBALS['egw_info']['apps']['stylite']) + $actions = parent::get_actions($appname, $group); + + // Add in merge to mail document + if ($GLOBALS['egw_info']['user']['apps']['mail'] && class_exists($appname.'_merge')) { - array_unshift($actions['share']['children'], array( - 'caption' => lang('EPL Only'), - 'group' => 0 - )); - foreach($actions['share']['children'] as &$child) + $documents = call_user_func(array($appname.'_merge', 'document_action'), + $GLOBALS['egw_info']['user']['preferences']['addressbook']['document_dir'], + 1, 'Insert in document', 'shareDocument_' + ); + $documents['order'] = 20; + + // Mail only + foreach($documents['children'] as $key => &$document) { - $child['enabled'] = false; + if(strpos($document['target'],'compose_') === FALSE) + { + unset($documents['children'][$key]); + continue; + } + + $document['allowOnMultiple'] = true; + $document['onExecute'] = "javaScript:app.$appname.share_merge"; } + $documents['enabled'] = !!($GLOBALS['egw_info']['user']['apps']['stylite']); + $actions['share']['children']['shareDocuments'] = $documents; } + return $actions; } diff --git a/api/src/Sharing.php b/api/src/Sharing.php index be879a7ca9..2e63bfce5a 100644 --- a/api/src/Sharing.php +++ b/api/src/Sharing.php @@ -389,31 +389,31 @@ class Sharing 'allowOnMultiple' => false, 'children' => array( 'shareReadonlyLink' => array( - 'caption' => lang('Readonly Share'), + 'caption' => lang('Share link'), 'group' => 1, 'icon' => 'view', 'order' => 11, 'enabled' => "javaScript:app.$appname.is_share_enabled", 'onExecute' => "javaScript:app.$appname.share_link" ), - 'shareWritableLink' => array( - 'caption' => lang('Writable Share'), - 'group' => 1, + 'shareWritable' => array( + 'caption' => lang('Writable'), + 'group' => 2, 'icon' => 'edit', - 'allowOnMultiple' => false, - 'order' => 11, + 'allowOnMultiple' => true, 'enabled' => "javaScript:app.$appname.is_share_enabled", - 'onExecute' => "javaScript:app.$appname.share_link" + 'checkbox' => true ), 'shareFiles' => array( 'caption' => lang('Share files'), 'group' => 2, + 'allowOnMultiple' => true, 'enabled' => "javaScript:app.$appname.is_share_enabled", 'checkbox' => true ) ), )); - if(!$GLOBALS['egw_info']['apps']['stylite']) + if(!$GLOBALS['egw_info']['user']['apps']['stylite']) { array_unshift($actions['share']['children'], array( 'caption' => lang('EPL Only'), @@ -591,24 +591,28 @@ class Sharing * * @param String $action * @param String $path + * @param boolean $writable * @param boolean $files */ - public static function ajax_create($action, $path, $files) + public static function ajax_create($action, $path, $writable = false, $files = false) { $class = self::get_share_class(array('share_path' => $path)); $share = $class::create( $path, - $action == 'shareWritableLink' ? Sharing::WRITABLE : Sharing::READONLY, - basename($selected), + $action == $writable ? Sharing::WRITABLE : Sharing::READONLY, + basename($path), array(), array( - 'share_writable' => $action == 'shareWritableLink', + 'share_writable' => $writable, 'include_files' => $files ) ); + // Store share in session so Merge can find this one and not create a read-only one + \EGroupware\Api\Cache::setSession(__CLASS__, $path, $share); $arr = array( 'action' => $action, + 'writable' => $writable, 'share_link' => $class::share2link($share), 'template' => Etemplate\Widget\Template::rel2url('/filemanager/templates/default/share_dialog.xet') ); diff --git a/api/src/Storage/Merge.php b/api/src/Storage/Merge.php index c9b3d60307..aef875b630 100644 --- a/api/src/Storage/Merge.php +++ b/api/src/Storage/Merge.php @@ -450,6 +450,58 @@ abstract class Merge return $array; } + /** + * Get share placeholder + * + * If the placeholder is present in the content, the share will be automatically + * created. + */ + protected function share_placeholder($app, $id, $prefix, &$content) + { + $replacements = array(); + + // Skip if no content or content has no share placeholder + if(!$content || strpos($content, '$$share') === FALSE) + { + return $replacements; + } + + if(!$GLOBALS['egw_info']['user']['apps']['stylite']) + { + $replacements['$$'.$prefix.'share$$'] = lang('EPL Only'); + return $replacements; + } + + // Get or create the share + // Check if some other process created the share (with custom options) + // and put it in the session cache for us + $path = "$app::$id"; + $session = \EGroupware\Api\Cache::getSession(Api\Sharing::class, $path); + if($session && $session['share_path'] == $path) + { + $share = $session; + } + else + { + // Need to create the share here. + // No way to know here if it should be writable, or who it's going to + $mode = /* ? ? Sharing::WRITABLE :*/ Api\Sharing::READONLY; + $recipients = array(); + $extra = array(); + + //$extra['share_writable'] |= ($mode == Sharing::WRITABLE ? 1 : 0); + + $share = \EGroupware\Stylite\Link\Sharing::create($path, $mode, NULL, $recipients, $extra); + } + + if($share) + { + $replacements['$$'.$prefix.'share$$'] = $link = Api\Sharing::share2link($share); + } + + return $replacements; + } + /** * Format a datetime * @@ -850,6 +902,9 @@ abstract class Merge $replacements['$$datetime$$'] = Api\DateTime::to('now'); $replacements['$$time$$'] = Api\DateTime::to('now',false); + $app = $this->get_app(); + $replacements += $this->share_placeholder($app, $id, $prefix, $content); + // does our extending class registered table-plugins AND document contains table tags if ($this->table_plugins && preg_match_all('/\\$\\$table\\/([A-Za-z0-9_]+)\\$\\$(.*?)\\$\\$endtable\\$\\$/s',$content,$matches,PREG_SET_ORDER)) { @@ -1438,6 +1493,31 @@ abstract class Merge } } + /** + * Figure out which app we're running as + * + * @return string + */ + protected function get_app() + { + switch (get_class($this)) + { + case 'EGroupware\Api\Contacts\Merge': + $app = 'addressbook'; + break; + default: + $app = str_replace('_merge','',get_class($this)); + if(!in_array($app, $GLOBALS['egw_info']['apps'])) + { + $app = false; + } + break; + + } + + return $app; + } + /** * Get the replacements for any entry specified by app & id *