analytics backend update
This commit is contained in:
76
app/Conductors/AnalyticsConductor.php
Normal file
76
app/Conductors/AnalyticsConductor.php
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace App\Conductors;
|
||||
|
||||
use App\Models\Media;
|
||||
use App\Models\User;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Contracts\Container\BindingResolutionException;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\InvalidCastException;
|
||||
use Illuminate\Database\Eloquent\MissingAttributeException;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Http\Request;
|
||||
use LogicException;
|
||||
|
||||
class AnalyticsConductor extends Conductor
|
||||
{
|
||||
/**
|
||||
* The Model Class
|
||||
* @var string
|
||||
*/
|
||||
protected $class = '\App\Models\Analytics';
|
||||
|
||||
/**
|
||||
* The default sorting field
|
||||
* @var string
|
||||
*/
|
||||
protected $sort = 'created_at';
|
||||
|
||||
|
||||
/**
|
||||
* Return if the current model is visible.
|
||||
*
|
||||
* @param Model $model The model.
|
||||
* @return boolean Allow model to be visible.
|
||||
*/
|
||||
public static function viewable(Model $model)
|
||||
{
|
||||
$user = auth()->user();
|
||||
return ($user !== null && $user->hasPermission('admin/analytics') === true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the current model is creatable.
|
||||
*
|
||||
* @return boolean Allow creating model.
|
||||
*/
|
||||
public static function creatable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the current model is updatable.
|
||||
*
|
||||
* @param Model $model The model.
|
||||
* @return boolean Allow updating model.
|
||||
*/
|
||||
public static function updatable(Model $model)
|
||||
{
|
||||
$user = auth()->user();
|
||||
return ($user !== null && $user->hasPermission('admin/analytics') === true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the current model is destroyable.
|
||||
*
|
||||
* @param Model $model The model.
|
||||
* @return boolean Allow deleting model.
|
||||
*/
|
||||
public static function destroyable(Model $model)
|
||||
{
|
||||
$user = auth()->user();
|
||||
return ($user !== null && $user->hasPermission('admin/analytics') === true);
|
||||
}
|
||||
}
|
||||
133
app/Http/Controllers/Api/AnalyticsController.php
Normal file
133
app/Http/Controllers/Api/AnalyticsController.php
Normal file
@@ -0,0 +1,133 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Conductors\AnalyticsConductor;
|
||||
use App\Enum\HttpResponseCodes;
|
||||
use App\Http\Requests\AnalyticsRequest;
|
||||
use App\Models\Media;
|
||||
use App\Models\Analytics;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Carbon\Exceptions\InvalidFormatException;
|
||||
use Illuminate\Contracts\Container\BindingResolutionException;
|
||||
use Illuminate\Database\Eloquent\InvalidCastException;
|
||||
use Illuminate\Database\Eloquent\MassAssignmentException;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class AnalyticsController extends ApiController
|
||||
{
|
||||
/**
|
||||
* AnalyticsController constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('auth:sanctum')
|
||||
->only([
|
||||
'index',
|
||||
'update',
|
||||
'delete'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request The endpoint request.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
list($collection, $total) = AnalyticsConductor::request($request);
|
||||
|
||||
return $this->respondAsResource(
|
||||
$collection,
|
||||
['isCollection' => true,
|
||||
'appendData' => ['total' => $total]
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request The endpoint request.
|
||||
* @param \App\Models\Analytics $analytics The analyics model.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function show(Request $request, Analytics $analytics)
|
||||
{
|
||||
if (AnalyticsConductor::viewable($analytics) === true) {
|
||||
return $this->respondAsResource(AnalyticsConductor::model($request, $analytics));
|
||||
}
|
||||
|
||||
return $this->respondForbidden();
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\AnalyticsRequest $request The user request.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(AnalyticsRequest $request)
|
||||
{
|
||||
if (AnalyticsConductor::creatable() === true) {
|
||||
$analytics = null;
|
||||
$user = $request->user();
|
||||
|
||||
$data = [
|
||||
'type' => $request->input('type'),
|
||||
'attribute' => $request->input('attribute', ''),
|
||||
'useragent' => $request->userAgent(),
|
||||
'ip' => $request->ip()
|
||||
];
|
||||
|
||||
if ($user !== null && $user->hasPermission('admin/analytics') === true && $request->has('session') === true) {
|
||||
$data['session'] = $request->input('session');
|
||||
$analytics = Analytics::create($data);
|
||||
} else {
|
||||
$analytics = Analytics::createWithSession($data);
|
||||
}
|
||||
|
||||
return $this->respondAsResource(
|
||||
AnalyticsConductor::model($request, $analytics),
|
||||
['respondCode' => HttpResponseCodes::HTTP_CREATED]
|
||||
);
|
||||
} else {
|
||||
return $this->respondForbidden();
|
||||
}//end if
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\AnalyticsRequest $request The analytics update request.
|
||||
* @param \App\Models\Analytics $analytics The specified analytics.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(AnalyticsRequest $request, Analytics $analytics)
|
||||
{
|
||||
if (AnalyticsConductor::updatable($analytics) === true) {
|
||||
$analytics->update($request->all());
|
||||
return $this->respondAsResource(AnalyticsConductor::model($request, $analytics));
|
||||
}
|
||||
|
||||
return $this->respondForbidden();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \App\Models\Analytics $analytics The specified analytics.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(Analytics $analytics)
|
||||
{
|
||||
if (AnalyticsConductor::destroyable($analytics) === true) {
|
||||
$analytics->delete();
|
||||
return $this->respondNoContent();
|
||||
} else {
|
||||
return $this->respondForbidden();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,8 +21,8 @@ class LogRequest
|
||||
$response = $next($request);
|
||||
|
||||
try {
|
||||
Analytics::create([
|
||||
'type' => 'pageview',
|
||||
Analytics::createWithSession([
|
||||
'type' => 'apirequest',
|
||||
'attribute' => $request->path(),
|
||||
'useragent' => $request->userAgent(),
|
||||
'ip' => $request->ip(),
|
||||
|
||||
35
app/Http/Requests/AnalyticsRequest.php
Normal file
35
app/Http/Requests/AnalyticsRequest.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class AnalyticsRequest extends BaseRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to POST requests.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function postRules()
|
||||
{
|
||||
return [
|
||||
'type' => 'required|string',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to PUT request.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function putRules()
|
||||
{
|
||||
return [
|
||||
'type' => 'string',
|
||||
'useragent' => 'string',
|
||||
'ip' => 'ipv4|ipv6',
|
||||
'session' => 'number',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -15,4 +15,31 @@ class Analytics extends Model
|
||||
* @var array
|
||||
*/
|
||||
protected $guarded = [];
|
||||
|
||||
|
||||
/**
|
||||
* Create a new row in the analytics table with the given attributes,
|
||||
* automatically assigning a session value based on previous rows.
|
||||
*
|
||||
* @param array $attributes Model attributes.
|
||||
* @return static
|
||||
*/
|
||||
public static function createWithSession(array $attributes)
|
||||
{
|
||||
$previousRow = self::where('useragent', $attributes['useragent'])
|
||||
->where('ip', $attributes['ip'])
|
||||
->where('created_at', '>=', now()->subMinutes(30))
|
||||
->whereNotNull('session')
|
||||
->orderBy('created_at', 'desc')
|
||||
->first();
|
||||
|
||||
if ($previousRow !== null) {
|
||||
$attributes['session'] = $previousRow->session;
|
||||
} else {
|
||||
$lastSession = self::max('session');
|
||||
$attributes['session'] = ($lastSession + 1);
|
||||
}
|
||||
|
||||
return static::create($attributes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('analytics', function (Blueprint $table) {
|
||||
$table->bigInteger('session')->nullable(false);
|
||||
$table->string('attribute')->default('')->change();
|
||||
});
|
||||
|
||||
DB::table('analytics')
|
||||
->where('type', 'pageview')
|
||||
->update(['type' => 'apirequest']);
|
||||
|
||||
$rows = DB::table('analytics')
|
||||
->whereNull('session')
|
||||
->orderBy('created_at', 'asc')
|
||||
->get();
|
||||
|
||||
// Loop through the rows and update `session` based on the logic you described
|
||||
$session = 1;
|
||||
foreach ($rows as $row) {
|
||||
// Check if this is the first row
|
||||
if ($row->created_at === $rows->first()->created_at) {
|
||||
DB::table('analytics')
|
||||
->where('id', $row->id)
|
||||
->update(['session' => $session]);
|
||||
} else {
|
||||
// Look for a previous row with the same useragent and ip within the last 30 minutes
|
||||
$previousRow = DB::table('analytics')
|
||||
->where('useragent', $row->useragent)
|
||||
->where('ip', $row->ip)
|
||||
->where('created_at', '>=', date('Y-m-d H:i:s', strtotime('-30 minutes', strtotime($row->created_at))))
|
||||
->whereNotNull('session')
|
||||
->orderBy('created_at', 'desc')
|
||||
->first();
|
||||
|
||||
if ($previousRow) {
|
||||
// If a previous row is found, set the session to the same value
|
||||
DB::table('analytics')
|
||||
->where('id', $row->id)
|
||||
->update(['session' => $previousRow->session]);
|
||||
} else {
|
||||
// If no previous row is found, increment the session value
|
||||
$session++;
|
||||
DB::table('analytics')
|
||||
->where('id', $row->id)
|
||||
->update(['session' => $session]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('analytics', function (Blueprint $table) {
|
||||
$table->dropColumn('session');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -25,6 +25,9 @@ use App\Http\Controllers\Api\UserController;
|
||||
Route::post('/login', [AuthController::class, 'login'])->name('login');
|
||||
Route::post('/register', [UserController::class, 'register']);
|
||||
|
||||
Route::get('/analytics', [AnalyticsController::class, 'index']);
|
||||
Route::post('/analytics', [AnalyticsController::class, 'store']);
|
||||
|
||||
Route::apiResource('users', UserController::class);
|
||||
Route::post('/users/forgotUsername', [UserController::class, 'forgotUsername']);
|
||||
Route::post('/users/forgotPassword', [UserController::class, 'forgotPassword']);
|
||||
|
||||
Reference in New Issue
Block a user