- when member upload files or create folder in team folder, the true owner of the content is creator of team member. That means the upload bandwidth and storage go to creator responsibility

This commit is contained in:
Čarodej
2022-03-30 09:34:25 +02:00
parent 0fbb8fd8ee
commit 0ca67c2348
31 changed files with 256 additions and 396 deletions
+11 -14
View File
@@ -1,9 +1,8 @@
<?php
namespace Domain\Files\Actions;
use App\Users\Models\User;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Auth;
use Domain\Folders\Models\Folder;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Storage;
use Domain\Files\Requests\UploadRequest;
@@ -60,13 +59,14 @@ class UploadFileAction
// File name
$fileName = Str::uuid() . '.' . $request->input('extension');
// Get user data
$user = $userId ? User::find($userId) : Auth::user();
// Get user
$user = $request->filled('parent_id')
? Folder::find($request->input('parent_id'))->getLatestParent()->user
: auth()->user();
// File Info
$fileSize = $disk_local->size("chunks/$chunkName");
$file_mimetype = $disk_local->mimeType("chunks/$chunkName");
$fileMimetype = $disk_local->mimeType("chunks/$chunkName");
// Check if user has enough space to upload file
if (! $user->canUpload($fileSize)) {
@@ -80,27 +80,24 @@ class UploadFileAction
// Create multiple image thumbnails
($this->createImageThumbnail)($fileName, $file, $user->id);
// Move files to external storage
if (! isStorageDriver('local')) {
($this->moveFileToExternalStorage)($fileName, $user->id);
}
// Store user upload size
($this->recordUpload)($fileSize, $user->id);
// Create new file
$item = UserFile::create([
'mimetype' => get_file_type_from_mimetype($file_mimetype),
'type' => get_file_type($file_mimetype),
'mimetype' => get_file_type_from_mimetype($fileMimetype),
'type' => get_file_type($fileMimetype),
'parent_id' => ($this->getFileParentId)($request, $user->id),
'name' => $request->input('filename'),
'basename' => $fileName,
'author' => $userId ? 'visitor' : 'user',
'filesize' => $fileSize,
'user_id' => $user->id,
'creator_id' => auth()->id(),
]);
// Store exif metadata for files
($this->storeExifMetadata)($item, $file);
@@ -27,7 +27,7 @@ class GetFileController extends Controller
->firstOrFail();
// Check if user can download file
if (! $file->owner->canDownload()) {
if (! $file->user->canDownload()) {
return response(userActionNotAllowedError(), 401);
}
+10 -1
View File
@@ -2,6 +2,7 @@
namespace Domain\Files\Models;
use App\Users\Models\User;
use Domain\Traffic\Actions\RecordUploadAction;
use Illuminate\Support\Str;
use Laravel\Scout\Searchable;
use Domain\Sharing\Models\Share;
@@ -174,7 +175,12 @@ class File extends Model
return $this->hasOne(Share::class, 'item_id', 'id');
}
public function owner(): HasOne
public function creator(): HasOne
{
return $this->hasOne(User::class, 'id', 'creator_id');
}
public function user(): HasOne
{
return $this->hasOne(User::class, 'id', 'user_id');
}
@@ -207,6 +213,9 @@ class File extends Model
static::creating(function ($file) {
$file->id = (string) Str::uuid();
// Store upload record
resolve(RecordUploadAction::class)($file->filesize, $file->user_id);
});
static::deleting(function ($file) {
+10 -10
View File
@@ -29,10 +29,10 @@ class FileResource extends JsonResource
'file_url' => $this->file_url,
'thumbnail' => $this->thumbnail,
'parent_id' => $this->parent_id,
'created_at' => set_time_by_user_timezone($this->owner, $this->created_at),
'updated_at' => set_time_by_user_timezone($this->owner, $this->updated_at),
'created_at' => set_time_by_user_timezone($this->user, $this->created_at),
'updated_at' => set_time_by_user_timezone($this->user, $this->updated_at),
'deleted_at' => $this->deleted_at
? set_time_by_user_timezone($this->owner, $this->deleted_at)
? set_time_by_user_timezone($this->user, $this->deleted_at)
: null,
],
'relationships' => [
@@ -50,15 +50,15 @@ class FileResource extends JsonResource
],
],
]),
$this->mergeWhen($this->owner, fn () => [
'owner' => [
$this->mergeWhen($this->creator, fn () => [
'creator' => [
'data' => [
'type' => 'owner',
'id' => $this->user_id,
'type' => 'creator',
'id' => $this->creator->id,
'attributes' => [
'name' => $this->owner->settings->name,
'avatar' => $this->owner->settings->avatar,
'color' => $this->owner->settings->color,
'name' => $this->creator->settings->name,
'avatar' => $this->creator->settings->avatar,
'color' => $this->creator->settings->color,
],
],
],
@@ -18,35 +18,31 @@ class CreateFolderAction
CreateFolderRequest $request,
?Share $shared = null,
): Folder|array {
// Get user model
$user = $shared
? $shared->user
: Auth::user();
// Get stuff
$isFilledParentId = $request->filled('parent_id');
$parentId = $request->input('parent_id');
// Get user
$user = $isFilledParentId
? Folder::find($parentId)->getLatestParent()->user
: auth()->user();
// Check if user can create folder
if (! $user->canCreateFolder()) {
throw new InvalidUserActionException();
}
/*
* Check if exist parent team folder, if yes,
* then get the latest parent folder to detect whether it is team_folder
*/
if ($request->has('parent_id')) {
$isTeamFolder = Folder::find($request->input('parent_id'))
->getLatestParent()
->team_folder;
}
// Create folder record
return Folder::create([
'parent_id' => $request->input('parent_id'),
'parent_id' => $parentId,
'name' => $request->input('name'),
'color' => $request->input('color') ?? null,
'emoji' => $request->input('emoji') ?? null,
'author' => $shared ? 'visitor' : 'user',
'user_id' => $user->id,
'team_folder' => $isTeamFolder ?? false,
'team_folder' => $isFilledParentId
? Folder::find($parentId)->getLatestParent()->team_folder
: false
]);
}
}
+1 -1
View File
@@ -192,7 +192,7 @@ class Folder extends Model
->withPivot('permission');
}
public function owner(): HasOne
public function user(): HasOne
{
return $this->hasOne(User::class, 'id', 'user_id');
}
@@ -22,10 +22,10 @@ class FolderResource extends JsonResource
'isTeamFolder' => $this->team_folder,
'items' => $this->items,
'trashed_items' => $this->trashed_items,
'created_at' => set_time_by_user_timezone($this->owner, $this->created_at),
'updated_at' => set_time_by_user_timezone($this->owner, $this->updated_at),
'created_at' => set_time_by_user_timezone($this->user, $this->created_at),
'updated_at' => set_time_by_user_timezone($this->user, $this->updated_at),
'deleted_at' => $this->deleted_at
? set_time_by_user_timezone($this->owner, $this->deleted_at)
? set_time_by_user_timezone($this->user, $this->deleted_at)
: null,
],
'relationships' => [
@@ -49,15 +49,15 @@ class FolderResource extends JsonResource
],
],
]),
$this->mergeWhen($this->owner, fn () => [
'owner' => [
$this->mergeWhen($this->user, fn () => [
'user' => [
'data' => [
'type' => 'owner',
'type' => 'user',
'id' => $this->user_id,
'attributes' => [
'name' => $this->owner->settings->name,
'avatar' => $this->owner->settings->avatar,
'color' => $this->owner->settings->color,
'name' => $this->user->settings->name,
'avatar' => $this->user->settings->avatar,
'color' => $this->user->settings->color,
],
],
],
@@ -1,72 +0,0 @@
<?php
namespace Domain\Teams\Actions;
use Illuminate\Support\Arr;
use Domain\Folders\Models\Folder;
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 = getThumbnailFileList($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");
}
}
@@ -6,11 +6,6 @@ use Domain\Folders\Models\Folder;
class UpdateMembersAction
{
public function __construct(
public TransferContentOwnershipToTeamFolderOwnerAction $transferContentOwnership,
) {
}
public function __invoke(Folder $folder, $members): void
{
$existingMembers = $folder
@@ -28,9 +23,6 @@ class UpdateMembersAction
->where('parent_id', $folder->id)
->whereIn('user_id', $deletedMembers->toArray())
->delete();
// Transfer files/folders ownership to team folder owner
$deletedMembers->each(fn ($memberId) => ($this->transferContentOwnership)($folder, $memberId));
}
// Update privileges
@@ -28,7 +28,7 @@ class ConvertFolderIntoTeamFolderController extends Controller
}
// Check if user didn't exceed max team members limit
if (! $folder->owner->canInviteTeamMembers($request->input('invitations'))) {
if (! $folder->user->canInviteTeamMembers($request->input('invitations'))) {
return response([
'type' => 'error',
'message' => 'You exceed your members limit.',
@@ -1,22 +1,16 @@
<?php
namespace Domain\Teams\Controllers;
use Auth;
use Gate;
use Illuminate\Http\Response;
use Domain\Folders\Models\Folder;
use App\Http\Controllers\Controller;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\Routing\ResponseFactory;
use Domain\Teams\Actions\TransferContentOwnershipToTeamFolderOwnerAction;
use Illuminate\Support\Facades\DB;
class LeaveTeamFolderController extends Controller
{
public function __construct(
public TransferContentOwnershipToTeamFolderOwnerAction $transferContentOwnership,
) {
}
public function __invoke(Folder $folder): Response|Application|ResponseFactory
{
// Abort in demo mode
@@ -29,8 +23,11 @@ class LeaveTeamFolderController extends Controller
abort(403, 'Access Denied');
}
// Transfer files/folders ownership to team folder owner
($this->transferContentOwnership)($folder, Auth::id());
// Find and delete attached member from team folder
DB::table('team_folder_members')
->where('parent_id', $folder->id)
->where('user_id', auth()->id())
->delete();
return response('Done.', 204);
}