diff --git a/public/mix-manifest.json b/public/mix-manifest.json
index 36bd8771..0ffd8251 100644
--- a/public/mix-manifest.json
+++ b/public/mix-manifest.json
@@ -59,7 +59,7 @@
"/chunks/plans.js": "/chunks/plans.js?id=6fca685daa45f22e4c8f",
"/chunks/platform.js": "/chunks/platform.js?id=1863e0b77ad5c26a05bc",
"/chunks/platform~chunks/settings-subscription~chunks/shared~chunks/user-subscription.js": "/chunks/platform~chunks/settings-subscription~chunks/shared~chunks/user-subscription.js?id=8656b69a97cace919251",
- "/chunks/platform~chunks/shared.js": "/chunks/platform~chunks/shared.js?id=1bb410d04a3fb0bdd15c",
+ "/chunks/platform~chunks/shared.js": "/chunks/platform~chunks/shared.js?id=f0d10b45321b77d9fb21",
"/chunks/profile.js": "/chunks/profile.js?id=022c1617a575d4aab4e1",
"/chunks/profile~chunks/settings-password.js": "/chunks/profile~chunks/settings-password.js?id=58edfb3a35062e1ba4e0",
"/chunks/purchase-code.js": "/chunks/purchase-code.js?id=f8b2619e393a5823bf29",
@@ -1488,5 +1488,13 @@
"/chunks/shared-with-me.93d1862a2d1291f017c5.hot-update.js": "/chunks/shared-with-me.93d1862a2d1291f017c5.hot-update.js",
"/chunks/team-folders.5f3b12c7626c1febc1f4.hot-update.js": "/chunks/team-folders.5f3b12c7626c1febc1f4.hot-update.js",
"/chunks/team-folders.9a710c5840f0fe78b845.hot-update.js": "/chunks/team-folders.9a710c5840f0fe78b845.hot-update.js",
- "/chunks/shared-with-me.de7b0068aa7d3daa54d0.hot-update.js": "/chunks/shared-with-me.de7b0068aa7d3daa54d0.hot-update.js"
+ "/chunks/shared-with-me.de7b0068aa7d3daa54d0.hot-update.js": "/chunks/shared-with-me.de7b0068aa7d3daa54d0.hot-update.js",
+ "/js/main.b96dce782e1445910175.hot-update.js": "/js/main.b96dce782e1445910175.hot-update.js",
+ "/js/main.d367944ae8ff81bdfd36.hot-update.js": "/js/main.d367944ae8ff81bdfd36.hot-update.js",
+ "/js/main.8e230d654f8e6dc09627.hot-update.js": "/js/main.8e230d654f8e6dc09627.hot-update.js",
+ "/js/main.254907f280bbbbaaa3cf.hot-update.js": "/js/main.254907f280bbbbaaa3cf.hot-update.js",
+ "/chunks/platform~chunks/shared.f81c519d38811aa1937b.hot-update.js": "/chunks/platform~chunks/shared.f81c519d38811aa1937b.hot-update.js",
+ "/chunks/platform~chunks/shared.1b7dcdcf4abc08a8b218.hot-update.js": "/chunks/platform~chunks/shared.1b7dcdcf4abc08a8b218.hot-update.js",
+ "/chunks/platform~chunks/shared.61307263989bd7deb32e.hot-update.js": "/chunks/platform~chunks/shared.61307263989bd7deb32e.hot-update.js",
+ "/chunks/platform~chunks/shared.3f8787077c840fc65667.hot-update.js": "/chunks/platform~chunks/shared.3f8787077c840fc65667.hot-update.js"
}
diff --git a/resources/js/components/FilesView/InfoSidebar.vue b/resources/js/components/FilesView/InfoSidebar.vue
index de93f415..8e7b36cc 100644
--- a/resources/js/components/FilesView/InfoSidebar.vue
+++ b/resources/js/components/FilesView/InfoSidebar.vue
@@ -37,8 +37,8 @@
:title="$t('Author')"
>
-
- {{ singleFile.data.relationships.user.data.attributes.name }}
+
+ {{ singleFile.data.relationships.owner.data.attributes.name }}
@@ -165,7 +165,7 @@
canShowAuthor() {
return this.$isThisRoute(this.$route, ['SharedWithMe', 'TeamFolders'])
&& this.clipboard[0].data.type !== 'folder'
- && this.user.data.id !== this.clipboard[0].data.relationships.user.data.id
+ && this.user.data.id !== this.clipboard[0].data.relationships.owner.data.id
},
},
methods: {
diff --git a/resources/js/helpers/itemHelpers.js b/resources/js/helpers/itemHelpers.js
index d84cbace..2ba34a9b 100644
--- a/resources/js/helpers/itemHelpers.js
+++ b/resources/js/helpers/itemHelpers.js
@@ -48,7 +48,7 @@ const itemHelpers = {
Vue.prototype.$detachMeFromTeamFolder = function (folder) {
events.$emit('confirm:open', {
title: this.$t('Are you sure you want to leave this team?'),
- message: this.$t('You will not have access to the files in this team folder.'),
+ message: this.$t("You will don't have access to the files and all your previously uploaded content will be part of this Team Folder you are leaving."),
action: {
id: folder.data.id,
operation: 'leave-team-folder',
diff --git a/src/Domain/Teams/Actions/SetTeamFolderPropertyForAllChildrenAction.php b/src/Domain/Teams/Actions/SetTeamFolderPropertyForAllChildrenAction.php
index 978959e7..eba6d82e 100644
--- a/src/Domain/Teams/Actions/SetTeamFolderPropertyForAllChildrenAction.php
+++ b/src/Domain/Teams/Actions/SetTeamFolderPropertyForAllChildrenAction.php
@@ -17,7 +17,7 @@ class SetTeamFolderPropertyForAllChildrenAction
// Set all children as team_folder = true
DB::table('folders')
- ->whereIn('id', Arr::flatten([filter_folders_ids($childrenFolderIds)]))
+ ->whereIn('id', Arr::flatten(filter_folders_ids($childrenFolderIds)))
->update(['team_folder' => $isTeamFolder]);
}
}
\ No newline at end of file
diff --git a/src/Domain/Teams/Actions/TransferContentOwnershipToTeamFolderOwnerAction.php b/src/Domain/Teams/Actions/TransferContentOwnershipToTeamFolderOwnerAction.php
new file mode 100644
index 00000000..2051a2ad
--- /dev/null
+++ b/src/Domain/Teams/Actions/TransferContentOwnershipToTeamFolderOwnerAction.php
@@ -0,0 +1,72 @@
+where('parent_id', $folder->id)
+ ->where('user_id', $leavingUserId)
+ ->delete();
+
+ // Get all inherited folder from team folder
+ $childrenFolderIds = Folder::with('folders:id,parent_id')
+ ->where('id', $folder->id)
+ ->get('id');
+
+ $teamFolderIds = Arr::flatten(filter_folders_ids($childrenFolderIds));
+
+ // Replace leaver content ownership for author of team folder
+ DB::table('files')
+ ->whereIn('parent_id', $teamFolderIds)
+ ->where('user_id', $leavingUserId)
+ ->cursor()
+ ->each(fn ($file) =>
+ $this->move_files_to_the_new_destination($file, $folder)
+ );
+
+ DB::table('files')
+ ->whereIn('parent_id', $teamFolderIds)
+ ->where('user_id', $leavingUserId)
+ ->update(['user_id' => $folder->user_id]);
+
+ DB::table('folders')
+ ->whereIn('id', $teamFolderIds)
+ ->where('user_id', $leavingUserId)
+ ->update(['user_id' => $folder->user_id]);
+ }
+
+ /**
+ * @param $file
+ * @param Folder $folder
+ */
+ private function move_files_to_the_new_destination($file, Folder $folder): void
+ {
+ // Move image thumbnails
+ if ($file->type === 'image') {
+
+ // Get image thumbnail list
+ $thumbnailList = get_thumbnail_file_list($file->basename);
+
+ // move thumbnails to the new location
+ $thumbnailList->each(function ($basename) use ($file, $folder) {
+
+ $oldPath = "files/$file->user_id/$basename";
+ $newPath = "files/$folder->user_id/$basename";
+
+ if (Storage::exists($oldPath)) Storage::move($oldPath, $newPath);
+ });
+ }
+
+ // Move single file
+ Storage::move("files/$file->user_id/$file->basename", "files/$folder->user_id/$file->basename");
+ }
+}
\ No newline at end of file
diff --git a/src/Domain/Teams/Actions/UpdateMembersAction.php b/src/Domain/Teams/Actions/UpdateMembersAction.php
index 538a9abc..b7cc31e8 100644
--- a/src/Domain/Teams/Actions/UpdateMembersAction.php
+++ b/src/Domain/Teams/Actions/UpdateMembersAction.php
@@ -6,6 +6,7 @@ use Domain\Folders\Models\Folder;
class UpdateMembersAction
{
+ // TODO: after removing user from team folder from administrator, set file owner
public function __invoke(Folder $folder, $members): void
{
$existingMembers = $folder
diff --git a/src/Domain/Teams/Controllers/LeaveTeamFolderController.php b/src/Domain/Teams/Controllers/LeaveTeamFolderController.php
index 2ffcd5fa..a1efa8ed 100644
--- a/src/Domain/Teams/Controllers/LeaveTeamFolderController.php
+++ b/src/Domain/Teams/Controllers/LeaveTeamFolderController.php
@@ -1,23 +1,31 @@
where('parent_id', $folder->id)
- ->where('user_id', Auth::id())
- ->delete();
+ // Authorize action
+ if (! Gate::any(['can-edit', 'can-view'], [$folder, null])) {
+ abort(403, 'Access Denied');
+ }
+
+ // Transfer files/folders ownership to team folder owner
+ ($this->transferContentOwnership)($folder, Auth::id());
return response('Done.', 204);
}
diff --git a/src/Support/helpers.php b/src/Support/helpers.php
index 9d491272..ec14688d 100644
--- a/src/Support/helpers.php
+++ b/src/Support/helpers.php
@@ -599,6 +599,17 @@ if (! function_exists('get_file_type')) {
}
}
+if (! function_exists('get_thumbnail_file_list')) {
+ /**
+ * Get list of image thumbnails
+ */
+ function get_thumbnail_file_list(string $basename): Collection
+ {
+ return collect(config('vuefilemanager.image_sizes'))
+ ->map(fn ($item) => $item['name'] . '-' . $basename);
+ }
+}
+
if (! function_exists('map_language_translations')) {
/**
* It map language translations as language key and language value
diff --git a/tests/Domain/Teams/TeamManagementTest.php b/tests/Domain/Teams/TeamManagementTest.php
index e21a9fdc..c05b8c7b 100644
--- a/tests/Domain/Teams/TeamManagementTest.php
+++ b/tests/Domain/Teams/TeamManagementTest.php
@@ -2,6 +2,9 @@
namespace Tests\Domain\Teams;
+use Domain\Files\Models\File;
+use Illuminate\Http\UploadedFile;
+use Illuminate\Support\Facades\Storage;
use Str;
use Notification;
use Tests\TestCase;
@@ -574,10 +577,62 @@ class TeamManagementTest extends TestCase
$folder = Folder::factory()
->create([
+ 'name' => 'Team Folder',
'user_id' => $user->id,
'team_folder' => 1,
]);
+ $folderWithin = Folder::factory()
+ ->create([
+ 'name' => 'Member Content',
+ 'parent_id' => $folder->id,
+ 'user_id' => $member->id,
+ 'team_folder' => 1,
+ ]);
+
+ $file = File::factory()
+ ->create([
+ 'name' => 'Member File',
+ 'basename' => 'fake-file.zip',
+ 'parent_id' => $folderWithin->id,
+ 'user_id' => $member->id,
+ 'type' => 'file',
+ ]);
+
+ // Create fake file
+ $fakeFile = UploadedFile::fake()
+ ->create('fake-file.zip', 2000, 'application/zip');
+
+ // Put fake file into correct directory
+ Storage::putFileAs("files/$member->id", $fakeFile, 'fake-file.zip');
+
+ File::factory()
+ ->create([
+ 'name' => 'Good image',
+ 'basename' => 'fake-image.jpeg',
+ 'parent_id' => $folderWithin->id,
+ 'user_id' => $member->id,
+ 'type' => 'image',
+ ]);
+
+ // Create fake image
+ $fakeFile = UploadedFile::fake()
+ ->create("fake-image.jpeg", 2000, 'image/jpeg');
+
+ // Put fake image into correct directory
+ Storage::putFileAs("files/$member->id", $fakeFile, $fakeFile->name);
+
+ // Create fake image thumbnails
+ collect(config('vuefilemanager.image_sizes'))
+ ->each(function ($item) use ($member) {
+
+ $fakeFile = UploadedFile::fake()
+ ->create("{$item['name']}-fake-image.jpeg", 2000, 'image/jpeg');
+
+ Storage::putFileAs("files/$member->id", $fakeFile, $fakeFile->name);
+ });
+
+ // add member to the team folder
DB::table('team_folder_members')
->insert([
[
@@ -592,11 +647,31 @@ class TeamManagementTest extends TestCase
->deleteJson("/api/teams/folders/{$folder->id}/leave")
->assertNoContent();
+ // Check if file was moved from member directory to owner directory
+ Storage::assertMissing("files/$member->id/fake-file.zip");
+ Storage::assertExists("files/$user->id/fake-file.zip");
+
+ // Assert if image thumbnails was moved correctly to the new destination
+ collect(config('vuefilemanager.image_sizes'))
+ ->each(function ($item) use ($user) {
+ Storage::assertExists("files/$user->id/{$item['name']}-fake-image.jpeg");
+ });
+
$this
->assertDatabaseMissing('team_folder_members', [
'parent_id' => $folder->id,
'user_id' => $member->id,
'permission' => 'can-edit',
+ ])
+ ->assertDatabaseHas('files', [
+ 'id' => $file->id,
+ 'parent_id' => $folderWithin->id,
+ 'user_id' => $user->id,
+ ])
+ ->assertDatabaseHas('folders', [
+ 'id' => $folderWithin->id,
+ 'parent_id' => $folder->id,
+ 'user_id' => $user->id,
]);
}