diff options
-rw-r--r-- | Zotlabs/Module/Wall_attach.php | 64 | ||||
-rw-r--r-- | include/attach.php | 101 | ||||
-rw-r--r-- | include/feedutils.php | 59 | ||||
-rwxr-xr-x | view/tpl/jot-header.tpl | 172 | ||||
-rwxr-xr-x | view/tpl/jot.tpl | 3 |
5 files changed, 252 insertions, 147 deletions
diff --git a/Zotlabs/Module/Wall_attach.php b/Zotlabs/Module/Wall_attach.php index c6fe7518e..5b3768da9 100644 --- a/Zotlabs/Module/Wall_attach.php +++ b/Zotlabs/Module/Wall_attach.php @@ -8,10 +8,21 @@ require_once('include/photos.php'); class Wall_attach extends \Zotlabs\Web\Controller { + function init() { + logger('request_method: ' . $_SERVER['REQUEST_METHOD'],LOGGER_DATA,LOG_INFO); + logger('wall_attach: ' . print_r($_REQUEST,true),LOGGER_DEBUG,LOG_INFO); + logger('wall_attach files: ' . print_r($_FILES,true),LOGGER_DEBUG,LOG_INFO); + // for testing without actually storing anything + // http_status_exit(200,'OK'); + } + + function post() { $using_api = false; - + + $result = []; + if($_REQUEST['api_source'] && array_key_exists('media',$_FILES)) { $using_api = true; } @@ -28,7 +39,44 @@ class Wall_attach extends \Zotlabs\Web\Controller { if(! $channel) killme(); - + + $matches = []; + $partial = false; + + $x = preg_match('/bytes (\d*)\-(\d*)\/(\d*)/',$_SERVER['HTTP_CONTENT_RANGE'],$matches); + if($x) { + // logger('Content-Range: ' . print_r($matches,true)); + $partial = true; + } + + if($partial) { + $x = save_chunk($channel,$matches[1],$matches[2],$matches[3]); + if($x['partial']) { + header('Range: bytes=0-' . (($x['length']) ? $x['length'] - 1 : 0)); + json_return_and_die($result); + } + else { + $_FILES['userfile'] = [ + 'name' => $x['name'], + 'type' => $x['type'], + 'tmp_name' => $x['tmp_name'], + 'error' => $x['error'], + 'size' => $x['size'] + ]; + } + } + else { + if(! array_key_exists('userfile',$_FILES)) { + $_FILES['userfile'] = [ + 'name' => $_FILES['files']['name'], + 'type' => $_FILES['files']['type'], + 'tmp_name' => $_FILES['files']['tmp_name'], + 'error' => $_FILES['files']['error'], + 'size' => $_FILES['files']['size'] + ]; + } + } + $observer = \App::get_observer(); @@ -51,10 +99,14 @@ class Wall_attach extends \Zotlabs\Web\Controller { if($using_api) return $s; - - echo $s; - killme(); - + + + if($partial) + header('Range: bytes=0-' . (($x['length']) ? $x['length'] - 1 : 0)); + $result['message'] = $s; + json_return_and_die($result); + } + } diff --git a/include/attach.php b/include/attach.php index ac50b05b1..3a0c8b7ba 100644 --- a/include/attach.php +++ b/include/attach.php @@ -2355,3 +2355,104 @@ function attach_upgrade() { } } + +function save_chunk($channel,$start,$end,$len) { + + $result = []; + + $tmp_path = $_FILES['files']['tmp_name']; + $new_base = 'store/[data]/' . $channel['channel_address'] . '/tmp'; + os_mkdir($new_base,STORAGE_DEFAULT_PERMISSIONS,true); + + $new_path = $new_base . '/' . $_FILES['files']['name']; + + if(! file_exists($new_path)) { + rename($tmp_path,$new_path); + } + else { + $istream = fopen($tmp_path,'rb'); + $ostream = fopen($new_path,'ab'); + if($istream && $ostream) { + pipe_streams($istream,$ostream); + fclose($istream); + fclose($ostream); + } + } + if(($len - 1) == $end) { + unlink($tmp_path); + $result['name'] = $_FILES['files']['tmp_name']; + $result['type'] = $_FILES['files']['type']; + $result['tmp_name'] = $new_path; + $result['error'] = 0; + $result['size'] = $len; + $result['complete'] = true; + return $result; + } + $result['partial'] = true; + $result['length'] = intval(filesize($new_path)); + return $result; +} + + +/* + * chunkloader + * Submit handler for chunked uploads + * + */ + +function chunkloader($channel,$arr) { + + logger('request: ' . print_r($arr,true), LOGGER_DEBUG); + logger('files: ' . print_r($_FILES,true), LOGGER_DEBUG); + + + $result = []; + + + $tmp_path = $_FILES['file']['tmp_name']; + $new_base = 'store/[data]/' . $channel['channel_address'] . '/tmp'; + os_mkdir($new_base,STORAGE_DEFAULT_PERMISSIONS,true); + + $new_path = $new_base . '/' . $arr['resumableFilename']; + + rename($tmp_path,$new_path . '.' . intval($arr['resumableChunkNumber'])); + + $missing_parts = false; + for($x = 1; $x <= intval($arr['resumableTotalChunks']); $x ++) { + if(! file_exists($new_path . '.' . $x)) { + $missing_parts = true; + break; + } + } + + if($missing_parts) { + $result['partial'] = true; + return $result; + } + + if(intval($arr['resumableTotalChunks']) === 1) { + rename($new_path . '.' . '1', $new_path); + } + else { + for($x = 1; $x <= intval($arr['resumableTotalChunks']); $x ++) { + $istream = fopen($new_path . '.' . $x,'rb'); + $ostream = fopen($new_path,'ab'); + if($istream && $ostream) { + pipe_streams($istream,$ostream); + fclose($istream); + fclose($ostream); + } + unlink($new_path . '.' . $x); + } + } + + $result['name'] = $arr['resumableFilename']; + $result['type'] = $arr['resumableType']; + $result['tmp_name'] = $new_path; + $result['error'] = 0; + $result['size'] = $arr['resumableTotalSize']; + $result['complete'] = true; + return $result; + +} + diff --git a/include/feedutils.php b/include/feedutils.php index 8696cc867..b1fcce9d3 100644 --- a/include/feedutils.php +++ b/include/feedutils.php @@ -516,7 +516,7 @@ function get_atom_elements($feed, $item, &$author) { // turn Mastodon content warning into a #nsfw hashtag if($mastodon && $summary) { - $res['body'] .= "\n\n#nsfw\n"; + $res['body'] .= "\n\n#ContentWarning\n"; } @@ -1085,6 +1085,7 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) { // next try thr:in_reply_to if($conv_id) { + logger('find_parent: conversation_id: ' . $conv_id, LOGGER_DEBUG); $c = q("select parent_mid from item left join iconfig on item.id = iconfig.iid where iconfig.cat = 'ostatus' and iconfig.k = 'conversation' and iconfig.v = '%s' and item.uid = %d order by item.id limit 1", dbesc($conv_id), intval($importer['channel_id']) @@ -1146,7 +1147,50 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) { } } - if(! $pmid) { + if($pmid) { + + // check comment permissions on the parent + + $parent_item = 0; + + $r = q("select * from item where parent_mid = '%s' and parent_mid = mid and uid = %d limit 1", + dbesc($pmid), + intval($importer['channel_id']) + ); + if($r) { + $parent_item = $r[0]; + if(intval($parent_item['item_nocomment']) || $parent_item['comment_policy'] === 'none' + || ($parent_item['comments_closed'] > NULL_DATE && $parent_item['comments_closed'] < datetime_convert())) { + logger('comments disabled for post ' . $parent_item['mid']); + continue; + } + } + + $allowed = false; + + if($parent_item) { + if($parent_item['owner_xchan'] == $importer['channel_hash']) + $allowed = perm_is_allowed($importer['channel_id'],$contact['xchan_hash'],'post_comments'); + else + $allowed = true; + + if(! $allowed) { + logger('Ignoring this comment author.'); + $status = 202; + continue; + } + } + else { + if((! perm_is_allowed($importer['channel_id'],$contact['xchan_hash'],'send_stream')) && (! $importer['system'])) { + // @fixme check for and process ostatus autofriend + // otherwise + + logger('Ignoring this author.'); + continue; + } + } + } + else { // immediate parent wasn't found. Turn into a top-level post if permissions allow // but save the thread_parent in case we need to refer to it later. @@ -1197,17 +1241,6 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) { $datarray['author_xchan'] = ''; - if(activity_match($datarray['verb'],ACTIVITY_FOLLOW) && $datarray['obj_type'] === ACTIVITY_OBJ_PERSON) { - $cb = array('item' => $datarray,'channel' => $importer, 'xchan' => [ 'placeholder' => '' ], 'author' => $author, 'caught' => false); - call_hooks('follow_from_feed',$cb); - if($cb['caught']) { - if($cb['return_code']) - http_status_exit($cb['return_code']); - - continue; - } - } - if($author['author_link'] != $contact['xchan_url']) { $name = ''; if($author['full_name']) { diff --git a/view/tpl/jot-header.tpl b/view/tpl/jot-header.tpl index 1cc5a898a..d8f296aa4 100755 --- a/view/tpl/jot-header.tpl +++ b/view/tpl/jot-header.tpl @@ -100,77 +100,44 @@ function enableOnUser(){ initEditor(); } </script> -<script type="text/javascript" src="{{$baseurl}}/view/js/ajaxupload.js" ></script> + +<script src="library/blueimp_upload/js/vendor/jquery.ui.widget.js"></script> +<script src="library/blueimp_upload/js/jquery.iframe-transport.js"></script> +<script src="library/blueimp_upload/js/jquery.fileupload.js"></script> + <script> $(document).ready(function() { /* enable tinymce on focus and click */ $("#profile-jot-text").focus(enableOnUser); $("#profile-jot-text").click(enableOnUser); - var upload_title = $('#wall-image-upload').attr('title'); - var attach_title = $('#wall-file-upload').attr('title'); - try { - var uploader = new window.AjaxUpload('wall-image-upload', - { action: '{{$baseurl}}/wall_upload/{{$nickname}}', - name: 'userfile', - title: upload_title, - onSubmit: function(file,ext) { $('#profile-rotator').spin('tiny'); }, - onComplete: function(file,response) { - addeditortext(response); - $('#jot-media').val($('#jot-media').val() + response); - $('#profile-rotator').spin(false); - } - }); - } catch (e) { - } - try { - var uploader_sub = new window.AjaxUpload('wall-image-upload-sub', - { action: '{{$baseurl}}/wall_upload/{{$nickname}}', - name: 'userfile', - title: upload_title, - onSubmit: function(file,ext) { $('#profile-rotator').spin('tiny'); }, - onComplete: function(file,response) { - addeditortext(response); - $('#jot-media').val($('#jot-media').val() + response); - $('#profile-rotator').spin(false); - } - }); - } catch(e) { - } - try { - var file_uploader = new window.AjaxUpload('wall-file-upload', - { action: '{{$baseurl}}/wall_attach/{{$nickname}}', - name: 'userfile', - title: attach_title, - onSubmit: function(file,ext) { $('#profile-rotator').spin('tiny'); }, - onComplete: function(file,response) { - addeditortext(response); - $('#jot-media').val($('#jot-media').val() + response); - $('#profile-rotator').spin(false); - } - }); - } catch(e) { - } - try { - var file_uploader_sub = new window.AjaxUpload('wall-file-upload-sub', - { action: '{{$baseurl}}/wall_attach/{{$nickname}}', - name: 'userfile', - title: attach_title, - onSubmit: function(file,ext) { $('#profile-rotator').spin('tiny'); }, - onComplete: function(file,response) { - addeditortext(response); - $('#jot-media').val($('#jot-media').val() + response); - $('#profile-rotator').spin(false); - } - }); - } catch(e) { - } - - + + $('#invisible-wall-file-upload').fileupload({ + url: 'wall_attach/{{$nickname}}', + dataType: 'json', + dropZone: $('#profile-jot-text'), + maxChunkSize: 4 * 1024 * 1024, + add: function(e,data) { + $('#profile-rotator').spin('tiny'); + data.submit(); + }, + done: function(e,data) { + addeditortext(data.result.message); + $('#jot-media').val($('#jot-media').val() + data.result.message); + }, + stop: function(e,data) { + $('#profile-rotator').spin(false); + }, + }); + + $('#wall-file-upload').click(function(event) { event.preventDefault(); $('#invisible-wall-file-upload').trigger('click'); return false;}); + $('#wall-file-upload-sub').click(function(event) { event.preventDefault(); $('#invisible-wall-file-upload').trigger('click'); return false;}); + // call initialization file if (window.File && window.FileList && window.FileReader) { DragDropUploadInit(); } + }); function deleteCheckedItems() { @@ -291,15 +258,17 @@ function enableOnUser(){ function linkdrop(event) { var reply = event.dataTransfer.getData("text/uri-list"); - event.preventDefault(); - var editwin = '#' + event.target.id; - var commentwin = false; - if(editwin) { - commentwin = ((editwin.indexOf('comment') >= 0) ? true : false); - if(commentwin) { - var commentid = editwin.substring(editwin.lastIndexOf('-') + 1); - commentOpen(document.getElementById(event.target.id),commentid); + if(reply) { + event.preventDefault(); + var editwin = '#' + event.target.id; + var commentwin = false; + if(editwin) { + commentwin = ((editwin.indexOf('comment') >= 0) ? true : false); + if(commentwin) { + var commentid = editwin.substring(editwin.lastIndexOf('-') + 1); + commentOpen(document.getElementById(event.target.id),commentid); + } } } @@ -353,8 +322,6 @@ function enableOnUser(){ commentBusy = true; $('body').css('cursor', 'wait'); $.get('{{$baseurl}}/filer/' + id + '?term=' + reply, NavUpdate); -// if(timer) clearTimeout(timer); -// timer = setTimeout(NavUpdate,3000); liking = 1; $('#item-filer-dialog').modal('hide'); } @@ -499,32 +466,20 @@ function enableOnUser(){ }; // - // initialize + // initialize drag-drop function DragDropUploadInit() { var filedrag = $("#profile-jot-text"); - // is XHR2 available? - var xhr = new XMLHttpRequest(); - if (xhr.upload) { - - // file drop + // file drop filedrag.on("dragover", DragDropUploadFileHover); filedrag.on("dragleave", DragDropUploadFileHover); filedrag.on("drop", DragDropUploadFileSelectHandler); - } - - window.filesToUpload = 0; - window.fileUploadsCompleted = 0; - - } // file drag hover function DragDropUploadFileHover(e) { - e.stopPropagation(); - e.preventDefault(); e.target.className = (e.type == "dragover" ? "hover" : ""); } @@ -533,49 +488,12 @@ function enableOnUser(){ // cancel event and hover styling DragDropUploadFileHover(e); - if (!editor) $("#profile-jot-text").val(""); - - - // fetch FileList object - var files = e.target.files || e.originalEvent.dataTransfer.files; - // process all File objects - for (var i = 0, f; f = files[i]; i++) { - DragDropUploadFile(f, i); - } - - } - - // upload files - function DragDropUploadFile(file, idx) { - - window.filesToUpload = window.filesToUpload + 1; - - var xhr = new XMLHttpRequest(); - xhr.withCredentials = true; // Include the SESSION cookie info for authentication - (xhr.upload || xhr).addEventListener('progress', function (e) { - $('#profile-rotator').spin('tiny'); - }); - xhr.addEventListener('load', function (e) { - //console.log('xhr upload complete', e); - window.fileUploadsCompleted = window.fileUploadsCompleted + 1; - - initEditor(function() { - addeditortext(xhr.responseText); - }); - - $('#jot-media').val($('#jot-media').val() + xhr.responseText); - // When all the uploads have completed, refresh the page - if (window.filesToUpload > 0 && window.fileUploadsCompleted === window.filesToUpload) { - $('#profile-rotator').spin(false); - window.fileUploadsCompleted = window.filesToUpload = 0; - } - }); - // POST to the wall_upload endpoint - xhr.open('post', '{{$baseurl}}/wall_attach/{{$nickname}}', true); + // open editor if it isn't yet initialised + if (!editor) { + initEditor(); + } + linkdrop(e); - var data = new FormData(); - data.append('userfile', file); - xhr.send(data); } </script> diff --git a/view/tpl/jot.tpl b/view/tpl/jot.tpl index dbbb470c5..cf99ede42 100755 --- a/view/tpl/jot.tpl +++ b/view/tpl/jot.tpl @@ -1,3 +1,4 @@ +<input id="invisible-wall-file-upload" type="file" name="files" style="visibility:hidden;position:absolute;top:-50;left:-50;width:0;height:0;" multiple> <form id="profile-jot-form" action="{{$action}}" method="post" class="acl-form" data-form_id="profile-jot-form" data-allow_cid='{{$allow_cid}}' data-allow_gid='{{$allow_gid}}' data-deny_cid='{{$deny_cid}}' data-deny_gid='{{$deny_gid}}'> {{$mimeselect}} {{$layoutselect}} @@ -39,7 +40,7 @@ </div> {{/if}} <div id="jot-text-wrap"> - <textarea class="profile-jot-text" id="profile-jot-text" name="body" tabindex="2" placeholder="{{$share}}" ondragenter="linkdropper(event);" ondragover="linkdropper(event);" ondrop="linkdrop(event);" >{{$content}}</textarea> + <textarea class="profile-jot-text" id="profile-jot-text" name="body" tabindex="2" placeholder="{{$share}}" >{{$content}}</textarea> </div> {{if $attachment}} <div id="jot-attachment-wrap"> |