Quellcode durchsuchen

feat: :sparkles: feat (log acessos) criada tabela de log de acessos

foi criada a tabela de log de acessos do associado e parceiro para o layout adm, abaixo da tabela de gestao associados

fase:dev | origin:escopo
Gustavo Zanatta vor 2 Wochen
Ursprung
Commit
33c8c8030b

+ 27 - 0
app/Http/Controllers/UserAccessLogController.php

@@ -0,0 +1,27 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use App\Http\Resources\UserAccessLogResource;
+use App\Services\UserAccessLogService;
+use Illuminate\Http\JsonResponse;
+use Illuminate\Http\Request;
+
+class UserAccessLogController extends Controller
+{
+    public function __construct(protected UserAccessLogService $service) {}
+
+    public function index(Request $request): JsonResponse
+    {
+        $filters = $request->only(['type', 'date_from', 'date_to']);
+        $perPage = min((int) $request->get('per_page', 10), 100);
+        $paginator = $this->service->getAllPaginated($filters, $perPage);
+
+        return $this->successResponse(payload: [
+            'data'  => UserAccessLogResource::collection($paginator->items()),
+            'total' => $paginator->total(),
+            'from'  => $paginator->firstItem() ?? 0,
+            'to'    => $paginator->lastItem() ?? 0,
+        ]);
+    }
+}

+ 20 - 0
app/Http/Resources/UserAccessLogResource.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace App\Http\Resources;
+
+use Illuminate\Http\Request;
+use Illuminate\Http\Resources\Json\JsonResource;
+
+class UserAccessLogResource extends JsonResource
+{
+    public function toArray(Request $request): array
+    {
+        return [
+            'id'          => $this->id,
+            'user_id'     => $this->user_id,
+            'user_name'   => $this->user?->name,
+            'user_type'   => $this->user?->type?->value,
+            'accessed_at' => $this->accessed_at?->toIso8601String(),
+        ];
+    }
+}

+ 6 - 5
app/Http/Resources/UserResource.php

@@ -33,11 +33,12 @@ class UserResource extends JsonResource
             'position'       => $this->whenLoaded('position', fn() => ['id' => $this->position->id, 'name' => $this->position->name]),
             'sector_id'      => $this->sector_id,
             'sector'         => $this->whenLoaded('sector', fn() => ['id' => $this->sector->id, 'name' => $this->sector->name]),
-            'photo_url'      => $this->photo_path
-                                    ? Storage::disk('s3')->temporaryUrl($this->photo_path, now()->addHours(24))
-                                    : null,
-            'created_at'     => Carbon::parse($this->created_at)->format('Y-m-d H:i:s'),
-            'updated_at'     => Carbon::parse($this->updated_at)->format('Y-m-d H:i:s'),
+            'photo_url'                  => $this->photo_path
+                                                ? Storage::disk('s3')->temporaryUrl($this->photo_path, now()->addHours(24))
+                                                : null,
+            'unread_notifications_count' => (int) ($this->unread_notifications_count ?? 0),
+            'created_at'                 => Carbon::parse($this->created_at)->format('Y-m-d H:i:s'),
+            'updated_at'                 => Carbon::parse($this->updated_at)->format('Y-m-d H:i:s'),
         ];
     }
 

+ 5 - 0
app/Models/User.php

@@ -161,6 +161,11 @@ class User extends Authenticatable
         return $this->hasMany(StoreItemInterest::class);
     }
 
+    public function accessLogs(): HasMany
+    {
+        return $this->hasMany(UserAccessLog::class);
+    }
+
     /**
      * @return BelongsToMany
      */

+ 34 - 0
app/Models/UserAccessLog.php

@@ -0,0 +1,34 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
+
+/**
+ * @property int $id
+ * @property int $user_id
+ * @property \Illuminate\Support\Carbon $accessed_at
+ * @property-read \App\Models\User $user
+ * @mixin \Eloquent
+ */
+class UserAccessLog extends Model
+{
+    public $timestamps = false;
+
+    protected $table = 'users_access_logs';
+
+    protected $fillable = [
+        'user_id',
+        'accessed_at',
+    ];
+
+    protected $casts = [
+        'accessed_at' => 'datetime',
+    ];
+
+    public function user(): BelongsTo
+    {
+        return $this->belongsTo(User::class);
+    }
+}

+ 9 - 0
app/Services/AuthService.php

@@ -4,6 +4,8 @@ namespace App\Services;
 
 use App\Models\User;
 use App\Models\PersonalAccessToken;
+use App\Models\UserAccessLog;
+use App\Enums\UserTypeEnum;
 use Carbon\Carbon;
 use Illuminate\Support\Facades\Auth;
 use Illuminate\Support\Facades\DB;
@@ -24,6 +26,13 @@ class AuthService
             return ["error" => "wrong_type"];
         }
 
+        if (in_array($user->type, [UserTypeEnum::ASSOCIADO, UserTypeEnum::PARCEIRO])) {
+            UserAccessLog::create([
+                'user_id'     => $user->id,
+                'accessed_at' => now(),
+            ]);
+        }
+
         $deviceId = Str::uuid()->toString();
 
         $accessToken = $user->createAccessToken($deviceId);

+ 29 - 0
app/Services/UserAccessLogService.php

@@ -0,0 +1,29 @@
+<?php
+
+namespace App\Services;
+
+use App\Models\UserAccessLog;
+use Illuminate\Pagination\LengthAwarePaginator;
+
+class UserAccessLogService
+{
+    public function getAllPaginated(array $filters = [], int $perPage = 10): LengthAwarePaginator
+    {
+        $query = UserAccessLog::with(['user:id,name,type'])
+            ->orderBy('accessed_at', 'desc');
+
+        if (!empty($filters['type'])) {
+            $query->whereHas('user', fn($q) => $q->where('type', $filters['type']));
+        }
+
+        if (!empty($filters['date_from'])) {
+            $query->whereDate('accessed_at', '>=', $filters['date_from']);
+        }
+
+        if (!empty($filters['date_to'])) {
+            $query->whereDate('accessed_at', '<=', $filters['date_to']);
+        }
+
+        return $query->paginate($perPage);
+    }
+}

+ 2 - 1
app/Services/UserService.php

@@ -13,7 +13,8 @@ class UserService
     public function authUser(): ?User
     {
         $user = Auth::user();
-        return $user?->load(['position', 'sector']);
+        return $user?->load(['position', 'sector'])
+                     ->loadCount(['notificationSends as unread_notifications_count' => fn($q) => $q->where('read', false)]);
     }
 
     public function getAll(): Collection

+ 25 - 0
database/migrations/2026_05_25_000001_create_users_access_logs_table.php

@@ -0,0 +1,25 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+    public function up(): void
+    {
+        Schema::create('users_access_logs', function (Blueprint $table) {
+            $table->id();
+            $table->foreignId('user_id')->constrained('users')->cascadeOnDelete();
+            $table->timestamp('accessed_at');
+
+            $table->index('user_id');
+            $table->index('accessed_at');
+        });
+    }
+
+    public function down(): void
+    {
+        Schema::dropIfExists('users_access_logs');
+    }
+};

+ 8 - 0
routes/authRoutes/user_access_log.php

@@ -0,0 +1,8 @@
+<?php
+
+use Illuminate\Support\Facades\Route;
+use App\Http\Controllers\UserAccessLogController;
+
+Route::controller(UserAccessLogController::class)->prefix('user-access-log')->group(function () {
+    Route::get('/', 'index')->middleware('permission:config.user,view');
+});