Merge branch '1-view-count' into 'master'

Resolve "View Count"

Closes #1

See merge request daniel/personal-website!2
This commit is contained in:
Daniel_I_Am 2021-09-04 10:36:16 +00:00
commit 81356ac945
9 changed files with 355 additions and 10 deletions

View File

@ -20,6 +20,8 @@ FILESYSTEM_DRIVER=local
QUEUE_CONNECTION=sync QUEUE_CONNECTION=sync
SESSION_DRIVER=file SESSION_DRIVER=file
SESSION_LIFETIME=120 SESSION_LIFETIME=120
# Only required if using a custom port on APP_URL
# SANCTUM_STATEFUL_DOMAINS=localhost:8000
MEMCACHED_HOST=127.0.0.1 MEMCACHED_HOST=127.0.0.1

View File

@ -61,7 +61,7 @@ class BlogArticleController extends Controller
public function popular() public function popular()
{ {
$data = BlogArticle::select() $data = BlogArticle::select()
->orderBy('views', 'desc') ->orderByUniqueViews('desc')
->orderBy('date', 'desc') ->orderBy('date', 'desc')
->where('published', true) ->where('published', true)
->limit(5) ->limit(5)
@ -89,14 +89,23 @@ class BlogArticleController extends Controller
* @param \App\Models\BlogArticle $blogArticle * @param \App\Models\BlogArticle $blogArticle
* @return \Illuminate\Http\JsonResponse * @return \Illuminate\Http\JsonResponse
*/ */
public function show(BlogArticle $blogArticle) public function show(int $id)
{ {
if (!$this->authService->isAuthenticated() && !$blogArticle->published) { $blogArticle = BlogArticle::withCount('views')->find($id);
if ($blogArticle === null) {
abort(404); abort(404);
} }
$blogArticle->views += 1; if (!$this->authService->isAuthenticated()) {
$blogArticle->save(); if (!$blogArticle->published) {
abort(404);
}
views($blogArticle)
->cooldown(now()->addHour())
->record();
}
return response()->json($blogArticle); return response()->json($blogArticle);
} }

View File

@ -40,7 +40,7 @@ class Kernel extends HttpKernel
], ],
'api' => [ 'api' => [
// \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class, \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:api', 'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class, \Illuminate\Routing\Middleware\SubstituteBindings::class,
], ],

View File

@ -2,12 +2,15 @@
namespace App\Models; namespace App\Models;
use CyrildeWit\EloquentViewable\Contracts\Viewable;
use CyrildeWit\EloquentViewable\InteractsWithViews;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
class BlogArticle extends Model class BlogArticle extends Model implements Viewable
{ {
use HasFactory; use HasFactory;
use InteractsWithViews;
protected $fillable = [ protected $fillable = [
'title', 'title',
@ -15,7 +18,6 @@ class BlogArticle extends Model
'date', 'date',
'summary', 'summary',
'content', 'content',
'views',
'published' 'published'
]; ];
@ -24,7 +26,8 @@ class BlogArticle extends Model
'created_at' => 'datetime', 'created_at' => 'datetime',
'updated_at' => 'datetime', 'updated_at' => 'datetime',
'date' => 'datetime', 'date' => 'datetime',
'views' => 'integer',
'published' => 'boolean', 'published' => 'boolean',
]; ];
protected $removeViewsOnDelete = true;
} }

View File

