vendor and env first commit
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace Vanguard\UserActivity;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Vanguard\User;
|
||||
use Vanguard\UserActivity\Database\Factories\ActivityFactory;
|
||||
|
||||
class Activity extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
const UPDATED_AT = null;
|
||||
|
||||
protected $table = 'user_activity';
|
||||
|
||||
protected $fillable = ['description', 'user_id', 'ip_address', 'user_agent'];
|
||||
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo(User::class, 'user_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new factory instance for the model.
|
||||
*/
|
||||
protected static function newFactory(): ActivityFactory
|
||||
{
|
||||
return new ActivityFactory;
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Vanguard\UserActivity\Http\Controllers\Api;
|
||||
|
||||
use Spatie\QueryBuilder\AllowedFilter;
|
||||
use Spatie\QueryBuilder\QueryBuilder;
|
||||
use Vanguard\Http\Controllers\Api\ApiController;
|
||||
use Vanguard\UserActivity\Activity;
|
||||
use Vanguard\UserActivity\Http\Requests\GetActivitiesRequest;
|
||||
use Vanguard\UserActivity\Http\Resources\ActivityResource;
|
||||
|
||||
class ActivityController extends ApiController
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('auth');
|
||||
$this->middleware('permission:users.activity');
|
||||
}
|
||||
|
||||
/**
|
||||
* Paginate user activities.
|
||||
*/
|
||||
public function index(GetActivitiesRequest $request): \Illuminate\Http\Resources\Json\AnonymousResourceCollection
|
||||
{
|
||||
$activities = QueryBuilder::for(Activity::class)
|
||||
->allowedIncludes('user')
|
||||
->allowedFilters([
|
||||
AllowedFilter::partial('description'),
|
||||
AllowedFilter::exact('user', 'user_id'),
|
||||
])
|
||||
->allowedSorts('created_at')
|
||||
->defaultSort('-created_at')
|
||||
->paginate($request->per_page ?: 20);
|
||||
|
||||
return ActivityResource::collection($activities);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Vanguard\UserActivity\Http\Controllers\Api;
|
||||
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Vanguard\Http\Controllers\Api\ApiController;
|
||||
use Vanguard\UserActivity\Repositories\Activity\ActivityRepository;
|
||||
|
||||
class StatsController extends ApiController
|
||||
{
|
||||
public function __construct(private readonly ActivityRepository $activities)
|
||||
{
|
||||
$this->middleware('auth');
|
||||
}
|
||||
|
||||
public function show(): JsonResponse
|
||||
{
|
||||
$data = $this->activities->userActivityForPeriod(
|
||||
Auth::user()->id,
|
||||
Carbon::now()->subWeeks(2),
|
||||
Carbon::now()
|
||||
);
|
||||
|
||||
return response()->json($data);
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Vanguard\UserActivity\Http\Controllers\Web;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
use Vanguard\Http\Controllers\Controller;
|
||||
use Vanguard\UserActivity\Repositories\Activity\ActivityRepository;
|
||||
|
||||
class ActivityController extends Controller
|
||||
{
|
||||
public function __construct(private readonly ActivityRepository $activities)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the page with activities for all system users.
|
||||
*/
|
||||
public function index(Request $request): View
|
||||
{
|
||||
$activities = $this->activities->paginateActivities(perPage: 20, search: $request->search);
|
||||
|
||||
return view('user-activity::index', [
|
||||
'adminView' => true,
|
||||
'activities' => $activities,
|
||||
]);
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace Vanguard\UserActivity\Http\Controllers\Web;
|
||||
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Http\Request;
|
||||
use Vanguard\Http\Controllers\Controller;
|
||||
use Vanguard\User;
|
||||
use Vanguard\UserActivity\Repositories\Activity\ActivityRepository;
|
||||
|
||||
class UserActivityController extends Controller
|
||||
{
|
||||
public function __construct(private readonly ActivityRepository $activities)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the activity log page for specific user.
|
||||
*/
|
||||
public function index(User $user, Request $request): View
|
||||
{
|
||||
$activities = $this->activities->paginateActivitiesForUser(
|
||||
userId: $user->id,
|
||||
search: $request->search,
|
||||
);
|
||||
|
||||
return view('user-activity::index', [
|
||||
'user' => $user,
|
||||
'adminView' => true,
|
||||
'activities' => $activities,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display user activity log.
|
||||
*/
|
||||
public function show(Request $request): View
|
||||
{
|
||||
$user = auth()->user();
|
||||
|
||||
$activities = $this->activities->paginateActivitiesForUser(
|
||||
userId: $user->id,
|
||||
search: $request->get('search'),
|
||||
);
|
||||
|
||||
return view('user-activity::index', compact('activities', 'user'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Vanguard\UserActivity\Http\Requests;
|
||||
|
||||
use Vanguard\Http\Requests\Request;
|
||||
|
||||
class GetActivitiesRequest extends Request
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'per_page' => 'integer|max:100',
|
||||
];
|
||||
}
|
||||
|
||||
public function messages(): array
|
||||
{
|
||||
return [
|
||||
'per_page.max' => __('Maximum number of records per page is 100.'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Vanguard\UserActivity\Http\Resources;
|
||||
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class ActivityResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
*/
|
||||
public function toArray($request): array
|
||||
{
|
||||
$agent = app('agent');
|
||||
$agent->setUserAgent($this->resource->user_agent);
|
||||
|
||||
return [
|
||||
'id' => (int) $this->id,
|
||||
'user_id' => (int) $this->user_id,
|
||||
'ip_address' => $this->ip_address,
|
||||
'user_agent' => $this->user_agent,
|
||||
'browser' => $agent->browser(),
|
||||
'platform' => $agent->platform(),
|
||||
'device' => $agent->device(),
|
||||
'description' => $this->description,
|
||||
'created_at' => (string) $this->created_at,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace Vanguard\UserActivity\Http\View\Composers;
|
||||
|
||||
use Illuminate\View\View;
|
||||
use Vanguard\UserActivity\Repositories\Activity\ActivityRepository;
|
||||
|
||||
class ShowUserComposer
|
||||
{
|
||||
public function __construct(private readonly ActivityRepository $activity)
|
||||
{
|
||||
}
|
||||
|
||||
public function compose(View $view): void
|
||||
{
|
||||
$user = $view->getData()['user'];
|
||||
|
||||
$view->with('activities', $this->activity->getLatestActivitiesForUser($user->id));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace Vanguard\UserActivity\Listeners;
|
||||
|
||||
use Illuminate\Events\Dispatcher;
|
||||
use Vanguard\Events\Permission\Created;
|
||||
use Vanguard\Events\Permission\Deleted;
|
||||
use Vanguard\Events\Permission\Updated;
|
||||
use Vanguard\UserActivity\Logger;
|
||||
|
||||
class PermissionEventsSubscriber
|
||||
{
|
||||
public function __construct(private readonly Logger $logger)
|
||||
{
|
||||
}
|
||||
|
||||
public function onCreate(Created $event): void
|
||||
{
|
||||
$permission = $event->getPermission();
|
||||
|
||||
$name = $permission->display_name ?: $permission->name;
|
||||
$message = trans('user-activity::log.new_permission', ['name' => $name]);
|
||||
|
||||
$this->logger->log($message);
|
||||
}
|
||||
|
||||
public function onUpdate(Updated $event): void
|
||||
{
|
||||
$permission = $event->getPermission();
|
||||
|
||||
$name = $permission->display_name ?: $permission->name;
|
||||
$message = trans('user-activity::log.updated_permission', ['name' => $name]);
|
||||
|
||||
$this->logger->log($message);
|
||||
}
|
||||
|
||||
public function onDelete(Deleted $event): void
|
||||
{
|
||||
$permission = $event->getPermission();
|
||||
|
||||
$name = $permission->display_name ?: $permission->name;
|
||||
$message = trans('user-activity::log.deleted_permission', ['name' => $name]);
|
||||
|
||||
$this->logger->log($message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the listeners for the subscriber.
|
||||
*/
|
||||
public function subscribe(Dispatcher $events): void
|
||||
{
|
||||
$class = self::class;
|
||||
|
||||
$events->listen(Created::class, "{$class}@onCreate");
|
||||
$events->listen(Updated::class, "{$class}@onUpdate");
|
||||
$events->listen(Deleted::class, "{$class}@onDelete");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Vanguard\UserActivity\Listeners;
|
||||
|
||||
use Illuminate\Events\Dispatcher;
|
||||
use Vanguard\Events\Role\Created;
|
||||
use Vanguard\Events\Role\Deleted;
|
||||
use Vanguard\Events\Role\PermissionsUpdated;
|
||||
use Vanguard\Events\Role\Updated;
|
||||
use Vanguard\UserActivity\Logger;
|
||||
|
||||
class RoleEventsSubscriber
|
||||
{
|
||||
public function __construct(private readonly Logger $logger)
|
||||
{
|
||||
}
|
||||
|
||||
public function onCreate(Created $event): void
|
||||
{
|
||||
$message = trans(
|
||||
'user-activity::log.new_role',
|
||||
['name' => $event->getRole()->display_name]
|
||||
);
|
||||
|
||||
$this->logger->log($message);
|
||||
}
|
||||
|
||||
public function onUpdate(Updated $event): void
|
||||
{
|
||||
$message = trans(
|
||||
'user-activity::log.updated_role',
|
||||
['name' => $event->getRole()->display_name]
|
||||
);
|
||||
|
||||
$this->logger->log($message);
|
||||
}
|
||||
|
||||
public function onDelete(Deleted $event): void
|
||||
{
|
||||
$message = trans(
|
||||
'user-activity::log.deleted_role',
|
||||
['name' => $event->getRole()->display_name]
|
||||
);
|
||||
|
||||
$this->logger->log($message);
|
||||
}
|
||||
|
||||
public function onPermissionsUpdate(PermissionsUpdated $event): void
|
||||
{
|
||||
$this->logger->log(trans('user-activity::log.updated_role_permissions'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the listeners for the subscriber.
|
||||
*/
|
||||
public function subscribe(Dispatcher $events): void
|
||||
{
|
||||
$class = self::class;
|
||||
|
||||
$events->listen(Created::class, "{$class}@onCreate");
|
||||
$events->listen(Updated::class, "{$class}@onUpdate");
|
||||
$events->listen(Deleted::class, "{$class}@onDelete");
|
||||
$events->listen(PermissionsUpdated::class, "{$class}@onPermissionsUpdate");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
<?php
|
||||
|
||||
namespace Vanguard\UserActivity\Listeners;
|
||||
|
||||
use Illuminate\Auth\Events\PasswordReset;
|
||||
use Illuminate\Auth\Events\Registered;
|
||||
use Illuminate\Events\Dispatcher;
|
||||
use Lab404\Impersonate\Events\LeaveImpersonation;
|
||||
use Lab404\Impersonate\Events\TakeImpersonation;
|
||||
use Vanguard\Events\Settings\Updated as SettingsUpdated;
|
||||
use Vanguard\Events\User\Banned;
|
||||
use Vanguard\Events\User\ChangedAvatar;
|
||||
use Vanguard\Events\User\Created;
|
||||
use Vanguard\Events\User\Deleted;
|
||||
use Vanguard\Events\User\LoggedIn;
|
||||
use Vanguard\Events\User\LoggedOut;
|
||||
use Vanguard\Events\User\RequestedPasswordResetEmail;
|
||||
use Vanguard\Events\User\TwoFactorDisabled;
|
||||
use Vanguard\Events\User\TwoFactorDisabledByAdmin;
|
||||
use Vanguard\Events\User\TwoFactorEnabled;
|
||||
use Vanguard\Events\User\TwoFactorEnabledByAdmin;
|
||||
use Vanguard\Events\User\UpdatedByAdmin;
|
||||
use Vanguard\Events\User\UpdatedProfileDetails;
|
||||
use Vanguard\UserActivity\Logger;
|
||||
|
||||
class UserEventsSubscriber
|
||||
{
|
||||
public function __construct(private readonly Logger $logger)
|
||||
{
|
||||
}
|
||||
|
||||
public function onLogin(LoggedIn $event): void
|
||||
{
|
||||
$this->logger->log(trans('user-activity::log.logged_in'));
|
||||
}
|
||||
|
||||
public function onLogout(LoggedOut $event): void
|
||||
{
|
||||
$this->logger->log(trans('user-activity::log.logged_out'));
|
||||
}
|
||||
|
||||
public function onRegister(Registered $event): void
|
||||
{
|
||||
$this->logger->setUser($event->user);
|
||||
$this->logger->log(trans('user-activity::log.created_account'));
|
||||
}
|
||||
|
||||
public function onAvatarChange(ChangedAvatar $event): void
|
||||
{
|
||||
$this->logger->log(trans('user-activity::log.updated_avatar'));
|
||||
}
|
||||
|
||||
public function onProfileDetailsUpdate(UpdatedProfileDetails $event): void
|
||||
{
|
||||
$this->logger->log(trans('user-activity::log.updated_profile'));
|
||||
}
|
||||
|
||||
public function onDelete(Deleted $event): void
|
||||
{
|
||||
$message = trans(
|
||||
'user-activity::log.deleted_user',
|
||||
['name' => $event->getDeletedUser()->present()->nameOrEmail]
|
||||
);
|
||||
|
||||
$this->logger->log($message);
|
||||
}
|
||||
|
||||
public function onBan(Banned $event): void
|
||||
{
|
||||
$message = trans(
|
||||
'user-activity::log.banned_user',
|
||||
['name' => $event->getBannedUser()->present()->nameOrEmail]
|
||||
);
|
||||
|
||||
$this->logger->log($message);
|
||||
}
|
||||
|
||||
public function onUpdateByAdmin(UpdatedByAdmin $event): void
|
||||
{
|
||||
$message = trans(
|
||||
'user-activity::log.updated_profile_details_for',
|
||||
['name' => $event->getUpdatedUser()->present()->nameOrEmail]
|
||||
);
|
||||
|
||||
$this->logger->log($message);
|
||||
}
|
||||
|
||||
public function onCreate(Created $event): void
|
||||
{
|
||||
$message = trans(
|
||||
'user-activity::log.created_account_for',
|
||||
['name' => $event->getCreatedUser()->present()->nameOrEmail]
|
||||
);
|
||||
|
||||
$this->logger->log($message);
|
||||
}
|
||||
|
||||
public function onSettingsUpdate(SettingsUpdated $event): void
|
||||
{
|
||||
$this->logger->log(trans('user-activity::log.updated_settings'));
|
||||
}
|
||||
|
||||
public function onTwoFactorEnable(TwoFactorEnabled $event): void
|
||||
{
|
||||
$this->logger->log(trans('user-activity::log.enabled_2fa'));
|
||||
}
|
||||
|
||||
public function onTwoFactorDisable(TwoFactorDisabled $event): void
|
||||
{
|
||||
$this->logger->log(trans('user-activity::log.disabled_2fa'));
|
||||
}
|
||||
|
||||
public function onTwoFactorEnableByAdmin(TwoFactorEnabledByAdmin $event): void
|
||||
{
|
||||
$message = trans(
|
||||
'user-activity::log.enabled_2fa_for',
|
||||
['name' => $event->getUser()->present()->nameOrEmail]
|
||||
);
|
||||
|
||||
$this->logger->log($message);
|
||||
}
|
||||
|
||||
public function onTwoFactorDisableByAdmin(TwoFactorDisabledByAdmin $event): void
|
||||
{
|
||||
$message = trans(
|
||||
'user-activity::log.disabled_2fa_for',
|
||||
['name' => $event->getUser()->present()->nameOrEmail]
|
||||
);
|
||||
|
||||
$this->logger->log($message);
|
||||
}
|
||||
|
||||
public function onPasswordResetEmailRequest(RequestedPasswordResetEmail $event): void
|
||||
{
|
||||
$this->logger->setUser($event->getUser());
|
||||
$this->logger->log(trans('user-activity::log.requested_password_reset'));
|
||||
}
|
||||
|
||||
public function onPasswordReset(PasswordReset $event): void
|
||||
{
|
||||
$this->logger->setUser($event->user);
|
||||
$this->logger->log(trans('user-activity::log.reseted_password'));
|
||||
}
|
||||
|
||||
public function onStartImpersonating(TakeImpersonation $event): void
|
||||
{
|
||||
$this->logger->setUser($event->impersonator);
|
||||
|
||||
$message = trans('user-activity::log.started_impersonating', [
|
||||
'id' => $event->impersonated->id,
|
||||
'name' => $event->impersonated->present()->name,
|
||||
]);
|
||||
|
||||
$this->logger->log($message);
|
||||
}
|
||||
|
||||
public function onStopImpersonating(LeaveImpersonation $event): void
|
||||
{
|
||||
$this->logger->setUser($event->impersonator);
|
||||
|
||||
$message = trans('user-activity::log.stopped_impersonating', [
|
||||
'id' => $event->impersonated->id,
|
||||
'name' => $event->impersonated->present()->name,
|
||||
]);
|
||||
|
||||
$this->logger->log($message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the listeners for the subscriber.
|
||||
*/
|
||||
public function subscribe(Dispatcher $events)
|
||||
{
|
||||
$class = self::class;
|
||||
|
||||
$events->listen(LoggedIn::class, "{$class}@onLogin");
|
||||
$events->listen(LoggedOut::class, "{$class}@onLogout");
|
||||
$events->listen(Registered::class, "{$class}@onRegister");
|
||||
$events->listen(Created::class, "{$class}@onCreate");
|
||||
$events->listen(ChangedAvatar::class, "{$class}@onAvatarChange");
|
||||
$events->listen(UpdatedProfileDetails::class, "{$class}@onProfileDetailsUpdate");
|
||||
$events->listen(UpdatedByAdmin::class, "{$class}@onUpdateByAdmin");
|
||||
$events->listen(Deleted::class, "{$class}@onDelete");
|
||||
$events->listen(Banned::class, "{$class}@onBan");
|
||||
$events->listen(SettingsUpdated::class, "{$class}@onSettingsUpdate");
|
||||
$events->listen(TwoFactorEnabled::class, "{$class}@onTwoFactorEnable");
|
||||
$events->listen(TwoFactorDisabled::class, "{$class}@onTwoFactorDisable");
|
||||
$events->listen(TwoFactorEnabledByAdmin::class, "{$class}@onTwoFactorEnableByAdmin");
|
||||
$events->listen(TwoFactorDisabledByAdmin::class, "{$class}@onTwoFactorDisableByAdmin");
|
||||
$events->listen(RequestedPasswordResetEmail::class, "{$class}@onPasswordResetEmailRequest");
|
||||
$events->listen(PasswordReset::class, "{$class}@onPasswordReset");
|
||||
$events->listen(TakeImpersonation::class, "{$class}@onStartImpersonating");
|
||||
$events->listen(LeaveImpersonation::class, "{$class}@onStopImpersonating");
|
||||
}
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace Vanguard\UserActivity;
|
||||
|
||||
use Illuminate\Contracts\Auth\Factory;
|
||||
use Illuminate\Http\Request;
|
||||
use Vanguard\User;
|
||||
use Vanguard\UserActivity\Repositories\Activity\ActivityRepository;
|
||||
|
||||
class Logger
|
||||
{
|
||||
protected ?User $user = null;
|
||||
|
||||
public function __construct(
|
||||
private readonly Request $request,
|
||||
private readonly Factory $auth,
|
||||
private readonly ActivityRepository $activities
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Log user action.
|
||||
*/
|
||||
public function log($description): Activity
|
||||
{
|
||||
return $this->activities->log([
|
||||
'description' => $description,
|
||||
'user_id' => $this->getUserId(),
|
||||
'ip_address' => $this->request->ip(),
|
||||
'user_agent' => $this->getUserAgent(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get id if the user for who we want to log this action.
|
||||
* If user was manually set, then we will just return id of that user.
|
||||
* If not, we will return the id of currently logged user.
|
||||
*/
|
||||
private function getUserId(): ?int
|
||||
{
|
||||
if ($this->user) {
|
||||
return $this->user->id;
|
||||
}
|
||||
|
||||
return $this->auth->guard()->id();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user agent from request headers.
|
||||
*/
|
||||
private function getUserAgent(): string
|
||||
{
|
||||
return substr((string) $this->request->header('User-Agent'), 0, 500);
|
||||
}
|
||||
|
||||
public function setUser(?User $user): void
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace Vanguard\UserActivity\Repositories\Activity;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Support\Collection as BaseCollection;
|
||||
use Vanguard\UserActivity\Activity;
|
||||
|
||||
interface ActivityRepository
|
||||
{
|
||||
/**
|
||||
* Log user activity.
|
||||
*
|
||||
* @param $data array Array with following fields:
|
||||
* description (string) - Description of user activity.
|
||||
* user_id (int) - User unique identifier.
|
||||
* ip_address (string) - Ip address from which user is accessing the website.
|
||||
* user_agent (string) - User's browser info.
|
||||
* @return mixed
|
||||
*/
|
||||
public function log(array $data): Activity;
|
||||
|
||||
/**
|
||||
* Paginate activities for user.
|
||||
*/
|
||||
public function paginateActivitiesForUser(
|
||||
int $userId,
|
||||
int $perPage = 20,
|
||||
?string $search = null
|
||||
): LengthAwarePaginator;
|
||||
|
||||
/**
|
||||
* Get specified number of latest user activity logs.
|
||||
*
|
||||
* @return Collection<Activity>
|
||||
*/
|
||||
public function getLatestActivitiesForUser(int $userId, int $activitiesCount = 10): Collection;
|
||||
|
||||
/**
|
||||
* Paginate all activity records.
|
||||
*/
|
||||
public function paginateActivities(int $perPage = 20, ?string $search = null): LengthAwarePaginator;
|
||||
|
||||
/**
|
||||
* Get count of user activities per day for given period of time.
|
||||
*/
|
||||
public function userActivityForPeriod(int $userId, Carbon $from, Carbon $to): BaseCollection;
|
||||
}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
namespace Vanguard\UserActivity\Repositories\Activity;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use DB;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Support\Collection as BaseCollection;
|
||||
use Vanguard\UserActivity\Activity;
|
||||
|
||||
class EloquentActivity implements ActivityRepository
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function log($data): Activity
|
||||
{
|
||||
return Activity::create($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function paginateActivitiesForUser(
|
||||
int $userId,
|
||||
int $perPage = 20,
|
||||
?string $search = null
|
||||
): LengthAwarePaginator {
|
||||
$query = Activity::where('user_id', $userId);
|
||||
|
||||
return $this->paginateAndFilterResults($perPage, $search, $query);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getLatestActivitiesForUser(int $userId, int $activitiesCount = 10): Collection
|
||||
{
|
||||
return Activity::where('user_id', $userId)
|
||||
->orderBy('created_at', 'DESC')
|
||||
->limit($activitiesCount)
|
||||
->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function paginateActivities(int $perPage = 20, ?string $search = null): LengthAwarePaginator
|
||||
{
|
||||
$query = Activity::with('user');
|
||||
|
||||
return $this->paginateAndFilterResults($perPage, $search, $query);
|
||||
}
|
||||
|
||||
private function paginateAndFilterResults($perPage, $search, $query): LengthAwarePaginator
|
||||
{
|
||||
if ($search) {
|
||||
$query->where('description', 'LIKE', "%$search%");
|
||||
}
|
||||
|
||||
$result = $query->orderBy('created_at', 'DESC')
|
||||
->paginate($perPage);
|
||||
|
||||
if ($search) {
|
||||
$result->appends(['search' => $search]);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function userActivityForPeriod($userId, Carbon $from, Carbon $to): BaseCollection
|
||||
{
|
||||
$result = Activity::select([
|
||||
DB::raw('DATE(created_at) as day'),
|
||||
DB::raw('count(id) as count'),
|
||||
])
|
||||
->where('user_id', $userId)
|
||||
->whereBetween('created_at', [$from, $to])
|
||||
->groupBy('day')
|
||||
->orderBy('day', 'ASC')
|
||||
->pluck('count', 'day');
|
||||
|
||||
while (! $from->isSameDay($to)) {
|
||||
if (! $result->has($from->toDateString())) {
|
||||
$result->put($from->toDateString(), 0);
|
||||
}
|
||||
$from->addDay();
|
||||
}
|
||||
|
||||
return $result->sortBy(function ($value, $key) {
|
||||
return strtotime($key);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
namespace Vanguard\UserActivity;
|
||||
|
||||
use Event;
|
||||
use Route;
|
||||
use Vanguard\Plugins\Plugin;
|
||||
use Vanguard\Support\Sidebar\Item;
|
||||
use Vanguard\UserActivity\Http\View\Composers\ShowUserComposer;
|
||||
use Vanguard\UserActivity\Listeners\PermissionEventsSubscriber;
|
||||
use Vanguard\UserActivity\Listeners\RoleEventsSubscriber;
|
||||
use Vanguard\UserActivity\Listeners\UserEventsSubscriber;
|
||||
use Vanguard\UserActivity\Repositories\Activity\ActivityRepository;
|
||||
use Vanguard\UserActivity\Repositories\Activity\EloquentActivity;
|
||||
use View;
|
||||
|
||||
class UserActivity extends Plugin
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function sidebar(): Item
|
||||
{
|
||||
return Item::create(__('Activity Log'))
|
||||
->route('activity.index')
|
||||
->icon('fas fa-server')
|
||||
->active('activity*')
|
||||
->permissions('users.activity');
|
||||
}
|
||||
|
||||
/**
|
||||
* Register services.
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
$this->app->singleton(ActivityRepository::class, EloquentActivity::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap services.
|
||||
*
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Container\BindingResolutionException
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
$this->loadViewsFrom(__DIR__.'/../resources/views', 'user-activity');
|
||||
$this->loadTranslationsFrom(__DIR__.'/../resources/lang', 'user-activity');
|
||||
$this->loadJsonTranslationsFrom(__DIR__.'/../resources/lang');
|
||||
|
||||
$this->publishes([
|
||||
__DIR__.'/../database/migrations' => database_path('migrations'),
|
||||
], 'migrations');
|
||||
|
||||
$this->app->booted(function () {
|
||||
$this->mapWebRoutes();
|
||||
|
||||
if ($this->app['config']->get('auth.expose_api')) {
|
||||
$this->mapApiRoutes();
|
||||
}
|
||||
});
|
||||
|
||||
$this->attachViewComposers();
|
||||
|
||||
$this->registerEventListeners();
|
||||
}
|
||||
|
||||
/**
|
||||
* Map web plugin related routes.
|
||||
*/
|
||||
protected function mapWebRoutes(): void
|
||||
{
|
||||
Route::group([
|
||||
'namespace' => 'Vanguard\UserActivity\Http\Controllers\Web',
|
||||
'middleware' => 'web',
|
||||
], function () {
|
||||
$this->loadRoutesFrom(__DIR__.'/../routes/web.php');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Map API plugin related routes.
|
||||
*/
|
||||
protected function mapApiRoutes(): void
|
||||
{
|
||||
Route::group([
|
||||
'namespace' => 'Vanguard\UserActivity\Http\Controllers\Api',
|
||||
'middleware' => 'api',
|
||||
'prefix' => 'api',
|
||||
], function () {
|
||||
$this->loadRoutesFrom(__DIR__.'/../routes/api.php');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Register event subscribers for the plugin.
|
||||
*/
|
||||
private function registerEventListeners(): void
|
||||
{
|
||||
Event::subscribe(PermissionEventsSubscriber::class);
|
||||
Event::subscribe(RoleEventsSubscriber::class);
|
||||
Event::subscribe(UserEventsSubscriber::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach view composers to add necessary data to the view.
|
||||
*/
|
||||
private function attachViewComposers(): void
|
||||
{
|
||||
View::composer('user.view', ShowUserComposer::class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace Vanguard\UserActivity\Widgets;
|
||||
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Vanguard\Plugins\Widget;
|
||||
use Vanguard\User;
|
||||
use Vanguard\UserActivity\Repositories\Activity\ActivityRepository;
|
||||
|
||||
class ActivityWidget extends Widget
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public ?string $width = '12';
|
||||
|
||||
private ?array $userActivity = null;
|
||||
|
||||
public function __construct(private readonly ActivityRepository $activities)
|
||||
{
|
||||
$this->permissions(function (User $user) {
|
||||
return $user->hasRole('User');
|
||||
});
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
{
|
||||
return view('user-activity::widgets.user-activity', [
|
||||
'activities' => $this->getActivity(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function scripts(): View
|
||||
{
|
||||
return view('user-activity::widgets.user-activity-scripts', [
|
||||
'activities' => $this->getActivity(),
|
||||
]);
|
||||
}
|
||||
|
||||
private function getActivity(): array
|
||||
{
|
||||
if ($this->userActivity) {
|
||||
return $this->userActivity;
|
||||
}
|
||||
|
||||
return $this->userActivity = $this->activities->userActivityForPeriod(
|
||||
Auth::user()->id,
|
||||
Carbon::now()->subWeeks(2),
|
||||
Carbon::now()
|
||||
)->toArray();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user