This commit is contained in:
Bozhidar Slaveykov 2024-04-02 20:43:56 +03:00
parent 0e64baf925
commit 7178d7b530
17 changed files with 525 additions and 2 deletions

View file

@ -21,6 +21,8 @@ class CronJobResource extends Resource
protected static ?string $navigationGroup = 'System';
protected static ?int $navigationSort = 98;
public static function form(Form $form): Form
{
return $form

View file

@ -0,0 +1,88 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\UserResource\Pages;
use App\Filament\Resources\UserResource\RelationManagers;
use App\Models\User;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
class UserResource extends Resource
{
protected static ?string $model = User::class;
protected static ?string $navigationIcon = 'heroicon-o-users';
protected static ?string $navigationGroup = 'System';
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\TextInput::make('name')
->label('Name')
->required(),
Forms\Components\TextInput::make('email')
->label('Email')
->required()
->email(),
Forms\Components\TextInput::make('password')
->label('Password')
->password()
->autocomplete('new-password')
->required(),
Forms\Components\TextInput::make('password_confirmation')
->label('Confirm Password')
->password()
->autocomplete('new-password')
->required(),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('name')
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('email')
->searchable()
->sortable(),
])
->filters([
//
])
->actions([
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListUsers::route('/'),
'create' => Pages\CreateUser::route('/create'),
'edit' => Pages\EditUser::route('/{record}/edit'),
];
}
}

View file

@ -0,0 +1,12 @@
<?php
namespace App\Filament\Resources\UserResource\Pages;
use App\Filament\Resources\UserResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateUser extends CreateRecord
{
protected static string $resource = UserResource::class;
}

View file

@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\UserResource\Pages;
use App\Filament\Resources\UserResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditUser extends EditRecord
{
protected static string $resource = UserResource::class;
protected function getHeaderActions(): array
{
return [
Actions\DeleteAction::make(),
];
}
}

View file

