Commit 5a45743b authored by Mario's avatar Mario
Browse files

files_ng: first batch of files UI rewrite and allow providing custom acl for mod rpost

parent 9de437dc
Pipeline #368469 failed with stage
in 9 minutes and 34 seconds
......@@ -10,7 +10,7 @@ require_once('include/zot.php');
/**
* remote post
*
*
* https://yoursite/rpost?f=&title=&body=&remote_return=
*
* This can be called via either GET or POST, use POST for long body content as suhosin often limits GET parameter length
......@@ -20,7 +20,7 @@ require_once('include/zot.php');
* body= Body of post
* url= URL which will be parsed and the results appended to the body
* source= Source application
* post_id= post_id of post to 'share' (local use only)
* post_id= post_id of post to 'share' (local use only)
* remote_return= absolute URL to return after posting is finished
* type= choices are 'html' or 'bbcode', default is 'bbcode'
*
......@@ -32,16 +32,16 @@ require_once('include/zot.php');
class Rpost extends \Zotlabs\Web\Controller {
function get() {
$o = '';
if(! local_channel()) {
if(remote_channel()) {
// redirect to your own site.
// We can only do this with a GET request so you'll need to keep the text short or risk getting truncated
// by the wretched beast called 'suhosin'. All the browsers now allow long GET requests, but suhosin
// blocks them.
$url = get_rpost_path(\App::get_observer());
// make sure we're not looping to our own hub
if(($url) && (! stristr($url, \App::get_hostname()))) {
......@@ -53,10 +53,10 @@ class Rpost extends \Zotlabs\Web\Controller {
goaway($url);
}
}
// The login procedure is going to bugger our $_REQUEST variables
// so save them in the session.
if(array_key_exists('body',$_REQUEST)) {
$_SESSION['rpost'] = $_REQUEST;
}
......@@ -64,14 +64,14 @@ class Rpost extends \Zotlabs\Web\Controller {
}
nav_set_selected('Post');
// If we have saved rpost session variables, but nothing in the current $_REQUEST, recover the saved variables
if((! array_key_exists('body',$_REQUEST)) && (array_key_exists('rpost',$_SESSION))) {
$_REQUEST = $_SESSION['rpost'];
unset($_SESSION['rpost']);
}
if(array_key_exists('channel',$_REQUEST)) {
$r = q("select channel_id from channel where channel_account_id = %d and channel_address = '%s' limit 1",
intval(get_account_id()),
......@@ -82,7 +82,7 @@ class Rpost extends \Zotlabs\Web\Controller {
$change = change_channel($r[0]['channel_id']);
}
}
if($_REQUEST['remote_return']) {
$_SESSION['remote_return'] = $_REQUEST['remote_return'];
}
......@@ -91,21 +91,27 @@ class Rpost extends \Zotlabs\Web\Controller {
goaway($_SESSION['remote_return']);
goaway(z_root() . '/network');
}
$plaintext = true;
if(array_key_exists('type', $_REQUEST) && $_REQUEST['type'] === 'html') {
require_once('include/html2bbcode.php');
$_REQUEST['body'] = html2bbcode($_REQUEST['body']);
$_REQUEST['body'] = html2bbcode($_REQUEST['body']);
}
$channel = \App::get_channel();
$acl = new \Zotlabs\Access\AccessList($channel);
$channel_acl = $acl->get();
if($_REQUEST['acl']) {
$acl = new \Zotlabs\Access\AccessList([]);
$acl->set($_REQUEST['acl']);
$channel_acl = $acl->get();
}
else {
$acl = new \Zotlabs\Access\AccessList($channel);
$channel_acl = $acl->get();
}
if($_REQUEST['url']) {
$x = z_fetch_url(z_root() . '/linkinfo?f=&url=' . urlencode($_REQUEST['url']));
if($x['success'])
......@@ -115,7 +121,7 @@ class Rpost extends \Zotlabs\Web\Controller {
if($_REQUEST['post_id']) {
$_REQUEST['body'] .= '[share=' . intval($_REQUEST['post_id']) . '][/share]';
}
$x = array(
'is_owner' => true,
'allow_location' => ((intval(get_pconfig($channel['channel_id'],'system','use_browser_location'))) ? '1' : ''),
......@@ -137,19 +143,19 @@ class Rpost extends \Zotlabs\Web\Controller {
'bbcode' => true,
'jotnets' => true
);
$editor = status_editor($a,$x,false,'Rpost');
$o .= replace_macros(get_markup_template('edpost_head.tpl'), array(
'$title' => t('Edit post'),
'$cancel' => '',
'$editor' => $editor
));
return $o;
}
}
......@@ -203,12 +203,12 @@ class Browser extends DAV\Browser\Plugin {
}
// generate preview icons for tile view.
// generate preview icons for tile view.
// Currently we only handle images, but this could potentially be extended with plugins
// to provide document and video thumbnails. SVG, PDF and office documents have some
// to provide document and video thumbnails. SVG, PDF and office documents have some
// security concerns and should only be allowed on single-user sites with tightly controlled
// upload access. system.thumbnail_security should be set to 1 if you want to include these
// types
// upload access. system.thumbnail_security should be set to 1 if you want to include these
// types
$is_creator = false;
$photo_icon = '';
......@@ -234,7 +234,7 @@ class Browser extends DAV\Browser\Plugin {
intval(PHOTO_RES_PROFILE_80)
);
if($p) {
$photo_icon = 'photo/' . $p[0]['resource_id'] . '-' . $p[0]['imgscale'];
$photo_icon = 'photo/' . $p[0]['resource_id'] . '-' . $p[0]['imgscale'];
}
if($type === 'image/svg+xml' && $preview_style > 0) {
$photo_icon = $relPath;
......@@ -273,6 +273,12 @@ class Browser extends DAV\Browser\Plugin {
$ft['allow_gid'] = acl2json($r[0]['allow_gid']);
$ft['deny_cid'] = acl2json($r[0]['deny_cid']);
$ft['deny_gid'] = acl2json($r[0]['deny_gid']);
$ft['raw_allow_cid'] = $r[0]['allow_cid'];
$ft['raw_allow_gid'] = $r[0]['allow_gid'];
$ft['raw_deny_cid'] = $r[0]['deny_cid'];
$ft['raw_deny_gid'] = $r[0]['deny_gid'];
$ft['lockstate'] = $lockstate;
$ft['resource'] = $r[0]['hash'];
$ft['folder'] = $r[0]['folder'];
......@@ -284,17 +290,16 @@ class Browser extends DAV\Browser\Plugin {
// can not copy a folder into itself
unset($folders[$parentHash]);
}
$ft['newfolder'] = ['newfolder_' . $id, t('Move to directory'), $r[0]['folder'], '', $folders];
$ft['copy'] = array('copy_' . $id, t('Copy instead of move'), 0, '', array(t('No'), t('Yes')));
$ft['recurse'] = array('recurse_' . $id, t('Change permission fo all files and sub folders'), 0, '', array(t('No'), t('Yes')));
$ft['notify'] = array('notify_edit_' . $id, t('Show in your contacts shared folder'), 0, '', array(t('No'), t('Yes')));
$ft['newfolder'] = ['newfolder_' . $id, t('Select a target location'), $r[0]['folder'], '', $folders];
$ft['copy'] = array('copy_' . $id, t('Copy to target location'), 0, '', array(t('No'), t('Yes')));
$ft['recurse'] = array('recurse_' . $id, t('Set permissions for all files and sub folders'), 0, '', array(t('No'), t('Yes')));
$ft['notify'] = array('notify_edit_' . $id, t('Notify your contacts about this file'), 0, '', array(t('No'), t('Yes')));
$f[] = $ft;
}
$output = '';
if ($this->enablePost) {
$this->server->emit('onHTMLActionsPanel', array($parent, &$output, $path));
......@@ -327,7 +332,7 @@ class Browser extends DAV\Browser\Plugin {
'$size' => t('Size'),
'$lastmod' => t('Last Modified'),
'$parent' => t('parent'),
'$edit' => t('Edit'),
'$edit' => t('Submit'),
'$delete' => t('Delete'),
'$nick' => $this->auth->getCurrentUser(),
......
#files-mkdir-tools,
#files-upload-tools,
.cloud-tools,
.link-code,
[id^="perms-panel-"] {
.cloud-tool {
display: none;
}
......@@ -35,20 +34,20 @@
word-break: break-all;
}
#cloud-index th:nth-child(8),
#cloud-index td:nth-child(8){
padding: 7px 3px;
#cloud-index th:nth-child(5),
#cloud-index td:nth-child(5){
padding: 7px 0px;
white-space: nowrap;
}
#cloud-index th:nth-child(9),
#cloud-index td:nth-child(9){
padding: 7px 10px 7px 7px;
#cloud-index th:nth-child(6),
#cloud-index td:nth-child(6){
padding: 7px 0px;
white-space: nowrap;
}
.cloud-index-tool {
padding: 7px 10px;
padding: 7px 0px;
}
#files-upload {
......
......@@ -30,7 +30,7 @@ function ACL(backend_url) {
that.custom = $("#acl-custom");
that.acl_select = $("#acl-select");
// set the initial ACL lists in case the enclosing form gets submitted before the ajax loader completes.
// set the initial ACL lists in case the enclosing form gets submitted before the ajax loader completes.
//that.on_submit();
/*events*/
......@@ -90,7 +90,7 @@ ACL.prototype.get_form_data = function(event) {
}
// no longer called only on submit - call to update whenever a change occurs to the acl list.
// no longer called only on submit - call to update whenever a change occurs to the acl list.
ACL.prototype.on_submit = function() {
$('.acl-field').remove();
......
......@@ -44,7 +44,7 @@ if(localStorage.getItem('uid') !== localUser.toString()) {
window.onstorage = function(e) {
if(e.key === 'uid' && parseInt(e.newValue) !== localUser) {
if(window_needs_alert) {
window_needs_alert = false;
window_needs_alert = false;
alert("Your identity has changed. Page reload required!");
window.location.reload();
return;
......@@ -99,12 +99,12 @@ $(document).ready(function() {
wordSeparator : aStr['t16'],
numbers : aStr['t17'],
};
jQuery.timeago.settings.allowFuture = true;
if(sse_enabled) {
if(typeof(window.SharedWorker) === 'undefined') {
// notifications with multiple tabs open will not work very well in this scenario
// notifications with multiple tabs open will not work very well in this scenario
var evtSource = new EventSource('/sse');
evtSource.addEventListener('notifications', function(e) {
......@@ -298,7 +298,7 @@ function handle_comment_form(e) {
$('#' + commentElm).addClass('expanded').removeAttr('placeholder');
$('#' + commentElm).attr('tabindex','9');
$('#' + submitElm).attr('tabindex','10');
form.find(':not(:visible)').show();
}
......@@ -452,7 +452,7 @@ function insertCommentAttach(comment,id) {
$('body').css('cursor', 'wait');
$('#invisible-comment-upload').trigger('click');
return false;
}
......@@ -631,7 +631,7 @@ function updateConvItems(mode,data) {
if(mode === 'append') {
next = 'threads-end';
}
if(mode === 'replace') {
$('.thread-parent').remove(); // clear existing content
}
......@@ -652,7 +652,7 @@ function updateConvItems(mode,data) {
if($('#collapsed-comments-'+itmId).is(':visible'))
isVisible = true;
// insert the content according to the mode and first_page
// insert the content according to the mode and first_page
// and whether or not the content exists already (overwrite it)
if($('#' + ident).length == 0) {
......@@ -765,7 +765,7 @@ function updateConvItems(mode,data) {
}
// Setup to determine if the media player is playing. This affects
// some content loading decisions.
// some content loading decisions.
$('video').off('playing');
$('video').off('pause');
......@@ -1340,18 +1340,6 @@ function lockview(type, id) {
});
}
function filestorage(event, nick, id) {
$('#cloud-index-' + last_filestorage_id).removeClass('cloud-index-active');
$('#perms-panel-' + last_filestorage_id).hide().html('');
$('#file-edit-' + id).show();
$.get('filestorage/' + nick + '/' + id + '/edit', function(data) {
$('#cloud-index-' + id).addClass('cloud-index-active');
$('#perms-panel-' + id).html(data).show();
$('#file-edit-' + id).hide();
last_filestorage_id = id;
});
}
function submitPoll(id) {
$.post('vote/' + id,
......@@ -1474,17 +1462,17 @@ function preview_mail() {
}
function bin2hex(s) {
// Converts the binary representation of data to hex
//
// version: 812.316
// discuss at: http://phpjs.org/functions/bin2hex
// + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// + bugfixed by: Onno Marsman
// + bugfixed by: Linuxworld
// * example 1: bin2hex('Kev');
// * returns 1: '4b6576'
// * example 2: bin2hex(String.fromCharCode(0x00));
// * returns 2: '00'
// Converts the binary representation of data to hex
//
// version: 812.316
// discuss at: http://phpjs.org/functions/bin2hex
// + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// + bugfixed by: Onno Marsman
// + bugfixed by: Linuxworld
// * example 1: bin2hex('Kev');
// * returns 1: '4b6576'
// * example 2: bin2hex(String.fromCharCode(0x00));
// * returns 2: '00'
var v,i, f = 0, a = [];
s += '';
f = s.length;
......
......@@ -7,9 +7,53 @@ $(document).ready(function () {
if (window.File && window.FileList && window.FileReader) {
UploadInit();
}
$('.cloud-tool-perms-btn').on('click', function (e) {
e.preventDefault();
let id = $(this).data('id');
$('.cloud-tool').hide();
$('.cloud-index').removeClass('cloud-index-active');
$('#cloud-tool-submit-' + id).show();
$('#cloud-index-' + id).addClass('cloud-index-active');
});
$('.cloud-tool-rename-btn').on('click', function (e) {
e.preventDefault();
let id = $(this).data('id');
$('.cloud-tool').hide();
$('.cloud-index').removeClass('cloud-index-active');
$('#cloud-tool-rename-' + id + ', #cloud-tool-submit-' + id).show();
$('#cloud-index-' + id).addClass('cloud-index-active');
});
$('.cloud-tool-move-btn').on('click', function (e) {
e.preventDefault();
let id = $(this).data('id');
$('.cloud-tool').hide();
$('.cloud-index').removeClass('cloud-index-active');
$('#cloud-tool-move-' + id + ', #cloud-tool-submit-' + id).show();
$('#cloud-index-' + id).addClass('cloud-index-active');
});
$('.cloud-tool-download-btn').on('click', function (e) {
let id = $(this).data('id');
$('.cloud-tool').hide();
});
$('.cloud-tool-cancel-btn').on('click', function (e) {
e.preventDefault();
let id = $(this).data('id');
$('.cloud-tool').hide();
$('#cloud-index-' + id).removeClass('cloud-index-active');
$('#attach_edit_form_' + id).trigger('reset');
});
});
//
// initialize
function UploadInit() {
......@@ -18,7 +62,6 @@ function UploadInit() {
var submit = $("#upload-submit");
var count = 1;
$('#invisible-cloud-file-upload').fileupload({
url: 'file_upload',
dataType: 'json',
......@@ -26,8 +69,8 @@ function UploadInit() {
maxChunkSize: 4 * 1024 * 1024,
add: function(e,data) {
$(data.files).each( function() { this.count = ++ count; prepareHtml(this); });
$(data.files).each( function() { this.count = ++ count; prepareHtml(this); });
var allow_cid = ($('#ajax-upload-files').data('allow_cid') || []);
var allow_gid = ($('#ajax-upload-files').data('allow_gid') || []);
var deny_cid = ($('#ajax-upload-files').data('deny_cid') || []);
......@@ -58,7 +101,7 @@ function UploadInit() {
// there will only be one file, the one we are looking for
$(data.files).each( function() {
$(data.files).each( function() {
var idx = this.count;
// Dynamically update the percentage complete displayed in the file upload list
......@@ -246,7 +289,7 @@ function UploadFile(file, idx) {
$('#upload-progress-' + idx).html('<span style="color: red;">ERROR</span>');
});
// POST to the entire cloud path
// POST to the entire cloud path
// xhr.open('post', 'file_upload', true);
// var formfields = $("#ajax-upload-files").serializeArray();
......
<div id="cloud-drag-area" class="section-content-wrapper-np">
{{if $tiles}}
{{if $tiles}}
<table id="cloud-index">
<tr id="new-upload-progress-bar-1"></tr> {{* this is needed to append the upload files in the right order *}}
</table>
{{if $parentpath}}
<div class="cloud-container" >
<div class="cloud-icon tiles"><a href="{{$parentpath.path}}">
<div class="cloud-icon-container"><i class="fa fa-fw fa-level-up" ></i></div>
</a>
</div>
<div class="cloud-title"><a href="{{$parentpath.path}}">..</a>
</div>
<div class="cloud-icon tiles">
<a href="{{$parentpath.path}}">
<div class="cloud-icon-container">
<i class="fa fa-fw fa-level-up" ></i>
</div>
</a>
</div>
<div class="cloud-title">
<a href="{{$parentpath.path}}">..</a>
</div>
</div>
{{/if}}
{{foreach $entries as $item}}
<div class="cloud-container">
<div class="cloud-icon tiles"><a href="{{$item.relPath}}">
{{if $item.photo_icon}}
<img src="{{$item.photo_icon}}" title="{{$item.type}}" >
{{else}}
<div class="cloud-icon-container"><i class="fa fa-fw {{$item.iconFromType}}" title="{{$item.type}}"></i></div>
{{/if}}
</a>
</div>
<div class="cloud-title"><a href="{{$item.relPath}}">
{{$item.displayName}}
</a>
</div>
{{if $item.is_owner}}
{{/if}}
<div class="cloud-icon tiles"><a href="{{$item.relPath}}">
{{if $item.photo_icon}}
<img src="{{$item.photo_icon}}" title="{{$item.type}}" >
{{else}}
<div class="cloud-icon-container">
<i class="fa fa-fw {{$item.iconFromType}}" title="{{$item.type}}"></i>
</div>
{{/if}}
</div>
<div class="cloud-title">
<a href="{{$item.relPath}}">
{{$item.displayName}}
</a>
</div>
{{if $item.is_owner}}
{{* add file tools here*}}
{{/if}}
</div>
{{/foreach}}
<div class="clear"></div>
{{else}}
{{else}}
<table id="cloud-index">
<tr>
<th width="1%"></th>
<th width="92%">{{$name}}</th>
<th width="1%"></th><th width="1%"></th><th width="1%"></th><th width="1%"></th>
<th width="1%">{{*{{$type}}*}}</th>
<th width="1%">{{* icon *}}</th>
<th width="95%">{{$name}}</th>
<th width="1%">{{* lock icon *}}</th>
<th width="1%">{{* tools icon *}}</th>
<th width="1%" class="d-none d-md-table-cell">{{$size}}</th>
<th width="1%" class="d-none d-md-table-cell">{{$lastmod}}</th>
</tr>
{{if $parentpath}}
<tr>
{{if $parentpath}}
<tr id="cloud-index-0">
<td><i class="fa fa-level-up"></i>{{*$parentpath.icon*}}</td>
<td><a href="{{$parentpath.path}}" title="{{$parent}}">..</a></td>
<td></td><td></td><td></td><td></td>
<td>{{*[{{$parent}}]*}}</td>
<td class="d-none d-md-table-cell"></td>
<td class="d-none d-md-table-cell"></td>
<td colspan="5"><a href="{{$parentpath.path}}" title="{{$parent}}">..</a></td>
</tr>
{{/if}}
{{/if}}
<tr id="new-upload-progress-bar-1"></tr> {{* this is needed to append the upload files in the right order *}}
{{foreach $entries as $item}}
<tr id="cloud-index-{{$item.attachId}}">
{{foreach $entries as $item}}
<tr id="cloud-index-{{$item.attachId}}" class="cloud-index">
<td><i class="fa {{$item.iconFromType}}" title="{{$item.type}}"></i></td>
<td><a href="{{$item.relPath}}">{{$item.displayName}}</a></td>
{{if $item.is_owner}}
<td class="cloud-index-tool">{{$item.attachIcon}}</td>
<td class="cloud-index-tool"><div id="file-edit-{{$item.attachId}}" class="spinner-wrapper"><div class="spinner s"></div></div></td>
<td class="cloud-index-tool cursor-pointer" onclick="openCloseTR('cloud-tools-{{$item.attachId}}');"><i class="fa fa-pencil"></i></td>
<td class="cloud-index-tool"><a href="#" title="{{$delete}}" onclick="dropItem('{{$item.fileStorageUrl}}/{{$item.attachId}}/delete/json', '#cloud-index-{{$item.attachId}},#cloud-tools-{{$item.attachId}}'); return false;"><i class="fa fa-trash-o drop-icons"></i></a></td>
{{else}}
<td></td><td></td><td></td>{{if ($is_admin || $item.is_creator) && $item.attachId}}<td class="cloud-index-tool"><a href="#" title="{{if $is_admin}}{{$admin_delete}}{{else}}{{$delete}}{{/if}}" onclick="dropItem('{{$item.fileStorageUrl}}/{{$item.attachId}}/delete/json', '#cloud-index-{{$item.attachId}},#cloud-tools-{{$item.attachId}}'); return false;"><i class="fa fa-trash-o drop-icons"></i></a>{{else}}<td>{{/if}}</td>
{{/if}}
<td>{{*{{$item.type}}*}}</td>
<td class="d-none d-md-table-cell">{{$item.sizeFormatted}}</td>
<td class="d-none d-md-table-cell">{{$item.lastmodified}}</td>
<td><a href="{{$item.relPath}}" class="p-2">{{$item.displayName}}</a></td>
<td class="cloud-index-tool p-2">{{if $item.lockstate == 'lock'}}<i class="fa fa-fw fa-{{$item.lockstate}}"></i>{{/if}}</td>
{{if $item.is_owner}}
<td class="cloud-index-tool">
<div class="dropdown">
<button class="btn btn-link btn-sm" id="dropdown-button-{{$item.attachId}}" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fa fa-ellipsis-v"></i>
</button>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdown-button-{{$item.attachId}}">
<a id="cloud-tool-perms-btn-{{$item.attachId}}" class="dropdown-item cloud-tool-perms-btn" href="#" data-id="{{$item.attachId}}"><i class="fa fa-fw fa-{{$item.lockstate}}"></i> Adjust permissions</a>
<a id="cloud-tool-rename-btn-{{$item.attachId}}" class="dropdown-item cloud-tool-rename-btn" href="#" data-id="{{$item.attachId}}"><i class="fa fa-fw fa-pencil"></i> Rename</a>
<a id="cloud-tool-move-btn-{{$item.attachId}}" class="dropdown-item cloud-tool-move-btn" href="#" data-id="{{$item.attachId}}"><i class="fa fa-fw fa-copy"></i> Move or copy</a>
{{if !$item.collection}}
<a id="cloud-tool-share-btn-{{$item.attachId}}" class="dropdown-item cloud-tool-share-btn" href="/rpost?attachment=[attachment]{{$item.resource}},{{$item.revision}}[/attachment]&acl[allow_cid]={{$item.raw_allow_cid}}&acl[allow_gid]={{$item.raw_allow_gid}}&acl[deny_cid]={{$item.raw_deny_cid}}&acl[deny_gid]={{$item.raw_deny_gid}}" data-id="{{$item.attachId}}"><i class="fa fa-fw fa-share-square-o"></i> Post</a>
<a id="cloud-tool-download-btn-{{$item.attachId}}" class="dropdown-item cloud-tool-download-btn" href="/attach/{{$item.resource}}" data-id="{{$item.attachId}}"><i class="fa fa-fw fa-cloud-download"></i> Download</a>
{{/if}}
<a id="cloud-tool-delete-btn-{{$item.attachId}}" class="dropdown-item cloud-tool-delete-btn" href="#" data-id="{{$item.attachId}}" onclick="dropItem('{{$item.fileStorageUrl}}/{{$item.attachId}}/delete/json', '#cloud-index-{{$item.attachId}},#cloud-tools-{{$item.attachId}}'); return false;"><i class="fa fa-fw fa-trash-o"></i> {{$delete}}</a>
</div>
</div>
</td>