From 2a154f8c9a772d61e7dabb5e3fd110ba00cc6007 Mon Sep 17 00:00:00 2001 From: Mario Date: Mon, 14 Dec 2020 11:02:20 +0000 Subject: merge branch files_ng into dev --- include/attach.php | 290 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 257 insertions(+), 33 deletions(-) (limited to 'include/attach.php') diff --git a/include/attach.php b/include/attach.php index c9649a4ce..69ccceaf6 100644 --- a/include/attach.php +++ b/include/attach.php @@ -647,12 +647,12 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) { $pathname = filepath_macro($newalbum); } elseif(array_key_exists('folder',$arr)) { - $x = q("select filename from attach where hash = '%s' and uid = %d limit 1", + $x = q("select display_path from attach where hash = '%s' and uid = %d limit 1", dbesc($arr['folder']), intval($channel['channel_id']) ); if($x) - $pathname = $x[0]['filename']; + $pathname = $x[0]['display_path']; } else { $pathname = filepath_macro($album); @@ -1534,7 +1534,7 @@ function attach_drop_photo($channel_id,$resource) { $interactive = (($x[0]['item_hidden']) ? false : true); drop_item($x[0]['id'], $interactive, $stage); } - + $r = q("SELECT content FROM photo WHERE resource_id = '%s' AND uid = %d AND os_storage = 1", dbesc($resource), intval($channel_id) @@ -1544,7 +1544,7 @@ function attach_drop_photo($channel_id,$resource) { @unlink(dbunescbin($i['content'])); } } - + q("DELETE FROM photo WHERE uid = %d AND resource_id = '%s'", intval($channel_id), dbesc($resource) @@ -2495,7 +2495,7 @@ function copy_folder_to_cloudfiles($channel, $observer_hash, $srcpath, $cloudpat return true; } /** - * This function performs an in place directory-to-directory move of a stored attachment or photo. + * This function performs an in place directory-to-directory move of a stored resource. * The data is physically moved in the store/nickname storage location and the paths adjusted * in the attach structure (and if applicable the photo table). The new 'album name' is recorded * for photos and will show up immediately there. @@ -2507,60 +2507,64 @@ function copy_folder_to_cloudfiles($channel, $observer_hash, $srcpath, $cloudpat * @param int $channel_id * @param int $resource_id * @param string $new_folder_hash - * @return void|boolean + * @param (optional) string $newname + * @param (optional) boolean $recurse + * @return array Associative array with: + * * \e boolean \b success + * * \e string \b resource_id */ -function attach_move($channel_id, $resource_id, $new_folder_hash) { +function attach_move($channel_id, $resource_id, $new_folder_hash, $newname = '', $recurse = true) { + + $ret = [ + 'success' => false, + 'resource_id' => $resource_id + ]; $c = channelx_by_n($channel_id); if(! ($c && $resource_id)) - return false; - + return $ret; // find the resource to be moved - $r = q("select * from attach where hash = '%s' and uid = %d limit 1", dbesc($resource_id), intval($channel_id) ); if(! $r) { logger('resource_id not found'); - return false; + return $ret; } $oldstorepath = dbunescbin($r[0]['content']); - // find the resource we are moving to - if($new_folder_hash) { $n = q("select * from attach where hash = '%s' and uid = %d and is_dir = 1 limit 1", dbesc($new_folder_hash), intval($channel_id) ); if(! $n) - return false; + return $ret; + $newdirname = $n[0]['filename']; $newalbumname = $n[0]['display_path']; $newstorepath = dbunescbin($n[0]['content']) . '/' . $resource_id; } else { - // root directory - + $newdirname = EMPTY_STR; $newalbumname = EMPTY_STR; $newstorepath = 'store/' . $c['channel_address'] . '/' . $resource_id; } - rename($oldstorepath,$newstorepath); - - // duplicate detection. If 'overwrite' is specified, return false because we can't yet do that. - - $filename = $r[0]['filename']; - - // don't do duplicate check unless our parent folder has changed. + if ($recurse) { + rename($oldstorepath,$newstorepath); + } - if($r[0]['folder'] !== $new_folder_hash) { + $oldfilename = $r[0]['filename']; + $filename = (($newname) ? basename($newname) : $oldfilename); + // duplicate detection. + if($recurse) { $s = q("select filename, id, hash, filesize from attach where filename = '%s' and folder = '%s' ", dbesc($filename), dbesc($new_folder_hash) @@ -2568,9 +2572,10 @@ function attach_move($channel_id, $resource_id, $new_folder_hash) { if($s) { $overwrite = get_pconfig($channel_id,'system','overwrite_dup_files'); + // If 'overwrite' is specified, return false because we can't yet do that. if($overwrite) { /// @fixme - return; + return $ret; } else { if(strpos($filename,'.') !== false) { @@ -2586,7 +2591,8 @@ function attach_move($channel_id, $resource_id, $new_folder_hash) { if(preg_match('/(.*?)\([0-9]{1,}\)$/',$basename,$matches)) $basename = $matches[1]; - $v = q("select filename from attach where ( filename = '%s' OR filename like '%s' ) and folder = '%s' ", + $v = q("select filename from attach where uid = %d and ( filename = '%s' OR filename like '%s' ) and folder = '%s' ", + intval($channel_id), dbesc($basename . $ext), dbesc($basename . '(%)' . $ext), dbesc($new_folder_hash) @@ -2609,12 +2615,14 @@ function attach_move($channel_id, $resource_id, $new_folder_hash) { while($found); $filename = $basename . '(' . $x . ')' . $ext; } - else + else { $filename = $basename . $ext; + } } } } + q("update attach set content = '%s', folder = '%s', filename = '%s' where id = %d", dbescbin($newstorepath), dbesc($new_folder_hash), @@ -2631,7 +2639,6 @@ function attach_move($channel_id, $resource_id, $new_folder_hash) { intval($r[0]['id']) ); - if($r[0]['is_photo']) { q("update photo set album = '%s', filename = '%s', os_path = '%s', display_path = '%s' where resource_id = '%s' and uid = %d", @@ -2643,11 +2650,24 @@ function attach_move($channel_id, $resource_id, $new_folder_hash) { intval($channel_id) ); - q("update photo set content = '%s' where resource_id = '%s' and uid = %d and imgscale = 0", + q("update photo set content = CASE imgscale WHEN 0 THEN '%s' ELSE CONCAT('%s', '-', imgscale) END where resource_id = '%s' and uid = %d and os_storage = 1", + dbescbin($newstorepath), dbescbin($newstorepath), dbesc($resource_id), intval($channel_id) ); + + // now rename the thumbnails in os_storage - the original should have been copied before already + $ps = q("SELECT content, imgscale FROM photo WHERE uid = %d AND resource_id = '%s' and imgscale > 0 and os_storage = 1", + intval($channel_id), + dbesc($resource_id) + ); + + if ($recurse) { + foreach($ps as $p) { + rename($oldstorepath . '-' . $p['imgscale'], $p['content']); + } + } } if($r[0]['is_dir']) { @@ -2658,19 +2678,223 @@ function attach_move($channel_id, $resource_id, $new_folder_hash) { ); if($x) { foreach($x as $xv) { - $rs = attach_move($channel_id,$xv['hash'],$r[0]['hash']); - if(! $rs) { + $rs = attach_move($channel_id, $xv['hash'], $r[0]['hash'], '', false); + if(! $rs['success']) { $move_success = false; break; } } } - return $move_success; + + $ret['success'] = $move_success; + return $ret; } - return true; + $ret['success'] = true; + return $ret; } +/** + * This function performs an in place directory-to-directory copy of a stored resource. + * The data is physically copyed in the store/nickname storage location and the paths adjusted + * in the attach structure (and if applicable the photo table). The new 'album name' is recorded + * for photos and will show up immediately there. + * This takes a channel_id, attach.hash of the file to copy (this is the same as a photo resource_id), and + * the attach.hash of the new parent folder, which must already exist. If $new_folder_hash is blank or empty, + * the new file is copyed to the root of the channel's storage area. + * + * + * @param int $channel_id + * @param int $resource_id + * @param string $new_folder_hash + * @param (optional) string $newname + * @param (optional) boolean $recurse + * @return array Associative array with: + * * \e boolean \b success + * * \e string \b resource_id of the new resource + */ +function attach_copy($channel_id, $resource_id, $new_folder_hash, $newname = '', $recurse = true) { + + $ret = [ + 'success' => false, + 'resource_id' => '' + ]; + + $c = channelx_by_n($channel_id); + if(! ($c && $resource_id)) + return $ret; + + // find the resource to be copied + $r = q("select * from attach where hash = '%s' and uid = %d limit 1", + dbesc($resource_id), + intval($channel_id) + ); + if(! $r) { + logger('resource_id not found'); + return $ret; + } + + $a = $r[0]; + $new_resource_id = new_uuid(); + + $ret['resource_id'] = $new_resource_id; + + $oldstorepath = dbunescbin($r[0]['content']); + + // find the resource we are copying to + if($new_folder_hash) { + $n = q("select * from attach where hash = '%s' and uid = %d and is_dir = 1 limit 1", + dbesc($new_folder_hash), + intval($channel_id) + ); + if(! $n) { + logger('new_folder_hash not found'); + return $ret; + } + + $newdirname = $n[0]['filename']; + $newalbumname = $n[0]['display_path']; + $newstorepath = dbunescbin($n[0]['content']) . '/' . $new_resource_id; + } + else { + // root directory + $newdirname = EMPTY_STR; + $newalbumname = EMPTY_STR; + $newstorepath = 'store/' . $c['channel_address'] . '/' . $new_resource_id; + } + + if(is_dir($oldstorepath)) { + os_mkdir($newstorepath,STORAGE_DEFAULT_PERMISSIONS,true); + } + else { + copy($oldstorepath,$newstorepath); + } + + $oldfilename = $r[0]['filename']; + $filename = (($newname) ? basename($newname) : $oldfilename); + + // duplicate detection. If 'overwrite' is specified, return false because we can't yet do that. + if($recurse) { + $s = q("select filename, id, hash, filesize from attach where filename = '%s' and folder = '%s' ", + dbesc($filename), + dbesc($new_folder_hash) + ); + + if($s) { + $overwrite = get_pconfig($channel_id,'system','overwrite_dup_files'); + if($overwrite) { + /// @fixme + return $ret; + } + else { + if(strpos($filename,'.') !== false) { + $basename = substr($filename,0,strrpos($filename,'.')); + $ext = substr($filename,strrpos($filename,'.')); + } + else { + $basename = $filename; + $ext = ''; + } + + $matches = false; + if(preg_match('/(.*?)\([0-9]{1,}\)$/',$basename,$matches)) + $basename = $matches[1]; + + $v = q("select filename from attach where uid = %d and ( filename = '%s' OR filename like '%s' ) and folder = '%s' ", + intval($channel_id), + dbesc($basename . $ext), + dbesc($basename . '(%)' . $ext), + dbesc($new_folder_hash) + ); + + if($v) { + $x = 1; + + do { + $found = false; + foreach($v as $vv) { + if($vv['filename'] === $basename . '(' . $x . ')' . $ext) { + $found = true; + break; + } + } + if($found) + $x++; + } + while($found); + $filename = $basename . '(' . $x . ')' . $ext; + } + else { + $filename = $basename . $ext; + } + } + } + } + + unset($a['id']); + $a['hash'] = $new_resource_id; + $a['content'] = $newstorepath; + $a['folder'] = $new_folder_hash; + $a['filename'] = $filename; + + create_table_from_array('attach', $a, ['content']); + + $x = attach_syspaths($channel_id, $new_resource_id); + + q("update attach set os_path = '%s', display_path = '%s' where hash = '%s'", + dbesc($x['os_path']), + dbesc($x['path']), + dbesc($new_resource_id) + ); + + if($a['is_photo']) { + + $ps = q("SELECT * FROM photo WHERE uid = %d AND resource_id = '%s'", + intval($channel_id), + dbesc($resource_id) + ); + + foreach($ps as $p) { + unset($p['id']); + $p['resource_id'] = $new_resource_id; + $p['album'] = $newalbumname; + $p['filename'] = $filename; + $p['os_path'] = $x['os_path']; + $p['display_path'] = $x['path']; + if($p['os_storage']) { + $p['content'] = (($p['imgscale'] == 0) ? $newstorepath : $newstorepath . '-' . $p['imgscale']); + + //the original should have been copied before already + if($p['imgscale'] > 0) + copy($oldstorepath, $p['content']); + } + create_table_from_array('photo', $p, ['content']); + } + } + + if($r[0]['is_dir']) { + $copy_success = true; + $x = q("select hash from attach where folder = '%s' and uid = %d", + dbesc($r[0]['hash']), + intval($channel_id) + ); + if($x) { + foreach($x as $xv) { + $rs = attach_copy($channel_id,$xv['hash'],$new_resource_id, '', false); + if(! $rs['success']) { + $copy_success = false; + break; + } + } + } + + $ret['success'] = $copy_success; + return $ret; + } + + $ret['success'] = true; + return $ret; +} /** * Used to generate a select input box of all your folders -- cgit v1.2.3 From e58e27ce2256ce4192c6ac7670ccb301fb40e60a Mon Sep 17 00:00:00 2001 From: Mario Date: Mon, 14 Dec 2020 21:38:49 +0000 Subject: sync categories --- include/attach.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'include/attach.php') diff --git a/include/attach.php b/include/attach.php index 69ccceaf6..515de9b4d 100644 --- a/include/attach.php +++ b/include/attach.php @@ -2306,6 +2306,18 @@ function attach_export_data($channel, $resource_id, $deleted = false) { $r[0]['content'] = dbunescbin($r[0]['content']); $hash_ptr = $r[0]['folder']; + + $r[0]['term'] = []; + + $term = q("SELECT * FROM term WHERE uid = %d AND oid = %d AND otype = %d", + intval($channel['channel_id']), + intval($r[0]['id']), + intval(TERM_OBJ_FILE) + ); + + if ($term) + $r[0]['term'] = array_reverse($term); + $paths[] = $r[0]; } while($hash_ptr); @@ -2314,7 +2326,6 @@ function attach_export_data($channel, $resource_id, $deleted = false) { $ret['attach'] = $paths; - if($attach_ptr['is_photo']) { // This query could potentially result in a few megabytes of data use. -- cgit v1.2.3 From 8e488e291347857407dbedaf05d63941701d82d2 Mon Sep 17 00:00:00 2001 From: Mario Date: Mon, 14 Dec 2020 21:56:19 +0000 Subject: handle removal of terms in attach_delete() when deleting a ressource --- include/attach.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'include/attach.php') diff --git a/include/attach.php b/include/attach.php index 515de9b4d..7ef5c4d0e 100644 --- a/include/attach.php +++ b/include/attach.php @@ -1432,7 +1432,7 @@ function attach_delete($channel_id, $resource, $is_photo = 0) { $channel_address = (($c) ? $c[0]['channel_address'] : 'notfound'); $photo_sql = (($is_photo) ? " and is_photo = 1 " : ''); - $r = q("SELECT hash, os_storage, flags, is_dir, is_photo, folder FROM attach WHERE hash = '%s' AND uid = %d $photo_sql limit 1", + $r = q("SELECT id, hash, os_storage, flags, is_dir, is_photo, folder FROM attach WHERE hash = '%s' AND uid = %d $photo_sql limit 1", dbesc($resource), intval($channel_id) ); @@ -1453,6 +1453,12 @@ function attach_delete($channel_id, $resource, $is_photo = 0) { return; } + q("DELETE FROM term WHERE uid = %d AND oid = %d AND otype = %d", + intval($channel_id), + intval($r[0]['id']), + intval(TERM_OBJ_FILE) + ); + // If resource is a directory delete everything in the directory recursive if(intval($r[0]['is_dir'])) { $x = q("SELECT hash, os_storage, is_dir, flags FROM attach WHERE folder = '%s' AND uid = %d", -- cgit v1.2.3 From b4b566318a0e52b6396445ddc21c20c0abcc8ce4 Mon Sep 17 00:00:00 2001 From: Mario Date: Wed, 16 Dec 2020 16:57:56 +0000 Subject: files_ng: fix regression in finding the right path in certain situations and add a info panel with attach and zrl bbcode --- include/attach.php | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) (limited to 'include/attach.php') diff --git a/include/attach.php b/include/attach.php index 7ef5c4d0e..8ebe2d243 100644 --- a/include/attach.php +++ b/include/attach.php @@ -647,17 +647,15 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) { $pathname = filepath_macro($newalbum); } elseif(array_key_exists('folder',$arr)) { - $x = q("select display_path from attach where hash = '%s' and uid = %d limit 1", - dbesc($arr['folder']), - intval($channel['channel_id']) - ); - if($x) - $pathname = $x[0]['display_path']; + $pathname = find_path_by_hash($channel['channel_id'], $arr['folder']); } else { $pathname = filepath_macro($album); } } + elseif(array_key_exists('folder',$arr)) { + $pathname = find_path_by_hash($channel['channel_id'], $arr['folder']); + } if(! $pathname) { $pathname = filepath_macro($upload_path); } @@ -807,6 +805,7 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) { $os_relpath = ltrim($os_relpath,'/'); $os_path = $os_relpath; + $display_path = ltrim($pathname . '/' . $filename,'/'); if($src) { @@ -890,7 +889,6 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) { ); } else { - $r = q("INSERT INTO attach ( aid, uid, hash, creator, filename, filetype, folder, filesize, revision, os_storage, is_photo, content, created, edited, os_path, display_path, allow_cid, allow_gid,deny_cid, deny_gid ) VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', %d, %d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ", intval($channel['channel_account_id']), @@ -1746,6 +1744,29 @@ function find_filename_by_hash($channel_id, $attachHash) { return $filename; } +/** + * @brief Returns the display_path of an attachment in a given channel. + * + * @param int $channel_id + * The id of the channel + * @param string $attachHash + * The hash of the attachment + * @return string + * The filename of the attachment + */ +function find_path_by_hash($channel_id, $attachHash) { + $r = q("SELECT display_path FROM attach WHERE uid = %d AND hash = '%s' LIMIT 1", + intval($channel_id), + dbesc($attachHash) + ); + $display_path = ''; + if ($r) { + $display_path = $r[0]['display_path']; + } + + return $display_path; +} + /** * @brief Pipes $in to $out in 16KB chunks. * -- cgit v1.2.3 From d118ab71e6aa4f300ba6e42663d13a63a2323122 Mon Sep 17 00:00:00 2001 From: Mario Date: Mon, 21 Dec 2020 21:37:10 +0000 Subject: files_ng: implement directory and bulk file download --- include/attach.php | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) (limited to 'include/attach.php') diff --git a/include/attach.php b/include/attach.php index 8ebe2d243..b4f697f81 100644 --- a/include/attach.php +++ b/include/attach.php @@ -300,6 +300,44 @@ function attach_by_hash($hash, $observer_hash, $rev = 0) { } +/** + * @brief Find an attachment by id. + * + * Returns the entire attach structure including data. + * + * This could exhaust memory so most useful only when immediately sending the data. + * + * @param string $hash + * @param string $observer_hash + * @return array + */ +function attach_by_id($id, $observer_hash) { + + $ret = array('success' => false); + + // Check for existence, which will also provide us the owner uid + + $r = q("SELECT * FROM attach WHERE id = %d", + intval($id) + ); + if(! $r) { + $ret['message'] = t('Item was not found.'); + return $ret; + } + + if(! attach_can_view($r[0]['uid'], $observer_hash, $r[0]['hash'])) { + $ret['message'] = t('Permission denied.'); + return $ret; + } + + $r[0]['content'] = dbunescbin($r[0]['content']); + + $ret['success'] = true; + $ret['data'] = $r[0]; + + return $ret; +} + function attach_can_view($uid,$ob_hash,$resource) { $sql_extra = permissions_sql($uid,$ob_hash); @@ -1120,7 +1158,6 @@ function attach_mkdir($channel, $observer_hash, $arr = null) { if(! is_dir($os_basepath)) os_mkdir($os_basepath,STORAGE_DEFAULT_PERMISSIONS, true); - $os_basepath .= '/'; if(! perm_is_allowed($channel_id, $observer_hash, 'write_storage')) { -- cgit v1.2.3 From d80f2a621d47b372328743437871101ab0fbaa1d Mon Sep 17 00:00:00 2001 From: Mario Date: Wed, 6 Jan 2021 19:22:29 +0000 Subject: simplify attach_folder_select_list() (cherry picked from commit c7010dac3c74e25eac8855d87d78d892052d3c4e) --- include/attach.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'include/attach.php') diff --git a/include/attach.php b/include/attach.php index b4f697f81..bcb3061f4 100644 --- a/include/attach.php +++ b/include/attach.php @@ -2987,10 +2987,7 @@ function attach_folder_select_list($channel_id) { if($r) { foreach($r as $rv) { - $x = attach_folder_rpaths($r,$rv); - if($x) { - $out[$x[0]] = $x[1]; - } + $out[$rv['hash']] = $rv['display_path']; } } -- cgit v1.2.3 From 52fa350138aa19301850909fa13b0786e3c7dbb2 Mon Sep 17 00:00:00 2001 From: Mario Date: Wed, 6 Jan 2021 19:32:36 +0000 Subject: error in logic (cherry picked from commit 16082456dfbb3e3108ba1a1db627f7333d10ddce) --- include/attach.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/attach.php') diff --git a/include/attach.php b/include/attach.php index bcb3061f4..f65f41477 100644 --- a/include/attach.php +++ b/include/attach.php @@ -3017,7 +3017,7 @@ function attach_folder_rpaths($all_folders,$that_folder) { if(! $found) $error = true; } - while((! $found) && (! $error) && ($parent_hash != '')); + while((! $error) && ($parent_hash != '')); } return (($error) ? false : [ $current_hash , $path ]); -- cgit v1.2.3 From 3105f514e4dc49facaf759e893a47a866ad85c54 Mon Sep 17 00:00:00 2001 From: Mario Date: Fri, 15 Jan 2021 10:00:13 +0000 Subject: make attach_upgrade() catch entries where only display_path is missing (cherry picked from commit 42812078c51acb9ffc26cc3cfc52e5048fed16b8) --- include/attach.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'include/attach.php') diff --git a/include/attach.php b/include/attach.php index f65f41477..9ba6be109 100644 --- a/include/attach.php +++ b/include/attach.php @@ -3064,8 +3064,7 @@ function attach_syspaths($channel_id,$attach_hash) { function attach_upgrade() { - - $r = q("select id, uid, hash from attach where os_path = '' and display_path = '' limit 100"); + $r = q("SELECT id, uid, hash FROM attach WHERE os_path = '' OR display_path = '' LIMIT 100"); if($r) { foreach($r as $rv) { $x = attach_syspaths($rv['uid'],$rv['hash']); -- cgit v1.2.3