├── src ├── Http │ ├── Controllers │ │ ├── Users.php │ │ ├── Destroy.php │ │ ├── Store.php │ │ ├── Index.php │ │ └── Update.php │ ├── Resources │ │ ├── TaggedUser.php │ │ └── Comment.php │ └── Requests │ │ ├── ValidateCommentStore.php │ │ ├── ValidateCommentUpdate.php │ │ └── ValidateCommentFetch.php ├── Exceptions │ └── CommentConflict.php ├── AuthServiceProvider.php ├── Dynamics │ ├── CommentTags.php │ └── Comments.php ├── Traits │ └── Commentable.php ├── Policies │ └── Comment.php ├── AppServiceProvider.php ├── Models │ └── Comment.php └── Notifications │ └── CommentTagNotification.php ├── config └── comments.php ├── .styleci.yml ├── resources └── views │ └── emails │ └── tagged.blade.php ├── database ├── factories │ └── CommentFactory.php └── migrations │ ├── 2017_01_01_144000_create_structure_for_comments.php │ ├── 2017_01_01_143000_create_comment_user_pivot_table.php │ └── 2017_01_01_142000_create_comments_table.php ├── .github └── issue_template.md ├── routes └── api.php ├── codesize.xml ├── LICENSE ├── composer.json ├── README.md └── tests └── features └── CommentTest.php /src/Http/Controllers/Users.php: -------------------------------------------------------------------------------- 1 | 24 * 60 * 60, 5 | 'onDelete' => 'cascade', 6 | 'humanReadableDates' => true, 7 | 'loggableMorph' => [ 8 | 'commentable' => [], 9 | ], 10 | ]; 11 | -------------------------------------------------------------------------------- /.styleci.yml: -------------------------------------------------------------------------------- 1 | risky: true 2 | 3 | preset: laravel 4 | 5 | enabled: 6 | - strict 7 | - unalign_double_arrow 8 | - phpdoc_order 9 | - phpdoc_separation 10 | 11 | disabled: 12 | - short_array_syntax 13 | 14 | finder: 15 | exclude: 16 | - "public" 17 | - "resources" 18 | - "tests" 19 | name: 20 | - "*.php" 21 | -------------------------------------------------------------------------------- /src/Exceptions/CommentConflict.php: -------------------------------------------------------------------------------- 1 | $this->id, 13 | 'name' => $this->person->name, 14 | ]; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Http/Requests/ValidateCommentStore.php: -------------------------------------------------------------------------------- 1 | 'required', 15 | 'path' => 'required', 16 | 'taggedUsers' => 'array', 17 | ]; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/AuthServiceProvider.php: -------------------------------------------------------------------------------- 1 | Policy::class, 13 | ]; 14 | 15 | public function boot() 16 | { 17 | $this->registerPolicies(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Http/Requests/ValidateCommentUpdate.php: -------------------------------------------------------------------------------- 1 | 'required', 18 | 'path' => 'required', 19 | 'taggedUsers' => 'array', 20 | ]; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /resources/views/emails/tagged.blade.php: -------------------------------------------------------------------------------- 1 | @component('mail::message') 2 | {{ __('Hi :appellative', ['appellative' => $appellative]) }}, 3 | 4 | {{ __("You were just tagged in a comment:") }} 5 | 6 | @component('mail::panel') 7 | {{ $body }} 8 | @endcomponent 9 | 10 | {{ __('To view the full conversation click the button below.') }} 11 | 12 | @component('mail::button', ['url' => $url, 'color' => 'blue']) 13 | {{ __('View conversation') }} 14 | @endcomponent 15 | 16 | {{ __('Thank you') }},
17 | {{ __(config('app.name')) }} 18 | @endcomponent 19 | -------------------------------------------------------------------------------- /database/factories/CommentFactory.php: -------------------------------------------------------------------------------- 1 | $this->faker->randomKey, 16 | 'commentable_type' => $this->faker->word, 17 | 'body' => $this->faker->sentence, 18 | ]; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Http/Controllers/Destroy.php: -------------------------------------------------------------------------------- 1 | authorize('destroy', $comment); 16 | 17 | $comment->delete(); 18 | 19 | return ['count' => $comment->commentable->comments()->count()]; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Dynamics/CommentTags.php: -------------------------------------------------------------------------------- 1 | $user->belongsToMany(Comment::class); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Dynamics/Comments.php: -------------------------------------------------------------------------------- 1 | $user->hasMany(Comment::class, 'created_by'); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Http/Requests/ValidateCommentFetch.php: -------------------------------------------------------------------------------- 1 | 'required', 26 | 'commentable_type' => 'required|string', 27 | ]; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /.github/issue_template.md: -------------------------------------------------------------------------------- 1 | 2 | This is a **bug | feature request**. 3 | 4 | 5 | ### Prerequisites 6 | * [ ] Are you running the latest version? 7 | * [ ] Are you reporting to the correct repository? 8 | * [ ] Did you check the documentation? 9 | * [ ] Did you perform a cursory search? 10 | 11 | ### Description 12 | 13 | 14 | ### Steps to Reproduce 15 | 20 | 21 | ### Expected behavior 22 | 23 | 24 | ### Actual behavior 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /database/migrations/2017_01_01_144000_create_structure_for_comments.php: -------------------------------------------------------------------------------- 1 | 'core.comments.users', 'description' => 'Get taggable users options for select', 'is_default' => true], 9 | ['name' => 'core.comments.index', 'description' => 'List comments for commentable', 'is_default' => true], 10 | ['name' => 'core.comments.store', 'description' => 'Create comment', 'is_default' => true], 11 | ['name' => 'core.comments.update', 'description' => 'Update edited comment', 'is_default' => true], 12 | ['name' => 'core.comments.destroy', 'description' => 'Delete comment', 'is_default' => true], 13 | ]; 14 | }; 15 | -------------------------------------------------------------------------------- /routes/api.php: -------------------------------------------------------------------------------- 1 | prefix('api/core/comments') 12 | ->as('core.comments.') 13 | ->group(function () { 14 | Route::get('', Index::class)->name('index'); 15 | Route::post('', Store::class)->name('store'); 16 | Route::patch('{comment}', Update::class)->name('update'); 17 | Route::delete('{comment}', Destroy::class)->name('destroy'); 18 | 19 | Route::get('users', Users::class)->name('users'); 20 | }); 21 | -------------------------------------------------------------------------------- /src/Http/Controllers/Store.php: -------------------------------------------------------------------------------- 1 | fill($request->validatedExcept('taggedUsers', 'path')); 15 | 16 | tap($comment)->save() 17 | ->syncTags($request->get('taggedUsers')) 18 | ->notify($request->get('path')); 19 | 20 | return new Resource($comment->load([ 21 | 'createdBy.person', 'createdBy.avatar', 'taggedUsers.person', 22 | ])); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Http/Controllers/Index.php: -------------------------------------------------------------------------------- 1 | for($request->validated()) 16 | ->with('createdBy.person', 'createdBy.avatar', 'updatedBy', 'taggedUsers') 17 | ->get(); 18 | 19 | return Resource::collection($comments)->additional([ 20 | 'humanReadableDates' => Config::get('enso.comments.humanReadableDates'), 21 | ]); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /codesize.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | custom rules 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/Http/Controllers/Update.php: -------------------------------------------------------------------------------- 1 | authorize('update', $comment); 18 | 19 | tap($comment)->update($request->only('body')) 20 | ->syncTags($request->get('taggedUsers')) 21 | ->notify($request->get('path')); 22 | 23 | return new Resource($comment->load([ 24 | 'createdBy.person', 'createdBy.avatar', 'updatedBy', 'taggedUsers.person', 25 | ])); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /database/migrations/2017_01_01_143000_create_comment_user_pivot_table.php: -------------------------------------------------------------------------------- 1 | integer('comment_id')->unsigned()->index(); 13 | $table->foreign('comment_id')->references('id')->on('comments') 14 | ->onDelete('cascade'); 15 | 16 | $table->integer('user_id')->unsigned()->index(); 17 | $table->foreign('user_id')->references('id')->on('users') 18 | ->onDelete('cascade'); 19 | 20 | $table->primary(['comment_id', 'user_id']); 21 | }); 22 | } 23 | 24 | public function down() 25 | { 26 | Schema::drop('comment_user'); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /database/migrations/2017_01_01_142000_create_comments_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 13 | 14 | $table->morphs('commentable'); 15 | 16 | $table->text('body'); 17 | 18 | $table->integer('created_by')->unsigned()->nullable()->index(); 19 | $table->foreign('created_by')->references('id')->on('users'); 20 | 21 | $table->integer('updated_by')->unsigned()->nullable(); 22 | $table->foreign('updated_by')->references('id')->on('users'); 23 | 24 | $table->timestamps(); 25 | }); 26 | } 27 | 28 | public function down() 29 | { 30 | Schema::dropIfExists('comments'); 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /src/Http/Resources/Comment.php: -------------------------------------------------------------------------------- 1 | $this->id, 14 | 'body' => $this->body, 15 | 'owner' => new User($this->whenLoaded('createdBy')), 16 | 'taggedUsers' => TaggedUser::collection($this->whenLoaded('taggedUsers')), 17 | 'isEditable' => $this->isEditable($request), 18 | 'isDeletable' => $this->isDeletable($request), 19 | 'createdAt' => $this->created_at->toDatetimeString(), 20 | 'updatedAt' => $this->updated_at->toDatetimeString(), 21 | ]; 22 | } 23 | 24 | public function isEditable($request) 25 | { 26 | return $request->user()->can('update', $this->resource); 27 | } 28 | 29 | public function isDeletable($request) 30 | { 31 | return $request->user()->can('destroy', $this->resource); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 laravel-enso 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/Traits/Commentable.php: -------------------------------------------------------------------------------- 1 | $model->attemptCommentableDeletion()); 14 | 15 | self::deleted(fn ($model) => $model->cascadeCommentDeletion()); 16 | } 17 | 18 | public function comment() 19 | { 20 | return $this->morphOne(Comment::class, 'commentable'); 21 | } 22 | 23 | public function comments() 24 | { 25 | return $this->morphMany(Comment::class, 'commentable'); 26 | } 27 | 28 | private function attemptCommentableDeletion() 29 | { 30 | $restricted = Config::get('enso.comments.onDelete') === 'restrict'; 31 | 32 | if ($restricted && $this->comments()->exists()) { 33 | throw CommentConflict::delete(); 34 | } 35 | } 36 | 37 | private function cascadeCommentDeletion() 38 | { 39 | if (Config::get('enso.comments.onDelete') === 'cascade') { 40 | $this->comments()->delete(); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Policies/Comment.php: -------------------------------------------------------------------------------- 1 | isSuperior()) { 18 | return true; 19 | } 20 | } 21 | 22 | public function update(User $user, Model $comment) 23 | { 24 | return $this->ownsComment($user, $comment) 25 | && $this->isRecent($comment); 26 | } 27 | 28 | public function destroy(User $user, Model $comment) 29 | { 30 | return $this->ownsComment($user, $comment) 31 | && $this->isRecent($comment); 32 | } 33 | 34 | private function ownsComment(User $user, Model $comment) 35 | { 36 | return $user->id === (int) $comment->created_by; 37 | } 38 | 39 | private function isRecent(Model $comment) 40 | { 41 | return (int) $comment->created_at->diffInSeconds(Carbon::now(), true) 42 | < Config::get('enso.comments.editableTimeLimit'); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/AppServiceProvider.php: -------------------------------------------------------------------------------- 1 | load() 12 | ->publish(); 13 | } 14 | 15 | private function load() 16 | { 17 | $this->mergeConfigFrom(__DIR__.'/../config/comments.php', 'enso.comments'); 18 | 19 | $this->loadRoutesFrom(__DIR__.'/../routes/api.php'); 20 | 21 | $this->loadMigrationsFrom(__DIR__.'/../database/migrations'); 22 | 23 | $this->loadViewsFrom(__DIR__.'/../resources/views', 'laravel-enso/comments'); 24 | 25 | return $this; 26 | } 27 | 28 | private function publish() 29 | { 30 | $this->publishes([ 31 | __DIR__.'/../config' => config_path('enso'), 32 | ], ['comments-config', 'enso-config']); 33 | 34 | $this->publishes([ 35 | __DIR__.'/../resources/views' => resource_path('views/vendor/laravel-enso/comments'), 36 | ], ['comments-mail', 'enso-mail']); 37 | 38 | $this->publishes([ 39 | __DIR__.'/../database/factories' => database_path('factories'), 40 | ], ['comments-factory', 'enso-factories']); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "laravel-enso/comments", 3 | "description": "Comments Manager for Laravel Enso", 4 | "keywords": [ 5 | "laravel-enso", 6 | "comments", 7 | "comments-manager", 8 | "comments" 9 | ], 10 | "homepage": "https://github.com/laravel-enso/comments", 11 | "type": "library", 12 | "license": "MIT", 13 | "authors": [ 14 | { 15 | "name": "Adrian Ocneanu", 16 | "email": "aocneanu@gmail.com", 17 | "homepage": "https://laravel-enso.com", 18 | "role": "Developer" 19 | } 20 | ], 21 | "require": { 22 | "laravel-enso/core": "^10.0", 23 | "laravel-enso/dynamic-methods": "^3.0", 24 | "laravel-enso/helpers": "^3.0", 25 | "laravel-enso/migrator": "^2.1", 26 | "laravel-enso/track-who": "^2.0" 27 | }, 28 | "autoload": { 29 | "psr-4": { 30 | "LaravelEnso\\Comments\\": "src/", 31 | "LaravelEnso\\Comments\\Database\\Factories\\": "database/factories/" 32 | } 33 | }, 34 | "extra": { 35 | "laravel": { 36 | "providers": [ 37 | "LaravelEnso\\Comments\\AppServiceProvider", 38 | "LaravelEnso\\Comments\\AuthServiceProvider" 39 | ], 40 | "aliases": [] 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Models/Comment.php: -------------------------------------------------------------------------------- 1 | morphTo(); 26 | } 27 | 28 | public function taggedUsers() 29 | { 30 | return $this->belongsToMany(User::class); 31 | } 32 | 33 | public function scopeFor(Builder $query, array $params): Builder 34 | { 35 | return $query->whereCommentableId($params['commentable_id']) 36 | ->whereCommentableType($params['commentable_type']); 37 | } 38 | 39 | public function syncTags(array $taggedUsers) 40 | { 41 | $this->taggedUsers()->sync( 42 | Collection::wrap($taggedUsers)->pluck('id') 43 | ); 44 | 45 | return $this; 46 | } 47 | 48 | public function notify(string $path) 49 | { 50 | $this->taggedUsers->each 51 | ->notify((new CommentTagNotification($this->body, $path)) 52 | ->onQueue('notifications')); 53 | } 54 | 55 | public function getLoggableMorph() 56 | { 57 | return config('enso.comments.loggableMorph'); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Notifications/CommentTagNotification.php: -------------------------------------------------------------------------------- 1 | 'info', 31 | 'title' => __('New Comment Tag'), 32 | 'icon' => 'comment', 33 | 'body' => __('You were just tagged').': '.$this->body, 34 | ]); 35 | } 36 | 37 | public function toMail($notifiable) 38 | { 39 | $app = Config::get('app.name'); 40 | 41 | return (new MailMessage()) 42 | ->subject("[ {$app} ] {$this->subject()}") 43 | ->markdown('laravel-enso/comments::emails.tagged', [ 44 | 'appellative' => $notifiable->person->appellative(), 45 | 'body' => $this->body, 46 | 'url' => url($this->path), 47 | ]); 48 | } 49 | 50 | public function toArray() 51 | { 52 | return [ 53 | 'body' => $this->body, 54 | 'path' => $this->path, 55 | 'icon' => 'comment', 56 | ]; 57 | } 58 | 59 | private function subject(): string 60 | { 61 | return __('Comment Tag Notification'); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Comments 2 | 3 | [![Codacy Badge](https://app.codacy.com/project/badge/Grade/5510612164da41249665f892c88cffff)](https://www.codacy.com/gh/laravel-enso/comments?utm_source=github.com&utm_medium=referral&utm_content=laravel-enso/comments&utm_campaign=Badge_Grade) 4 | [![StyleCI](https://github.styleci.io/repos/85583597/shield?branch=master)](https://github.styleci.io/repos/85583597) 5 | [![License](https://poser.pugx.org/laravel-enso/comments/license)](https://packagist.org/packages/laravel-enso/comments) 6 | [![Total Downloads](https://poser.pugx.org/laravel-enso/comments/downloads)](https://packagist.org/packages/laravel-enso/comments) 7 | [![Latest Stable Version](https://poser.pugx.org/laravel-enso/comments/version)](https://packagist.org/packages/laravel-enso/comments) 8 | 9 | Comments Manager for [Laravel Enso](https://github.com/laravel-enso/Enso). 10 | 11 | This package works exclusively within the [Enso](https://github.com/laravel-enso/Enso) ecosystem. 12 | 13 | There is a front end implementation for this this api in the [accessories](https://github.com/enso-ui/accessories) package. 14 | 15 | For live examples and demos, you may visit [laravel-enso.com](https://www.laravel-enso.com) 16 | 17 | [![Watch the demo](https://laravel-enso.github.io/comments/screenshots/bulma_018_thumb.png)](https://laravel-enso.github.io/comments/videos/bulma_demo_01.webm) 18 | 19 | click on the photo to view a short demo in compatible browsers 20 | 21 | ### Installation, Configuration & Usage 22 | 23 | Be sure to check out the full documentation for this package available at [docs.laravel-enso.com](https://docs.laravel-enso.com/backend/comments.html) 24 | 25 | ### Contributions 26 | 27 | are welcome. Pull requests are great, but issues are good too. 28 | 29 | ### License 30 | 31 | This package is released under the MIT license. 32 | # Comments 33 | 34 | [![Codacy Badge](https://api.codacy.com/project/badge/Grade/d96ab52d782d46b9a94e00ea6059b34c)](https://www.codacy.com/app/laravel-enso/comments?utm_source=github.com&utm_medium=referral&utm_content=laravel-enso/comments&utm_campaign=Badge_Grade) 35 | [![StyleCI](https://github.styleci.io/repos/85583597/shield?branch=master)](https://github.styleci.io/repos/85583597) 36 | [![License](https://poser.pugx.org/laravel-enso/comments/license)](https://packagist.org/packages/laravel-enso/comments) 37 | [![Total Downloads](https://poser.pugx.org/laravel-enso/comments/downloads)](https://packagist.org/packages/laravel-enso/comments) 38 | [![Latest Stable Version](https://poser.pugx.org/laravel-enso/comments/version)](https://packagist.org/packages/laravel-enso/comments) 39 | 40 | Comments Manager for [Laravel Enso](https://github.com/laravel-enso/Enso). 41 | 42 | This package works exclusively within the [Enso](https://github.com/laravel-enso/Enso) ecosystem. 43 | 44 | There is a front end implementation for this this api in the [accessories](https://github.com/enso-ui/accessories) package. 45 | 46 | For live examples and demos, you may visit [laravel-enso.com](https://www.laravel-enso.com) 47 | 48 | [![Watch the demo](https://laravel-enso.github.io/comments/screenshots/bulma_018_thumb.png)](https://laravel-enso.github.io/comments/videos/bulma_demo_01.webm) 49 | 50 | click on the photo to view a short demo in compatible browsers 51 | 52 | ### Installation, Configuration & Usage 53 | 54 | Be sure to check out the full documentation for this package available at [docs.laravel-enso.com](https://docs.laravel-enso.com/backend/comments.html) 55 | 56 | ### Contributions 57 | 58 | are welcome. Pull requests are great, but issues are good too. 59 | 60 | ### License 61 | 62 | This package is released under the MIT license. 63 | -------------------------------------------------------------------------------- /tests/features/CommentTest.php: -------------------------------------------------------------------------------- 1 | seed() 27 | ->actingAs($this->user = User::first()); 28 | 29 | $this->createTestTable(); 30 | 31 | $this->faker = Factory::create(); 32 | 33 | $this->testModel = Comment::factory()->create([ 34 | 'commentable_id' => CommentableTestModel::create(['name' => 'commentable'])->id, 35 | 'commentable_type' => CommentableTestModel::class, 36 | ]); 37 | } 38 | 39 | /** @test */ 40 | public function can_create_comment() 41 | { 42 | $this->post( 43 | route('core.comments.store'), 44 | $this->postParams()->toArray() + [ 45 | 'taggedUsers' => [], 46 | 'path' => $this->faker->url, 47 | ] 48 | )->assertStatus(201) 49 | ->assertJsonStructure(['body']); 50 | } 51 | 52 | /** @test */ 53 | public function can_get_comments_index() 54 | { 55 | $this->get(route('core.comments.index', $this->testModel->toArray(), false)) 56 | ->assertStatus(200) 57 | ->assertJsonStructure(['data' => 'data']); 58 | } 59 | 60 | /** @test */ 61 | public function can_update_comment() 62 | { 63 | $this->testModel->body = 'edited'; 64 | 65 | $this->patch( 66 | route('core.comments.update', $this->testModel->id, false), 67 | $this->testModel->toArray() + [ 68 | 'taggedUsers' => [], 69 | 'path' => $this->faker->url, 70 | ] 71 | )->assertStatus(200) 72 | ->assertJsonFragment(['body' => $this->testModel->body]); 73 | 74 | $this->assertEquals( 75 | $this->testModel->body, 76 | $this->testModel->fresh()->body 77 | ); 78 | } 79 | 80 | /** @test */ 81 | public function can_delete_comment() 82 | { 83 | $this->assertNotNull($this->testModel); 84 | 85 | $this->delete(route('core.comments.destroy', $this->testModel->id, false)) 86 | ->assertStatus(200); 87 | 88 | $this->assertNull($this->testModel->fresh()); 89 | } 90 | 91 | /** @test */ 92 | public function can_store_with_tagged_user() 93 | { 94 | Notification::fake(); 95 | 96 | $taggedUser = User::factory()->create(); 97 | 98 | $taggedUsers = [[ 99 | 'id' => $taggedUser->id, 100 | 'name' => $taggedUser->person->name, 101 | ]]; 102 | 103 | $response = $this->post( 104 | route('core.comments.store', [], false), 105 | $this->postParams()->toArray() + [ 106 | 'taggedUsers' => $taggedUsers, 107 | 'path' => $this->faker->url, 108 | ] 109 | )->assertStatus(201) 110 | ->assertJsonFragment(['taggedUsers' => $taggedUsers]); 111 | 112 | $commentId = $response->json()['id']; 113 | 114 | $this->assertEquals( 115 | Comment::find($commentId)->taggedUsers()->first()->id, 116 | $taggedUser->id 117 | ); 118 | 119 | Notification::assertSentTo( 120 | User::find($taggedUser->id), 121 | CommentTagNotification::class 122 | ); 123 | } 124 | 125 | /** @test */ 126 | public function can_update_with_tagged_user() 127 | { 128 | Notification::fake(); 129 | 130 | $taggedUser = User::factory()->create(); 131 | 132 | $this->testModel->body = 'edited'; 133 | 134 | $taggedUsers = [[ 135 | 'id' => $taggedUser->id, 136 | 'name' => $taggedUser->person->name, 137 | ]]; 138 | 139 | $this->patch( 140 | route('core.comments.update', [$this->testModel->id], false), 141 | $this->testModel->toArray() + [ 142 | 'taggedUsers' => $taggedUsers, 143 | 'path' => $this->faker->url, 144 | ] 145 | )->assertStatus(200) 146 | ->assertJsonFragment(['taggedUsers' => $taggedUsers]); 147 | 148 | $this->assertEquals( 149 | $this->testModel->taggedUsers()->first()->id, 150 | $taggedUser->id 151 | ); 152 | 153 | Notification::assertSentTo( 154 | User::find($taggedUser->id), 155 | CommentTagNotification::class 156 | ); 157 | } 158 | 159 | private function createTestTable() 160 | { 161 | Schema::create('commentable_test_models', function ($table) { 162 | $table->increments('id'); 163 | $table->string('name'); 164 | $table->timestamps(); 165 | }); 166 | } 167 | 168 | private function postParams() 169 | { 170 | return Comment::factory()->make([ 171 | 'commentable_id' => CommentableTestModel::create(['name' => 'commentable'])->id, 172 | 'commentable_type' => CommentableTestModel::class, 173 | ]); 174 | } 175 | } 176 | 177 | class CommentableTestModel extends Model 178 | { 179 | use Commentable; 180 | 181 | protected $fillable = ['name']; 182 | } 183 | --------------------------------------------------------------------------------