diff options
-rw-r--r-- | Zotlabs/Lib/ThreadItem.php | 4 | ||||
-rw-r--r-- | Zotlabs/Module/Filestorage.php | 39 | ||||
-rw-r--r-- | Zotlabs/Module/Item.php | 28 | ||||
-rw-r--r-- | Zotlabs/Module/Oep.php | 2 | ||||
-rw-r--r-- | Zotlabs/Module/Photos.php | 41 | ||||
-rw-r--r-- | Zotlabs/Module/Settings/Channel.php | 15 | ||||
-rw-r--r-- | Zotlabs/Storage/Browser.php | 4 | ||||
-rw-r--r-- | Zotlabs/Storage/File.php | 2 | ||||
-rw-r--r-- | include/attach.php | 2 | ||||
-rwxr-xr-x | include/items.php | 1 | ||||
-rw-r--r-- | include/network.php | 4 | ||||
-rw-r--r-- | include/photos.php | 26 | ||||
-rw-r--r-- | include/text.php | 4 | ||||
-rw-r--r-- | view/js/main.js | 2 | ||||
-rw-r--r-- | view/tpl/cloud_directory.tpl | 4 | ||||
-rwxr-xr-x | view/tpl/settings.tpl | 1 |
16 files changed, 126 insertions, 53 deletions
diff --git a/Zotlabs/Lib/ThreadItem.php b/Zotlabs/Lib/ThreadItem.php index 61a012f9d..b7fc8e65d 100644 --- a/Zotlabs/Lib/ThreadItem.php +++ b/Zotlabs/Lib/ThreadItem.php @@ -141,6 +141,10 @@ class ThreadItem { 'delete' => t('Delete'), ); } + elseif(is_site_admin()) { + $drop = [ 'dropping' => true, 'delete' => t('Admin Delete') ]; + } + // FIXME if($observer_is_pageowner) { $multidrop = array( diff --git a/Zotlabs/Module/Filestorage.php b/Zotlabs/Module/Filestorage.php index 5c8557e5a..cd9ab601d 100644 --- a/Zotlabs/Module/Filestorage.php +++ b/Zotlabs/Module/Filestorage.php @@ -66,7 +66,7 @@ class Filestorage extends \Zotlabs\Web\Controller { $perms = get_all_perms($owner, $ob_hash); - if(! $perms['view_storage']) { + if(! ($perms['view_storage'] || is_site_admin())){ notice( t('Permission denied.') . EOL); return; } @@ -75,15 +75,29 @@ class Filestorage extends \Zotlabs\Web\Controller { // need to return for anyone other than the owner, despite the perms check for now. $is_owner = (((local_channel()) && ($owner == local_channel())) ? true : false); - if(! $is_owner) { + if(! ($is_owner || is_site_admin())){ info( t('Permission Denied.') . EOL ); return; } if(argc() > 3 && argv(3) === 'delete') { + + if(argc() > 4 && argv(4) === 'json') + $json_return = true; + + + $admin_delete = false; + if(! $perms['write_storage']) { - notice( t('Permission denied.') . EOL); - return; + if(is_site_admin()) { + $admin_delete = true; + } + else { + notice( t('Permission denied.') . EOL); + if($json_return) + json_return_and_die([ 'success' => false ]); + return; + } } $file = intval(argv(2)); @@ -92,22 +106,31 @@ class Filestorage extends \Zotlabs\Web\Controller { intval($owner) ); if(! $r) { + if($json_return) + json_return_and_die([ 'success' => false ]); + notice( t('File not found.') . EOL); goaway(z_root() . '/cloud/' . $which); } $f = $r[0]; - $channel = \App::get_channel(); + + $channel = channelx_by_n($owner); $url = get_cloud_url($channel['channel_id'], $channel['channel_address'], $f['hash']); attach_delete($owner, $f['hash']); - $sync = attach_export_data($channel, $f['hash'], true); - if($sync) { - build_sync_packet($channel['channel_id'], array('file' => array($sync))); + if(! $admin_delete) { + $sync = attach_export_data($channel, $f['hash'], true); + if($sync) { + build_sync_packet($channel['channel_id'], array('file' => array($sync))); + } } + if(json_return) + json_return_and_die([ 'success' => true ]); + goaway(dirname($url)); } diff --git a/Zotlabs/Module/Item.php b/Zotlabs/Module/Item.php index bba1dc02d..fd99c4a64 100644 --- a/Zotlabs/Module/Item.php +++ b/Zotlabs/Module/Item.php @@ -1084,24 +1084,36 @@ class Item extends \Zotlabs\Web\Controller { if((argc() == 3) && (argv(1) === 'drop') && intval(argv(2))) { require_once('include/items.php'); - $i = q("select id, uid, author_xchan, owner_xchan, source_xchan, item_type from item where id = %d limit 1", + + + $i = q("select id, uid, item_origin, author_xchan, owner_xchan, source_xchan, item_type from item where id = %d limit 1", intval(argv(2)) ); if($i) { $can_delete = false; $local_delete = false; - if(local_channel() && local_channel() == $i[0]['uid']) + + if(local_channel() && local_channel() == $i[0]['uid']) { $local_delete = true; - - $sys = get_sys_channel(); - if(is_site_admin() && $sys['channel_id'] == $i[0]['uid']) - $can_delete = true; + } $ob_hash = get_observer_hash(); - if($ob_hash && ($ob_hash === $i[0]['author_xchan'] || $ob_hash === $i[0]['owner_xchan'] || $ob_hash === $i[0]['source_xchan'])) + if($ob_hash && ($ob_hash === $i[0]['author_xchan'] || $ob_hash === $i[0]['owner_xchan'] || $ob_hash === $i[0]['source_xchan'])) { $can_delete = true; - + } + + // The site admin can delete any post/item on the site. + // If the item originated on this site+channel the deletion will propagate downstream. + // Otherwise just the local copy is removed. + + if(is_site_admin()) { + $local_delete = true; + if(intval($i[0]['item_origin'])) + $can_delete = true; + } + + if(! ($can_delete || $local_delete)) { notice( t('Permission denied.') . EOL); return; diff --git a/Zotlabs/Module/Oep.php b/Zotlabs/Module/Oep.php index ec40bf9db..0f20a5f9a 100644 --- a/Zotlabs/Module/Oep.php +++ b/Zotlabs/Module/Oep.php @@ -72,7 +72,7 @@ class Oep extends \Zotlabs\Web\Controller { $url = $args['url']; $maxwidth = intval($args['maxwidth']); $maxheight = intval($args['maxheight']); - logger('processing display'); + if(preg_match('#//(.*?)/display/(.*?)(&|\?|$)#',$url,$matches)) { $res = $matches[2]; } diff --git a/Zotlabs/Module/Photos.php b/Zotlabs/Module/Photos.php index a143c4d4c..e21f3025c 100644 --- a/Zotlabs/Module/Photos.php +++ b/Zotlabs/Module/Photos.php @@ -102,14 +102,7 @@ class Photos extends \Zotlabs\Web\Controller { if($_REQUEST['dropalbum'] == t('Delete Album')) { - - // This is dangerous because we combined file storage and photos into one interface - // This function will remove all photos from any directory with the same name since - // we have not passed the path value. - - // The correct solution would be to use a full pathname from your storage root for 'album' - // We also need to prevent/block removing the storage root folder. - + $folder_hash = ''; $r = q("select * from attach where is_dir = 1 and uid = %d and hash = '%s'", @@ -124,7 +117,8 @@ class Photos extends \Zotlabs\Web\Controller { $res = array(); - + $admin_delete = false; + // get the list of photos we are about to delete if(remote_channel() && (! local_channel())) { @@ -133,6 +127,10 @@ class Photos extends \Zotlabs\Web\Controller { elseif(local_channel()) { $str = photos_album_get_db_idstr(local_channel(),$album); } + elseif(is_site_admin()) { + $str = photos_album_get_db_idstr_admin($page_owner_uid,$album); + $admin_delete = true; + } else { $str = null; } @@ -145,7 +143,7 @@ class Photos extends \Zotlabs\Web\Controller { ); if($r) { foreach($r as $i) { - attach_delete($page_owner_uid, $i['resource_id'], 1 ); + attach_delete($page_owner_uid, $i['resource_id'], true ); } } @@ -158,12 +156,14 @@ class Photos extends \Zotlabs\Web\Controller { // @FIXME do the same for the linked attach if($folder_hash) { - attach_delete($page_owner_uid,$folder_hash, 1); - - $sync = attach_export_data(\App::$data['channel'],$folder_hash, true); + attach_delete($page_owner_uid, $folder_hash, true ); + + if(! $admin_delete) { + $sync = attach_export_data(\App::$data['channel'],$folder_hash, true); - if($sync) - build_sync_packet($page_owner_uid,array('file' => array($sync))); + if($sync) + build_sync_packet($page_owner_uid,array('file' => array($sync))); + } } } @@ -181,17 +181,22 @@ class Photos extends \Zotlabs\Web\Controller { $r = q("SELECT id, resource_id FROM photo WHERE ( xchan = '%s' or uid = %d ) AND resource_id = '%s' LIMIT 1", dbesc($ob_hash), intval(local_channel()), - dbesc(\App::$argv[2]) + dbesc(argv(2)) ); if($r) { - attach_delete($page_owner_uid, $r[0]['resource_id'], 1 ); + attach_delete($page_owner_uid, $r[0]['resource_id'], true ); $sync = attach_export_data(\App::$data['channel'],$r[0]['resource_id'], true); if($sync) build_sync_packet($page_owner_uid,array('file' => array($sync))); } - + elseif(is_site_admin()) { + // If the admin deletes a photo, don't sync + attach_delete($page_owner_uid, argv(2), true); + } + + goaway(z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/album/' . $_SESSION['album_return']); } diff --git a/Zotlabs/Module/Settings/Channel.php b/Zotlabs/Module/Settings/Channel.php index 65b9b197e..beb62a3a3 100644 --- a/Zotlabs/Module/Settings/Channel.php +++ b/Zotlabs/Module/Settings/Channel.php @@ -146,6 +146,7 @@ class Channel { $unkmail = (((x($_POST,'unkmail')) && (intval($_POST['unkmail']) == 1)) ? 1: 0); $cntunkmail = ((x($_POST,'cntunkmail')) ? intval($_POST['cntunkmail']) : 0); $suggestme = ((x($_POST,'suggestme')) ? intval($_POST['suggestme']) : 0); + $autoperms = ((x($_POST,'autoperms')) ? intval($_POST['autoperms']) : 0); $post_newfriend = (($_POST['post_newfriend'] == 1) ? 1: 0); $post_joingroup = (($_POST['post_joingroup'] == 1) ? 1: 0); @@ -252,6 +253,7 @@ class Channel { set_pconfig(local_channel(),'system','default_permcat',$defpermcat); set_pconfig(local_channel(),'system','email_notify_host',$mailhost); set_pconfig(local_channel(),'system','profile_assign',$profile_assign); + set_pconfig(local_channel(),'system','autoperms',$autoperms); $r = q("update channel set channel_name = '%s', channel_pageflags = %d, channel_timezone = '%s', channel_location = '%s', channel_notifyflags = %d, channel_max_anon_mail = %d, channel_max_friend_req = %d, channel_expire_days = %d $set_perms where channel_id = %d", dbesc($username), @@ -479,13 +481,21 @@ class Channel { if($permissions_role === 'social_party') $permissions_role = 'social_federation'; - + if(in_array($permissions_role,['forum','repository'])) + $autoperms = replace_macros(get_markup_template('field_checkbox.tpl'), [ + '$field' => [ 'autoperms',t('Automatic membership approval'), ((get_pconfig(local_channel(),'system','autoperms')) ? 1 : 0), t('If enabled, connection requests will be approved without your interaction'), $yes_no ]]); + else + $autoperms = '<input type="hidden" name="autoperms" value="' . intval(get_pconfig(local_channel(),'system','autoperms')) . '" />'; + $permissions_set = (($permissions_role != 'custom') ? true : false); $perm_roles = \Zotlabs\Access\PermissionRoles::roles(); if((get_account_techlevel() < 4) && $permissions_role !== 'custom') unset($perm_roles[t('Other')]); + + + $vnotify = get_pconfig(local_channel(),'system','vnotify'); $always_show_in_notices = get_pconfig(local_channel(),'system','always_show_in_notices'); if($vnotify === false) @@ -497,6 +507,7 @@ class Channel { $disable_discover_tab = intval(get_config('system','disable_discover_tab',1)) == 1; $site_firehose = intval(get_config('system','site_firehose',0)) == 1; + $o .= replace_macros($stpl,array( '$ptitle' => t('Channel Settings'), @@ -553,7 +564,7 @@ class Channel { '$unkmail' => $unkmail, '$cntunkmail' => array('cntunkmail', t('Maximum private messages per day from unknown people:'), intval($channel['channel_max_anon_mail']) ,t("Useful to reduce spamming")), - + '$autoperms' => $autoperms, '$h_not' => t('Notification Settings'), '$activity_options' => t('By default post a status message when:'), '$post_newfriend' => array('post_newfriend', t('accepting a friend request'), $post_newfriend, '', $yes_no), diff --git a/Zotlabs/Storage/Browser.php b/Zotlabs/Storage/Browser.php index 508c39d22..f4f906ad1 100644 --- a/Zotlabs/Storage/Browser.php +++ b/Zotlabs/Storage/Browser.php @@ -241,7 +241,7 @@ class Browser extends DAV\Browser\Plugin { // put the array for this file together $ft['attachId'] = $this->findAttachIdByHash($attachHash); - $ft['fileStorageUrl'] = substr($fullPath, 0, strpos($fullPath, "cloud/")) . "filestorage/" . $this->auth->getCurrentUser(); + $ft['fileStorageUrl'] = substr($fullPath, 0, strpos($fullPath, "cloud/")) . "filestorage/" . $this->auth->owner_nick; $ft['icon'] = $icon; $ft['photo_icon'] = $photo_icon; $ft['attachIcon'] = (($size) ? $attachIcon : ''); @@ -276,6 +276,8 @@ class Browser extends DAV\Browser\Plugin { '$create' => t('Create'), '$upload' => t('Add Files'), '$is_owner' => $is_owner, + '$is_admin' => is_site_admin(), + '$admin_delete' => t('Admin Delete'), '$parentpath' => $parentpath, '$cpath' => bin2hex(\App::$query_string), '$tiles' => intval($_SESSION['cloud_tiles']), diff --git a/Zotlabs/Storage/File.php b/Zotlabs/Storage/File.php index 53d5d3476..4610aceb7 100644 --- a/Zotlabs/Storage/File.php +++ b/Zotlabs/Storage/File.php @@ -49,7 +49,7 @@ class File extends DAV\Node implements DAV\IFile { $this->data = $data; $this->auth = $auth; - logger(print_r($this->data, true), LOGGER_DATA); + // logger(print_r($this->data, true), LOGGER_DATA); } /** diff --git a/include/attach.php b/include/attach.php index 0d2b43b58..2a9badaac 100644 --- a/include/attach.php +++ b/include/attach.php @@ -1585,8 +1585,8 @@ function get_cloud_url($channel_id, $channel_name, $attachHash) { } } while ($parentHash); - $url = z_root() . '/cloud/' . $channel_name . '/' . $parentFullPath . find_filename_by_hash($channel_id, $attachHash); + $url = z_root() . '/cloud/' . $channel_name . '/' . $parentFullPath . find_filename_by_hash($channel_id, $attachHash); return $url; } diff --git a/include/items.php b/include/items.php index 8bc4595b6..2c9d84ef3 100755 --- a/include/items.php +++ b/include/items.php @@ -3561,7 +3561,6 @@ function item_expire($uid,$days,$comment_days = 7) { drop_item($item['id'],false); } -// Zotlabs\Daemon\Master::Summon(array('Notifier','expire',$uid)); } function retain_item($id) { diff --git a/include/network.php b/include/network.php index 8b7490a8a..a00ede6bf 100644 --- a/include/network.php +++ b/include/network.php @@ -797,7 +797,7 @@ function xml2array($contents, $namespaces = true, $get_attributes=1, $priority = if($namespaces) $parser = @xml_parser_create_ns("UTF-8",':'); else - $parser = @xml_parser_create(); + $parser = @xml_parser_create('UTF-8'); if(! $parser) { logger('xml2array: xml_parser_create: no resource'); @@ -807,7 +807,7 @@ function xml2array($contents, $namespaces = true, $get_attributes=1, $priority = xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, "UTF-8"); // http://minutillo.com/steve/weblog/2004/6/17/php-xml-and-character-encodings-a-tale-of-sadness-rage-and-data-loss xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0); - xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); + xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0); @xml_parse_into_struct($parser, trim($contents), $xml_values); @xml_parser_free($parser); diff --git a/include/photos.php b/include/photos.php index 9ae0e6874..495043bbf 100644 --- a/include/photos.php +++ b/include/photos.php @@ -786,17 +786,31 @@ function photos_album_get_db_idstr($channel_id, $album, $remote_xchan = '') { ); } if ($r) { - $arr = array(); - foreach ($r as $rr) { - $arr[] = "'" . dbesc($rr['hash']) . "'" ; - } - $str = implode(',',$arr); - return $str; + return ids_to_querystr($r,'hash',true); } return false; } +function photos_album_get_db_idstr_admin($channel_id, $album) { + + if(! is_site_admin()) + return false; + + $r = q("SELECT hash from attach where uid = %d and folder = '%s' ", + intval($channel_id), + dbesc($album) + ); + + if ($r) { + return ids_to_querystr($r,'hash',true); + } + + return false; +} + + + /** * @brief Creates a new photo item. * diff --git a/include/text.php b/include/text.php index 24f8e1623..dc3a155de 100644 --- a/include/text.php +++ b/include/text.php @@ -3313,9 +3313,9 @@ function cleanup_bbcode($body) { $body = preg_replace_callback('/\[zrl(.*?)\[\/(zrl)\]/ism','\red_escape_codeblock',$body); - $body = preg_replace_callback("/([^\]\='".'"'."\/]|^|\#\^)(https?\:\/\/[a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\@\_\~\#\%\$\!\\ + $body = preg_replace_callback("/([^\]\='".'"'."\/\{]|^|\#\^)(https?\:\/\/[a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\@\_\~\#\%\$\!\\ +\,\(\)]+)/ismu", '\nakedoembed', $body); - $body = preg_replace_callback("/([^\]\='".'"'."\/]|^|\#\^)(https?\:\/\/[a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\@\_\~\#\%\$\!\\ + $body = preg_replace_callback("/([^\]\='".'"'."\/\{]|^|\#\^)(https?\:\/\/[a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\@\_\~\#\%\$\!\\ +\,\(\)]+)/ismu", '\red_zrl_callback', $body); $body = preg_replace_callback('/\[\$b64zrl(.*?)\[\/(zrl)\]/ism','\red_unescape_codeblock',$body); diff --git a/view/js/main.js b/view/js/main.js index acb9b462f..3e24e8177 100644 --- a/view/js/main.js +++ b/view/js/main.js @@ -1057,7 +1057,9 @@ function doprofilelike(ident, verb) { $.get('like/' + ident + '?verb=' + verb, function() { window.location.href=window.location.href; }); } + function dropItem(url, object) { + var confirm = confirmDelete(); if(confirm) { $('body').css('cursor', 'wait'); diff --git a/view/tpl/cloud_directory.tpl b/view/tpl/cloud_directory.tpl index 1f0addc95..51178a9ba 100644 --- a/view/tpl/cloud_directory.tpl +++ b/view/tpl/cloud_directory.tpl @@ -65,10 +65,10 @@ <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"><i class="fakelink fa fa-pencil" onclick="filestorage(event, '{{$nick}}', {{$item.attachId}});"></i></td> - <td class="cloud-index-tool"><a href="#" title="{{$delete}}" onclick="dropItem('{{$item.fileStorageUrl}}/{{$item.attachId}}/delete', '#cloud-index-{{$item.attachId}},#cloud-tools-{{$item.attachId}}'); return false;"><i class="fa fa-trash-o drop-icons"></i></a></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><td></td> + <td></td><td></td><td></td>{{if $is_admin}}<td class="cloud-index-tool"><a href="#" title="{{$admin_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>{{else}}<td>{{/if}}</td> {{/if}} <td>{{*{{$item.type}}*}}</td> <td class="d-none d-md-table-cell">{{$item.sizeFormatted}}</td> diff --git a/view/tpl/settings.tpl b/view/tpl/settings.tpl index d258f1992..b5e871c36 100755 --- a/view/tpl/settings.tpl +++ b/view/tpl/settings.tpl @@ -45,6 +45,7 @@ <div id="privacy-settings-collapse" class="collapse" role="tabpanel" aria-labelledby="privacy-settings" data-parent="#settings"> <div class="section-content-tools-wrapper"> {{include file="field_select_grouped.tpl" field=$role}} + {{$autoperms}} <div id="advanced-perm" style="display:{{if $permissions_set}}none{{else}}block{{/if}};"> <div class="form-group"> <button type="button" class="btn btn-outline-secondary" data-toggle="modal" data-target="#apsModal">{{$lbl_p2macro}}</button> |