create team folder

This commit is contained in:
Peter Papp
2021-08-24 10:58:03 +02:00
parent fdd9c5a591
commit ca1d037975
20 changed files with 317 additions and 23 deletions

View File

@@ -28,6 +28,7 @@
"laravel/ui": "^3.2.0",
"league/flysystem-aws-s3-v3": "^1.0.29",
"league/flysystem-cached-adapter": "^1.1.0",
"spatie/data-transfer-object": "^3.6",
"spatie/laravel-backup": "^6.16.1",
"spatie/laravel-query-builder": "^3.5",
"spatie/laravel-queueable-action": "^2.12",

68
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "3c897439f8ef41534a743d4a05020502",
"content-hash": "b97469c2ea6b8b1e89c432391ec6ffc2",
"packages": [
{
"name": "amphp/amp",
@@ -7390,6 +7390,72 @@
],
"time": "2020-09-28T06:39:44+00:00"
},
{
"name": "spatie/data-transfer-object",
"version": "3.6.1",
"source": {
"type": "git",
"url": "https://github.com/spatie/data-transfer-object.git",
"reference": "2dd4e4d5e758b5892e6219bc444a9f38ad77c5af"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/data-transfer-object/zipball/2dd4e4d5e758b5892e6219bc444a9f38ad77c5af",
"reference": "2dd4e4d5e758b5892e6219bc444a9f38ad77c5af",
"shasum": ""
},
"require": {
"php": "^8.0"
},
"require-dev": {
"illuminate/collections": "^8.36",
"jetbrains/phpstorm-attributes": "^1.0",
"larapack/dd": "^1.1",
"phpunit/phpunit": "^9.0"
},
"suggest": {
"phpstan/phpstan": "Take advantage of checkUninitializedProperties with \\Spatie\\DataTransferObject\\PHPstan\\PropertiesAreAlwaysInitializedExtension"
},
"type": "library",
"autoload": {
"psr-4": {
"Spatie\\DataTransferObject\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Brent Roose",
"email": "brent@spatie.be",
"homepage": "https://spatie.be",
"role": "Developer"
}
],
"description": "Data transfer objects with batteries included",
"homepage": "https://github.com/spatie/data-transfer-object",
"keywords": [
"data-transfer-object",
"spatie"
],
"support": {
"issues": "https://github.com/spatie/data-transfer-object/issues",
"source": "https://github.com/spatie/data-transfer-object/tree/3.6.1"
},
"funding": [
{
"url": "https://spatie.be/open-source/support-us",
"type": "custom"
},
{
"url": "https://github.com/spatie",
"type": "github"
}
],
"time": "2021-08-17T03:36:52+00:00"
},
{
"name": "spatie/db-dumper",
"version": "2.21.1",

View File

@@ -21,6 +21,8 @@ class CreateFileManagerFolders extends Migration
$table->string('color')->nullable();
$table->longText('emoji')->nullable();
$table->boolean('team_folder')->default(0);
$table->enum('author', ['user', 'member', 'visitor'])->default('user');
$table->uuid('author_id')->nullable();

View File

@@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateTeamFoldersInvitationsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('team_folders_invitations', function (Blueprint $table) {
$table->uuid('id')->primary();
$table->uuid('folder_id');
$table->text('email');
$table->enum('status', ['pending', 'accepted', 'rejected'])->default('pending');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('invitations');
}
}

View File

@@ -11,6 +11,7 @@ use App\Users\Controllers\ForgotPasswordController;
use Domain\Folders\Controllers\FavouriteController;
use Domain\Plans\Controllers\ActivePlansController;
use Domain\Folders\Controllers\CreateFolderController;
use Domain\Browsing\Controllers\BrowseFolderController;
use Domain\Sharing\Controllers\ShareViaEmailController;
use Domain\Items\Controllers\MoveFileOrFolderController;
use Domain\Items\Controllers\DeleteFileOrFolderController;
@@ -21,7 +22,6 @@ use Domain\Browsing\Controllers\BrowseLatestFilesController;
use Domain\Browsing\Controllers\BrowseSharedItemsController;
use Domain\Browsing\Controllers\BrowseTrashContentController;
use Domain\Homepage\Controllers\SendContactMessageController;
use Domain\Browsing\Controllers\BrowseFolderController;
use Domain\Folders\Controllers\NavigationFolderTreeController;
use Domain\Browsing\Controllers\SearchFilesAndFoldersController;

View File

@@ -6,11 +6,11 @@ use Domain\Files\Controllers\VisitorShowFileController;
use Domain\Files\Controllers\VisitorUploadFileController;
use Domain\Folders\Controllers\VisitorCreateFolderController;
use Domain\Sharing\Controllers\WebCrawlerOpenGraphController;
use Domain\Browsing\Controllers\VisitorBrowseFolderController;
use Domain\Items\Controllers\VisitorMoveFileOrFolderController;
use Domain\Items\Controllers\VisitorDeleteFileOrFolderController;
use Domain\Items\Controllers\VisitorRenameFileOrFolderController;
use Domain\Sharing\Controllers\VisitorUnlockLockedShareController;
use Domain\Browsing\Controllers\VisitorBrowseFolderController;
use Domain\Folders\Controllers\VisitorNavigationFolderTreeController;
use Domain\Browsing\Controllers\VisitorSearchFilesAndFoldersController;

5
routes/teams.php Normal file
View File

@@ -0,0 +1,5 @@
<?php
use Domain\Teams\Controllers\TeamFoldersController;
Route::apiResource('/team-folders', TeamFoldersController::class);

View File

@@ -43,6 +43,8 @@ class RouteServiceProvider extends ServiceProvider
$this->mapFileRoutes();
$this->mapTeamsRoutes();
$this->mapWebRoutes();
}
@@ -106,6 +108,13 @@ class RouteServiceProvider extends ServiceProvider
->group(base_path('routes/user.php'));
}
protected function mapTeamsRoutes()
{
Route::prefix('api/teams')
->middleware(['api', 'auth:sanctum'])
->group(base_path('routes/teams.php'));
}
protected function mapSetupWizardApiRoutes()
{
Route::middleware(['setup-wizard'])

View File

@@ -24,7 +24,7 @@ use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
/**
* @property mixed id
* @property string id
* @property Setting settings
* @property string email
* @property mixed favouriteFolders
@@ -34,6 +34,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsToMany;
* @method static forceCreate(array $array)
* @method static where(string $string, string $string1, string $toDateString)
* @method static create(array $array)
* @method static find(mixed $email)
*/
class User extends Authenticatable implements MustVerifyEmail
{

View File

@@ -4,7 +4,6 @@ namespace Domain\Browsing\Controllers;
use Illuminate\Http\Request;
use Domain\Files\Models\File;
use Domain\Folders\Models\Folder;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Auth;
class BrowseFolderController

View File

@@ -14,7 +14,6 @@ class BrowseTrashContentController
$requestedFolder = $root_id ? Folder::withTrashed()->findOrFail($root_id) : null;
if ($root_id) {
// Get folders and files
$folders = Folder::onlyTrashed()
->with('parent')

View File

@@ -4,7 +4,6 @@ namespace Domain\Browsing\Controllers;
use Domain\Files\Models\File;
use Domain\Sharing\Models\Share;
use Domain\Folders\Models\Folder;
use Illuminate\Support\Collection;
use Domain\Sharing\Actions\ProtectShareRecordAction;
use Domain\Sharing\Actions\VerifyAccessToItemAction;
@@ -23,7 +22,6 @@ class VisitorBrowseFolderController
string $id,
Share $shared,
): array {
// Check ability to access protected share record
($this->protectShareRecord)($shared);

View File

@@ -20,6 +20,7 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
* @method static find(mixed $id)
* @method static where(string $string, string $user_id)
* @method static findOrFail(string $root_id)
* @method static create(array $array)
* @property string id
* @property string user_id
* @property string parent_id
@@ -31,6 +32,7 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
* @property string created_at
* @property string updated_at
* @property string deleted_at
* @property bool team_folder
*/
class Folder extends Model
{

View File

@@ -3,7 +3,7 @@ namespace Domain\Sharing\Actions;
use Spatie\QueueableAction\QueueableAction;
use Illuminate\Support\Facades\Notification;
use Domain\Sharing\Notifications\SharedSendViaEmail;
use Domain\Teams\Notifications\SharedSendViaEmail;
class SendViaEmailAction
{

View File

@@ -0,0 +1,41 @@
<?php
namespace Domain\Teams\Controllers;
use Illuminate\Http\Request;
use Domain\Folders\Models\Folder;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Response;
use Domain\Teams\DTO\CreateTeamFolderData;
use Illuminate\Support\Facades\Notification;
use Domain\Teams\Models\TeamFoldersInvitation;
use Domain\Teams\Notifications\InvitationIntoTeamFolder;
class TeamFoldersController extends Controller
{
public function store(Request $request): Response
{
$data = CreateTeamFolderData::fromRequest($request);
$teamFolder = Folder::create([
'user_id' => $request->user()->id,
'name' => $data->name,
'team_folder' => 1,
]);
collect($data->members)
->each(function ($email) use ($teamFolder) {
// Create invitation
$invitation = TeamFoldersInvitation::create([
'folder_id' => $teamFolder->id,
'email' => $email,
]);
// Invite user
Notification::route('mail', $email)
->notify(new InvitationIntoTeamFolder($teamFolder, $invitation));
});
return response($teamFolder, 201);
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace Domain\Teams\DTO;
use Spatie\DataTransferObject\DataTransferObject;
class CreateTeamFolderData extends DataTransferObject
{
public string $name;
public array $members;
public static function fromRequest($request): self
{
return new self([
'name' => $request->input('name'),
'members' => $request->input('members'),
]);
}
}

View File

@@ -0,0 +1,39 @@
<?php
namespace Domain\Teams\Models;
use Illuminate\Support\Str;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
/**
* @method static create(array $array)
* @property string id
* @property string folder_id
* @property string email
* @property string status
* @property string created_at
* @property string updated_at
*/
class TeamFoldersInvitation extends Model
{
use HasFactory;
protected $casts = [
'id' => 'string',
];
protected $guarded = ['id'];
public $incrementing = false;
protected $keyType = 'string';
protected static function boot()
{
parent::boot();
static::creating(function ($model) {
$model->id = Str::uuid();
});
}
}

View File

@@ -0,0 +1,54 @@
<?php
namespace Domain\Teams\Notifications;
use App\Users\Models\User;
use Illuminate\Bus\Queueable;
use Domain\Folders\Models\Folder;
use Illuminate\Notifications\Notification;
use Domain\Teams\Models\TeamFoldersInvitation;
use Illuminate\Notifications\Messages\MailMessage;
class InvitationIntoTeamFolder extends Notification
{
use Queueable;
public function __construct(
public Folder $teamFolder,
public TeamFoldersInvitation $invitation,
) {
}
/**
* Get the notification's delivery channels.
*/
public function via(): array
{
return ['mail'];
}
/**
* Get the mail representation of the notification.
*/
public function toMail(): MailMessage
{
$appTitle = get_settings('app_title') ?? 'VueFileManager';
$user = User::find($this->invitation->email);
if ($user) {
return (new MailMessage)
->subject("You are invited to collaboration with team folder in $appTitle")
->greeting('Hello!')
->line('You are invited to collaboration with team folder')
->action('Join into Team Folder', url('/team-folder-invitation', ['id' => $this->invitation->id]))
->salutation("Regards, $appTitle");
}
return (new MailMessage)
->subject("You are invited to collaboration with team folder in $appTitle")
->greeting('Hello!')
->line('You are invited to collaboration with team folder. But at first, you have to create an account to proceed into team folder.')
->action('Join & Create an Account', url('/team-folder-invitation', ['id' => $this->invitation->id]))
->salutation("Regards, $appTitle");
}
}

View File

@@ -7,7 +7,7 @@ use Laravel\Sanctum\Sanctum;
use Domain\Files\Models\File;
use Domain\Folders\Models\Folder;
use Illuminate\Support\Facades\Notification;
use Domain\Sharing\Notifications\SharedSendViaEmail;
use Domain\Teams\Notifications\SharedSendViaEmail;
class UserShareTest extends TestCase
{

View File

@@ -1,19 +1,54 @@
<?php
namespace Tests\Domain\Teams;
use Notification;
use Tests\TestCase;
use App\Users\Models\User;
use Domain\Teams\Notifications\InvitationIntoTeamFolder;
class TeamsTest extends TestCase
{
/**
* @test
*
*/
public function it_create_team_folder()
{
User::factory(User::class)
->create([
'email' => 'john@internal.com',
]);
$user = User::factory()
->create();
$this
->actingAs($user)
->post('/api/teams/team-folders', [
'name' => 'Company Project',
'members' => [
'john@internal.com',
'jane@external.com',
],
])
->assertCreated()
->assertJsonFragment([
'name' => 'Company Project',
]);
$this
->assertDatabaseHas('folders', [
'name' => 'Company Project',
'team_folder' => 1,
])
->assertDatabaseHas('team_folders_invitations', [
'email' => 'john@internal.com',
])
->assertDatabaseHas('team_folders_invitations', [
'email' => 'jane@external.com',
]);
Notification::assertTimesSent(2, InvitationIntoTeamFolder::class);
}
/**
@@ -21,7 +56,6 @@ class TeamsTest extends TestCase
*/
public function it_convert_team_folder()
{
}
/**
@@ -29,7 +63,6 @@ class TeamsTest extends TestCase
*/
public function it_add_member_into_team_folder()
{
}
/**
@@ -37,7 +70,6 @@ class TeamsTest extends TestCase
*/
public function member_accept_team_folder_invite()
{
}
/**
@@ -45,7 +77,6 @@ class TeamsTest extends TestCase
*/
public function member_reject_team_folder_invite()
{
}
/**
@@ -53,7 +84,6 @@ class TeamsTest extends TestCase
*/
public function it_remove_member_from_team_folder()
{
}
/**
@@ -61,7 +91,6 @@ class TeamsTest extends TestCase
*/
public function it_dissolve_team_folder()
{
}
/**
@@ -69,7 +98,6 @@ class TeamsTest extends TestCase
*/
public function it_move_items_into_team_folder()
{
}
/**
@@ -77,7 +105,6 @@ class TeamsTest extends TestCase
*/
public function it_get_all_team_folders()
{
}
/**
@@ -85,6 +112,5 @@ class TeamsTest extends TestCase
*/
public function it_get_team_folders_shared_with_another_user()
{
}
}
}