firs commit
This commit is contained in:
commit
8cbae222cc
18
.editorconfig
Normal file
18
.editorconfig
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
indent_size = 4
|
||||||
|
indent_style = space
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
|
[*.{yml,yaml}]
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[docker-compose.yml]
|
||||||
|
indent_size = 4
|
||||||
41
.env.example
Normal file
41
.env.example
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
APP_ENV=production
|
||||||
|
APP_DEBUG=false
|
||||||
|
APP_KEY=
|
||||||
|
APP_URL=http://vanguard.test
|
||||||
|
|
||||||
|
LOG_CHANNEL=stack
|
||||||
|
|
||||||
|
DB_CONNECTION=mysql
|
||||||
|
DB_HOST=localhost
|
||||||
|
DB_DATABASE=vanguard
|
||||||
|
DB_USERNAME=homestead
|
||||||
|
DB_PASSWORD=secret
|
||||||
|
DB_PREFIX=vg_
|
||||||
|
|
||||||
|
BROADCAST_DRIVER=log
|
||||||
|
CACHE_DRIVER=file
|
||||||
|
QUEUE_DRIVER=sync
|
||||||
|
SESSION_DRIVER=database
|
||||||
|
SESSION_LIFETIME=120
|
||||||
|
|
||||||
|
REDIS_HOST=127.0.0.1
|
||||||
|
REDIS_PASSWORD=null
|
||||||
|
REDIS_PORT=6379
|
||||||
|
|
||||||
|
MAIL_MAILER=mail
|
||||||
|
MAIL_FROM_NAME=Vanguard
|
||||||
|
MAIL_FROM_ADDRESS=vanguard@test.dev
|
||||||
|
MAIL_HOST=smtp.mailtrap.io
|
||||||
|
MAIL_PORT=2525
|
||||||
|
MAIL_USERNAME=null
|
||||||
|
MAIL_PASSWORD=null
|
||||||
|
MAIL_ENCRYPTION=null
|
||||||
|
|
||||||
|
PUSHER_APP_ID=
|
||||||
|
PUSHER_APP_KEY=
|
||||||
|
PUSHER_APP_SECRET=
|
||||||
|
PUSHER_APP_CLUSTER=mt1
|
||||||
|
|
||||||
|
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
|
||||||
|
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
||||||
|
|
||||||
11
.gitattributes
vendored
Normal file
11
.gitattributes
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
* text=auto eol=lf
|
||||||
|
|
||||||
|
*.blade.php diff=html
|
||||||
|
*.css diff=css
|
||||||
|
*.html diff=html
|
||||||
|
*.md diff=markdown
|
||||||
|
*.php diff=php
|
||||||
|
|
||||||
|
/.github export-ignore
|
||||||
|
CHANGELOG.md export-ignore
|
||||||
|
.styleci.yml export-ignore
|
||||||
23
.gitignore
vendored
Normal file
23
.gitignore
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
.DS_Store
|
||||||
|
/node_modules
|
||||||
|
/public/hot
|
||||||
|
/public/storage
|
||||||
|
/storage/*.key
|
||||||
|
/vendor
|
||||||
|
/.idea
|
||||||
|
/.fleet
|
||||||
|
/.vscode
|
||||||
|
/.vagrant
|
||||||
|
Homestead.json
|
||||||
|
Homestead.yaml
|
||||||
|
npm-debug.log
|
||||||
|
yarn-error.log
|
||||||
|
.env
|
||||||
|
.phpunit.result.cache
|
||||||
|
.php_cs.cache
|
||||||
|
/documentation
|
||||||
|
/.phpunit.cache
|
||||||
|
/public/build
|
||||||
|
.env.backup
|
||||||
|
.env.production
|
||||||
|
auth.json
|
||||||
9
.styleci.yml
Normal file
9
.styleci.yml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
php:
|
||||||
|
preset: laravel
|
||||||
|
disabled:
|
||||||
|
- no_unused_imports
|
||||||
|
finder:
|
||||||
|
not-name:
|
||||||
|
- index.php
|
||||||
|
js: true
|
||||||
|
css: true
|
||||||
28365
_ide_helper.php
Normal file
28365
_ide_helper.php
Normal file
File diff suppressed because it is too large
Load Diff
27
app/Console/Kernel.php
Normal file
27
app/Console/Kernel.php
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Console;
|
||||||
|
|
||||||
|
use Illuminate\Console\Scheduling\Schedule;
|
||||||
|
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
||||||
|
|
||||||
|
class Kernel extends ConsoleKernel
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Define the application's command schedule.
|
||||||
|
*/
|
||||||
|
protected function schedule(Schedule $schedule): void
|
||||||
|
{
|
||||||
|
// $schedule->command('inspire')->hourly();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the commands for the application.
|
||||||
|
*/
|
||||||
|
protected function commands(): void
|
||||||
|
{
|
||||||
|
$this->load(__DIR__.'/Commands');
|
||||||
|
|
||||||
|
require base_path('routes/console.php');
|
||||||
|
}
|
||||||
|
}
|
||||||
34
app/Country.php
Normal file
34
app/Country.php
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property string|null $capital
|
||||||
|
* @property string|null $citizenship
|
||||||
|
* @property string $country_code
|
||||||
|
* @property string|null $currency
|
||||||
|
* @property string|null $currency_code
|
||||||
|
* @property string|null $currency_sub_unit
|
||||||
|
* @property string|null $currency_symbol
|
||||||
|
* @property string|null $full_name
|
||||||
|
* @property string $iso_3166_2
|
||||||
|
* @property string $iso_3166_3
|
||||||
|
* @property string $name
|
||||||
|
* @property string $region_code
|
||||||
|
* @property string $sub_region_code
|
||||||
|
* @property int $eea
|
||||||
|
* @property string|null $calling_code
|
||||||
|
* @property string|null $flag
|
||||||
|
*/
|
||||||
|
class Country extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $table = 'countries';
|
||||||
|
|
||||||
|
public $timestamps = false;
|
||||||
|
}
|
||||||
8
app/Events/Event.php
Normal file
8
app/Events/Event.php
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Events;
|
||||||
|
|
||||||
|
abstract class Event
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
7
app/Events/Permission/Created.php
Normal file
7
app/Events/Permission/Created.php
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Events\Permission;
|
||||||
|
|
||||||
|
class Created extends PermissionEvent
|
||||||
|
{
|
||||||
|
}
|
||||||
7
app/Events/Permission/Deleted.php
Normal file
7
app/Events/Permission/Deleted.php
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Events\Permission;
|
||||||
|
|
||||||
|
class Deleted extends PermissionEvent
|
||||||
|
{
|
||||||
|
}
|
||||||
17
app/Events/Permission/PermissionEvent.php
Normal file
17
app/Events/Permission/PermissionEvent.php
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Events\Permission;
|
||||||
|
|
||||||
|
use Vanguard\Permission;
|
||||||
|
|
||||||
|
abstract class PermissionEvent
|
||||||
|
{
|
||||||
|
public function __construct(protected Permission $permission)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPermission(): Permission
|
||||||
|
{
|
||||||
|
return $this->permission;
|
||||||
|
}
|
||||||
|
}
|
||||||
7
app/Events/Permission/Updated.php
Normal file
7
app/Events/Permission/Updated.php
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Events\Permission;
|
||||||
|
|
||||||
|
class Updated extends PermissionEvent
|
||||||
|
{
|
||||||
|
}
|
||||||
7
app/Events/Role/Created.php
Normal file
7
app/Events/Role/Created.php
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Events\Role;
|
||||||
|
|
||||||
|
class Created extends RoleEvent
|
||||||
|
{
|
||||||
|
}
|
||||||
7
app/Events/Role/Deleted.php
Normal file
7
app/Events/Role/Deleted.php
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Events\Role;
|
||||||
|
|
||||||
|
class Deleted extends RoleEvent
|
||||||
|
{
|
||||||
|
}
|
||||||
7
app/Events/Role/PermissionsUpdated.php
Normal file
7
app/Events/Role/PermissionsUpdated.php
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Events\Role;
|
||||||
|
|
||||||
|
class PermissionsUpdated
|
||||||
|
{
|
||||||
|
}
|
||||||
17
app/Events/Role/RoleEvent.php
Normal file
17
app/Events/Role/RoleEvent.php
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Events\Role;
|
||||||
|
|
||||||
|
use Vanguard\Role;
|
||||||
|
|
||||||
|
abstract class RoleEvent
|
||||||
|
{
|
||||||
|
public function __construct(protected Role $role)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRole(): Role
|
||||||
|
{
|
||||||
|
return $this->role;
|
||||||
|
}
|
||||||
|
}
|
||||||
7
app/Events/Role/Updated.php
Normal file
7
app/Events/Role/Updated.php
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Events\Role;
|
||||||
|
|
||||||
|
class Updated extends RoleEvent
|
||||||
|
{
|
||||||
|
}
|
||||||
7
app/Events/Settings/Updated.php
Normal file
7
app/Events/Settings/Updated.php
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Events\Settings;
|
||||||
|
|
||||||
|
class Updated
|
||||||
|
{
|
||||||
|
}
|
||||||
17
app/Events/User/Approved.php
Normal file
17
app/Events/User/Approved.php
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Events\User;
|
||||||
|
|
||||||
|
use Vanguard\User;
|
||||||
|
|
||||||
|
class Approved
|
||||||
|
{
|
||||||
|
public function __construct(protected User $approvedUser)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApprovedUser(): User
|
||||||
|
{
|
||||||
|
return $this->approvedUser;
|
||||||
|
}
|
||||||
|
}
|
||||||
17
app/Events/User/Banned.php
Normal file
17
app/Events/User/Banned.php
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Events\User;
|
||||||
|
|
||||||
|
use Vanguard\User;
|
||||||
|
|
||||||
|
class Banned
|
||||||
|
{
|
||||||
|
public function __construct(protected User $bannedUser)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBannedUser(): User
|
||||||
|
{
|
||||||
|
return $this->bannedUser;
|
||||||
|
}
|
||||||
|
}
|
||||||
7
app/Events/User/ChangedAvatar.php
Normal file
7
app/Events/User/ChangedAvatar.php
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Events\User;
|
||||||
|
|
||||||
|
class ChangedAvatar
|
||||||
|
{
|
||||||
|
}
|
||||||
17
app/Events/User/Created.php
Normal file
17
app/Events/User/Created.php
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Events\User;
|
||||||
|
|
||||||
|
use Vanguard\User;
|
||||||
|
|
||||||
|
class Created
|
||||||
|
{
|
||||||
|
public function __construct(protected User $createdUser)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCreatedUser(): User
|
||||||
|
{
|
||||||
|
return $this->createdUser;
|
||||||
|
}
|
||||||
|
}
|
||||||
17
app/Events/User/Deleted.php
Normal file
17
app/Events/User/Deleted.php
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Events\User;
|
||||||
|
|
||||||
|
use Vanguard\User;
|
||||||
|
|
||||||
|
class Deleted
|
||||||
|
{
|
||||||
|
public function __construct(protected User $deletedUser)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDeletedUser(): User
|
||||||
|
{
|
||||||
|
return $this->deletedUser;
|
||||||
|
}
|
||||||
|
}
|
||||||
7
app/Events/User/LoggedIn.php
Normal file
7
app/Events/User/LoggedIn.php
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Events\User;
|
||||||
|
|
||||||
|
class LoggedIn
|
||||||
|
{
|
||||||
|
}
|
||||||
7
app/Events/User/LoggedOut.php
Normal file
7
app/Events/User/LoggedOut.php
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Events\User;
|
||||||
|
|
||||||
|
class LoggedOut
|
||||||
|
{
|
||||||
|
}
|
||||||
17
app/Events/User/RequestedPasswordResetEmail.php
Normal file
17
app/Events/User/RequestedPasswordResetEmail.php
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Events\User;
|
||||||
|
|
||||||
|
use Vanguard\User;
|
||||||
|
|
||||||
|
class RequestedPasswordResetEmail
|
||||||
|
{
|
||||||
|
public function __construct(protected User $user)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUser(): User
|
||||||
|
{
|
||||||
|
return $this->user;
|
||||||
|
}
|
||||||
|
}
|
||||||
7
app/Events/User/TwoFactorDisabled.php
Normal file
7
app/Events/User/TwoFactorDisabled.php
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Events\User;
|
||||||
|
|
||||||
|
class TwoFactorDisabled
|
||||||
|
{
|
||||||
|
}
|
||||||
17
app/Events/User/TwoFactorDisabledByAdmin.php
Normal file
17
app/Events/User/TwoFactorDisabledByAdmin.php
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Events\User;
|
||||||
|
|
||||||
|
use Vanguard\User;
|
||||||
|
|
||||||
|
class TwoFactorDisabledByAdmin
|
||||||
|
{
|
||||||
|
public function __construct(protected User $user)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUser(): User
|
||||||
|
{
|
||||||
|
return $this->user;
|
||||||
|
}
|
||||||
|
}
|
||||||
7
app/Events/User/TwoFactorEnabled.php
Normal file
7
app/Events/User/TwoFactorEnabled.php
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Events\User;
|
||||||
|
|
||||||
|
class TwoFactorEnabled
|
||||||
|
{
|
||||||
|
}
|
||||||
17
app/Events/User/TwoFactorEnabledByAdmin.php
Normal file
17
app/Events/User/TwoFactorEnabledByAdmin.php
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Events\User;
|
||||||
|
|
||||||
|
use Vanguard\User;
|
||||||
|
|
||||||
|
class TwoFactorEnabledByAdmin
|
||||||
|
{
|
||||||
|
public function __construct(protected User $user)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUser(): User
|
||||||
|
{
|
||||||
|
return $this->user;
|
||||||
|
}
|
||||||
|
}
|
||||||
17
app/Events/User/UpdatedByAdmin.php
Normal file
17
app/Events/User/UpdatedByAdmin.php
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Events\User;
|
||||||
|
|
||||||
|
use Vanguard\User;
|
||||||
|
|
||||||
|
class UpdatedByAdmin
|
||||||
|
{
|
||||||
|
public function __construct(protected User $updatedUser)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUpdatedUser(): User
|
||||||
|
{
|
||||||
|
return $this->updatedUser;
|
||||||
|
}
|
||||||
|
}
|
||||||
7
app/Events/User/UpdatedProfileDetails.php
Normal file
7
app/Events/User/UpdatedProfileDetails.php
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Events\User;
|
||||||
|
|
||||||
|
class UpdatedProfileDetails
|
||||||
|
{
|
||||||
|
}
|
||||||
40
app/Exceptions/Handler.php
Normal file
40
app/Exceptions/Handler.php
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Exceptions;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
class Handler extends ExceptionHandler
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* A list of the exception types that are not reported.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $dontReport = [
|
||||||
|
//
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of the inputs that are never flashed for validation exceptions.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $dontFlash = [
|
||||||
|
'current_password',
|
||||||
|
'password',
|
||||||
|
'password_confirmation',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the exception handling callbacks for the application.
|
||||||
|
*/
|
||||||
|
public function register(): void
|
||||||
|
{
|
||||||
|
$this->reportable(function (Throwable $e) {
|
||||||
|
//
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
77
app/Http/Controllers/Api/ApiController.php
Normal file
77
app/Http/Controllers/Api/ApiController.php
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Api;
|
||||||
|
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Vanguard\Http\Controllers\Controller;
|
||||||
|
|
||||||
|
abstract class ApiController extends Controller
|
||||||
|
{
|
||||||
|
protected int $statusCode = Response::HTTP_OK;
|
||||||
|
|
||||||
|
public function getStatusCode(): int
|
||||||
|
{
|
||||||
|
return $this->statusCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setStatusCode($statusCode): self
|
||||||
|
{
|
||||||
|
$this->statusCode = $statusCode;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function respondWithSuccess($statusCode = Response::HTTP_OK): JsonResponse
|
||||||
|
{
|
||||||
|
return $this->setStatusCode($statusCode)
|
||||||
|
->respondWithArray(['success' => true]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function respondWithArray(array $array, array $headers = []): JsonResponse
|
||||||
|
{
|
||||||
|
$response = \Response::json($array, $this->statusCode, $headers);
|
||||||
|
|
||||||
|
$response->header('Content-Type', 'application/json');
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function respondWithError($message): JsonResponse
|
||||||
|
{
|
||||||
|
if ($this->statusCode === Response::HTTP_OK) {
|
||||||
|
trigger_error(
|
||||||
|
'You better have a really good reason for erroring on a 200...',
|
||||||
|
E_USER_WARNING
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->respondWithArray([
|
||||||
|
'message' => $message,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function errorForbidden(string $message = 'Forbidden'): JsonResponse
|
||||||
|
{
|
||||||
|
return $this->setStatusCode(Response::HTTP_FORBIDDEN)
|
||||||
|
->respondWithError($message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function errorInternalError(string $message = 'Internal Error'): JsonResponse
|
||||||
|
{
|
||||||
|
return $this->setStatusCode(Response::HTTP_INTERNAL_SERVER_ERROR)
|
||||||
|
->respondWithError($message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function errorNotFound(string $message = 'Resource Not Found'): JsonResponse
|
||||||
|
{
|
||||||
|
return $this->setStatusCode(Response::HTTP_NOT_FOUND)
|
||||||
|
->respondWithError($message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function errorUnauthorized(string $message = 'Unauthorized'): JsonResponse
|
||||||
|
{
|
||||||
|
return $this->setStatusCode(Response::HTTP_UNAUTHORIZED)
|
||||||
|
->respondWithError($message);
|
||||||
|
}
|
||||||
|
}
|
||||||
81
app/Http/Controllers/Api/Auth/AuthController.php
Normal file
81
app/Http/Controllers/Api/Auth/AuthController.php
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Api\Auth;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Container\BindingResolutionException;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
|
use Vanguard\Events\User\LoggedIn;
|
||||||
|
use Vanguard\Events\User\LoggedOut;
|
||||||
|
use Vanguard\Http\Controllers\Api\ApiController;
|
||||||
|
use Vanguard\Http\Requests\Auth\ApiLoginRequest;
|
||||||
|
use Vanguard\User;
|
||||||
|
|
||||||
|
class AuthController extends ApiController
|
||||||
|
{
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->middleware('guest')->only('login');
|
||||||
|
$this->middleware('auth')->only('logout');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to log the user in and generate unique JWT token on successful authentication.
|
||||||
|
*
|
||||||
|
* @throws BindingResolutionException
|
||||||
|
* @throws ValidationException
|
||||||
|
*/
|
||||||
|
public function token(ApiLoginRequest $request): JsonResponse
|
||||||
|
{
|
||||||
|
$user = $this->findUser($request);
|
||||||
|
|
||||||
|
if ($user->isBanned()) {
|
||||||
|
return $this->errorUnauthorized(trans('auth.banned'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($user->isWaitingApproval()) {
|
||||||
|
return $this->errorUnauthorized(trans('auth.approval'));
|
||||||
|
}
|
||||||
|
|
||||||
|
Auth::setUser($user);
|
||||||
|
|
||||||
|
event(new LoggedIn);
|
||||||
|
|
||||||
|
return $this->respondWithArray([
|
||||||
|
'token' => $user->createToken($request->device_name)->plainTextToken,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the user instance from the API request.
|
||||||
|
*
|
||||||
|
* @throws BindingResolutionException
|
||||||
|
* @throws ValidationException
|
||||||
|
*/
|
||||||
|
private function findUser(ApiLoginRequest $request): ?User
|
||||||
|
{
|
||||||
|
$user = User::where($request->getCredentials())->first();
|
||||||
|
|
||||||
|
if (! $user || ! Hash::check($request->password, $user->password)) {
|
||||||
|
throw ValidationException::withMessages([
|
||||||
|
'username' => [trans('auth.failed')],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $user;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logout user and invalidate token.
|
||||||
|
*/
|
||||||
|
public function logout(): JsonResponse
|
||||||
|
{
|
||||||
|
event(new LoggedOut);
|
||||||
|
|
||||||
|
auth()->user()->currentAccessToken()->delete();
|
||||||
|
|
||||||
|
return $this->respondWithSuccess();
|
||||||
|
}
|
||||||
|
}
|
||||||
30
app/Http/Controllers/Api/Auth/Password/RemindController.php
Normal file
30
app/Http/Controllers/Api/Auth/Password/RemindController.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Api\Auth\Password;
|
||||||
|
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Password;
|
||||||
|
use Vanguard\Events\User\RequestedPasswordResetEmail;
|
||||||
|
use Vanguard\Http\Controllers\Api\ApiController;
|
||||||
|
use Vanguard\Http\Requests\Auth\PasswordRemindRequest;
|
||||||
|
use Vanguard\Mail\ResetPassword;
|
||||||
|
use Vanguard\Repositories\User\UserRepository;
|
||||||
|
|
||||||
|
class RemindController extends ApiController
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Send a reset link to the given user.
|
||||||
|
*/
|
||||||
|
public function index(PasswordRemindRequest $request, UserRepository $users): JsonResponse
|
||||||
|
{
|
||||||
|
$user = $users->findByEmail($request->email);
|
||||||
|
|
||||||
|
$token = Password::getRepository()->create($user);
|
||||||
|
|
||||||
|
\Mail::to($user)->send(new ResetPassword($token));
|
||||||
|
|
||||||
|
event(new RequestedPasswordResetEmail($user));
|
||||||
|
|
||||||
|
return $this->respondWithSuccess();
|
||||||
|
}
|
||||||
|
}
|
||||||
39
app/Http/Controllers/Api/Auth/Password/ResetController.php
Normal file
39
app/Http/Controllers/Api/Auth/Password/ResetController.php
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Api\Auth\Password;
|
||||||
|
|
||||||
|
use Illuminate\Auth\Events\PasswordReset;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Password;
|
||||||
|
use Vanguard\Http\Controllers\Api\ApiController;
|
||||||
|
use Vanguard\Http\Requests\Auth\PasswordResetRequest;
|
||||||
|
|
||||||
|
class ResetController extends ApiController
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Reset the given user's password.
|
||||||
|
*/
|
||||||
|
public function index(PasswordResetRequest $request): JsonResponse
|
||||||
|
{
|
||||||
|
$response = Password::reset($request->credentials(), function ($user, $password) {
|
||||||
|
$this->resetPassword($user, $password);
|
||||||
|
});
|
||||||
|
|
||||||
|
return match ($response) {
|
||||||
|
Password::PASSWORD_RESET, Password::INVALID_USER => $this->respondWithSuccess(),
|
||||||
|
default => $this->setStatusCode(400)
|
||||||
|
->respondWithError(trans($response)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset the given user's password.
|
||||||
|
*/
|
||||||
|
protected function resetPassword(\Illuminate\Contracts\Auth\CanResetPassword $user, string $password): void
|
||||||
|
{
|
||||||
|
$user->password = $password;
|
||||||
|
$user->save();
|
||||||
|
|
||||||
|
event(new PasswordReset($user));
|
||||||
|
}
|
||||||
|
}
|
||||||
57
app/Http/Controllers/Api/Auth/RegistrationController.php
Normal file
57
app/Http/Controllers/Api/Auth/RegistrationController.php
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Api\Auth;
|
||||||
|
|
||||||
|
use Illuminate\Auth\Events\Registered;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Vanguard\Http\Controllers\Api\ApiController;
|
||||||
|
use Vanguard\Http\Requests\Auth\RegisterRequest;
|
||||||
|
use Vanguard\Repositories\Role\RoleRepository;
|
||||||
|
use Vanguard\Repositories\User\UserRepository;
|
||||||
|
use Vanguard\Role;
|
||||||
|
use Vanguard\Support\Enum\UserStatus;
|
||||||
|
|
||||||
|
class RegistrationController extends ApiController
|
||||||
|
{
|
||||||
|
public function __construct(private readonly UserRepository $users, private readonly RoleRepository $roles)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index(RegisterRequest $request): JsonResponse
|
||||||
|
{
|
||||||
|
$role = $this->roles->findByName(Role::DEFAULT_USER_ROLE);
|
||||||
|
|
||||||
|
$user = $this->users->create(
|
||||||
|
array_merge($request->validFormData(), ['role_id' => $role->id])
|
||||||
|
);
|
||||||
|
|
||||||
|
event(new Registered($user));
|
||||||
|
|
||||||
|
return $this->setStatusCode(201)
|
||||||
|
->respondWithArray([
|
||||||
|
'requires_email_confirmation' => (bool) setting('reg_email_confirmation'),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify email via email confirmation token.
|
||||||
|
*/
|
||||||
|
public function verifyEmail($token): JsonResponse
|
||||||
|
{
|
||||||
|
if (! setting('reg_email_confirmation')) {
|
||||||
|
return $this->errorNotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($user = $this->users->findByConfirmationToken($token)) {
|
||||||
|
$this->users->update($user->id, [
|
||||||
|
'status' => setting('approval.enabled') ? UserStatus::WAITING_APPROVAL : UserStatus::ACTIVE,
|
||||||
|
'confirmation_token' => null,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $this->respondWithSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->setStatusCode(400)
|
||||||
|
->respondWithError('Invalid confirmation token.');
|
||||||
|
}
|
||||||
|
}
|
||||||
58
app/Http/Controllers/Api/Auth/SocialLoginController.php
Normal file
58
app/Http/Controllers/Api/Auth/SocialLoginController.php
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Api\Auth;
|
||||||
|
|
||||||
|
use Auth;
|
||||||
|
use Exception;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Socialite;
|
||||||
|
use Vanguard\Events\User\LoggedIn;
|
||||||
|
use Vanguard\Http\Controllers\Api\ApiController;
|
||||||
|
use Vanguard\Http\Requests\Auth\Social\ApiAuthenticateRequest;
|
||||||
|
use Vanguard\Repositories\User\UserRepository;
|
||||||
|
use Vanguard\Services\Auth\Social\SocialManager;
|
||||||
|
|
||||||
|
class SocialLoginController extends ApiController
|
||||||
|
{
|
||||||
|
public function __construct(private readonly UserRepository $users, private readonly SocialManager $socialManager)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index(ApiAuthenticateRequest $request): JsonResponse
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$socialUser = Socialite::driver($request->network)->userFromToken($request->social_token);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return $this->errorInternalError('Could not connect to specified social network.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = $this->users->findBySocialId(
|
||||||
|
$request->network,
|
||||||
|
$socialUser->getId()
|
||||||
|
);
|
||||||
|
|
||||||
|
if (! $user) {
|
||||||
|
if (! setting('reg_enabled')) {
|
||||||
|
return $this->errorForbidden('Only users who already created an account can log in.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = $this->socialManager->associate($socialUser, $request->network);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($user->isBanned()) {
|
||||||
|
return $this->errorForbidden(__('Your account is banned by administrators.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($user->isWaitingApproval()) {
|
||||||
|
return $this->errorForbidden(__('Your account is waiting approval from administrators.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
Auth::setUser($user);
|
||||||
|
|
||||||
|
event(new LoggedIn);
|
||||||
|
|
||||||
|
return $this->respondWithArray([
|
||||||
|
'token' => $user->createToken($request->device_name)->plainTextToken,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
90
app/Http/Controllers/Api/Auth/VerificationController.php
Normal file
90
app/Http/Controllers/Api/Auth/VerificationController.php
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Api\Auth;
|
||||||
|
|
||||||
|
use Illuminate\Auth\Access\AuthorizationException;
|
||||||
|
use Illuminate\Auth\Events\Verified;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\Response;
|
||||||
|
use Illuminate\Routing\Exceptions\InvalidSignatureException;
|
||||||
|
use Vanguard\Http\Controllers\Api\ApiController;
|
||||||
|
use Vanguard\Http\Requests\Auth\ApiVerifyEmailRequest;
|
||||||
|
|
||||||
|
class VerificationController extends ApiController
|
||||||
|
{
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->middleware('throttle:6,1')->only('resend');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark the authenticated user's email address as verified.
|
||||||
|
*
|
||||||
|
* @throws AuthorizationException
|
||||||
|
*/
|
||||||
|
public function verify(ApiVerifyEmailRequest $request): JsonResponse
|
||||||
|
{
|
||||||
|
if (! setting('reg_email_confirmation')) {
|
||||||
|
return $this->errorNotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->verifySignature($request);
|
||||||
|
|
||||||
|
if ($request->user()->hasVerifiedEmail()) {
|
||||||
|
return $this->emailAlreadyVerifiedResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->user()->markEmailAsVerified()) {
|
||||||
|
event(new Verified($request->user()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->respondWithSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify request signature.
|
||||||
|
*
|
||||||
|
* @throws AuthorizationException
|
||||||
|
*/
|
||||||
|
private function verifySignature(ApiVerifyEmailRequest $baseRequest): void
|
||||||
|
{
|
||||||
|
$request = Request::create(
|
||||||
|
route('verification.verify', $baseRequest->only('id', 'hash')),
|
||||||
|
Request::METHOD_GET,
|
||||||
|
$baseRequest->only('expires', 'signature')
|
||||||
|
);
|
||||||
|
|
||||||
|
if (! $request->hasValidSignature()) {
|
||||||
|
throw new InvalidSignatureException;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! hash_equals((string) $baseRequest->id, (string) auth()->user()->getKey())) {
|
||||||
|
throw new AuthorizationException;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! hash_equals((string) $baseRequest->hash, sha1(auth()->user()->getEmailForVerification()))) {
|
||||||
|
throw new AuthorizationException;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function emailAlreadyVerifiedResponse(): JsonResponse
|
||||||
|
{
|
||||||
|
return $this->setStatusCode(Response::HTTP_BAD_REQUEST)
|
||||||
|
->respondWithError(__('E-Mail already verified.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resend the email verification notification.
|
||||||
|
*/
|
||||||
|
public function resend(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
if ($request->user()->hasVerifiedEmail()) {
|
||||||
|
return $this->emailAlreadyVerifiedResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
$request->user()->sendEmailVerificationNotification();
|
||||||
|
|
||||||
|
return $this->respondWithSuccess(Response::HTTP_ACCEPTED);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,69 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Api\Authorization;
|
||||||
|
|
||||||
|
use Spatie\QueryBuilder\AllowedFilter;
|
||||||
|
use Spatie\QueryBuilder\QueryBuilder;
|
||||||
|
use Vanguard\Http\Controllers\Api\ApiController;
|
||||||
|
use Vanguard\Http\Requests\Permission\CreatePermissionRequest;
|
||||||
|
use Vanguard\Http\Requests\Permission\RemovePermissionRequest;
|
||||||
|
use Vanguard\Http\Requests\Permission\UpdatePermissionRequest;
|
||||||
|
use Vanguard\Http\Resources\PermissionResource;
|
||||||
|
use Vanguard\Permission;
|
||||||
|
use Vanguard\Repositories\Permission\PermissionRepository;
|
||||||
|
|
||||||
|
class PermissionsController extends ApiController
|
||||||
|
{
|
||||||
|
public function __construct(private readonly PermissionRepository $permissions)
|
||||||
|
{
|
||||||
|
$this->middleware('permission:permissions.manage');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index(): \Illuminate\Http\Resources\Json\AnonymousResourceCollection
|
||||||
|
{
|
||||||
|
$permissions = QueryBuilder::for(Permission::class)
|
||||||
|
->allowedFilters([
|
||||||
|
AllowedFilter::partial('name'),
|
||||||
|
AllowedFilter::partial('display_name'),
|
||||||
|
AllowedFilter::exact('role', 'role_id'),
|
||||||
|
])
|
||||||
|
->allowedSorts(['name', 'created_at'])
|
||||||
|
->defaultSort('created_at')
|
||||||
|
->paginate();
|
||||||
|
|
||||||
|
return PermissionResource::collection($permissions);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store(CreatePermissionRequest $request): PermissionResource
|
||||||
|
{
|
||||||
|
$permission = $this->permissions->create(
|
||||||
|
$request->only(['name', 'display_name', 'description'])
|
||||||
|
);
|
||||||
|
|
||||||
|
return new PermissionResource($permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function show(Permission $permission): PermissionResource
|
||||||
|
{
|
||||||
|
return new PermissionResource($permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(Permission $permission, UpdatePermissionRequest $request): PermissionResource
|
||||||
|
{
|
||||||
|
$input = collect($request->all());
|
||||||
|
|
||||||
|
$permission = $this->permissions->update(
|
||||||
|
$permission->id,
|
||||||
|
$input->only(['name', 'display_name', 'description'])->toArray()
|
||||||
|
);
|
||||||
|
|
||||||
|
return new PermissionResource($permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy(Permission $permission, RemovePermissionRequest $request): \Illuminate\Http\JsonResponse
|
||||||
|
{
|
||||||
|
$this->permissions->delete($permission->id);
|
||||||
|
|
||||||
|
return $this->respondWithSuccess();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Api\Authorization;
|
||||||
|
|
||||||
|
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
||||||
|
use Vanguard\Events\Role\PermissionsUpdated;
|
||||||
|
use Vanguard\Http\Controllers\Api\ApiController;
|
||||||
|
use Vanguard\Http\Requests\Role\UpdateRolePermissionsRequest;
|
||||||
|
use Vanguard\Http\Resources\PermissionResource;
|
||||||
|
use Vanguard\Repositories\Role\RoleRepository;
|
||||||
|
use Vanguard\Role;
|
||||||
|
|
||||||
|
class RolePermissionsController extends ApiController
|
||||||
|
{
|
||||||
|
public function __construct(private RoleRepository $roles)
|
||||||
|
{
|
||||||
|
$this->middleware('permission:permissions.manage');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function show(Role $role): AnonymousResourceCollection
|
||||||
|
{
|
||||||
|
return PermissionResource::collection($role->cachedPermissions());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(Role $role, UpdateRolePermissionsRequest $request): AnonymousResourceCollection
|
||||||
|
{
|
||||||
|
$this->roles->updatePermissions(
|
||||||
|
roleId: $role->id,
|
||||||
|
permissions: $request->permissions
|
||||||
|
);
|
||||||
|
|
||||||
|
event(new PermissionsUpdated);
|
||||||
|
|
||||||
|
return PermissionResource::collection($role->cachedPermissions());
|
||||||
|
}
|
||||||
|
}
|
||||||
78
app/Http/Controllers/Api/Authorization/RolesController.php
Normal file
78
app/Http/Controllers/Api/Authorization/RolesController.php
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Api\Authorization;
|
||||||
|
|
||||||
|
use Cache;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Spatie\QueryBuilder\QueryBuilder;
|
||||||
|
use Vanguard\Http\Controllers\Api\ApiController;
|
||||||
|
use Vanguard\Http\Requests\Role\CreateRoleRequest;
|
||||||
|
use Vanguard\Http\Requests\Role\RemoveRoleRequest;
|
||||||
|
use Vanguard\Http\Requests\Role\UpdateRoleRequest;
|
||||||
|
use Vanguard\Http\Resources\RoleResource;
|
||||||
|
use Vanguard\Repositories\Role\RoleRepository;
|
||||||
|
use Vanguard\Repositories\User\UserRepository;
|
||||||
|
use Vanguard\Role;
|
||||||
|
|
||||||
|
class RolesController extends ApiController
|
||||||
|
{
|
||||||
|
public function __construct(private RoleRepository $roles)
|
||||||
|
{
|
||||||
|
$this->middleware('permission:roles.manage');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index(): \Illuminate\Http\Resources\Json\AnonymousResourceCollection
|
||||||
|
{
|
||||||
|
$roles = QueryBuilder::for(Role::class)
|
||||||
|
->allowedIncludes(RoleResource::allowedIncludes())
|
||||||
|
->allowedFilters(['name'])
|
||||||
|
->allowedSorts(['name', 'created_at'])
|
||||||
|
->defaultSort('created_at')
|
||||||
|
->paginate();
|
||||||
|
|
||||||
|
return RoleResource::collection($roles);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store(CreateRoleRequest $request): RoleResource
|
||||||
|
{
|
||||||
|
$role = $this->roles->create(
|
||||||
|
$request->only(['name', 'display_name', 'description'])
|
||||||
|
);
|
||||||
|
|
||||||
|
return new RoleResource($role);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function show($id): RoleResource
|
||||||
|
{
|
||||||
|
$role = QueryBuilder::for(Role::where('id', $id))
|
||||||
|
->allowedIncludes(RoleResource::allowedIncludes())
|
||||||
|
->first();
|
||||||
|
|
||||||
|
return new RoleResource($role);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(Role $role, UpdateRoleRequest $request): RoleResource
|
||||||
|
{
|
||||||
|
$input = collect($request->all());
|
||||||
|
|
||||||
|
$role = $this->roles->update(
|
||||||
|
$role->id,
|
||||||
|
$input->only(['name', 'display_name', 'description'])->toArray()
|
||||||
|
);
|
||||||
|
|
||||||
|
return new RoleResource($role);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy(Role $role, UserRepository $users, RemoveRoleRequest $request): JsonResponse
|
||||||
|
{
|
||||||
|
$userRole = $this->roles->findByName(Role::DEFAULT_USER_ROLE);
|
||||||
|
|
||||||
|
$users->switchRolesForUsers($role->id, $userRole->id);
|
||||||
|
|
||||||
|
$this->roles->delete($role->id);
|
||||||
|
|
||||||
|
Cache::flush();
|
||||||
|
|
||||||
|
return $this->respondWithSuccess();
|
||||||
|
}
|
||||||
|
}
|
||||||
18
app/Http/Controllers/Api/CountriesController.php
Normal file
18
app/Http/Controllers/Api/CountriesController.php
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Api;
|
||||||
|
|
||||||
|
use Vanguard\Http\Resources\CountryResource;
|
||||||
|
use Vanguard\Repositories\Country\CountryRepository;
|
||||||
|
|
||||||
|
class CountriesController extends ApiController
|
||||||
|
{
|
||||||
|
public function __construct(private readonly CountryRepository $countries)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index(): \Illuminate\Http\Resources\Json\AnonymousResourceCollection
|
||||||
|
{
|
||||||
|
return CountryResource::collection($this->countries->all());
|
||||||
|
}
|
||||||
|
}
|
||||||
22
app/Http/Controllers/Api/Profile/AuthDetailsController.php
Normal file
22
app/Http/Controllers/Api/Profile/AuthDetailsController.php
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Api\Profile;
|
||||||
|
|
||||||
|
use Vanguard\Http\Controllers\Api\ApiController;
|
||||||
|
use Vanguard\Http\Requests\User\UpdateProfileLoginDetailsRequest;
|
||||||
|
use Vanguard\Http\Resources\UserResource;
|
||||||
|
use Vanguard\Repositories\User\UserRepository;
|
||||||
|
|
||||||
|
class AuthDetailsController extends ApiController
|
||||||
|
{
|
||||||
|
public function update(UpdateProfileLoginDetailsRequest $request, UserRepository $users): UserResource
|
||||||
|
{
|
||||||
|
$user = $request->user();
|
||||||
|
|
||||||
|
$data = $request->only(['email', 'username', 'password']);
|
||||||
|
|
||||||
|
$user = $users->update($user->id, $data);
|
||||||
|
|
||||||
|
return new UserResource($user);
|
||||||
|
}
|
||||||
|
}
|
||||||
72
app/Http/Controllers/Api/Profile/AvatarController.php
Normal file
72
app/Http/Controllers/Api/Profile/AvatarController.php
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Api\Profile;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Vanguard\Events\User\ChangedAvatar;
|
||||||
|
use Vanguard\Http\Controllers\Api\ApiController;
|
||||||
|
use Vanguard\Http\Requests\User\UploadAvatarRawRequest;
|
||||||
|
use Vanguard\Http\Resources\UserResource;
|
||||||
|
use Vanguard\Repositories\User\UserRepository;
|
||||||
|
use Vanguard\Services\Upload\UserAvatarManager;
|
||||||
|
|
||||||
|
class AvatarController extends ApiController
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly UserRepository $users,
|
||||||
|
private readonly UserAvatarManager $avatarManager
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(UploadAvatarRawRequest $request): UserResource
|
||||||
|
{
|
||||||
|
$name = $this->avatarManager->uploadAndCropAvatar(
|
||||||
|
$request->file('file')
|
||||||
|
);
|
||||||
|
|
||||||
|
$user = $this->users->update(
|
||||||
|
auth()->id(),
|
||||||
|
['avatar' => $name]
|
||||||
|
);
|
||||||
|
|
||||||
|
event(new ChangedAvatar);
|
||||||
|
|
||||||
|
return new UserResource($user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateExternal(Request $request): UserResource
|
||||||
|
{
|
||||||
|
$this->validate($request, [
|
||||||
|
'url' => 'required|url',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->avatarManager->deleteAvatarIfUploaded(
|
||||||
|
auth()->user()
|
||||||
|
);
|
||||||
|
|
||||||
|
$user = $this->users->update(
|
||||||
|
auth()->id(),
|
||||||
|
['avatar' => $request->url]
|
||||||
|
);
|
||||||
|
|
||||||
|
event(new ChangedAvatar);
|
||||||
|
|
||||||
|
return new UserResource($user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy(): UserResource
|
||||||
|
{
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
$this->avatarManager->deleteAvatarIfUploaded($user);
|
||||||
|
|
||||||
|
$user = $this->users->update(
|
||||||
|
$user->id,
|
||||||
|
['avatar' => null]
|
||||||
|
);
|
||||||
|
|
||||||
|
event(new ChangedAvatar);
|
||||||
|
|
||||||
|
return new UserResource($user);
|
||||||
|
}
|
||||||
|
}
|
||||||
39
app/Http/Controllers/Api/Profile/DetailsController.php
Normal file
39
app/Http/Controllers/Api/Profile/DetailsController.php
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Api\Profile;
|
||||||
|
|
||||||
|
use Vanguard\Events\User\UpdatedProfileDetails;
|
||||||
|
use Vanguard\Http\Controllers\Api\ApiController;
|
||||||
|
use Vanguard\Http\Requests\User\UpdateProfileDetailsRequest;
|
||||||
|
use Vanguard\Http\Resources\UserResource;
|
||||||
|
use Vanguard\Repositories\User\UserRepository;
|
||||||
|
|
||||||
|
class DetailsController extends ApiController
|
||||||
|
{
|
||||||
|
public function index(): UserResource
|
||||||
|
{
|
||||||
|
return new UserResource(auth()->user());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(UpdateProfileDetailsRequest $request, UserRepository $users): UserResource
|
||||||
|
{
|
||||||
|
$user = $request->user();
|
||||||
|
|
||||||
|
$data = collect($request->all());
|
||||||
|
|
||||||
|
$data = $data->only([
|
||||||
|
'first_name', 'last_name', 'birthday',
|
||||||
|
'phone', 'address', 'country_id',
|
||||||
|
])->toArray();
|
||||||
|
|
||||||
|
if (! isset($data['country_id'])) {
|
||||||
|
$data['country_id'] = $user->country_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = $users->update($user->id, $data);
|
||||||
|
|
||||||
|
event(new UpdatedProfileDetails);
|
||||||
|
|
||||||
|
return new UserResource($user);
|
||||||
|
}
|
||||||
|
}
|
||||||
23
app/Http/Controllers/Api/Profile/SessionsController.php
Normal file
23
app/Http/Controllers/Api/Profile/SessionsController.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Api\Profile;
|
||||||
|
|
||||||
|
use Vanguard\Http\Controllers\Api\ApiController;
|
||||||
|
use Vanguard\Http\Resources\SessionResource;
|
||||||
|
use Vanguard\Repositories\Session\SessionRepository;
|
||||||
|
|
||||||
|
class SessionsController extends ApiController
|
||||||
|
{
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->middleware('auth');
|
||||||
|
$this->middleware('session.database');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index(SessionRepository $sessions): \Illuminate\Http\Resources\Json\AnonymousResourceCollection
|
||||||
|
{
|
||||||
|
$sessions = $sessions->getUserSessions(auth()->id());
|
||||||
|
|
||||||
|
return SessionResource::collection($sessions);
|
||||||
|
}
|
||||||
|
}
|
||||||
74
app/Http/Controllers/Api/Profile/TwoFactorController.php
Normal file
74
app/Http/Controllers/Api/Profile/TwoFactorController.php
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Api\Profile;
|
||||||
|
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
|
use Laravel\Fortify\Actions\ConfirmTwoFactorAuthentication;
|
||||||
|
use Laravel\Fortify\Actions\EnableTwoFactorAuthentication;
|
||||||
|
use Vanguard\Events\User\TwoFactorDisabled;
|
||||||
|
use Vanguard\Events\User\TwoFactorEnabled;
|
||||||
|
use Vanguard\Http\Controllers\Api\ApiController;
|
||||||
|
use Vanguard\Http\Requests\TwoFactor\VerifyTwoFactorTokenRequest;
|
||||||
|
use Vanguard\Http\Resources\UserResource;
|
||||||
|
|
||||||
|
class TwoFactorController extends ApiController
|
||||||
|
{
|
||||||
|
public function update(EnableTwoFactorAuthentication $enable)
|
||||||
|
{
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
if ($user->twoFactorEnabled()) {
|
||||||
|
return $this->setStatusCode(422)
|
||||||
|
->respondWithError(trans('auth.2fa.already_enabled'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$enable($user);
|
||||||
|
|
||||||
|
return $this->respondWithArray([
|
||||||
|
'message' => trans('auth.2fa.token_sent'),
|
||||||
|
'qrcode' => $user->twoFactorQrCodeSvg(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify provided 2FA token.
|
||||||
|
*/
|
||||||
|
public function verify(VerifyTwoFactorTokenRequest $request, ConfirmTwoFactorAuthentication $confirm): UserResource|\Illuminate\Http\JsonResponse
|
||||||
|
{
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
try {
|
||||||
|
$confirm($user, $request->input('code'));
|
||||||
|
} catch (ValidationException $e) {
|
||||||
|
return $this->setStatusCode(422)
|
||||||
|
->respondWithError(trans('auth.2fa.invalid_token'));
|
||||||
|
}
|
||||||
|
|
||||||
|
event(new TwoFactorEnabled);
|
||||||
|
|
||||||
|
return new UserResource($user);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable 2FA for currently authenticated user.
|
||||||
|
*/
|
||||||
|
public function destroy(): UserResource|\Illuminate\Http\JsonResponse
|
||||||
|
{
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
if (!$user->twoFactorEnabled()) {
|
||||||
|
return $this->setStatusCode(422)
|
||||||
|
->respondWithError(trans('auth.2fa.not_enabled'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$user->forceFill([
|
||||||
|
'two_factor_secret' => null,
|
||||||
|
'two_factor_recovery_codes' => null,
|
||||||
|
'two_factor_confirmed_at' => null,
|
||||||
|
])->save();
|
||||||
|
|
||||||
|
event(new TwoFactorDisabled);
|
||||||
|
|
||||||
|
return new UserResource($user);
|
||||||
|
}
|
||||||
|
}
|
||||||
37
app/Http/Controllers/Api/SessionsController.php
Normal file
37
app/Http/Controllers/Api/SessionsController.php
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Api;
|
||||||
|
|
||||||
|
use Illuminate\Auth\Access\AuthorizationException;
|
||||||
|
use Vanguard\Http\Resources\SessionResource;
|
||||||
|
use Vanguard\Repositories\Session\SessionRepository;
|
||||||
|
|
||||||
|
class SessionsController extends ApiController
|
||||||
|
{
|
||||||
|
public function __construct(private readonly SessionRepository $sessions)
|
||||||
|
{
|
||||||
|
$this->middleware('session.database');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws AuthorizationException
|
||||||
|
*/
|
||||||
|
public function show($session): SessionResource
|
||||||
|
{
|
||||||
|
$this->authorize('manage-session', $session);
|
||||||
|
|
||||||
|
return new SessionResource($session);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws AuthorizationException
|
||||||
|
*/
|
||||||
|
public function destroy($session): \Illuminate\Http\JsonResponse
|
||||||
|
{
|
||||||
|
$this->authorize('manage-session', $session);
|
||||||
|
|
||||||
|
$this->sessions->invalidateSession($session->id);
|
||||||
|
|
||||||
|
return $this->respondWithSuccess();
|
||||||
|
}
|
||||||
|
}
|
||||||
18
app/Http/Controllers/Api/SettingsController.php
Normal file
18
app/Http/Controllers/Api/SettingsController.php
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Api;
|
||||||
|
|
||||||
|
use Setting;
|
||||||
|
|
||||||
|
class SettingsController extends ApiController
|
||||||
|
{
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->middleware('permission:settings.general');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index(): \Illuminate\Http\JsonResponse
|
||||||
|
{
|
||||||
|
return response()->json(Setting::all());
|
||||||
|
}
|
||||||
|
}
|
||||||
39
app/Http/Controllers/Api/StatsController.php
Normal file
39
app/Http/Controllers/Api/StatsController.php
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Api;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Vanguard\Http\Resources\UserResource;
|
||||||
|
use Vanguard\Repositories\User\UserRepository;
|
||||||
|
use Vanguard\Support\Enum\UserStatus;
|
||||||
|
|
||||||
|
class StatsController extends ApiController
|
||||||
|
{
|
||||||
|
public function __construct(private UserRepository $users)
|
||||||
|
{
|
||||||
|
$this->middleware('role:Admin');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index(): \Illuminate\Http\JsonResponse
|
||||||
|
{
|
||||||
|
$usersPerMonth = $this->users->countOfNewUsersPerMonthPerRole(
|
||||||
|
Carbon::now()->subYear()->startOfMonth(),
|
||||||
|
Carbon::now()->endOfMonth()
|
||||||
|
);
|
||||||
|
|
||||||
|
$usersPerStatus = [
|
||||||
|
'total' => $this->users->count(),
|
||||||
|
'new' => $this->users->newUsersCount(),
|
||||||
|
'banned' => $this->users->countByStatus(UserStatus::BANNED),
|
||||||
|
'unconfirmed' => $this->users->countByStatus(UserStatus::UNCONFIRMED),
|
||||||
|
];
|
||||||
|
|
||||||
|
$users = UserResource::collection($this->users->latest(7));
|
||||||
|
|
||||||
|
return $this->respondWithArray([
|
||||||
|
'users_per_month' => $usersPerMonth,
|
||||||
|
'users_per_status' => $usersPerStatus,
|
||||||
|
'latest_registrations' => $users->resolve(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
60
app/Http/Controllers/Api/Users/AvatarController.php
Normal file
60
app/Http/Controllers/Api/Users/AvatarController.php
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Api\Users;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Vanguard\Events\User\UpdatedByAdmin;
|
||||||
|
use Vanguard\Http\Controllers\Api\ApiController;
|
||||||
|
use Vanguard\Http\Requests\User\UploadAvatarRawRequest;
|
||||||
|
use Vanguard\Http\Resources\UserResource;
|
||||||
|
use Vanguard\Repositories\User\UserRepository;
|
||||||
|
use Vanguard\Services\Upload\UserAvatarManager;
|
||||||
|
use Vanguard\User;
|
||||||
|
|
||||||
|
class AvatarController extends ApiController
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly UserRepository $users,
|
||||||
|
private readonly UserAvatarManager $avatarManager
|
||||||
|
) {
|
||||||
|
$this->middleware('permission:users.manage');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(User $user, UploadAvatarRawRequest $request): UserResource
|
||||||
|
{
|
||||||
|
$name = $this->avatarManager->uploadAndCropAvatar($request->file('file'));
|
||||||
|
|
||||||
|
$user = $this->users->update($user->id, ['avatar' => $name]);
|
||||||
|
|
||||||
|
event(new UpdatedByAdmin($user));
|
||||||
|
|
||||||
|
return new UserResource($user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateExternal(User $user, Request $request): UserResource
|
||||||
|
{
|
||||||
|
$this->validate($request, ['url' => 'required|url']);
|
||||||
|
|
||||||
|
$this->avatarManager->deleteAvatarIfUploaded($user);
|
||||||
|
|
||||||
|
$user = $this->users->update($user->id, ['avatar' => $request->url]);
|
||||||
|
|
||||||
|
event(new UpdatedByAdmin($user));
|
||||||
|
|
||||||
|
return new UserResource($user);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove user's avatar and set it to null.
|
||||||
|
*/
|
||||||
|
public function destroy(User $user): UserResource
|
||||||
|
{
|
||||||
|
$this->avatarManager->deleteAvatarIfUploaded($user);
|
||||||
|
|
||||||
|
$user = $this->users->update($user->id, ['avatar' => null]);
|
||||||
|
|
||||||
|
event(new UpdatedByAdmin($user));
|
||||||
|
|
||||||
|
return new UserResource($user);
|
||||||
|
}
|
||||||
|
}
|
||||||
25
app/Http/Controllers/Api/Users/SessionsController.php
Normal file
25
app/Http/Controllers/Api/Users/SessionsController.php
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Api\Users;
|
||||||
|
|
||||||
|
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
||||||
|
use Vanguard\Http\Controllers\Api\ApiController;
|
||||||
|
use Vanguard\Http\Resources\SessionResource;
|
||||||
|
use Vanguard\Repositories\Session\SessionRepository;
|
||||||
|
use Vanguard\User;
|
||||||
|
|
||||||
|
class SessionsController extends ApiController
|
||||||
|
{
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->middleware('permission:users.manage');
|
||||||
|
$this->middleware('session.database');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index(User $user, SessionRepository $sessions): AnonymousResourceCollection
|
||||||
|
{
|
||||||
|
return SessionResource::collection(
|
||||||
|
$sessions->getUserSessions($user->id)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
78
app/Http/Controllers/Api/Users/TwoFactorController.php
Normal file
78
app/Http/Controllers/Api/Users/TwoFactorController.php
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Api\Users;
|
||||||
|
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
|
use Laravel\Fortify\Actions\ConfirmTwoFactorAuthentication;
|
||||||
|
use Laravel\Fortify\Actions\EnableTwoFactorAuthentication;
|
||||||
|
use Vanguard\Events\User\TwoFactorDisabledByAdmin;
|
||||||
|
use Vanguard\Events\User\TwoFactorEnabledByAdmin;
|
||||||
|
use Vanguard\Http\Controllers\Api\ApiController;
|
||||||
|
use Vanguard\Http\Requests\TwoFactor\VerifyTwoFactorTokenRequest;
|
||||||
|
use Vanguard\Http\Resources\UserResource;
|
||||||
|
use Vanguard\User;
|
||||||
|
|
||||||
|
class TwoFactorController extends ApiController
|
||||||
|
{
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->middleware('permission:users.manage');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable 2FA for the specified user.
|
||||||
|
*/
|
||||||
|
public function update(User $user, EnableTwoFactorAuthentication $enable): JsonResponse
|
||||||
|
{
|
||||||
|
if ($user->twoFactorEnabled()) {
|
||||||
|
return $this->setStatusCode(422)
|
||||||
|
->respondWithError(trans('auth.2fa.already_enabled'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$enable($user, false);
|
||||||
|
|
||||||
|
return $this->respondWithArray([
|
||||||
|
'message' => trans('auth.2fa.token_sent'),
|
||||||
|
'qrcode' => $user->twoFactorQrCodeSvg(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify provided 2FA token.
|
||||||
|
*/
|
||||||
|
public function verify(VerifyTwoFactorTokenRequest $request, User $user, ConfirmTwoFactorAuthentication $confirm): UserResource|JsonResponse
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$confirm($user, $request->input('code'));
|
||||||
|
} catch (ValidationException $e) {
|
||||||
|
return $this->setStatusCode(422)
|
||||||
|
->respondWithError(trans('auth.2fa.invalid_token'));
|
||||||
|
}
|
||||||
|
|
||||||
|
event(new TwoFactorEnabledByAdmin($user));
|
||||||
|
|
||||||
|
return new UserResource($user);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable 2FA for specified user.
|
||||||
|
*/
|
||||||
|
public function destroy(User $user): UserResource|JsonResponse
|
||||||
|
{
|
||||||
|
if (!$user->twoFactorEnabled()) {
|
||||||
|
return $this->setStatusCode(422)
|
||||||
|
->respondWithError(trans('auth.2fa.not_enabled'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$user->forceFill([
|
||||||
|
'two_factor_secret' => null,
|
||||||
|
'two_factor_recovery_codes' => null,
|
||||||
|
'two_factor_confirmed_at' => null,
|
||||||
|
])->save();
|
||||||
|
|
||||||
|
event(new TwoFactorDisabledByAdmin($user));
|
||||||
|
|
||||||
|
return new UserResource($user);
|
||||||
|
}
|
||||||
|
}
|
||||||
111
app/Http/Controllers/Api/Users/UsersController.php
Normal file
111
app/Http/Controllers/Api/Users/UsersController.php
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Api\Users;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Spatie\QueryBuilder\AllowedFilter;
|
||||||
|
use Spatie\QueryBuilder\QueryBuilder;
|
||||||
|
use Vanguard\Events\User\Banned;
|
||||||
|
use Vanguard\Events\User\Deleted;
|
||||||
|
use Vanguard\Events\User\UpdatedByAdmin;
|
||||||
|
use Vanguard\Http\Controllers\Api\ApiController;
|
||||||
|
use Vanguard\Http\Filters\UserKeywordSearch;
|
||||||
|
use Vanguard\Http\Requests\User\CreateUserRequest;
|
||||||
|
use Vanguard\Http\Requests\User\UpdateUserRequest;
|
||||||
|
use Vanguard\Http\Resources\UserResource;
|
||||||
|
use Vanguard\Repositories\User\UserRepository;
|
||||||
|
use Vanguard\Support\Enum\UserStatus;
|
||||||
|
use Vanguard\User;
|
||||||
|
|
||||||
|
class UsersController extends ApiController
|
||||||
|
{
|
||||||
|
public function __construct(private UserRepository $users)
|
||||||
|
{
|
||||||
|
$this->middleware('permission:users.manage');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Paginate all users.
|
||||||
|
*/
|
||||||
|
public function index(Request $request): \Illuminate\Http\Resources\Json\AnonymousResourceCollection
|
||||||
|
{
|
||||||
|
$users = QueryBuilder::for(User::class)
|
||||||
|
->allowedIncludes(UserResource::allowedIncludes())
|
||||||
|
->allowedFilters([
|
||||||
|
AllowedFilter::custom('search', new UserKeywordSearch),
|
||||||
|
AllowedFilter::exact('status'),
|
||||||
|
])
|
||||||
|
->allowedSorts(['id', 'first_name', 'last_name', 'email', 'created_at', 'updated_at'])
|
||||||
|
->defaultSort('id')
|
||||||
|
->paginate($request->per_page ?: 20);
|
||||||
|
|
||||||
|
return UserResource::collection($users);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store(CreateUserRequest $request): UserResource
|
||||||
|
{
|
||||||
|
$data = $request->only([
|
||||||
|
'email', 'password', 'username', 'first_name', 'last_name',
|
||||||
|
'phone', 'address', 'country_id', 'birthday', 'role_id',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$data += [
|
||||||
|
'status' => setting('approval.enabled') ? UserStatus::WAITING_APPROVAL : UserStatus::ACTIVE,
|
||||||
|
'email_verified_at' => $request->verified ? now() : null,
|
||||||
|
];
|
||||||
|
|
||||||
|
$user = $this->users->create($data);
|
||||||
|
|
||||||
|
return new UserResource($user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function show($id): UserResource
|
||||||
|
{
|
||||||
|
$user = QueryBuilder::for(User::where('id', $id))
|
||||||
|
->allowedIncludes(UserResource::allowedIncludes())
|
||||||
|
->firstOrFail();
|
||||||
|
|
||||||
|
return new UserResource($user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(User $user, UpdateUserRequest $request): UserResource
|
||||||
|
{
|
||||||
|
$data = $request->only([
|
||||||
|
'email', 'password', 'username', 'first_name', 'last_name',
|
||||||
|
'phone', 'address', 'country_id', 'birthday', 'status', 'role_id',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$user = $this->users->update($user->id, $data);
|
||||||
|
|
||||||
|
event(new UpdatedByAdmin($user));
|
||||||
|
|
||||||
|
// If user status was updated to "Banned",
|
||||||
|
// fire the appropriate event.
|
||||||
|
if ($this->userIsBanned($user, $request)) {
|
||||||
|
event(new Banned($user));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new UserResource($user);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if user is banned during last update.
|
||||||
|
*/
|
||||||
|
private function userIsBanned(User $user, Request $request): bool
|
||||||
|
{
|
||||||
|
return $user->status != $request->status && $request->status == UserStatus::BANNED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy(User $user): \Illuminate\Http\JsonResponse
|
||||||
|
{
|
||||||
|
if ($user->id == auth()->id()) {
|
||||||
|
return $this->errorForbidden(__('You cannot delete yourself.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
event(new Deleted($user));
|
||||||
|
|
||||||
|
$this->users->delete($user->id);
|
||||||
|
|
||||||
|
return $this->respondWithSuccess();
|
||||||
|
}
|
||||||
|
}
|
||||||
13
app/Http/Controllers/Controller.php
Normal file
13
app/Http/Controllers/Controller.php
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||||
|
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||||
|
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||||
|
use Illuminate\Routing\Controller as BaseController;
|
||||||
|
|
||||||
|
abstract class Controller extends BaseController
|
||||||
|
{
|
||||||
|
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
|
||||||
|
}
|
||||||
56
app/Http/Controllers/Web/Auth/ForgotPasswordController.php
Normal file
56
app/Http/Controllers/Web/Auth/ForgotPasswordController.php
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Web\Auth;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Auth\PasswordBroker;
|
||||||
|
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Vanguard\Http\Controllers\Controller;
|
||||||
|
|
||||||
|
class ForgotPasswordController extends Controller
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Password Reset Controller
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This controller is responsible for handling password reset emails and
|
||||||
|
| includes a trait which assists in sending these notifications from
|
||||||
|
| your application to your users. Feel free to explore this trait.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
use SendsPasswordResetEmails;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new controller instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->middleware('guest');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
protected function sendResetLinkResponse(Request $request, $response): RedirectResponse
|
||||||
|
{
|
||||||
|
return back()->with('success', trans($response));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
protected function sendResetLinkFailedResponse(Request $request, $response): RedirectResponse
|
||||||
|
{
|
||||||
|
$messages = ['email' => trans($response)];
|
||||||
|
$httpResponse = back()->withInput($request->only('email'));
|
||||||
|
|
||||||
|
return $response === PasswordBroker::INVALID_USER
|
||||||
|
? $httpResponse->withSuccess($messages)
|
||||||
|
: $httpResponse->withErrors($messages);
|
||||||
|
}
|
||||||
|
}
|
||||||
148
app/Http/Controllers/Web/Auth/LoginController.php
Normal file
148
app/Http/Controllers/Web/Auth/LoginController.php
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Web\Auth;
|
||||||
|
|
||||||
|
use Auth;
|
||||||
|
use Cache;
|
||||||
|
use Illuminate\Contracts\Auth\Authenticatable as BaseAuthenticatable;
|
||||||
|
use Illuminate\Contracts\View\View;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\Response;
|
||||||
|
use Vanguard\Events\User\LoggedIn;
|
||||||
|
use Vanguard\Events\User\LoggedOut;
|
||||||
|
use Vanguard\Http\Controllers\Controller;
|
||||||
|
use Vanguard\Http\Requests\Auth\LoginRequest;
|
||||||
|
use Vanguard\Repositories\Session\SessionRepository;
|
||||||
|
use Vanguard\Repositories\User\UserRepository;
|
||||||
|
use Vanguard\Services\Auth\ThrottlesLogins;
|
||||||
|
use Vanguard\Support\Authorization\PasswordChangeManager;
|
||||||
|
use Vanguard\User;
|
||||||
|
|
||||||
|
class LoginController extends Controller
|
||||||
|
{
|
||||||
|
use ThrottlesLogins;
|
||||||
|
|
||||||
|
public function __construct(private readonly UserRepository $users)
|
||||||
|
{
|
||||||
|
$this->middleware('guest')->except('logout');
|
||||||
|
$this->middleware('auth')->only('logout');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the application login form.
|
||||||
|
*/
|
||||||
|
public function show(): View
|
||||||
|
{
|
||||||
|
return view('auth.login', [
|
||||||
|
'socialProviders' => config('auth.social.providers'),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function login(
|
||||||
|
LoginRequest $request,
|
||||||
|
SessionRepository $sessions,
|
||||||
|
PasswordChangeManager $passwordChangeManager
|
||||||
|
): Response|RedirectResponse {
|
||||||
|
// In case that request throttling is enabled, we have to check if user can perform this request.
|
||||||
|
// We'll key this by the username and the IP address of the client making these requests into this application.
|
||||||
|
$throttles = (bool) setting('throttle_enabled');
|
||||||
|
|
||||||
|
//Redirect URL that can be passed as hidden field.
|
||||||
|
$to = $request->has('to') ? '?to='.$request->get('to') : '';
|
||||||
|
|
||||||
|
if ($throttles && $this->hasTooManyLoginAttempts($request)) {
|
||||||
|
return $this->sendLockoutResponse($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
$credentials = $request->getCredentials();
|
||||||
|
|
||||||
|
if (! Auth::validate($credentials)) {
|
||||||
|
// If the login attempt was unsuccessful we will increment the number of attempts
|
||||||
|
// to log in and redirect the user back to the login form. Of course, when this
|
||||||
|
// user surpasses their maximum number of attempts they will get locked out.
|
||||||
|
if ($throttles) {
|
||||||
|
$this->incrementLoginAttempts($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->to('login'.$to)
|
||||||
|
->withErrors(trans('auth.failed'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = Auth::getProvider()->retrieveByCredentials($credentials);
|
||||||
|
|
||||||
|
if ($user->isBanned()) {
|
||||||
|
return redirect()->to('login'.$to)
|
||||||
|
->withErrors(trans('auth.banned'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($user->isWaitingApproval()) {
|
||||||
|
return redirect()->to('login'.$to)
|
||||||
|
->withErrors(trans('auth.approval'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$maxSessions = setting('max_active_sessions');
|
||||||
|
if ($maxSessions && $sessions->getActiveSessionsCount($user->id) >= $maxSessions) {
|
||||||
|
return redirect()->to('login'.$to)
|
||||||
|
->withErrors(trans('auth.max_sessions_reached'));
|
||||||
|
}
|
||||||
|
|
||||||
|
Auth::login($user, setting('remember_me') && $request->get('remember'));
|
||||||
|
|
||||||
|
$passwordChangeManager->forcePasswordChange($user);
|
||||||
|
|
||||||
|
return $this->authenticated($request, $throttles, $user);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send the response after the user was authenticated.
|
||||||
|
*/
|
||||||
|
protected function authenticated(
|
||||||
|
Request $request,
|
||||||
|
bool $throttles,
|
||||||
|
BaseAuthenticatable $user,
|
||||||
|
): Response|RedirectResponse {
|
||||||
|
if ($throttles) {
|
||||||
|
$this->clearLoginAttempts($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
$redirectPage = $request->get('to');
|
||||||
|
|
||||||
|
if (setting('2fa.enabled') && $user->twoFactorEnabled()) {
|
||||||
|
return $this->logoutAndRedirectToTokenPage($request, $user, $redirectPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
event(new LoggedIn);
|
||||||
|
|
||||||
|
if ($redirectPage) {
|
||||||
|
return redirect()->to($redirectPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->intended();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function logoutAndRedirectToTokenPage(Request $request, $user, ?string $redirectPage): RedirectResponse
|
||||||
|
{
|
||||||
|
Auth::logout();
|
||||||
|
|
||||||
|
$request->session()->put('auth.2fa.id', $user->id);
|
||||||
|
|
||||||
|
if ($redirectPage) {
|
||||||
|
$request->session()->put('auth.redirect_to', $redirectPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('auth.token');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log the user out of the application.
|
||||||
|
*/
|
||||||
|
public function logout(): RedirectResponse
|
||||||
|
{
|
||||||
|
event(new LoggedOut);
|
||||||
|
|
||||||
|
Auth::logout();
|
||||||
|
|
||||||
|
return redirect('login');
|
||||||
|
}
|
||||||
|
}
|
||||||
50
app/Http/Controllers/Web/Auth/RegisterController.php
Normal file
50
app/Http/Controllers/Web/Auth/RegisterController.php
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Web\Auth;
|
||||||
|
|
||||||
|
use Illuminate\Auth\Events\Registered;
|
||||||
|
use Illuminate\Contracts\View\View;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Vanguard\Http\Controllers\Controller;
|
||||||
|
use Vanguard\Http\Requests\Auth\RegisterRequest;
|
||||||
|
use Vanguard\Repositories\Role\RoleRepository;
|
||||||
|
use Vanguard\Repositories\User\UserRepository;
|
||||||
|
use Vanguard\Role;
|
||||||
|
|
||||||
|
class RegisterController extends Controller
|
||||||
|
{
|
||||||
|
public function __construct(private readonly UserRepository $users)
|
||||||
|
{
|
||||||
|
$this->middleware('registration')->only('show', 'register');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function show(): View
|
||||||
|
{
|
||||||
|
return view('auth.register', [
|
||||||
|
'socialProviders' => config('auth.social.providers'),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function register(RegisterRequest $request, RoleRepository $roles): RedirectResponse
|
||||||
|
{
|
||||||
|
$user = $this->users->create(
|
||||||
|
array_merge(
|
||||||
|
$request->validFormData(),
|
||||||
|
['role_id' => $roles->findByName(Role::DEFAULT_USER_ROLE)->id],
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
event(new Registered($user));
|
||||||
|
|
||||||
|
$message = setting('reg_email_confirmation')
|
||||||
|
? __('Your account is created successfully! Please confirm your email.')
|
||||||
|
: __('Your account is created successfully!');
|
||||||
|
|
||||||
|
if (setting('approval.enabled')) {
|
||||||
|
return redirect('/login')->with('success', $message);
|
||||||
|
} else {
|
||||||
|
\Auth::login($user);
|
||||||
|
return redirect('/')->with('success', $message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
58
app/Http/Controllers/Web/Auth/ResetPasswordController.php
Normal file
58
app/Http/Controllers/Web/Auth/ResetPasswordController.php
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Web\Auth;
|
||||||
|
|
||||||
|
use Illuminate\Auth\Events\PasswordReset;
|
||||||
|
use Illuminate\Contracts\Auth\CanResetPassword;
|
||||||
|
use Illuminate\Foundation\Auth\ResetsPasswords;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use Vanguard\Http\Controllers\Controller;
|
||||||
|
|
||||||
|
class ResetPasswordController extends Controller
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Password Reset Controller
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This controller is responsible for handling password reset requests
|
||||||
|
| and uses a simple trait to include this behavior. You're free to
|
||||||
|
| explore this trait and override any methods you wish to tweak.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
use ResetsPasswords;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Where to redirect users after resetting their password.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $redirectTo = '/';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new controller instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->middleware('guest');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
protected function resetPassword(CanResetPassword $user, string $password)
|
||||||
|
{
|
||||||
|
$user->password = $password;
|
||||||
|
|
||||||
|
$user->setRememberToken(Str::random(60));
|
||||||
|
|
||||||
|
$user->save();
|
||||||
|
|
||||||
|
event(new PasswordReset($user));
|
||||||
|
|
||||||
|
$this->guard()->login($user);
|
||||||
|
}
|
||||||
|
}
|
||||||
115
app/Http/Controllers/Web/Auth/SocialAuthController.php
Normal file
115
app/Http/Controllers/Web/Auth/SocialAuthController.php
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Web\Auth;
|
||||||
|
|
||||||
|
use Auth;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Laravel\Socialite\Contracts\User as SocialUser;
|
||||||
|
use Socialite;
|
||||||
|
use Vanguard\Events\User\LoggedIn;
|
||||||
|
use Vanguard\Http\Controllers\Controller;
|
||||||
|
use Vanguard\Repositories\User\UserRepository;
|
||||||
|
use Vanguard\Services\Auth\Social\SocialManager;
|
||||||
|
use Vanguard\User;
|
||||||
|
|
||||||
|
class SocialAuthController extends Controller
|
||||||
|
{
|
||||||
|
public function __construct(private readonly UserRepository $users, private readonly SocialManager $socialManager)
|
||||||
|
{
|
||||||
|
$this->middleware('guest');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redirect user to specified provider in order to complete the authentication process.
|
||||||
|
*/
|
||||||
|
public function redirectToProvider(string $provider): RedirectResponse
|
||||||
|
{
|
||||||
|
session(['to' => request()->get('to')]);
|
||||||
|
|
||||||
|
if (strtolower($provider) == 'facebook') {
|
||||||
|
return Socialite::driver('facebook')->with(['auth_type' => 'rerequest'])->redirect();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Socialite::driver($provider)->redirect();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle response authentication provider.
|
||||||
|
*/
|
||||||
|
public function handleProviderCallback(string $provider): RedirectResponse
|
||||||
|
{
|
||||||
|
if (request()->get('error')) {
|
||||||
|
return redirect('login')
|
||||||
|
->withErrors(__('Something went wrong during the authentication process. Please try again.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$socialUser = $this->getUserFromProvider($provider);
|
||||||
|
|
||||||
|
$user = $this->users->findBySocialId($provider, $socialUser->getId());
|
||||||
|
|
||||||
|
if (! $user) {
|
||||||
|
if (! setting('reg_enabled')) {
|
||||||
|
return redirect('login')
|
||||||
|
->withErrors(__('Only users who already created an account can log in.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $socialUser->getEmail()) {
|
||||||
|
return redirect('login')
|
||||||
|
->withErrors(__('You have to provide your email address.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = $this->socialManager->associate($socialUser, $provider);
|
||||||
|
|
||||||
|
event(new \Illuminate\Auth\Events\Registered($user));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->loginAndRedirect($user);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get user from authentication provider.
|
||||||
|
*/
|
||||||
|
private function getUserFromProvider(string $provider): SocialUser
|
||||||
|
{
|
||||||
|
return Socialite::driver($provider)->user();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log provided user in and redirect him to intended page.
|
||||||
|
*/
|
||||||
|
private function loginAndRedirect(User $user): RedirectResponse
|
||||||
|
{
|
||||||
|
$redirectPage = session('to');
|
||||||
|
$to = $redirectPage ? '?to='.$redirectPage : '';
|
||||||
|
|
||||||
|
if ($user->isBanned()) {
|
||||||
|
return redirect()->to('login'.$to)
|
||||||
|
->withErrors(__('Your account is banned by administrator.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($user->isWaitingApproval()) {
|
||||||
|
return redirect()->to('login'.$to)
|
||||||
|
->withErrors(__('Your account is waiting approval from administrators.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setting('2fa.enabled') && $user->twoFactorEnabled()) {
|
||||||
|
session()->put('auth.2fa.id', $user->id);
|
||||||
|
|
||||||
|
if ($redirectPage) {
|
||||||
|
session()->put('auth.redirect_to', $redirectPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('auth.token');
|
||||||
|
}
|
||||||
|
|
||||||
|
Auth::login($user);
|
||||||
|
|
||||||
|
event(new LoggedIn);
|
||||||
|
|
||||||
|
if ($redirectPage) {
|
||||||
|
return redirect()->to($redirectPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->intended('/');
|
||||||
|
}
|
||||||
|
}
|
||||||
63
app/Http/Controllers/Web/Auth/TwoFactorTokenController.php
Normal file
63
app/Http/Controllers/Web/Auth/TwoFactorTokenController.php
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Web\Auth;
|
||||||
|
|
||||||
|
use Auth;
|
||||||
|
use Illuminate\Contracts\View\View;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||||
|
use Vanguard\Events\User\LoggedIn;
|
||||||
|
use Vanguard\Http\Controllers\Controller;
|
||||||
|
use Vanguard\Http\Requests\TwoFactor\TwoFactorLoginRequest;
|
||||||
|
use Vanguard\Repositories\User\UserRepository;
|
||||||
|
use Vanguard\Services\Auth\ThrottlesLogins;
|
||||||
|
|
||||||
|
class TwoFactorTokenController extends Controller
|
||||||
|
{
|
||||||
|
use ThrottlesLogins;
|
||||||
|
|
||||||
|
public function __construct(private readonly UserRepository $users)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show Two-Factor Token form.
|
||||||
|
*/
|
||||||
|
public function show(): View|RedirectResponse
|
||||||
|
{
|
||||||
|
return session('auth.2fa.id') ? view('auth.token') : redirect('login');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle Two-Factor token form submission.
|
||||||
|
*/
|
||||||
|
public function update(TwoFactorLoginRequest $request): RedirectResponse
|
||||||
|
{
|
||||||
|
$this->validate($request, ['code' => 'required']);
|
||||||
|
|
||||||
|
if (! session('auth.2fa.id')) {
|
||||||
|
return redirect('login');
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = $this->users->find(
|
||||||
|
$request->session()->pull('auth.2fa.id')
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!$user) {
|
||||||
|
throw new NotFoundHttpException;
|
||||||
|
}
|
||||||
|
|
||||||
|
$customRedirect = $request->session()->pull('auth.redirect_to') ?: '';
|
||||||
|
|
||||||
|
if (!$request->hasValidCode($user)) {
|
||||||
|
return redirect()->to('login' . ($customRedirect ? "?to={$customRedirect}" : ''))
|
||||||
|
->withErrors(trans('auth.2fa.invalid_token'));
|
||||||
|
}
|
||||||
|
|
||||||
|
Auth::login($user);
|
||||||
|
|
||||||
|
event(new LoggedIn);
|
||||||
|
|
||||||
|
return redirect()->intended($customRedirect ?: '/');
|
||||||
|
}
|
||||||
|
}
|
||||||
41
app/Http/Controllers/Web/Auth/VerificationController.php
Normal file
41
app/Http/Controllers/Web/Auth/VerificationController.php
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Web\Auth;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Auth\VerifiesEmails;
|
||||||
|
use Vanguard\Http\Controllers\Controller;
|
||||||
|
|
||||||
|
class VerificationController extends Controller
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Email Verification Controller
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This controller is responsible for handling email verification for any
|
||||||
|
| user that recently registered with the application. Emails may also
|
||||||
|
| be re-sent if the user didn't receive the original email message.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
use VerifiesEmails;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Where to redirect users after verification.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $redirectTo = '/';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new controller instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->middleware('auth');
|
||||||
|
$this->middleware('signed')->only('verify');
|
||||||
|
$this->middleware('throttle:6,1')->only('verify', 'resend');
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,74 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Web\Authorization;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\View\View;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||||
|
use Vanguard\Http\Controllers\Controller;
|
||||||
|
use Vanguard\Http\Requests\Permission\CreatePermissionRequest;
|
||||||
|
use Vanguard\Http\Requests\Permission\UpdatePermissionRequest;
|
||||||
|
use Vanguard\Permission;
|
||||||
|
use Vanguard\Repositories\Permission\PermissionRepository;
|
||||||
|
use Vanguard\Repositories\Role\RoleRepository;
|
||||||
|
|
||||||
|
class PermissionsController extends Controller
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly RoleRepository $roles,
|
||||||
|
private readonly PermissionRepository $permissions
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index(): View
|
||||||
|
{
|
||||||
|
return view('permission.index', [
|
||||||
|
'roles' => $this->roles->all(),
|
||||||
|
'permissions' => $this->permissions->all(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function create(): View
|
||||||
|
{
|
||||||
|
return view('permission.add-edit', ['edit' => false]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store(CreatePermissionRequest $request): RedirectResponse
|
||||||
|
{
|
||||||
|
$this->permissions->create($request->all());
|
||||||
|
|
||||||
|
return redirect()->route('permissions.index')
|
||||||
|
->withSuccess(__('Permission created successfully.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function edit(Permission $permission): View
|
||||||
|
{
|
||||||
|
return view('permission.add-edit', [
|
||||||
|
'edit' => true,
|
||||||
|
'permission' => $permission,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(Permission $permission, UpdatePermissionRequest $request): RedirectResponse
|
||||||
|
{
|
||||||
|
$this->permissions->update($permission->id, $request->all());
|
||||||
|
|
||||||
|
return redirect()->route('permissions.index')
|
||||||
|
->withSuccess(__('Permission updated successfully.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws NotFoundHttpException
|
||||||
|
*/
|
||||||
|
public function destroy(Permission $permission)
|
||||||
|
{
|
||||||
|
if (! $permission->removable) {
|
||||||
|
throw new NotFoundHttpException;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->permissions->delete($permission->id);
|
||||||
|
|
||||||
|
return redirect()->route('permissions.index')
|
||||||
|
->withSuccess(__('Permission deleted successfully.'));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Web\Authorization;
|
||||||
|
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Arr;
|
||||||
|
use Vanguard\Events\Role\PermissionsUpdated;
|
||||||
|
use Vanguard\Http\Controllers\Controller;
|
||||||
|
use Vanguard\Repositories\Role\RoleRepository;
|
||||||
|
|
||||||
|
class RolePermissionsController extends Controller
|
||||||
|
{
|
||||||
|
public function __construct(private readonly RoleRepository $roles)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(Request $request): RedirectResponse
|
||||||
|
{
|
||||||
|
$roles = $request->get('roles');
|
||||||
|
|
||||||
|
$allRoles = $this->roles->lists('id');
|
||||||
|
|
||||||
|
foreach ($allRoles as $roleId) {
|
||||||
|
$permissions = Arr::get($roles, $roleId, []);
|
||||||
|
$this->roles->updatePermissions($roleId, $permissions);
|
||||||
|
}
|
||||||
|
|
||||||
|
event(new PermissionsUpdated);
|
||||||
|
|
||||||
|
return redirect()->route('permissions.index')
|
||||||
|
->withSuccess(__('Permissions saved successfully.'));
|
||||||
|
}
|
||||||
|
}
|
||||||
73
app/Http/Controllers/Web/Authorization/RolesController.php
Normal file
73
app/Http/Controllers/Web/Authorization/RolesController.php
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Web\Authorization;
|
||||||
|
|
||||||
|
use Cache;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Illuminate\View\View;
|
||||||
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||||
|
use Vanguard\Http\Controllers\Controller;
|
||||||
|
use Vanguard\Http\Requests\Role\CreateRoleRequest;
|
||||||
|
use Vanguard\Http\Requests\Role\UpdateRoleRequest;
|
||||||
|
use Vanguard\Repositories\Role\RoleRepository;
|
||||||
|
use Vanguard\Repositories\User\UserRepository;
|
||||||
|
use Vanguard\Role;
|
||||||
|
|
||||||
|
class RolesController extends Controller
|
||||||
|
{
|
||||||
|
public function __construct(private readonly RoleRepository $roles)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index(): View
|
||||||
|
{
|
||||||
|
return view('role.index', ['roles' => $this->roles->getAllWithUsersCount()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function create(): View
|
||||||
|
{
|
||||||
|
return view('role.add-edit', ['edit' => false]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store(CreateRoleRequest $request): RedirectResponse
|
||||||
|
{
|
||||||
|
$this->roles->create($request->all());
|
||||||
|
|
||||||
|
return redirect()->route('roles.index')
|
||||||
|
->withSuccess(__('Role created successfully.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function edit(Role $role): View
|
||||||
|
{
|
||||||
|
return view('role.add-edit', [
|
||||||
|
'role' => $role,
|
||||||
|
'edit' => true,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(Role $role, UpdateRoleRequest $request): RedirectResponse
|
||||||
|
{
|
||||||
|
$this->roles->update($role->id, $request->all());
|
||||||
|
|
||||||
|
return redirect()->route('roles.index')
|
||||||
|
->withSuccess(__('Role updated successfully.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy(Role $role, UserRepository $userRepository): RedirectResponse
|
||||||
|
{
|
||||||
|
if (! $role->removable) {
|
||||||
|
throw new NotFoundHttpException;
|
||||||
|
}
|
||||||
|
|
||||||
|
$userRole = $this->roles->findByName(Role::DEFAULT_USER_ROLE);
|
||||||
|
|
||||||
|
$userRepository->switchRolesForUsers($role->id, $userRole->id);
|
||||||
|
|
||||||
|
$this->roles->delete($role->id);
|
||||||
|
|
||||||
|
Cache::flush();
|
||||||
|
|
||||||
|
return redirect()->route('roles.index')
|
||||||
|
->withSuccess(__('Role deleted successfully.'));
|
||||||
|
}
|
||||||
|
}
|
||||||
18
app/Http/Controllers/Web/DashboardController.php
Normal file
18
app/Http/Controllers/Web/DashboardController.php
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Web;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\View\View;
|
||||||
|
use Vanguard\Http\Controllers\Controller;
|
||||||
|
|
||||||
|
class DashboardController extends Controller
|
||||||
|
{
|
||||||
|
public function index(): View
|
||||||
|
{
|
||||||
|
if (session()->has('verified')) {
|
||||||
|
session()->flash('success', __('E-Mail verified successfully.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return view('dashboard.index');
|
||||||
|
}
|
||||||
|
}
|
||||||
278
app/Http/Controllers/Web/InstallController.php
Normal file
278
app/Http/Controllers/Web/InstallController.php
Normal file
@ -0,0 +1,278 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Web;
|
||||||
|
|
||||||
|
use Artisan;
|
||||||
|
use DB;
|
||||||
|
use Illuminate\Contracts\View\View;
|
||||||
|
use Illuminate\Encryption\Encrypter;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Arr;
|
||||||
|
use Session;
|
||||||
|
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||||
|
use Vanguard\Http\Controllers\Controller;
|
||||||
|
|
||||||
|
class InstallController extends Controller
|
||||||
|
{
|
||||||
|
public const TMP_APP_KEY = 'lsXxrP1d6nUGpfGO6vQ1ezNy1KCuDD3o';
|
||||||
|
|
||||||
|
public function index(): View
|
||||||
|
{
|
||||||
|
return view('install.start');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function requirements(): View
|
||||||
|
{
|
||||||
|
$requirements = $this->getRequirements();
|
||||||
|
$allLoaded = $this->allRequirementsLoaded();
|
||||||
|
|
||||||
|
return view('install.requirements', compact('requirements', 'allLoaded'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function permissions(): View|RedirectResponse
|
||||||
|
{
|
||||||
|
if (! $this->allRequirementsLoaded()) {
|
||||||
|
return redirect()->route('install.requirements');
|
||||||
|
}
|
||||||
|
|
||||||
|
$folders = $this->getPermissions();
|
||||||
|
$allGranted = $this->allPermissionsGranted();
|
||||||
|
|
||||||
|
return view('install.permissions', compact('folders', 'allGranted'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function databaseInfo(): View|RedirectResponse
|
||||||
|
{
|
||||||
|
if (! $this->allRequirementsLoaded()) {
|
||||||
|
return redirect()->route('install.requirements');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $this->allPermissionsGranted()) {
|
||||||
|
return redirect()->route('install.permissions');
|
||||||
|
}
|
||||||
|
|
||||||
|
return view('install.database');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function installation(Request $request): View|RedirectResponse
|
||||||
|
{
|
||||||
|
if (! $this->allRequirementsLoaded()) {
|
||||||
|
return redirect()->route('install.requirements');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $this->allPermissionsGranted()) {
|
||||||
|
return redirect()->route('install.permissions');
|
||||||
|
}
|
||||||
|
|
||||||
|
$dbCredentials = $request->only('host', 'username', 'password', 'database', 'prefix');
|
||||||
|
|
||||||
|
if (! $this->dbCredentialsAreValid($dbCredentials)) {
|
||||||
|
return redirect()->route('install.database')
|
||||||
|
->withInput(Arr::except($dbCredentials, 'password'))
|
||||||
|
->withErrors('Connection to your database cannot be established.
|
||||||
|
Please provide correct database credentials.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $this->foreignKeysAreEnabled()) {
|
||||||
|
return redirect()->route('install.database')
|
||||||
|
->withInput(Arr::except($dbCredentials, 'password'))
|
||||||
|
->withErrors('Database connection established but foreign keys are not enabled.
|
||||||
|
Please enable foreign key support to proceed.');
|
||||||
|
}
|
||||||
|
|
||||||
|
Session::put('install.db_credentials', $dbCredentials);
|
||||||
|
|
||||||
|
return view('install.installation');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function install(): RedirectResponse
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$db = Session::pull('install.db_credentials');
|
||||||
|
$appKey = $this->generateRandomKey();
|
||||||
|
|
||||||
|
$content = <<<PHP
|
||||||
|
APP_ENV=production
|
||||||
|
APP_DEBUG=false
|
||||||
|
APP_KEY={$appKey}
|
||||||
|
APP_URL=http://vanguard.test
|
||||||
|
|
||||||
|
LOG_CHANNEL=stack
|
||||||
|
|
||||||
|
DB_CONNECTION=mysql
|
||||||
|
DB_HOST="{$db['host']}"
|
||||||
|
DB_DATABASE="{$db['database']}"
|
||||||
|
DB_USERNAME="{$db['username']}"
|
||||||
|
DB_PASSWORD="{$db['password']}"
|
||||||
|
DB_PREFIX="{$db['prefix']}"
|
||||||
|
|
||||||
|
BROADCAST_DRIVER=log
|
||||||
|
CACHE_DRIVER=file
|
||||||
|
QUEUE_DRIVER=sync
|
||||||
|
SESSION_DRIVER=database
|
||||||
|
SESSION_LIFETIME=120
|
||||||
|
|
||||||
|
REDIS_HOST=127.0.0.1
|
||||||
|
REDIS_PASSWORD=null
|
||||||
|
REDIS_PORT=6379
|
||||||
|
|
||||||
|
MAIL_MAILER=mail
|
||||||
|
MAIL_FROM_NAME=Vanguard
|
||||||
|
MAIL_FROM_ADDRESS=vanguard@test.dev
|
||||||
|
MAIL_HOST=smtp.mailtrap.io
|
||||||
|
MAIL_PORT=2525
|
||||||
|
MAIL_USERNAME=null
|
||||||
|
MAIL_PASSWORD=null
|
||||||
|
MAIL_ENCRYPTION=null
|
||||||
|
|
||||||
|
PUSHER_APP_ID=
|
||||||
|
PUSHER_APP_KEY=
|
||||||
|
PUSHER_APP_SECRET=
|
||||||
|
PUSHER_APP_CLUSTER=mt1
|
||||||
|
|
||||||
|
MIX_PUSHER_APP_KEY="\${PUSHER_APP_KEY}"
|
||||||
|
MIX_PUSHER_APP_CLUSTER="\${PUSHER_APP_CLUSTER}"
|
||||||
|
PHP;
|
||||||
|
|
||||||
|
file_put_contents(base_path('.env'), $content);
|
||||||
|
|
||||||
|
$this->setDatabaseCredentials($db);
|
||||||
|
config(['app.debug' => true]);
|
||||||
|
|
||||||
|
\Setting::set('app_name', \request('app_name'));
|
||||||
|
\Setting::save();
|
||||||
|
|
||||||
|
Artisan::call('migrate', ['--force' => true]);
|
||||||
|
Artisan::call('db:seed', ['--force' => true]);
|
||||||
|
Artisan::call('db:seed', [
|
||||||
|
'--force' => true,
|
||||||
|
'--quiet' => true,
|
||||||
|
'--class' => '\\Vanguard\\Announcements\\Database\\Seeders\\AnnouncementsDatabaseSeeder',
|
||||||
|
]);
|
||||||
|
|
||||||
|
return redirect()->route('install.complete');
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
@unlink(base_path('.env'));
|
||||||
|
\Log::error($e->getMessage());
|
||||||
|
\Log::error($e->getTraceAsString());
|
||||||
|
|
||||||
|
return redirect()->route('install.error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function complete(): View
|
||||||
|
{
|
||||||
|
return view('install.complete');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function error(): View
|
||||||
|
{
|
||||||
|
return view('install.error');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getRequirements(): array
|
||||||
|
{
|
||||||
|
$requirements = [
|
||||||
|
'PHP Version (>= 8.2.0)' => version_compare(phpversion(), '8.2.0', '>='),
|
||||||
|
'BCMath Extension' => extension_loaded('bcmath'),
|
||||||
|
'OpenSSL Extension' => extension_loaded('openssl'),
|
||||||
|
'PDO Extension' => extension_loaded('PDO'),
|
||||||
|
'PDO MySQL Extension' => extension_loaded('pdo_mysql'),
|
||||||
|
'Mbstring Extension' => extension_loaded('mbstring'),
|
||||||
|
'Tokenizer Extension' => extension_loaded('tokenizer'),
|
||||||
|
'XML Extension' => extension_loaded('xml'),
|
||||||
|
'Ctype PHP Extension' => extension_loaded('ctype'),
|
||||||
|
'JSON PHP Extension' => extension_loaded('json'),
|
||||||
|
'GD Extension' => extension_loaded('gd'),
|
||||||
|
'Fileinfo Extension' => extension_loaded('fileinfo'),
|
||||||
|
];
|
||||||
|
|
||||||
|
if (extension_loaded('xdebug')) {
|
||||||
|
$requirements['Xdebug Max Nesting Level (>= 500)'] = (int) ini_get('xdebug.max_nesting_level') >= 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $requirements;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function allRequirementsLoaded(): bool
|
||||||
|
{
|
||||||
|
foreach ($this->getRequirements() as $loaded) {
|
||||||
|
if (! $loaded) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getPermissions(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'public/upload/users' => is_writable(public_path('upload/users')),
|
||||||
|
'storage/app' => is_writable(storage_path('app')),
|
||||||
|
'storage/framework/cache' => is_writable(storage_path('framework/cache')),
|
||||||
|
'storage/framework/sessions' => is_writable(storage_path('framework/sessions')),
|
||||||
|
'storage/framework/views' => is_writable(storage_path('framework/views')),
|
||||||
|
'storage/logs' => is_writable(storage_path('logs')),
|
||||||
|
'bootstrap/cache' => is_writable(base_path('bootstrap/cache')),
|
||||||
|
'Base Directory' => is_writable(base_path('')),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function allPermissionsGranted(): bool
|
||||||
|
{
|
||||||
|
foreach ($this->getPermissions() as $permission => $granted) {
|
||||||
|
if (! $granted) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function dbCredentialsAreValid($credentials): bool
|
||||||
|
{
|
||||||
|
$this->setDatabaseCredentials($credentials);
|
||||||
|
|
||||||
|
try {
|
||||||
|
DB::statement('SHOW FULL TABLES');
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
\Log::info($e->getMessage());
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function foreignKeysAreEnabled(): bool
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$result = DB::select('SELECT @@foreign_key_checks;');
|
||||||
|
|
||||||
|
return data_get($result, '0.@@foreign_key_checks') === 1;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
\Log::info($e->getMessage());
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function setDatabaseCredentials($credentials): void
|
||||||
|
{
|
||||||
|
$default = config('database.default');
|
||||||
|
|
||||||
|
config([
|
||||||
|
"database.connections.{$default}.host" => $credentials['host'],
|
||||||
|
"database.connections.{$default}.database" => $credentials['database'],
|
||||||
|
"database.connections.{$default}.username" => $credentials['username'],
|
||||||
|
"database.connections.{$default}.password" => $credentials['password'],
|
||||||
|
"database.connections.{$default}.prefix" => $credentials['prefix'],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function generateRandomKey(): string
|
||||||
|
{
|
||||||
|
return 'base64:'.base64_encode(Encrypter::generateKey(config('app.cipher')));
|
||||||
|
}
|
||||||
|
}
|
||||||
57
app/Http/Controllers/Web/Profile/AvatarController.php
Normal file
57
app/Http/Controllers/Web/Profile/AvatarController.php
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Web\Profile;
|
||||||
|
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Vanguard\Events\User\ChangedAvatar;
|
||||||
|
use Vanguard\Http\Controllers\Controller;
|
||||||
|
use Vanguard\Repositories\User\UserRepository;
|
||||||
|
use Vanguard\Services\Upload\UserAvatarManager;
|
||||||
|
|
||||||
|
class AvatarController extends Controller
|
||||||
|
{
|
||||||
|
public function __construct(private readonly UserRepository $users)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(Request $request, UserAvatarManager $avatarManager): RedirectResponse
|
||||||
|
{
|
||||||
|
$request->validate(['avatar' => 'image']);
|
||||||
|
|
||||||
|
$name = $avatarManager->uploadAndCropAvatar(
|
||||||
|
$request->file('avatar'),
|
||||||
|
$request->get('points')
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($name) {
|
||||||
|
return $this->handleAvatarUpdate($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('profile')
|
||||||
|
->withErrors(__('Avatar image cannot be updated. Please try again.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update avatar for currently logged-in user and fire appropriate event.
|
||||||
|
*/
|
||||||
|
private function handleAvatarUpdate(string|null $avatar): RedirectResponse
|
||||||
|
{
|
||||||
|
$this->users->update(auth()->id(), ['avatar' => $avatar]);
|
||||||
|
|
||||||
|
event(new ChangedAvatar);
|
||||||
|
|
||||||
|
return redirect()->route('profile')
|
||||||
|
->withSuccess(__('Avatar changed successfully.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update user's avatar from external location/url.
|
||||||
|
*/
|
||||||
|
public function updateExternal(Request $request, UserAvatarManager $avatarManager): RedirectResponse
|
||||||
|
{
|
||||||
|
$avatarManager->deleteAvatarIfUploaded(auth()->user());
|
||||||
|
|
||||||
|
return $this->handleAvatarUpdate($request->get('url'));
|
||||||
|
}
|
||||||
|
}
|
||||||
26
app/Http/Controllers/Web/Profile/DetailsController.php
Normal file
26
app/Http/Controllers/Web/Profile/DetailsController.php
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Web\Profile;
|
||||||
|
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Vanguard\Events\User\UpdatedProfileDetails;
|
||||||
|
use Vanguard\Http\Controllers\Controller;
|
||||||
|
use Vanguard\Http\Requests\User\UpdateProfileDetailsRequest;
|
||||||
|
use Vanguard\Repositories\User\UserRepository;
|
||||||
|
|
||||||
|
class DetailsController extends Controller
|
||||||
|
{
|
||||||
|
public function __construct(private readonly UserRepository $users)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(UpdateProfileDetailsRequest $request): RedirectResponse
|
||||||
|
{
|
||||||
|
$this->users->update(auth()->id(), $request->except('role_id', 'status'));
|
||||||
|
|
||||||
|
event(new UpdatedProfileDetails);
|
||||||
|
|
||||||
|
return redirect()->back()
|
||||||
|
->withSuccess(__('Profile updated successfully.'));
|
||||||
|
}
|
||||||
|
}
|
||||||
37
app/Http/Controllers/Web/Profile/LoginDetailsController.php
Normal file
37
app/Http/Controllers/Web/Profile/LoginDetailsController.php
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Web\Profile;
|
||||||
|
|
||||||
|
use Cache;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Vanguard\Http\Controllers\Controller;
|
||||||
|
use Vanguard\Http\Requests\User\UpdateProfileLoginDetailsRequest;
|
||||||
|
use Vanguard\Repositories\User\UserRepository;
|
||||||
|
use Vanguard\Support\Authorization\PasswordChangeManager;
|
||||||
|
|
||||||
|
class LoginDetailsController extends Controller
|
||||||
|
{
|
||||||
|
public function __construct(private readonly UserRepository $users)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(UpdateProfileLoginDetailsRequest $request, PasswordChangeManager $passwordChangeManager): RedirectResponse
|
||||||
|
{
|
||||||
|
$data = $request->except('role', 'status');
|
||||||
|
|
||||||
|
// If password is not provided, then we will
|
||||||
|
// just remove it from $data array and do not change it
|
||||||
|
if (! data_get($data, 'password')) {
|
||||||
|
unset($data['password']);
|
||||||
|
unset($data['password_confirmation']);
|
||||||
|
} else {
|
||||||
|
$data['force_password_change'] = false;
|
||||||
|
$passwordChangeManager->liftPasswordChangeRequest(auth()->user());
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->users->update(auth()->id(), $data);
|
||||||
|
|
||||||
|
return redirect()->route('profile')
|
||||||
|
->withSuccess(__('Login details updated successfully.'));
|
||||||
|
}
|
||||||
|
}
|
||||||
36
app/Http/Controllers/Web/Profile/ProfileController.php
Normal file
36
app/Http/Controllers/Web/Profile/ProfileController.php
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Web\Profile;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\View\View;
|
||||||
|
use Vanguard\Http\Controllers\Controller;
|
||||||
|
use Vanguard\Repositories\Country\CountryRepository;
|
||||||
|
use Vanguard\Repositories\Role\RoleRepository;
|
||||||
|
use Vanguard\Repositories\User\UserRepository;
|
||||||
|
use Vanguard\Support\Enum\UserStatus;
|
||||||
|
|
||||||
|
class ProfileController extends Controller
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly UserRepository $users,
|
||||||
|
private readonly RoleRepository $roles,
|
||||||
|
private readonly CountryRepository $countries
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function show(): View
|
||||||
|
{
|
||||||
|
$roles = $this->roles->all()->filter(function ($role) {
|
||||||
|
return $role->id == auth()->user()->role_id;
|
||||||
|
})->pluck('display_name', 'id');
|
||||||
|
|
||||||
|
return view('user.profile', [
|
||||||
|
'user' => auth()->user(),
|
||||||
|
'edit' => true,
|
||||||
|
'roles' => $roles,
|
||||||
|
'countries' => [0 => __('Select a Country')] + $this->countries->lists()->toArray(),
|
||||||
|
'socialLogins' => $this->users->getUserSocialLogins(auth()->id()),
|
||||||
|
'statuses' => UserStatus::lists(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
32
app/Http/Controllers/Web/Profile/SessionsController.php
Normal file
32
app/Http/Controllers/Web/Profile/SessionsController.php
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Web\Profile;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\View\View;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Vanguard\Http\Controllers\Controller;
|
||||||
|
use Vanguard\Repositories\Session\SessionRepository;
|
||||||
|
|
||||||
|
class SessionsController extends Controller
|
||||||
|
{
|
||||||
|
public function __construct(private readonly SessionRepository $sessions)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index(): View
|
||||||
|
{
|
||||||
|
return view('user.sessions', [
|
||||||
|
'profile' => true,
|
||||||
|
'user' => auth()->user(),
|
||||||
|
'sessions' => $this->sessions->getUserSessions(auth()->id()),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy($session): RedirectResponse
|
||||||
|
{
|
||||||
|
$this->sessions->invalidateSession($session->id);
|
||||||
|
|
||||||
|
return redirect()->route('profile.sessions')
|
||||||
|
->withSuccess(__('Session invalidated successfully.'));
|
||||||
|
}
|
||||||
|
}
|
||||||
114
app/Http/Controllers/Web/SettingsController.php
Normal file
114
app/Http/Controllers/Web/SettingsController.php
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Web;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\View\View;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Setting;
|
||||||
|
use Vanguard\Events\Settings\Updated as SettingsUpdated;
|
||||||
|
use Vanguard\Http\Controllers\Controller;
|
||||||
|
|
||||||
|
class SettingsController extends Controller
|
||||||
|
{
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->middleware('auth');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display general settings page.
|
||||||
|
*/
|
||||||
|
public function general(): View
|
||||||
|
{
|
||||||
|
return view('settings.general');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display Authentication & Registration settings page.
|
||||||
|
*/
|
||||||
|
public function auth(): View
|
||||||
|
{
|
||||||
|
return view('settings.auth');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(Request $request): RedirectResponse
|
||||||
|
{
|
||||||
|
$this->updateSetting($request->except('_token'));
|
||||||
|
|
||||||
|
return back()->withSuccess(__('Settings updated successfully.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function updateSetting(array $input): void
|
||||||
|
{
|
||||||
|
foreach ($input as $key => $value) {
|
||||||
|
Setting::set($key, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Setting::save();
|
||||||
|
|
||||||
|
event(new SettingsUpdated);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function enableTwoFactor(): RedirectResponse
|
||||||
|
{
|
||||||
|
$this->updateSetting(['2fa.enabled' => true]);
|
||||||
|
|
||||||
|
return back()->withSuccess(__('Two-Factor Authentication enabled successfully.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function disableTwoFactor(): RedirectResponse
|
||||||
|
{
|
||||||
|
$this->updateSetting(['2fa.enabled' => false]);
|
||||||
|
|
||||||
|
return back()->withSuccess(__('Two-Factor Authentication disabled successfully.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function enableApproval(): RedirectResponse
|
||||||
|
{
|
||||||
|
$this->updateSetting(['approval.enabled' => true]);
|
||||||
|
|
||||||
|
return back()->withSuccess(__('User Confirmation Flow enabled successfully.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function disableApproval(): RedirectResponse
|
||||||
|
{
|
||||||
|
$this->updateSetting(['approval.enabled' => false]);
|
||||||
|
|
||||||
|
return back()->withSuccess(__('User Confirmation Flow disabled successfully.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function enablePasswordChange(): RedirectResponse
|
||||||
|
{
|
||||||
|
$this->updateSetting(['password-change.enabled' => true]);
|
||||||
|
|
||||||
|
return back()->withSuccess(__('Force Password Change for users enabled successfully.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function disablePasswordChange(): RedirectResponse
|
||||||
|
{
|
||||||
|
$this->updateSetting(['password-change.enabled' => false]);
|
||||||
|
|
||||||
|
return back()->withSuccess(__('Force Password Change for users disabled successfully.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function enableCaptcha(): RedirectResponse
|
||||||
|
{
|
||||||
|
$this->updateSetting(['registration.captcha.enabled' => true]);
|
||||||
|
|
||||||
|
return back()->withSuccess(__('reCAPTCHA enabled successfully.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function disableCaptcha(): RedirectResponse
|
||||||
|
{
|
||||||
|
$this->updateSetting(['registration.captcha.enabled' => false]);
|
||||||
|
|
||||||
|
return back()->withSuccess(__('reCAPTCHA disabled successfully.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function notifications(): View
|
||||||
|
{
|
||||||
|
return view('settings.notifications');
|
||||||
|
}
|
||||||
|
}
|
||||||
111
app/Http/Controllers/Web/TwoFactorController.php
Normal file
111
app/Http/Controllers/Web/TwoFactorController.php
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Web;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\View\View;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
|
use Laravel\Fortify\Actions\ConfirmTwoFactorAuthentication;
|
||||||
|
use Laravel\Fortify\Actions\EnableTwoFactorAuthentication;
|
||||||
|
use Laravel\Fortify\Contracts\TwoFactorAuthenticationProvider;
|
||||||
|
use Vanguard\Events\User\TwoFactorEnabled;
|
||||||
|
use Vanguard\Events\User\TwoFactorEnabledByAdmin;
|
||||||
|
use Vanguard\Events\User\TwoFactorDisabled;
|
||||||
|
use Vanguard\Http\Controllers\Controller;
|
||||||
|
use Vanguard\Http\Requests\TwoFactor\DisableTwoFactorRequest;
|
||||||
|
use Vanguard\Http\Requests\TwoFactor\EnableTwoFactorRequest;
|
||||||
|
use Vanguard\Http\Requests\TwoFactor\VerifyTwoFactorTokenRequest;
|
||||||
|
use Vanguard\Repositories\User\UserRepository;
|
||||||
|
|
||||||
|
class TwoFactorController extends Controller
|
||||||
|
{
|
||||||
|
public function __construct(protected UserRepository $users, protected TwoFactorAuthenticationProvider $twoFactorProvider)
|
||||||
|
{
|
||||||
|
$this->middleware('auth');
|
||||||
|
|
||||||
|
$this->middleware(function ($request, $next) use ($users) {
|
||||||
|
$user = $request->get('user')
|
||||||
|
? $users->find($request->get('user'))
|
||||||
|
: auth()->user();
|
||||||
|
|
||||||
|
return $user->twoFactorEnabled() ? abort(404) : $next($request);
|
||||||
|
})->only('enable', 'verification', 'resend', 'verify');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable 2FA for currently logged user.
|
||||||
|
*/
|
||||||
|
public function enable(EnableTwoFactorRequest $request, EnableTwoFactorAuthentication $enable)
|
||||||
|
{
|
||||||
|
$user = $request->theUser();
|
||||||
|
|
||||||
|
$enable($user, $request->boolean('force', false));
|
||||||
|
|
||||||
|
session()->flash('tab', '2fa');
|
||||||
|
|
||||||
|
return redirect()->back()
|
||||||
|
->withSuccess(trans('auth.2fa.enabled_successfully'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows the phone verification page.
|
||||||
|
*/
|
||||||
|
public function verification(): View
|
||||||
|
{
|
||||||
|
return view('user.two-factor-verification', [
|
||||||
|
'user' => request('user'),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify 2FA token and enable 2FA if token is valid.
|
||||||
|
*/
|
||||||
|
public function verify(VerifyTwoFactorTokenRequest $request, ConfirmTwoFactorAuthentication $confirm): RedirectResponse
|
||||||
|
{
|
||||||
|
$user = $request->theUser();
|
||||||
|
|
||||||
|
try {
|
||||||
|
$confirm($user, $request->input('code'));
|
||||||
|
} catch (ValidationException $e) {
|
||||||
|
session()->flash('tab', '2fa');
|
||||||
|
|
||||||
|
return redirect()->back()
|
||||||
|
->withErrors(trans('auth.2fa.invalid_token'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$message = trans('auth.2fa.enabled_successfully');
|
||||||
|
|
||||||
|
if ($user->is(auth()->user())) {
|
||||||
|
event(new TwoFactorEnabled);
|
||||||
|
|
||||||
|
return redirect()->route('profile')->withSuccess($message);
|
||||||
|
}
|
||||||
|
|
||||||
|
event(new TwoFactorEnabledByAdmin($user));
|
||||||
|
|
||||||
|
return redirect()->route('users.edit', $user)->withSuccess($message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable 2FA for currently logged user.
|
||||||
|
*/
|
||||||
|
public function disable(DisableTwoFactorRequest $request): RedirectResponse
|
||||||
|
{
|
||||||
|
$user = $request->theUser();
|
||||||
|
|
||||||
|
if (!$user->twoFactorEnabled()) {
|
||||||
|
abort(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
$user->forceFill([
|
||||||
|
'two_factor_secret' => null,
|
||||||
|
'two_factor_recovery_codes' => null,
|
||||||
|
'two_factor_confirmed_at' => null,
|
||||||
|
])->save();
|
||||||
|
|
||||||
|
event(new TwoFactorDisabled);
|
||||||
|
|
||||||
|
return redirect()->back()
|
||||||
|
->withSuccess(trans('auth.2fa.disabled_successfully'));
|
||||||
|
}
|
||||||
|
}
|
||||||
61
app/Http/Controllers/Web/Users/AvatarController.php
Normal file
61
app/Http/Controllers/Web/Users/AvatarController.php
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Web\Users;
|
||||||
|
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
|
use Vanguard\Events\User\UpdatedByAdmin;
|
||||||
|
use Vanguard\Http\Controllers\Api\ApiController;
|
||||||
|
use Vanguard\Repositories\User\UserRepository;
|
||||||
|
use Vanguard\Services\Upload\UserAvatarManager;
|
||||||
|
use Vanguard\User;
|
||||||
|
|
||||||
|
class AvatarController extends ApiController
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly UserRepository $users,
|
||||||
|
private readonly UserAvatarManager $avatarManager
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ValidationException
|
||||||
|
*/
|
||||||
|
public function update(User $user, Request $request): RedirectResponse
|
||||||
|
{
|
||||||
|
$this->validate($request, ['avatar' => 'image']);
|
||||||
|
|
||||||
|
$name = $this->avatarManager->uploadAndCropAvatar(
|
||||||
|
$request->file('avatar'),
|
||||||
|
$request->get('points')
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($name) {
|
||||||
|
$this->users->update($user->id, ['avatar' => $name]);
|
||||||
|
|
||||||
|
event(new UpdatedByAdmin($user));
|
||||||
|
|
||||||
|
return redirect()->route('users.edit', $user)
|
||||||
|
->withSuccess(__('Avatar changed successfully.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('users.edit', $user)
|
||||||
|
->withErrors(__('Avatar image cannot be updated. Please try again.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update user's avatar from some external source (Gravatar, Facebook, Twitter...)
|
||||||
|
*/
|
||||||
|
public function updateExternal(User $user, Request $request): RedirectResponse
|
||||||
|
{
|
||||||
|
$this->avatarManager->deleteAvatarIfUploaded($user);
|
||||||
|
|
||||||
|
$this->users->update($user->id, ['avatar' => $request->get('url')]);
|
||||||
|
|
||||||
|
event(new UpdatedByAdmin($user));
|
||||||
|
|
||||||
|
return redirect()->route('users.edit', $user)
|
||||||
|
->withSuccess(__('Avatar changed successfully.'));
|
||||||
|
}
|
||||||
|
}
|
||||||
79
app/Http/Controllers/Web/Users/DetailsController.php
Normal file
79
app/Http/Controllers/Web/Users/DetailsController.php
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Web\Users;
|
||||||
|
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Vanguard\Events\User\Approved;
|
||||||
|
use Vanguard\Events\User\Banned;
|
||||||
|
use Vanguard\Events\User\UpdatedByAdmin;
|
||||||
|
use Vanguard\Http\Controllers\Controller;
|
||||||
|
use Vanguard\Http\Requests\User\UpdateDetailsRequest;
|
||||||
|
use Vanguard\Repositories\User\UserRepository;
|
||||||
|
use Vanguard\Support\Enum\UserStatus;
|
||||||
|
use Vanguard\User;
|
||||||
|
|
||||||
|
class DetailsController extends Controller
|
||||||
|
{
|
||||||
|
public function __construct(private readonly UserRepository $users)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(User $user, UpdateDetailsRequest $request): RedirectResponse
|
||||||
|
{
|
||||||
|
$data = $request->all();
|
||||||
|
|
||||||
|
if (! data_get($data, 'country_id')) {
|
||||||
|
$data['country_id'] = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->users->update($user->id, $data);
|
||||||
|
$this->users->setRole($user->id, $request->role_id);
|
||||||
|
|
||||||
|
event(new UpdatedByAdmin($user));
|
||||||
|
|
||||||
|
// If user status was updated to "Banned",
|
||||||
|
// fire the appropriate event.
|
||||||
|
if ($this->userWasBanned($user, $request)) {
|
||||||
|
event(new Banned($user));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->userWasApproved($user, $request)) {
|
||||||
|
event(new Approved($user));
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->back()
|
||||||
|
->withSuccess(__('User updated successfully.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function approve(User $user): RedirectResponse
|
||||||
|
{
|
||||||
|
$this->users->update($user->id, [
|
||||||
|
'status' => UserStatus::ACTIVE
|
||||||
|
]);
|
||||||
|
|
||||||
|
event(new UpdatedByAdmin($user));
|
||||||
|
event(new Approved($user));
|
||||||
|
|
||||||
|
return redirect()->back()
|
||||||
|
->withSuccess(__('User updated successfully.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if user is banned during last update.
|
||||||
|
*/
|
||||||
|
private function userWasBanned(User $user, Request $request): bool
|
||||||
|
{
|
||||||
|
return $user->status != $request->status
|
||||||
|
&& $request->status == UserStatus::BANNED->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if user is approved during last update.
|
||||||
|
*/
|
||||||
|
private function userWasApproved(User $user, Request $request): bool
|
||||||
|
{
|
||||||
|
return $user->status == UserStatus::WAITING_APPROVAL->value
|
||||||
|
&& $request->status == UserStatus::ACTIVE->value;
|
||||||
|
}
|
||||||
|
}
|
||||||
35
app/Http/Controllers/Web/Users/LoginDetailsController.php
Normal file
35
app/Http/Controllers/Web/Users/LoginDetailsController.php
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Web\Users;
|
||||||
|
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Vanguard\Events\User\UpdatedByAdmin;
|
||||||
|
use Vanguard\Http\Controllers\Controller;
|
||||||
|
use Vanguard\Http\Requests\User\UpdateLoginDetailsRequest;
|
||||||
|
use Vanguard\Repositories\User\UserRepository;
|
||||||
|
use Vanguard\User;
|
||||||
|
|
||||||
|
class LoginDetailsController extends Controller
|
||||||
|
{
|
||||||
|
public function __construct(private readonly UserRepository $users)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(User $user, UpdateLoginDetailsRequest $request): RedirectResponse
|
||||||
|
{
|
||||||
|
$data = $request->all();
|
||||||
|
$data['force_password_change'] = $request->filled('force_password_change');
|
||||||
|
|
||||||
|
if (! $data['password']) {
|
||||||
|
unset($data['password']);
|
||||||
|
unset($data['password_confirmation']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->users->update($user->id, $data);
|
||||||
|
|
||||||
|
event(new UpdatedByAdmin($user));
|
||||||
|
|
||||||
|
return redirect()->route('users.edit', $user->id)
|
||||||
|
->withSuccess(__('Login details updated successfully.'));
|
||||||
|
}
|
||||||
|
}
|
||||||
34
app/Http/Controllers/Web/Users/SessionsController.php
Normal file
34
app/Http/Controllers/Web/Users/SessionsController.php
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Web\Users;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\View\View;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Vanguard\Http\Controllers\Controller;
|
||||||
|
use Vanguard\Repositories\Session\SessionRepository;
|
||||||
|
use Vanguard\User;
|
||||||
|
|
||||||
|
class SessionsController extends Controller
|
||||||
|
{
|
||||||
|
public function __construct(private readonly SessionRepository $sessions)
|
||||||
|
{
|
||||||
|
$this->middleware('permission:users.manage');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index(User $user): View
|
||||||
|
{
|
||||||
|
return view('user.sessions', [
|
||||||
|
'adminView' => true,
|
||||||
|
'user' => $user,
|
||||||
|
'sessions' => $this->sessions->getUserSessions($user->id),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy(User $user, $session): RedirectResponse
|
||||||
|
{
|
||||||
|
$this->sessions->invalidateSession($session->id);
|
||||||
|
|
||||||
|
return redirect()->route('user.sessions', $user->id)
|
||||||
|
->withSuccess(__('Session invalidated successfully.'));
|
||||||
|
}
|
||||||
|
}
|
||||||
108
app/Http/Controllers/Web/Users/UsersController.php
Normal file
108
app/Http/Controllers/Web/Users/UsersController.php
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Controllers\Web\Users;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\View\View;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Vanguard\Events\User\Deleted;
|
||||||
|
use Vanguard\Http\Controllers\Controller;
|
||||||
|
use Vanguard\Http\Requests\User\CreateUserRequest;
|
||||||
|
use Vanguard\Repositories\Country\CountryRepository;
|
||||||
|
use Vanguard\Repositories\Role\RoleRepository;
|
||||||
|
use Vanguard\Repositories\User\UserRepository;
|
||||||
|
use Vanguard\Support\Enum\UserStatus;
|
||||||
|
use Vanguard\User;
|
||||||
|
|
||||||
|
class UsersController extends Controller
|
||||||
|
{
|
||||||
|
public function __construct(private readonly UserRepository $users)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index(Request $request): View
|
||||||
|
{
|
||||||
|
$users = $this->users->paginate($perPage = 20, $request->search, $request->status);
|
||||||
|
|
||||||
|
$statuses = ['' => __('All')] + UserStatus::lists();
|
||||||
|
|
||||||
|
return view('user.list', compact('users', 'statuses'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function show(User $user): View
|
||||||
|
{
|
||||||
|
return view('user.view', compact('user'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function create(CountryRepository $countryRepository, RoleRepository $roleRepository): View
|
||||||
|
{
|
||||||
|
return view('user.add', [
|
||||||
|
'countries' => $this->parseCountries($countryRepository),
|
||||||
|
'roles' => $roleRepository->lists(),
|
||||||
|
'statuses' => UserStatus::lists(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse countries into an array that also has a blank
|
||||||
|
* item as first element, which will allow users to
|
||||||
|
* leave the country field unpopulated.
|
||||||
|
*/
|
||||||
|
private function parseCountries(CountryRepository $countryRepository): array
|
||||||
|
{
|
||||||
|
return [0 => __('Select a Country')] + $countryRepository->lists()->toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store(CreateUserRequest $request): RedirectResponse
|
||||||
|
{
|
||||||
|
// When user is created by administrator, we will set his
|
||||||
|
// status to Active by default.
|
||||||
|
$data = $request->all() + [
|
||||||
|
'status' => UserStatus::ACTIVE,
|
||||||
|
'email_verified_at' => now(),
|
||||||
|
];
|
||||||
|
|
||||||
|
$data['force_password_change'] = !!setting('password-change.enabled');
|
||||||
|
|
||||||
|
if (! data_get($data, 'country_id')) {
|
||||||
|
$data['country_id'] = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Username should be updated only if it is provided.
|
||||||
|
if (! data_get($data, 'username')) {
|
||||||
|
$data['username'] = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->users->create($data);
|
||||||
|
|
||||||
|
return redirect()->route('users.index')
|
||||||
|
->withSuccess(__('User created successfully.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function edit(User $user, CountryRepository $countryRepository, RoleRepository $roleRepository): View
|
||||||
|
{
|
||||||
|
return view('user.edit', [
|
||||||
|
'edit' => true,
|
||||||
|
'user' => $user,
|
||||||
|
'countries' => $this->parseCountries($countryRepository),
|
||||||
|
'roles' => $roleRepository->lists(),
|
||||||
|
'statuses' => UserStatus::lists(),
|
||||||
|
'socialLogins' => $this->users->getUserSocialLogins($user->id),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy(User $user): RedirectResponse
|
||||||
|
{
|
||||||
|
if ($user->is(auth()->user())) {
|
||||||
|
return redirect()->route('users.index')
|
||||||
|
->withErrors(__('You cannot delete yourself.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->users->delete($user->id);
|
||||||
|
|
||||||
|
event(new Deleted($user));
|
||||||
|
|
||||||
|
return redirect()->route('users.index')
|
||||||
|
->withSuccess(__('User deleted successfully.'));
|
||||||
|
}
|
||||||
|
}
|
||||||
19
app/Http/Filters/UserKeywordSearch.php
Normal file
19
app/Http/Filters/UserKeywordSearch.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Filters;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Spatie\QueryBuilder\Filters\Filter;
|
||||||
|
|
||||||
|
class UserKeywordSearch implements Filter
|
||||||
|
{
|
||||||
|
public function __invoke(Builder $query, $search, string $property = ''): void
|
||||||
|
{
|
||||||
|
$query->where(function ($q) use ($search) {
|
||||||
|
$q->where('username', 'like', "%{$search}%");
|
||||||
|
$q->orWhere('email', 'like', "%{$search}%");
|
||||||
|
$q->orWhere('first_name', 'like', "%{$search}%");
|
||||||
|
$q->orWhere('last_name', 'like', "%{$search}%");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
98
app/Http/Kernel.php
Normal file
98
app/Http/Kernel.php
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\Kernel as HttpKernel;
|
||||||
|
|
||||||
|
class Kernel extends HttpKernel
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The application's global HTTP middleware stack.
|
||||||
|
*
|
||||||
|
* These middleware are run during every request to your application.
|
||||||
|
*
|
||||||
|
* @var array<int, class-string|string>
|
||||||
|
*/
|
||||||
|
protected $middleware = [
|
||||||
|
// \App\Http\Middleware\TrustHosts::class,
|
||||||
|
\Vanguard\Http\Middleware\TrustProxies::class,
|
||||||
|
\Illuminate\Http\Middleware\HandleCors::class,
|
||||||
|
\Vanguard\Http\Middleware\VerifyInstallation::class,
|
||||||
|
\Vanguard\Http\Middleware\PreventRequestsDuringMaintenance::class,
|
||||||
|
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
|
||||||
|
\Vanguard\Http\Middleware\TrimStrings::class,
|
||||||
|
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The application's route middleware groups.
|
||||||
|
*
|
||||||
|
* @var array<string, array<int, class-string|string>>
|
||||||
|
*/
|
||||||
|
protected $middlewareGroups = [
|
||||||
|
'web' => [
|
||||||
|
\Vanguard\Http\Middleware\EncryptCookies::class,
|
||||||
|
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
|
||||||
|
\Illuminate\Session\Middleware\StartSession::class,
|
||||||
|
// \Illuminate\Session\Middleware\AuthenticateSession::class,
|
||||||
|
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
||||||
|
\Vanguard\Http\Middleware\VerifyCsrfToken::class,
|
||||||
|
\Vanguard\Http\Middleware\SetLocale::class,
|
||||||
|
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||||
|
'banned',
|
||||||
|
],
|
||||||
|
'api' => [
|
||||||
|
\Vanguard\Http\Middleware\UseApiGuard::class,
|
||||||
|
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
|
||||||
|
'throttle:60,1',
|
||||||
|
'bindings',
|
||||||
|
'banned',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The application's route middleware.
|
||||||
|
*
|
||||||
|
* These middleware may be assigned to groups or used individually.
|
||||||
|
*
|
||||||
|
* @var array<string, class-string|string>
|
||||||
|
*/
|
||||||
|
protected $routeMiddleware = [
|
||||||
|
'auth' => \Vanguard\Http\Middleware\Authenticate::class,
|
||||||
|
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
|
||||||
|
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||||
|
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
|
||||||
|
'can' => \Illuminate\Auth\Middleware\Authorize::class,
|
||||||
|
'guest' => \Vanguard\Http\Middleware\RedirectIfAuthenticated::class,
|
||||||
|
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
|
||||||
|
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||||
|
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
|
||||||
|
'registration' => \Vanguard\Http\Middleware\RegistrationEnabled::class,
|
||||||
|
'social.login' => \Vanguard\Http\Middleware\SocialLogin::class,
|
||||||
|
'role' => \Vanguard\Http\Middleware\CheckRole::class,
|
||||||
|
'permission' => \Vanguard\Http\Middleware\CheckPermissions::class,
|
||||||
|
'session.database' => \Vanguard\Http\Middleware\DatabaseSession::class,
|
||||||
|
'two-factor' => \Vanguard\Http\Middleware\TwoFactorEnabled::class,
|
||||||
|
'verify-2fa-code' => \Vanguard\Http\Middleware\VerifyTwoFactorCode::class,
|
||||||
|
'password-reset' => \Vanguard\Http\Middleware\PasswordResetEnabled::class,
|
||||||
|
'banned' => \Vanguard\Http\Middleware\CheckIfBanned::class,
|
||||||
|
'approved' => \Vanguard\Http\Middleware\EnsureUserIsApproved::class,
|
||||||
|
'password-change' => \Vanguard\Http\Middleware\ForcePasswordChange::class,
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The priority-sorted list of middleware.
|
||||||
|
*
|
||||||
|
* This forces non-global middleware to always be in the given order.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $middlewarePriority = [
|
||||||
|
\Illuminate\Session\Middleware\StartSession::class,
|
||||||
|
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
||||||
|
\Vanguard\Http\Middleware\Authenticate::class,
|
||||||
|
\Illuminate\Session\Middleware\AuthenticateSession::class,
|
||||||
|
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||||
|
\Illuminate\Auth\Middleware\Authorize::class,
|
||||||
|
];
|
||||||
|
}
|
||||||
30
app/Http/Middleware/Authenticate.php
Normal file
30
app/Http/Middleware/Authenticate.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Contracts\Auth\Guard;
|
||||||
|
|
||||||
|
class Authenticate
|
||||||
|
{
|
||||||
|
public function __construct(private readonly Guard $auth)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function handle($request, Closure $next)
|
||||||
|
{
|
||||||
|
if ($this->auth->guest()) {
|
||||||
|
return $request->expectsJson()
|
||||||
|
? response('Unauthorized.', 401)
|
||||||
|
: redirect()->guest('login');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
23
app/Http/Middleware/CheckIfBanned.php
Normal file
23
app/Http/Middleware/CheckIfBanned.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
|
||||||
|
class CheckIfBanned
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function handle($request, Closure $next)
|
||||||
|
{
|
||||||
|
if ($request->user() && $request->user()->isBanned()) {
|
||||||
|
abort(403, __('Your account is banned by administrator.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
32
app/Http/Middleware/CheckPermissions.php
Normal file
32
app/Http/Middleware/CheckPermissions.php
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Contracts\Auth\Guard;
|
||||||
|
|
||||||
|
class CheckPermissions
|
||||||
|
{
|
||||||
|
public function __construct(protected Guard $auth)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function handle($request, Closure $next, $permissions)
|
||||||
|
{
|
||||||
|
if (! is_array($permissions)) {
|
||||||
|
$permissions = explode('|', $permissions);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->auth->guest() || ! $request->user()->hasPermission($permissions)) {
|
||||||
|
abort(403, 'Forbidden.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
28
app/Http/Middleware/CheckRole.php
Normal file
28
app/Http/Middleware/CheckRole.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Contracts\Auth\Guard;
|
||||||
|
|
||||||
|
class CheckRole
|
||||||
|
{
|
||||||
|
public function __construct(protected Guard $auth)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function handle($request, Closure $next, $role)
|
||||||
|
{
|
||||||
|
if ($this->auth->guest() || ! $request->user()->hasRole($role)) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
26
app/Http/Middleware/DatabaseSession.php
Normal file
26
app/Http/Middleware/DatabaseSession.php
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||||
|
|
||||||
|
class DatabaseSession
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function handle($request, Closure $next)
|
||||||
|
{
|
||||||
|
// If we are not using database session driver,
|
||||||
|
// just display 404 page
|
||||||
|
if (config('session.driver') != 'database') {
|
||||||
|
throw new NotFoundHttpException('The entity you are looking for does not exist.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
17
app/Http/Middleware/EncryptCookies.php
Normal file
17
app/Http/Middleware/EncryptCookies.php
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Middleware;
|
||||||
|
|
||||||
|
use Illuminate\Cookie\Middleware\EncryptCookies as Middleware;
|
||||||
|
|
||||||
|
class EncryptCookies extends Middleware
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The names of the cookies that should not be encrypted.
|
||||||
|
*
|
||||||
|
* @var array<int, string>
|
||||||
|
*/
|
||||||
|
protected $except = [
|
||||||
|
//
|
||||||
|
];
|
||||||
|
}
|
||||||
27
app/Http/Middleware/EnsureUserIsApproved.php
Normal file
27
app/Http/Middleware/EnsureUserIsApproved.php
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Support\Facades\Redirect;
|
||||||
|
use Illuminate\Support\Facades\URL;
|
||||||
|
|
||||||
|
class EnsureUserIsApproved
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function handle($request, Closure $next)
|
||||||
|
{
|
||||||
|
if ($request->user() && $request->user()->isWaitingApproval()) {
|
||||||
|
return $request->expectsJson()
|
||||||
|
? abort(403, __('Your account is waiting approval from administrators.'))
|
||||||
|
: Redirect::guest(URL::route('approval.notice'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
34
app/Http/Middleware/ForcePasswordChange.php
Normal file
34
app/Http/Middleware/ForcePasswordChange.php
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use \Vanguard\Support\Authorization\PasswordChangeManager;
|
||||||
|
|
||||||
|
class ForcePasswordChange
|
||||||
|
{
|
||||||
|
public function __construct(private readonly PasswordChangeManager $forcePasswordChange)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function handle($request, Closure $next)
|
||||||
|
{
|
||||||
|
if (!$this->forcePasswordChange->isPasswordChangeForcedForUser($request->user())) {
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_array($request->route()->getName(), ['profile', 'profile.update.login-details'])) {
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $request->expectsJson() ?
|
||||||
|
abort(403, __('Before continuing please update your password and set a new one.')) :
|
||||||
|
redirect(route('profile'));
|
||||||
|
}
|
||||||
|
}
|
||||||
24
app/Http/Middleware/PasswordResetEnabled.php
Normal file
24
app/Http/Middleware/PasswordResetEnabled.php
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||||
|
|
||||||
|
class PasswordResetEnabled
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function handle($request, Closure $next)
|
||||||
|
{
|
||||||
|
if (! setting('forgot_password')) {
|
||||||
|
throw new NotFoundHttpException;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
17
app/Http/Middleware/PreventRequestsDuringMaintenance.php
Normal file
17
app/Http/Middleware/PreventRequestsDuringMaintenance.php
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Middleware;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance as Middleware;
|
||||||
|
|
||||||
|
class PreventRequestsDuringMaintenance extends Middleware
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The URIs that should be reachable while maintenance mode is enabled.
|
||||||
|
*
|
||||||
|
* @var array<int, string>
|
||||||
|
*/
|
||||||
|
protected $except = [
|
||||||
|
//
|
||||||
|
];
|
||||||
|
}
|
||||||
33
app/Http/Middleware/RedirectIfAuthenticated.php
Normal file
33
app/Http/Middleware/RedirectIfAuthenticated.php
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Vanguard\Providers\RouteServiceProvider;
|
||||||
|
|
||||||
|
class RedirectIfAuthenticated
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
|
||||||
|
* @param string|null ...$guards
|
||||||
|
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
|
||||||
|
*/
|
||||||
|
public function handle(Request $request, Closure $next, ...$guards)
|
||||||
|
{
|
||||||
|
$guards = empty($guards) ? [null] : $guards;
|
||||||
|
|
||||||
|
foreach ($guards as $guard) {
|
||||||
|
if (Auth::guard($guard)->check()) {
|
||||||
|
return request()->has('to')
|
||||||
|
? redirect(request()->get('to'))
|
||||||
|
: redirect(RouteServiceProvider::HOME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
24
app/Http/Middleware/RegistrationEnabled.php
Normal file
24
app/Http/Middleware/RegistrationEnabled.php
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||||
|
|
||||||
|
class RegistrationEnabled
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function handle($request, Closure $next)
|
||||||
|
{
|
||||||
|
if (! setting('reg_enabled')) {
|
||||||
|
throw new NotFoundHttpException;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
60
app/Http/Middleware/SetLocale.php
Normal file
60
app/Http/Middleware/SetLocale.php
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Carbon;
|
||||||
|
use Psr\Container\ContainerExceptionInterface;
|
||||||
|
use Psr\Container\NotFoundExceptionInterface;
|
||||||
|
use Vanguard\Support\Locale;
|
||||||
|
|
||||||
|
class SetLocale
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*/
|
||||||
|
public function handle(Request $request, Closure $next): mixed
|
||||||
|
{
|
||||||
|
$locale = $this->getLocale($request);
|
||||||
|
|
||||||
|
app()->setLocale($locale);
|
||||||
|
Carbon::setLocale($locale);
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ContainerExceptionInterface
|
||||||
|
* @throws NotFoundExceptionInterface
|
||||||
|
*/
|
||||||
|
private function getLocale(Request $request): string
|
||||||
|
{
|
||||||
|
$newLocale = $request->get('lang');
|
||||||
|
|
||||||
|
if (! $newLocale || ! Locale::validateLocale($newLocale)) {
|
||||||
|
return $this->getSelectedLocale();
|
||||||
|
}
|
||||||
|
|
||||||
|
session()->put('locale', $newLocale);
|
||||||
|
|
||||||
|
return $newLocale;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ContainerExceptionInterface
|
||||||
|
* @throws NotFoundExceptionInterface
|
||||||
|
*/
|
||||||
|
private function getSelectedLocale(): string
|
||||||
|
{
|
||||||
|
if (session()->has('locale')) {
|
||||||
|
return session()->get('locale');
|
||||||
|
}
|
||||||
|
|
||||||
|
$locale = \Request::getPreferredLanguage(Locale::AVAILABLE_LOCALES) ?? config('app.locale');
|
||||||
|
|
||||||
|
session()->put('locale', $locale);
|
||||||
|
|
||||||
|
return $locale;
|
||||||
|
}
|
||||||
|
}
|
||||||
26
app/Http/Middleware/SocialLogin.php
Normal file
26
app/Http/Middleware/SocialLogin.php
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||||
|
|
||||||
|
class SocialLogin
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function handle($request, Closure $next)
|
||||||
|
{
|
||||||
|
$provider = $request->route()->parameter('provider');
|
||||||
|
|
||||||
|
if (! in_array($provider, config('auth.social.providers'))) {
|
||||||
|
throw new NotFoundHttpException;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
19
app/Http/Middleware/TrimStrings.php
Normal file
19
app/Http/Middleware/TrimStrings.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Middleware;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\Middleware\TrimStrings as Middleware;
|
||||||
|
|
||||||
|
class TrimStrings extends Middleware
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The names of the attributes that should not be trimmed.
|
||||||
|
*
|
||||||
|
* @var array<int, string>
|
||||||
|
*/
|
||||||
|
protected $except = [
|
||||||
|
'current_password',
|
||||||
|
'password',
|
||||||
|
'password_confirmation',
|
||||||
|
];
|
||||||
|
}
|
||||||
20
app/Http/Middleware/TrustHosts.php
Normal file
20
app/Http/Middleware/TrustHosts.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Vanguard\Http\Middleware;
|
||||||
|
|
||||||
|
use Illuminate\Http\Middleware\TrustHosts as Middleware;
|
||||||
|
|
||||||
|
class TrustHosts extends Middleware
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get the host patterns that should be trusted.
|
||||||
|
*
|
||||||
|
* @return array<int, string|null>
|
||||||
|
*/
|
||||||
|
public function hosts()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
$this->allSubdomainsOfApplicationUrl(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user