@ -6,6 +6,7 @@
"license": "MIT", "license": "MIT",
"require": { "require": {
"php": "^7.3|^8.0", "php": "^7.3|^8.0",
"cyrildewit/eloquent-viewable": "^6.0",
"doctrine/dbal": "^3.1", "doctrine/dbal": "^3.1",
"fruitcake/laravel-cors": "^2.0", "fruitcake/laravel-cors": "^2.0",
"guzzlehttp/guzzle": "^7.0.1", "guzzlehttp/guzzle": "^7.0.1",

131
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "2e27ad4aeb64c5f5afd5be0288a4a9e2", "content-hash": "5ceb5b6e26fc35fd4fd26e6d152d3b11",
"packages": [ "packages": [
{ {
"name": "asm89/stack-cors", "name": "asm89/stack-cors",
@ -195,6 +195,83 @@
], ],
"time": "2021-08-17T13:49:14+00:00" "time": "2021-08-17T13:49:14+00:00"
}, },
{
"name": "cyrildewit/eloquent-viewable",
"version": "v6.0.2",
"source": {
"type": "git",
"url": "https://github.com/cyrildewit/eloquent-viewable.git",
"reference": "699294489e397c18a59ff9fafadde8154be85c02"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/cyrildewit/eloquent-viewable/zipball/699294489e397c18a59ff9fafadde8154be85c02",
"reference": "699294489e397c18a59ff9fafadde8154be85c02",
"shasum": ""
},
"require": {
"illuminate/cache": "^6.0|^7.0|^8.0",
"illuminate/contracts": "^6.0|^7.0|^8.0",
"illuminate/cookie": "^6.0|^7.0|^8.0",
"illuminate/database": "^6.0|^7.0|^8.0",
"illuminate/http": "^6.0|^7.0|^8.0",
"illuminate/support": "^6.0|^7.0|^8.0",
"jaybizzle/crawler-detect": "^1.0",
"nesbot/carbon": "^2.0",
"php": "^7.4|^8.0"
},
"require-dev": {
"illuminate/config": "^6.0|^7.0|^8.0",
"mockery/mockery": "^1.2.4",
"orchestra/testbench": "^4.9.1|^5.9.1|^6.6.1",
"phpunit/phpunit": "^9.3.3"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"CyrildeWit\\EloquentViewable\\EloquentViewableServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"CyrildeWit\\EloquentViewable\\": "src/"
},
"files": [
"src/helpers.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Cyril de Wit",
"email": "info@cyrildewit.nl",
"homepage": "http://cyrildewit.nl",
"role": "Developer"
}
],
"description": "Laravel package that allows you to associate views with Eloquent models",
"homepage": "https://github.com/cyrildewit/eloquent-viewable",
"keywords": [
"counter",
"eloquent",
"hits",
"laravel",
"viewable",
"views",
"visitable",
"visits"
],
"support": {
"issues": "https://github.com/cyrildewit/eloquent-viewable/issues",
"source": "https://github.com/cyrildewit/eloquent-viewable/tree/v6.0.2"
},
"time": "2021-01-02T15:47:17+00:00"
},
{ {
"name": "dflydev/dot-access-data", "name": "dflydev/dot-access-data",
"version": "v3.0.1", "version": "v3.0.1",
@ -1295,6 +1372,58 @@
}, },
"time": "2021-06-30T20:03:07+00:00" "time": "2021-06-30T20:03:07+00:00"
}, },
{
"name": "jaybizzle/crawler-detect",
"version": "v1.2.106",
"source": {
"type": "git",
"url": "https://github.com/JayBizzle/Crawler-Detect.git",
"reference": "78bf6792cbf9c569dc0bf2465481978fd2ed0de9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/JayBizzle/Crawler-Detect/zipball/78bf6792cbf9c569dc0bf2465481978fd2ed0de9",
"reference": "78bf6792cbf9c569dc0bf2465481978fd2ed0de9",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8|^5.5|^6.5|^9.4"
},
"type": "library",
"autoload": {
"psr-4": {
"Jaybizzle\\CrawlerDetect\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Mark Beech",
"email": "m@rkbee.ch",
"role": "Developer"
}
],
"description": "CrawlerDetect is a PHP class for detecting bots/crawlers/spiders via the user agent",
"homepage": "https://github.com/JayBizzle/Crawler-Detect/",
"keywords": [
"crawler",
"crawler detect",
"crawler detector",
"crawlerdetect",
"php crawler detect"
],
"support": {
"issues": "https://github.com/JayBizzle/Crawler-Detect/issues",
"source": "https://github.com/JayBizzle/Crawler-Detect/tree/v1.2.106"
},
"time": "2021-05-24T20:30:32+00:00"
},
{ {
"name": "laravel/framework", "name": "laravel/framework",
"version": "v8.58.0", "version": "v8.58.0",

View File

@ -0,0 +1,107 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Eloquent Models
|--------------------------------------------------------------------------
*/
'models' => [
/*
* Here you can configure the default `View` model.
*/
'view' => [
'table_name' => 'views',
'connection' => env('DB_CONNECTION', 'mysql'),
],
],
/*
|--------------------------------------------------------------------------
| Cache Configuration
|--------------------------------------------------------------------------
*/
'cache' => [
/*
* Everthing will be stored under the following key.
*/
'key' => 'cyrildewit.eloquent-viewable.cache',
/*
* Here you may define the cache store that should be used.
*/
'store' => env('CACHE_DRIVER', 'file'),
],
/*
|--------------------------------------------------------------------------
| Cooldown Configuration
|--------------------------------------------------------------------------
*/
'cooldown' => [
/*
* Everthing will be stored under the following key in the session.
*/
'key' => 'cyrildewit.eloquent-viewable.cooldowns',
],
/*
|--------------------------------------------------------------------------
| Ignore Bots
|--------------------------------------------------------------------------
|
| If you want to ignore bots, you can specify that here. The default
| service that determines if a visitor is a crawler is a package
| by JayBizzle called CrawlerDetect.
|
*/
'ignore_bots' => true,
/*
|--------------------------------------------------------------------------
| Do Not Track Header
|--------------------------------------------------------------------------
|
| If you want to honor the DNT header, you can specify that here. We won't
| record views from visitors with the Do Not Track header.
|
*/
'honor_dnt' => true,
/*
|--------------------------------------------------------------------------
| Cookies
|--------------------------------------------------------------------------
|
| This package binds visitors to views using a cookie. If you want to
| give this cookie a custom name, you can specify that here.
|
*/
'visitor_cookie_key' => 'eloquent_viewable',
/*
|--------------------------------------------------------------------------
| Ignore IP Addresses
|--------------------------------------------------------------------------
|
| Ignore views of the following IP addresses.
|
*/
'ignored_ip_addresses' => [
// '127.0.0.1',
],
];

View File

@ -0,0 +1,62 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateViewsTable extends Migration
{
/**
* The database schema.
*
* @var \Illuminate\Support\Facades\Schema
*/
protected $schema;
/**
* The table name.
*
* @var string
*/
protected $table;
/**
* Create a new migration instance.
*
* @return void
*/
public function __construct()
{
$this->schema = Schema::connection(
config('eloquent-viewable.models.view.connection')
);
$this->table = config('eloquent-viewable.models.view.table_name');
}
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
$this->schema->create($this->table, function (Blueprint $table) {
$table->bigIncrements('id');
$table->morphs('viewable');
$table->text('visitor')->nullable();
$table->string('collection')->nullable();
$table->timestamp('viewed_at')->useCurrent();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
$this->schema->dropIfExists($this->table);
}
}

View File

@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class RemoveViewsFromBlogArticles extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('blog_articles', function (Blueprint $table) {
$table->dropColumn('views');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('blog_articles', function (Blueprint $table) {
$table->integer('views')->default(0);
});
}
}