add bookmark back

This commit is contained in:
2020-05-09 18:37:31 +02:00
parent 2f8e8ca378
commit a1b8962fe6
12 changed files with 520 additions and 0 deletions

View File

@@ -0,0 +1,57 @@
<?php
namespace App\Http\Controllers;
use App\Http\Requests\BookmarkRequest;
use App\Http\Resources\BookmarkCollection;
use App\Models\Bookmark;
use App\Http\Resources\Bookmark as BookmarkResource;
use Illuminate\Http\Request;
class BookmarkController extends Controller
{
public function index()
{
$this->authorize('viewAny', Bookmark::class);
return new BookmarkCollection(request()->user()->bookmarks);
}
public function store(BookmarkRequest $request)
{
$this->authorize('create', Bookmark::class);
$bookmark = request()->user()->bookmarks()->create($request->all());
return (new BookmarkResource($bookmark))
->response()
->setStatusCode(201);
}
public function show(Bookmark $bookmark)
{
$this->authorize('view', $bookmark);
return new BookmarkResource($bookmark);
}
public function update(BookmarkRequest $request, Bookmark $bookmark)
{
$this->authorize('update', $bookmark);
$bookmark->update($request->all());
return (new BookmarkResource($bookmark))
->response()
->setStatusCode(200);
}
public function destroy(Bookmark $bookmark)
{
$this->authorize('delete', $bookmark);
$bookmark->delete();
return response([], 204);
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class BookmarkRequest extends FormRequest
{
public function rules()
{
return [
'name' => 'max:65',
'url' => ['required', 'url', 'max:255'],
'favicon' => ['url', 'max:255'],
];
}
public function attributes()
{
return [
'name' => 'Nom du marque-page',
];
}
public function messages()
{
return [
'url.required' => 'Une url est nécessaire',
];
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class Bookmark extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'data' => [
'type' => 'bookmark',
'bookmark_id' => $this->id,
'attributes' => [
'data' => [
'name' => $this->name,
'url' => $this->url,
'favicon' => $this->favicon,
'created_at' => $this->created_at->diffForHumans(),
'last_updated' => $this->updated_at->diffForHumans(),
]
],
],
];
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
class BookmarkCollection extends ResourceCollection
{
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'data' => $this->collection,
'bookmarks_count' => $this->count(),
'links' => [
'self' => url('/bookmarks'),
]
];
}
}

10
app/Models/Bookmark.php Normal file
View File

@@ -0,0 +1,10 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Bookmark extends Model
{
protected $guarded = [];
}

View File

@@ -2,6 +2,7 @@
namespace App; namespace App;
use App\Models\Bookmark;
use App\Models\Image; use App\Models\Image;
use App\Models\Memo; use App\Models\Memo;
use App\Models\ToDoList; use App\Models\ToDoList;
@@ -64,6 +65,11 @@ class User extends Authenticatable
return $this->hasMany(ToDoList::class); return $this->hasMany(ToDoList::class);
} }
public function bookmarks() : HasMany
{
return $this->hasMany(Bookmark::class);
}
public function images(): MorphMany public function images(): MorphMany
{ {
return $this->morphMany(Image::class, 'imageable'); return $this->morphMany(Image::class, 'imageable');

View File

@@ -0,0 +1,94 @@
<?php
namespace App\Policies;
use App\Models\Bookmark;
use App\User;
use Illuminate\Auth\Access\HandlesAuthorization;
class BookmarkPolicy
{
use HandlesAuthorization;
/**
* Determine whether the user can view any bookmarks.
*
* @param \App\User $user
* @return mixed
*/
public function viewAny(User $user)
{
return true;
}
/**
* Determine whether the user can view the bookmark.
*
* @param \App\User $user
* @param \App\Models\Bookmark $bookmark
* @return mixed
*/
public function view(User $user, Bookmark $bookmark)
{
return $user->id == $bookmark->user_id;
}
/**
* Determine whether the user can create bookmarks.
*
* @param \App\User $user
* @return mixed
*/
public function create(User $user)
{
return true;
}
/**
* Determine whether the user can update the bookmark.
*
* @param \App\User $user
* @param \App\Models\Bookmark $bookmark
* @return mixed
*/
public function update(User $user, Bookmark $bookmark)
{
return $user->id == $bookmark->user_id;
}
/**
* Determine whether the user can delete the bookmark.
*
* @param \App\User $user
* @param \App\Models\Bookmark $bookmark
* @return mixed
*/
public function delete(User $user, Bookmark $bookmark)
{
return $user->id == $bookmark->user_id;
}
/**
* Determine whether the user can restore the bookmark.
*
* @param \App\User $user
* @param \App\Models\Bookmark $bookmark
* @return mixed
*/
public function restore(User $user, Bookmark $bookmark)
{
return false;
}
/**
* Determine whether the user can permanently delete the bookmark.
*
* @param \App\User $user
* @param \App\Models\Bookmark $bookmark
* @return mixed
*/
public function forceDelete(User $user, Bookmark $bookmark)
{
return false;
}
}

View File

@@ -18,6 +18,7 @@ class AuthServiceProvider extends ServiceProvider
'App\User' => 'App\Policies\UserPolicy', 'App\User' => 'App\Policies\UserPolicy',
'App\Models\Memo' => 'App\Policies\MemoPolicy', 'App\Models\Memo' => 'App\Policies\MemoPolicy',
'App\Models\ToDoList' => 'App\Policies\ToDoListPolicy', 'App\Models\ToDoList' => 'App\Policies\ToDoListPolicy',
'App\Models\Bookmark' => 'App\Policies\BookmarkPolicy',
]; ];
/** /**

View File

@@ -0,0 +1,15 @@
<?php
/** @var \Illuminate\Database\Eloquent\Factory $factory */
use App\Models\Bookmark;
use Faker\Generator as Faker;
$factory->define(Bookmark::class, function (Faker $faker) {
return [
'user_id' => factory(\App\User::class),
'name' => $faker->words(3, [false]),
'url' => $faker->url,
'favicon' => $faker->imageUrl(),
];
});

