Skip to content

Commit

Permalink
list following recommendation base on country and addiction type
Browse files Browse the repository at this point in the history
  • Loading branch information
= authored and muhammadmp97 committed Sep 23, 2023
1 parent ed295dc commit d0fef1f
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 3 deletions.
12 changes: 12 additions & 0 deletions app/Http/Controllers/UserFollowingController.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
namespace App\Http\Controllers;

use App\Http\Resources\TinyUserResource;
use App\Http\Resources\UserRecommendationResource;
use App\Models\User;
use App\Services\FollowingRecommendation;

class UserFollowingController extends Controller
{
Expand All @@ -23,4 +25,14 @@ public function index(User $user)
TinyUserResource::collection($following)
);
}

public function recommendations(User $user)
{
$recommendations = (new FollowingRecommendation($user))
->recommend();

return $this->ok(
UserRecommendationResource::collection($recommendations)
);
}
}
24 changes: 24 additions & 0 deletions app/Http/Resources/UserRecommendationResource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

namespace App\Http\Resources;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class UserRecommendationResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @return array<string, mixed>
*/
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'nick_name' => $this->nick_name,
'avatar_url' => $this->avatar_url,
'bio' => $this->bio,
];
}
}
32 changes: 32 additions & 0 deletions app/Services/FollowingRecommendation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace App\Services;

use App\Models\User;
use Illuminate\Support\Facades\DB;

class FollowingRecommendation
{
public function __construct(
private User $user,
) {
}

public function recommend($count = 5)
{
$followingIds = DB::table('followers')
->select('following_id')
->where('follower_id', $this->user->id)
->pluck('following_id');

return User::query()
->select('id', 'nick_name', 'avatar_url', 'bio')
->whereNotIn('id', $followingIds)
->whereNot('id', $this->user->id)
->where('country_id', '=', $this->user->country_id)
->where('addiction_type', '=', $this->user->addiction_type)
->inRandomOrder()
->limit($count)
->get();
}
}
4 changes: 2 additions & 2 deletions database/migrations/2014_10_12_000000_create_users_table.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ public function up(): void
$table->string('nick_name');
$table->string('bio')->nullable();
$table->string('avatar_url')->nullable();
$table->foreignId('country_id')->constrained();
$table->unsignedTinyInteger('addiction_type');
$table->foreignId('country_id')->index('country_id_index')->constrained();
$table->unsignedTinyInteger('addiction_type')->index('addiction_type_index');
$table->boolean('is_recovered')->default(false);
$table->unsignedInteger('score')->default(0);
$table->date('birth_date')->nullable();
Expand Down
7 changes: 6 additions & 1 deletion routes/api.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,13 @@
Route::post('comments/{comment}/likes', [CommentLikesController::class, 'store']);
Route::delete('comments/{comment}/likes', [CommentLikesController::class, 'destroy']);

Route::prefix('users/{user}/following')
->group(function () {
Route::get('/', [UserFollowingController::class, 'index']);
Route::get('/recommendations', [UserFollowingController::class, 'recommendations']);
});

Route::apiResource('users', UsersController::class)->only('index', 'show');
Route::get('users/{user}/following', [UserFollowingController::class, 'index']);
Route::get('users/{user}/followers', [UserFollowersController::class, 'index']);
Route::post('users/{user}/followers', [UserFollowersController::class, 'store']);
Route::delete('users/{user}/followers', [UserFollowersController::class, 'destroy']);
Expand Down
48 changes: 48 additions & 0 deletions tests/Feature/UserFollowingRecommendationTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

namespace Tests\Feature;

use App\Models\Country;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class UserFollowingRecommendationTest extends TestCase
{
use RefreshDatabase;

private $user;

public function setUp(): void
{
parent::setUp();

Country::create([
'code' => 'GB',
'name' => 'United Kingdom',
]);

$this->user = $this->signIn();
}

public function test_user_can_gets_recommendation_list_contain_users_from_same_addiction_and_country()
{
$followers = User::factory()->count(5)->create();
$this->user->following()->attach($followers->pluck('id'));
User::factory()->create();
$recommendations = User::factory()->count(5)->create([
'country_id' => $this->user->country_id,
'addiction_type' => $this->user->addiction_type,
]);

$response = $this
->getJson("api/users/{$this->user->id}/following/recommendations");

$response->assertOk();
$this->assertCount(5, $response['data']);
$this->assertEquals(
$recommendations->pluck(['id', 'nike_name', 'avatar_url', 'bio']),
collect($response['data'])->pluck(['id', 'nike_name', 'avatar_url', 'bio']),
);
}
}

0 comments on commit d0fef1f

Please sign in to comment.