@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\UserResource\Pages;
use App\Filament\Resources\UserResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListUsers extends ListRecords
{
protected static string $resource = UserResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View file

@ -7,10 +7,11 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
use Rappasoft\LaravelAuthenticationLog\Traits\AuthenticationLoggable;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
use HasApiTokens, HasFactory, Notifiable, AuthenticationLoggable;
/**
* The attributes that are mass assignable.

View file

@ -20,6 +20,7 @@ use Illuminate\Session\Middleware\AuthenticateSession;
use Illuminate\Session\Middleware\StartSession;
use Illuminate\View\Middleware\ShareErrorsFromSession;
use Outerweb\FilamentSettings\Filament\Plugins\FilamentSettingsPlugin;
use Tapp\FilamentAuthenticationLog\FilamentAuthenticationLogPlugin;
class AdminPanelProvider extends PanelProvider
{
@ -45,6 +46,7 @@ class AdminPanelProvider extends PanelProvider
Pages\Dashboard::class,
])
->plugins([
FilamentAuthenticationLogPlugin::make(),
FilamentSettingsPlugin::make()
->pages([
Settings::class,

View file

@ -23,6 +23,8 @@
"outerweb/filament-settings": "^1.2",
"symfony/process": "^6.3",
"symfony/yaml": "^7.0",
"tapp/filament-authentication-log": "^3.0",
"torann/geoip": "^3.0",
"wikimedia/composer-merge-plugin": "^2.1"
},
"require-dev": {

221
web/composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "b3fbcaa09543eb342a97b6018f7dbc2a",
"content-hash": "54fc8e1999adfcd032b56ace1d43ee45",
"packages": [
{
"name": "acmephp/core",
@ -5603,6 +5603,77 @@
],
"time": "2023-11-08T05:53:05+00:00"
},
{
"name": "rappasoft/laravel-authentication-log",
"version": "v3.0.0",
"source": {
"type": "git",
"url": "https://github.com/rappasoft/laravel-authentication-log.git",
"reference": "6ab94190c970deab60360ec17b79d06c2a4368cd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/rappasoft/laravel-authentication-log/zipball/6ab94190c970deab60360ec17b79d06c2a4368cd",
"reference": "6ab94190c970deab60360ec17b79d06c2a4368cd",
"shasum": ""
},
"require": {
"illuminate/contracts": "^10.0",
"php": "^8.1",
"spatie/laravel-package-tools": "^1.4.3"
},
"require-dev": {
"nunomaduro/collision": "^6.0",
"orchestra/testbench": "^7.0",
"pestphp/pest": "^1.21",
"pestphp/pest-plugin-laravel": "^1.2",
"spatie/laravel-ray": "^1.29",
"vimeo/psalm": "^4.20"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"Rappasoft\\LaravelAuthenticationLog\\LaravelAuthenticationLogServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"Rappasoft\\LaravelAuthenticationLog\\": "src",
"Rappasoft\\LaravelAuthenticationLog\\Database\\Factories\\": "database/factories"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Anthony Rappa",
"email": "rappa819@gmail.com",
"role": "Developer"
}
],
"description": "Log user authentication details and send new device notifications.",
"homepage": "https://github.com/rappasoft/laravel-authentication-log",
"keywords": [
"laravel",
"laravel-authentication-log",
"rappasoft"
],
"support": {
"issues": "https://github.com/rappasoft/laravel-authentication-log/issues",
"source": "https://github.com/rappasoft/laravel-authentication-log/tree/v3.0.0"
},
"funding": [
{
"url": "https://github.com/rappasoft",
"type": "github"
}
],
"time": "2023-02-23T18:45:01+00:00"
},
{
"name": "ryangjchandler/blade-capture-directive",
"version": "v1.0.0",
@ -8229,6 +8300,74 @@
],
"time": "2024-01-23T15:02:46+00:00"
},
{
"name": "tapp/filament-authentication-log",
"version": "v3.0.3",
"source": {
"type": "git",
"url": "https://github.com/TappNetwork/filament-authentication-log.git",
"reference": "66927755660baaa0f3b4d2f1c701517120047b12"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/TappNetwork/filament-authentication-log/zipball/66927755660baaa0f3b4d2f1c701517120047b12",
"reference": "66927755660baaa0f3b4d2f1c701517120047b12",
"shasum": ""
},
"require": {
"filament/filament": "^3.0-stable",
"php": "^8.1",
"rappasoft/laravel-authentication-log": "^3.0",
"spatie/laravel-package-tools": "^1.9"
},
"require-dev": {
"laravel/pint": "^1.11"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"Tapp\\FilamentAuthenticationLog\\FilamentAuthenticationLogServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"Tapp\\FilamentAuthenticationLog\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Tapp Network",
"email": "steve@tappnetwork.com",
"role": "Developer"
},
{
"name": "Tapp Network",
"email": "andreia.bohner@tappnetwork.com",
"role": "Developer"
}
],
"description": "Filament authentication log plugin.",
"homepage": "https://github.com/TappNetwork/filament-authentication-log",
"keywords": [
"Authentication",
"filament",
"log",
"relation manager",
"resource",
"tapp network"
],
"support": {
"issues": "https://github.com/TappNetwork/filament-authentication-log/issues",
"source": "https://github.com/TappNetwork/filament-authentication-log"
},
"time": "2024-03-08T17:01:28+00:00"
},
{
"name": "tijsverkoyen/css-to-inline-styles",
"version": "v2.2.7",
@ -8282,6 +8421,86 @@
},
"time": "2023-12-08T13:03:43+00:00"
},
{
"name": "torann/geoip",
"version": "3.0.7",
"source": {
"type": "git",
"url": "https://github.com/Torann/laravel-geoip.git",
"reference": "a0600618e2ea145e018361498ff4cadf773dbe5b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Torann/laravel-geoip/zipball/a0600618e2ea145e018361498ff4cadf773dbe5b",
"reference": "a0600618e2ea145e018361498ff4cadf773dbe5b",
"shasum": ""
},
"require": {
"illuminate/cache": "^8.0|^9.0|^10.0|^11.0",
"illuminate/console": "^8.0|^9.0|^10.0|^11.0",
"illuminate/support": "^8.0|^9.0|^10.0|^11.0",
"php": "^8.0|^8.1|^8.2|^8.3"
},
"require-dev": {
"geoip2/geoip2": "~2.1|~3.0",
"mockery/mockery": "^1.3",
"phpstan/phpstan": "^0.12.14|^1.9",
"phpunit/phpunit": "^8.0|^9.0|^10.0|^11.0",
"squizlabs/php_codesniffer": "^3.5",
"vlucas/phpdotenv": "^5.0"
},
"suggest": {
"geoip2/geoip2": "Required to use the MaxMind database or web service with GeoIP (~2.1).",
"monolog/monolog": "Allows for storing location not found errors to the log"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
},
"laravel": {
"providers": [
"Torann\\GeoIP\\GeoIPServiceProvider"
],
"aliases": {
"GeoIP": "Torann\\GeoIP\\Facades\\GeoIP"
}
}
},
"autoload": {
"files": [
"src/helpers.php"
],
"psr-4": {
"Torann\\GeoIP\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-2-Clause"
],
"authors": [
{
"name": "Daniel Stainback",
"email": "torann@gmail.com"
}
],
"description": "Support for multiple GeoIP services.",
"keywords": [
"IP API",
"geoip",
"geolocation",
"infoDB",
"laravel",
"location",
"maxmind"
],
"support": {
"issues": "https://github.com/Torann/laravel-geoip/issues",
"source": "https://github.com/Torann/laravel-geoip/tree/3.0.7"
},
"time": "2024-03-22T18:39:18+00:00"
},
{
"name": "vlucas/phpdotenv",
"version": "v5.6.0",

View file

@ -0,0 +1,45 @@
<?php
return [
// The database table name
// You can change this if the database keys get too long for your driver
'table_name' => 'authentication_log',
// The database connection where the authentication_log table resides. Leave empty to use the default
'db_connection' => null,
// The events the package listens for to log
'events' => [
'login' => \Illuminate\Auth\Events\Login::class,
'failed' => \Illuminate\Auth\Events\Failed::class,
'logout' => \Illuminate\Auth\Events\Logout::class,
'logout-other-devices' => \Illuminate\Auth\Events\OtherDeviceLogout::class,
],
'notifications' => [
'new-device' => [
// Send the NewDevice notification
'enabled' => env('NEW_DEVICE_NOTIFICATION', true),
// Use torann/geoip to attempt to get a location
'location' => true,
// The Notification class to send
'template' => \Rappasoft\LaravelAuthenticationLog\Notifications\NewDevice::class,
],
'failed-login' => [
// Send the FailedLogin notification
'enabled' => env('FAILED_LOGIN_NOTIFICATION', false),
// Use torann/geoip to attempt to get a location
'location' => true,
// The Notification class to send
'template' => \Rappasoft\LaravelAuthenticationLog\Notifications\FailedLogin::class,
],
],
// When the clean-up command is run, delete old logs greater than `purge` days
// Don't schedule the clean-up command if you want to keep logs forever.
'purge' => 365,
];

View file

@ -0,0 +1,25 @@
<?php
return [
'resources' => [
'AutenticationLogResource' => \Tapp\FilamentAuthenticationLog\Resources\AuthenticationLogResource::class,
],
'authenticable-resources' => [
\App\Models\User::class,
],
'navigation' => [
'authentication-log' => [
'register' => true,
'sort' => 1,
'icon' => 'heroicon-o-shield-check',
],
],
'sort' => [
'column' => 'login_at',
'direction' => 'desc',
],
];

View file

@ -0,0 +1,23 @@
<?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(config('authentication-log.table_name'), function (Blueprint $table) {
$table->id();
$table->morphs('authenticatable');
$table->string('ip_address', 45)->nullable();
$table->text('user_agent')->nullable();
$table->timestamp('login_at')->nullable();
$table->boolean('login_successful')->default(false);
$table->timestamp('logout_at')->nullable();
$table->boolean('cleared_by_user')->default(false);
$table->json('location')->nullable();
});
}
};

View file

@ -0,0 +1,15 @@
{
"A failed login to your account": "A failed login to your account",
"Account:": "Account:",
"Browser:": "Browser:",
"Hello!": "Hello!",
"If this was you, you can ignore this alert. If you suspect any suspicious activity on your account, please change your password.": "If this was you, you can ignore this alert. If you suspect any suspicious activity on your account, please change your password.",
"IP Address:": "IP Address:",
"Location:": "Location:",
"Regards,": "Regards,",
"There has been a failed login attempt to your :app account.": "There has been a failed login attempt to your :app account.",
"Time:": "Time:",
"Unknown City": "Unknown City",
"Unknown State": "Unknown State",
"Your :app account logged in from a new device.": "Your :app account logged in from a new device."
}

View file

@ -0,0 +1,15 @@
{
"A failed login to your account": "Échec de la connexion à votre compte",
"Account:": "Compte :",
"Browser:": "Navigateur :",
"Hello!": "Bonjour,",
"If this was you, you can ignore this alert. If you suspect any suspicious activity on your account, please change your password.": "Si cétait vous, vous pouvez ignorer cette alerte. Si vous soupçonnez une activité suspecte sur votre compte, veuillez modifier votre mot de passe.",
"IP Address:": "Adresse IP :",
"Location:": "Emplacement :",
"Regards,": "Cordialement,",
"There has been a failed login attempt to your :app account.": "Une tentative de connexion à votre compte sur :app a échoué.",
"Time:": "Heure :",
"Unknown City": "Ville inconnue",
"Unknown State": "État inconnu",
"Your :app account logged in from a new device.": "Connexion à votre compte sur :app depuis un nouvel appareil."
}

View file

View file

@ -0,0 +1,18 @@
@component('mail::message')
# @lang('Hello!')
@lang('There has been a failed login attempt to your :app account.', ['app' => config('app.name')])
> **@lang('Account:')** {{ $account->email }}<br/>
> **@lang('Time:')** {{ $time->toCookieString() }}<br/>
> **@lang('IP Address:')** {{ $ipAddress }}<br/>
> **@lang('Browser:')** {{ $browser }}<br/>
@if ($location && $location['default'] === false)
> **@lang('Location:')** {{ $location['city'] ?? __('Unknown City') }}, {{ $location['state'], __('Unknown State') }}
@endif
@lang('If this was you, you can ignore this alert. If you suspect any suspicious activity on your account, please change your password.')
@lang('Regards,')<br/>
{{ config('app.name') }}
@endcomponent

View file

@ -0,0 +1,18 @@
@component('mail::message')
# @lang('Hello!')
@lang('Your :app account logged in from a new device.', ['app' => config('app.name')])
> **@lang('Account:')** {{ $account->email }}<br/>
> **@lang('Time:')** {{ $time->toCookieString() }}<br/>
> **@lang('IP Address:')** {{ $ipAddress }}<br/>
> **@lang('Browser:')** {{ $browser }}<br/>
@if ($location && $location['default'] === false)
> **@lang('Location:')** {{ $location['city'] ?? __('Unknown City') }}, {{ $location['state'], __('Unknown State') }}
@endif
@lang('If this was you, you can ignore this alert. If you suspect any suspicious activity on your account, please change your password.')
@lang('Regards,')<br/>
{{ config('app.name') }}
@endcomponent