Skip to content

Commit

Permalink
initial implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
BobbyBorisov authored and joedixon committed Nov 24, 2019
1 parent 6da1775 commit ea92bd3
Show file tree
Hide file tree
Showing 15 changed files with 357 additions and 2 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ Homestead.yaml
.env
/aliases
/after.sh
.phpunit.result.cache
.phpunit.result.cache
10 changes: 10 additions & 0 deletions app/Exceptions/CannotLikeReplyTwice.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace App\Exceptions;

use Exception;

class CannotLikeReplyTwice extends Exception
{

}
47 changes: 47 additions & 0 deletions app/Helpers/HasLikes.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php
/**
* Created by PhpStorm.
* User: bobbyborisov
* Date: 12/3/17
* Time: 1:51 PM
*/

namespace App\Helpers;

use App\Models\Like;
use App\User;

trait HasLikes
{
protected static function bootHasLikes()
{
static::deleting(function ($model){
$model->likes->each->delete();
});
}

public function likedBy(User $user)
{
$this->likes()->create(['user_id' => $user->id]);
}

public function dislikedBy(User $user)
{
$this->likes()->where('user_id', $user->id)->get()->first()->delete();
}

public function likes()
{
return $this->morphMany(Like::class, 'liked');
}

public function isLikedBy(User $user)
{
return $this->likes()->where('user_id', $user->id)->exists();
}

public function getLikesCountAttribute()
{
return $this->likes->count();
}
}
16 changes: 16 additions & 0 deletions app/Http/Controllers/ReplyController.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
use App\Http\Middleware\RedirectIfUnconfirmed;
use App\Http\Requests\CreateReplyRequest;
use App\Http\Requests\UpdateReplyRequest;
use App\Jobs\DislikeReply;
use App\Jobs\LikeReply;
use App\Jobs\CreateReply;
use App\Jobs\DeleteReply;
use App\Jobs\UpdateReply;
Expand Down Expand Up @@ -62,6 +64,20 @@ public function delete(Reply $reply)
return $this->redirectToReplyAble($reply->replyAble());
}

public function like(Reply $reply)
{
$this->dispatchNow(new LikeReply($reply, auth()->user()));

return back();
}

public function dislike(Reply $reply)
{
$this->dispatchNow(new DislikeReply($reply, auth()->user()));

return back();
}

private function redirectToReplyAble(ReplyAble $replyAble): RedirectResponse
{
if ($replyAble instanceof Thread) {
Expand Down
48 changes: 48 additions & 0 deletions app/Jobs/DislikeReply.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

namespace App\Jobs;

use App\Models\Reply;
use App\User;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;

class DislikeReply implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

/**
* @var \App\Models\Reply
*/
private $reply;

/**
* @var \App\Jobs\User
*/
private $user;

/**
* Create a new job instance.
*
* @param \App\Models\Reply $reply
* @param \App\Jobs\User $user
*/
public function __construct(Reply $reply, User $user)
{
$this->reply = $reply;
$this->user = $user;
}

/**
* Execute the job.
*
* @return void
*/
public function handle()
{
$this->reply->dislikedBy($this->user);
}
}
55 changes: 55 additions & 0 deletions app/Jobs/LikeReply.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

namespace App\Jobs;

use App\Exceptions\CannotLikeReplyTwice;
use App\Models\Reply;
use App\User;
use Illuminate\Bus\Queueable;
use Illuminate\Database\QueryException;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;

class LikeReply implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

/**
* @var \App\Models\Reply
*/
private $reply;

/**
* @var \App\User
*/
private $user;

/**
* Create a new job instance.
*
* @param \App\Models\Reply $reply
* @param \App\User $user
*/
public function __construct(Reply $reply, User $user)
{
$this->reply = $reply;
$this->user = $user;
}

/**
* Execute the job.
*
* @return void
* @throws \App\Exceptions\CannotLikeReplyTwice
*/
public function handle()
{
try {
$this->reply->likedBy($this->user);
} catch (QueryException $exception) {
throw new CannotLikeReplyTwice('Sorry, you cannot like a reply twice');
}
}
}
10 changes: 10 additions & 0 deletions app/Models/Like.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Like extends Model
{
protected $fillable = ['user_id'];
}
8 changes: 7 additions & 1 deletion app/Models/Reply.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace App\Models;

