Transfer Content Ownership To Team Folder Owner

This commit is contained in:
Čarodej
2021-11-04 17:37:25 +01:00
parent 8d8fdbf9ba
commit d600ee7830
9 changed files with 189 additions and 14 deletions

View File

@@ -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"
}

View File

@@ -37,8 +37,8 @@
:title="$t('Author')"
>
<div class="flex items-center mt-1">
<MemberAvatar :size="32" :member="singleFile.data.relationships.user" />
<span class="ml-2 block">{{ singleFile.data.relationships.user.data.attributes.name }}</span>
<MemberAvatar :size="32" :member="singleFile.data.relationships.owner" />
<span class="ml-2 block">{{ singleFile.data.relationships.owner.data.attributes.name }}</span>
</div>
</ListInfoItem>
@@ -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: {

View File

@@ -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',

View File

@@ -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]);
}
}

View File

@@ -0,0 +1,72 @@
<?php
namespace Domain\Teams\Actions;
use Domain\Folders\Models\Folder;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
class TransferContentOwnershipToTeamFolderOwnerAction
{
public function __invoke(Folder $folder, $leavingUserId)
{
// Find and delete attached member from team folder
DB::table('team_folder_members')
->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");
}
}

View File

@@ -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

View File

@@ -1,23 +1,31 @@
<?php
namespace Domain\Teams\Controllers;
use Auth;
use Gate;
use Illuminate\Http\Response;
use Domain\Folders\Models\Folder;
use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\Routing\ResponseFactory;
use Domain\Teams\Actions\TransferContentOwnershipToTeamFolderOwnerAction;
class LeaveTeamFolderController extends Controller
{
public function __invoke(Folder $folder): Response | Application | ResponseFactory
public function __construct(
public TransferContentOwnershipToTeamFolderOwnerAction $transferContentOwnership,
) {}
public function __invoke(Folder $folder): Response|Application|ResponseFactory
{
// Find and delete attached member from team folder
DB::table('team_folder_members')
->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);
}

View File

@@ -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

View File

@@ -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,
]);
}