View File

@@ -0,0 +1,35 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateBookmarksTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('bookmarks', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id');
$table->string('name')->nullable();
$table->string('url');
$table->string('favicon')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('bookmarks');
}
}

View File

@@ -26,6 +26,7 @@ Route::middleware('auth:api')->group(function () {
'/meteo' => 'MeteoController', '/meteo' => 'MeteoController',
'/to-do-lists' => 'ToDoListController', '/to-do-lists' => 'ToDoListController',
'/to-do-lists/{toDoList}/to-do' => 'ToDoController', '/to-do-lists/{toDoList}/to-do' => 'ToDoController',
'/bookmarks' => 'BookmarkController',
// '/users/{user}/posts' => 'UserPostController', // '/users/{user}/posts' => 'UserPostController',
// '/friend-request' => 'FriendRequestController', // '/friend-request' => 'FriendRequestController',
]); ]);

View File

@@ -0,0 +1,212 @@
<?php
namespace Tests\Feature;
use App\Models\Bookmark;
use App\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;
class BookmarkTest extends TestCase
{
use RefreshDatabase;
/** @test */
public function an_unauthenticated_user_can_add_a_bookmark()
{
$this->withoutExceptionHandling();
$this->actingAs($user = factory(\App\User::class)->create(), 'api');
$response = $this->post('/api/bookmarks', $this->data());
$bookmark = Bookmark::first();
$this->assertCount(1, Bookmark::all());
$this->assertEquals('Test Name', $bookmark->name);
$this->assertEquals('https://portal.bricooli.fr', $bookmark->url);
$this->assertEquals('https://portal.bricooli.fr/img/logo.svg', $bookmark->favicon);
$response->assertStatus(201);
$response->assertJson([
'data' => [
'type' => 'bookmark',
'bookmark_id' => $bookmark->id,
'attributes' => [
'data' => [
'name' => $bookmark->name,
'url' => $bookmark->url,
'favicon' => $bookmark->favicon,
]
],
],
]);
}
/** @test */
public function bookmark_url_are_required()
{
$this->actingAs($user = factory(\App\User::class)->create(), 'api');
$response = $this->post('/api/bookmarks', array_merge($this->data(), ['url' => '']));
$response->assertSessionHasErrors('url');
$this->assertCount(0, Bookmark::all());
}
/** @test */
public function a_bookmark_can_be_retrieved()
{
$this->actingAs($user = factory(User::class)->create(), 'api');
$bookmark = factory(Bookmark::class)->create(['user_id' => $user->id]);
$response = $this->get('/api/bookmarks/' . $bookmark->id );
$response->assertJson([
'data' => [
'bookmark_id' => $bookmark->id,
'attributes' => [
'data' => [
'name' => $bookmark->name,
'url' => $bookmark->url,
'favicon' => $bookmark->favicon,
'last_updated' => $bookmark->updated_at->diffForHumans(),
]
],
],
]);
}
/** @test */
public function a_user_can_retrueved_all_this_to_do_lists()
{
$this->actingAs($user = factory(User::class)->create(), 'api');
$bookmarkOne = factory(Bookmark::class)->create(['user_id' => $user->id]);
$bookmarkTwo = factory(Bookmark::class)->create(['user_id' => $user->id]);
$response = $this->get('/api/bookmarks');
$response->assertJson([
'data' => [
[
'data' => [
'bookmark_id' => $bookmarkOne->id,
'attributes' => [
'data' => [
'name' => $bookmarkOne->name,
'last_updated' => $bookmarkOne->updated_at->diffForHumans(),
]
],
]
],
[
'data' => [
'bookmark_id' => $bookmarkTwo->id,
'attributes' => [
'data' => [
'name' => $bookmarkTwo->name,
'last_updated' => $bookmarkTwo->updated_at->diffForHumans(),
]
],
],
]
],
'links' => [
'self' => url('/bookmarks'),
]
]);
}
/** @test */
public function only_owner_bookmark_can_retrieved_it()
{
$user = factory(User::class)->create();
$bookmark = factory(Bookmark::class)->create(['user_id' => $user->id]);
$this->actingAs($userAnother = factory(User::class)->create(), 'api');
$response = $this->get('/api/bookmarks/' . $bookmark->id );
$response->assertStatus(403);
}
/** @test */
public function a_to_bookmark_can_be_patch()
{
$this->withoutExceptionHandling();
$this->actingAs($user = factory(User::class)->create(), 'api');
$bookmark = factory(Bookmark::class)->create(['user_id' => $user->id]);
$response = $this->patch('/api/bookmarks/' . $bookmark->id, [
'name' => 'Bookmark Update',
'url' => 'https://portal.bricooli.fr',
]);
$bookmark = $bookmark->fresh();
$this->assertEquals('Bookmark Update', $bookmark->name);
$this->assertEquals('https://portal.bricooli.fr', $bookmark->url);
$response->assertStatus(200);
$response->assertJson([
'data' => [
'bookmark_id' => $bookmark->id,
'attributes' => [
'data' => [
'name' => 'Bookmark Update'
]
]
]
]);
}
/** @test */
public function only_the_owner_can_patch_the_bookmark()
{
$user = factory(User::class)->create();
$bookmark = factory(Bookmark::class)->create(['id' => 123, 'user_id' => $user->id]);
$this->actingAs($anotherUser = factory(User::class)->create(), 'api');
$this->patch('/api/bookmarks/'. $bookmark->id, ['url' => 'https://portal.bricooli.fr'])
->assertStatus(403);
}
/** @test */
public function a_bookmark_can_be_delete()
{
$this->actingAs($user = factory(User::class)->create(), 'api');
$bookmark = factory(Bookmark::class)->create(['user_id' => $user->id]);
$response = $this->delete('/api/bookmarks/' . $bookmark->id);
$toDoList = $bookmark->fresh();
$this->assertCount(0, Bookmark::all());
$response->assertStatus(204);
}
/** @test */
public function only_the_owner_can_delete_the_bookmark()
{
$user = factory(User::class)->create();
$bookmark = factory(Bookmark::class)->create();
$this->actingAs($anotherUser = factory(User::class)->create(), 'api');
$response = $this->delete('/api/bookmarks/' . $bookmark->id);
$response->assertStatus(403);
}
private function data()
{
return [
'name' => 'Test Name',
'url' => 'https://portal.bricooli.fr',
'favicon' => 'https://portal.bricooli.fr/img/logo.svg',
];
}
}