use App\Helpers\HasAuthor;
use App\Helpers\HasLikes;
use App\Helpers\HasTimestamps;
use App\Helpers\ModelHelpers;
use Illuminate\Database\Eloquent\Model;
Expand All @@ -11,7 +12,8 @@

final class Reply extends Model
{
use HasAuthor, HasTimestamps, ModelHelpers;
use HasLikes,
HasAuthor, HasTimestamps, ModelHelpers;

/**
* {@inheritdoc}
Expand All @@ -25,6 +27,10 @@ final class Reply extends Model
'body',
];

protected $with = ['likes'];

protected $appends = ['likes_count'];

public function id(): int
{
return $this->id;
Expand Down
36 changes: 36 additions & 0 deletions database/migrations/2017_12_03_111900_create_likes_table.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateLikesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('likes', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('user_id');
$table->unsignedInteger('liked_id');
$table->string('liked_type');
$table->timestamps();

$table->unique(['user_id', 'liked_id' , 'liked_type']);
});
}

/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('likes');
}
}
13 changes: 13 additions & 0 deletions resources/views/forum/threads/show.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,19 @@
</div>
</div>
</div>
@endcan
<div class="thread-info-likes">
@if(!$reply->isLikedBy(auth()->user()))
{{ Form::open(['route' => ['replies.like', $reply], 'method' => 'PUT']) }}
<span>{{$reply->likes_count}}</span>
{{ Form::submit('like', ['class' => 'btn btn-xs btn-success']) }}
{{ Form::close() }}
@else
{{ Form::open(['route' => ['replies.dislike', $reply], 'method' => 'DELETE']) }}
<span>{{$reply->likes_count}}</span>
{{ Form::submit('dislike', ['class' => 'btn btn-xs btn-danger']) }}
{{ Form::close() }}
@endif
</div>
</div>

Expand Down
2 changes: 2 additions & 0 deletions routes/web.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@
Route::get('replies/{reply}/edit', 'ReplyController@edit')->name('replies.edit');
Route::put('replies/{reply}', 'ReplyController@update')->name('replies.update');
Route::delete('replies/{reply}', 'ReplyController@delete')->name('replies.delete');
Route::put('replies/{reply}/like', ['as' => 'replies.like', 'uses' => 'ReplyController@like']);
Route::delete('replies/{reply}/dislike', ['as' => 'replies.dislike', 'uses' => 'ReplyController@dislike']);

// Subscriptions
Route::get('subscriptions/{subscription}/unsubscribe', 'SubscriptionController@unsubscribe')
Expand Down
28 changes: 28 additions & 0 deletions tests/Components/Jobs/DislikeReplyTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

namespace Tests\Components\Jobs;

use App\Jobs\DislikeReply;
use App\Models\Reply;
use App\User;
use Tests\TestCase;
use Illuminate\Foundation\Testing\DatabaseMigrations;

class DislikeReplyTest extends TestCase
{
use DatabaseMigrations;

/** @test */
public function we_can_dislike_a_reply()
{
$user = factory(User::class)->create();
$reply = factory(Reply::class)->create();

$reply->likedBy($user);
$this->assertTrue($reply->fresh()->isLikedBy($user));

$this->dispatch(new DislikeReply($reply, $user));

$this->assertFalse($reply->fresh()->isLikedBy($user));
}
}
40 changes: 40 additions & 0 deletions tests/Components/Jobs/LikeReplyTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

namespace Tests\Components\Jobs;

use App\Exceptions\CannotLikeReplyTwice;
use App\Jobs\LikeReply;
use App\Models\Reply;
use App\User;
use Tests\TestCase;
use Illuminate\Foundation\Testing\DatabaseMigrations;

class LikeReplyTest extends TestCase
{
use DatabaseMigrations;

/** @test */
public function we_can_like_a_reply()
{
$user = factory(User::class)->create();
$reply = factory(Reply::class)->create();

$this->dispatch(new LikeReply($reply, $user));

$this->assertTrue($reply->fresh()->isLikedBy($user));
}

/** @test */
public function we_cannot_like_a_reply_twice()
{
$user = factory(User::class)->create();
$reply = factory(Reply::class)->create();

$this->dispatch(new LikeReply($reply, $user));

$this->assertTrue($reply->fresh()->isLikedBy($user));

$this->expectException(CannotLikeReplyTwice::class);
$this->dispatch(new LikeReply($reply, $user));
}
}
Loading

0 comments on commit ea92bd3

Please sign in to comment.