diff --git a/app/Concerns/MustSetInitialPassword.php b/app/Concerns/MustSetInitialPassword.php
new file mode 100644
index 00000000..4db9a342
--- /dev/null
+++ b/app/Concerns/MustSetInitialPassword.php
@@ -0,0 +1,51 @@
+password) {
+ $user->password = Hash::make(Str::random(128));
+ }
+ });
+
+ static::created(function (self $user) {
+ if (! app()->runningInConsole()) {
+ $user->sendWelcomeNotification();
+ }
+ });
+ }
+
+ public function hasSetPassword(): bool
+ {
+ return ! \is_null($this->password_set_at);
+ }
+
+ public function markPasswordAsSet(): bool
+ {
+ return $this->forceFill([
+ 'password_set_at' => $this->freshTimestamp(),
+ ])->save();
+ }
+
+ public function sendWelcomeNotification(): void
+ {
+ if ($this->role===UserRole::ngo_admin)
+ {
+ $this->notify(new WelcomeNotification());
+ return;
+ }
+ $this->notify(new AdminWelcomeNotification());
+ }
+}
diff --git a/app/Enums/UserRole.php b/app/Enums/UserRole.php
index f2ba12d2..878d3712 100644
--- a/app/Enums/UserRole.php
+++ b/app/Enums/UserRole.php
@@ -4,10 +4,19 @@
namespace App\Enums;
+use App\Concerns\ArrayableEnum;
+
enum UserRole: string
{
+ use ArrayableEnum;
case donor = 'donor';
case ngo_admin = 'ngo-admin';
case bb_manager = 'bb-manager';
case bb_admin = 'bb-admin';
+
+ public function translationKeyPrefix(): string
+ {
+ return 'user.roles';
+ }
+
}
diff --git a/app/Filament/Resources/UserResource.php b/app/Filament/Resources/UserResource.php
index 65cfc574..af523cb7 100644
--- a/app/Filament/Resources/UserResource.php
+++ b/app/Filament/Resources/UserResource.php
@@ -4,12 +4,16 @@
namespace App\Filament\Resources;
+use App\Enums\UserRole;
use App\Filament\Resources\UserResource\Pages;
use App\Models\User;
+use Filament\Forms\Components\Select;
+use Filament\Forms\Components\TextInput;
use Filament\Resources\Form;
use Filament\Resources\Resource;
use Filament\Resources\Table;
use Filament\Tables;
+use Filament\Tables\Columns\TextColumn;
class UserResource extends Resource
{
@@ -23,17 +27,15 @@ class UserResource extends Resource
public static function form(Form $form): Form
{
- return $form
- ->schema([
- //
- ]);
+ return $form;
}
public static function table(Table $table): Table
{
return $table
->columns([
- //
+ TextColumn::make('name')->searchable()->sortable(),
+ TextColumn::make('email')->searchable()->sortable(),
])
->filters([
//
diff --git a/app/Filament/Resources/UserResource/Pages/CreateUser.php b/app/Filament/Resources/UserResource/Pages/CreateUser.php
index 72b81bb0..4b834538 100644
--- a/app/Filament/Resources/UserResource/Pages/CreateUser.php
+++ b/app/Filament/Resources/UserResource/Pages/CreateUser.php
@@ -4,10 +4,51 @@
namespace App\Filament\Resources\UserResource\Pages;
+use App\Enums\UserRole;
use App\Filament\Resources\UserResource;
+use Filament\Forms\Components\Select;
+use Filament\Forms\Components\TextInput;
+use Filament\Resources\Form;
use Filament\Resources\Pages\CreateRecord;
class CreateUser extends CreateRecord
{
protected static string $resource = UserResource::class;
+ protected static bool $canCreateAnother = false;
+
+ public function form(Form $form): Form
+ {
+ return $form
+ ->schema([
+ TextInput::make('name')
+ ->label(__('user.name'))
+ ->required(),
+ TextInput::make('email')
+ ->label(__('user.email'))
+ ->email()
+ ->unique('users', 'email')
+ ->required(),
+ Select::make('role')
+ ->label(__('user.role'))
+ ->options(collect(
+ UserRole::options())->only([
+ UserRole::bb_admin->value,
+ UserRole::bb_manager->value,
+ UserRole::ngo_admin->value
+ ]
+ )->toArray()
+ )->reactive()
+ ->required(),
+ Select::make('organization')
+ ->label(__('user.organization'))
+ ->relationship('organization', 'name')
+ ->hidden(function (callable $get) {
+ return $get('role') !== UserRole::ngo_admin->value;
+ })
+ ->searchable()
+ ->preload()
+ ->required(),
+
+ ]);
+ }
}
diff --git a/app/Filament/Resources/UserResource/Pages/EditUser.php b/app/Filament/Resources/UserResource/Pages/EditUser.php
index 2e14c622..3d151732 100644
--- a/app/Filament/Resources/UserResource/Pages/EditUser.php
+++ b/app/Filament/Resources/UserResource/Pages/EditUser.php
@@ -4,8 +4,12 @@
namespace App\Filament\Resources\UserResource\Pages;
+use App\Enums\UserRole;
use App\Filament\Resources\UserResource;
+use Filament\Forms\Components\Select;
+use Filament\Forms\Components\TextInput;
use Filament\Pages\Actions;
+use Filament\Resources\Form;
use Filament\Resources\Pages\EditRecord;
class EditUser extends EditRecord
@@ -18,4 +22,40 @@ protected function getActions(): array
Actions\DeleteAction::make(),
];
}
+ public function form(Form $form): Form
+ {
+ return $form
+ ->schema([
+ TextInput::make('name')
+ ->label(__('user.name'))
+ ->required(),
+ TextInput::make('email')
+ ->label(__('user.email'))
+ ->email()
+ ->unique('users', 'email')
+ ->required(),
+ Select::make('role')
+ ->label(__('user.role'))
+ ->options(collect(
+ UserRole::options())->only([
+ UserRole::bb_admin->value,
+ UserRole::bb_manager->value,
+ UserRole::ngo_admin->value
+ ]
+ )->toArray()
+ )->reactive()
+ ->required(),
+ Select::make('organization')
+ ->label(__('user.organization'))
+ ->relationship('organization', 'name')
+ ->hidden(function (callable $get) {
+ return $get('role') !== UserRole::ngo_admin->value;
+ })
+ ->searchable()
+ ->preload()
+ ->required(),
+
+ ]);
+ }
+
}
diff --git a/app/Filament/Resources/UsersResource/Pages/CreateUsers.php b/app/Filament/Resources/UsersResource/Pages/CreateUsers.php
deleted file mode 100644
index 78288dc9..00000000
--- a/app/Filament/Resources/UsersResource/Pages/CreateUsers.php
+++ /dev/null
@@ -1,13 +0,0 @@
-hasValidSignature()) {
+ abort(Response::HTTP_FORBIDDEN, __('auth.welcome.invalid_signature'));
+ }
+
+ if (\is_null($user)) {
+ abort(Response::HTTP_FORBIDDEN, __('auth.welcome.no_user'));
+ }
+
+ if ($user->hasSetPassword()) {
+ abort(Response::HTTP_FORBIDDEN, __('auth.welcome.already_used'));
+ }
+ return Inertia::render('Auth/SetInitialPassword', [
+ 'user' => $user,
+ 'token' => sha1($user->email),
+ ]);
+ }
+ public function storeInitialPassword(Request $request, User $user): RedirectResponse
+ {
+ if ($request->token !== sha1($user->email)) {
+ abort(401);
+ }
+ $validated = $request->validate([
+ 'password' => ['required', Password::defaults(), 'confirmed'],
+ ]);
+
+ $user->update([
+ 'password' => Hash::make($validated['password']),
+ ]);
+ $user->markPasswordAsSet();
+
+ return redirect()->route('login')->with('success_message', __('user.messages.set_initial_password_success'));
+ }
}
diff --git a/app/Http/Livewire/Welcome.php b/app/Http/Livewire/Welcome.php
new file mode 100644
index 00000000..09d6f140
--- /dev/null
+++ b/app/Http/Livewire/Welcome.php
@@ -0,0 +1,112 @@
+check()) {
+ redirect()->intended(Filament::getUrl());
+ }
+
+ if (! $request->hasValidSignature()) {
+ abort(Response::HTTP_FORBIDDEN, __('auth.welcome.invalid_signature'));
+ }
+
+ $this->user = User::find($user)->first();
+
+ if (\is_null($this->user)) {
+ abort(Response::HTTP_FORBIDDEN, __('auth.welcome.no_user'));
+ }
+
+ if ($this->user->hasSetPassword()) {
+ abort(Response::HTTP_FORBIDDEN, __('auth.welcome.already_used'));
+ }
+
+ $this->form->fill([
+ 'email' => $this->user?->email,
+ ]);
+ }
+
+ public function handle(): ?LoginResponse
+ {
+ try {
+ $this->rateLimit(5);
+ } catch (TooManyRequestsException $exception) {
+ throw ValidationException::withMessages([
+ 'email' => __('filament::login.messages.throttled', [
+ 'seconds' => $exception->secondsUntilAvailable,
+ 'minutes' => ceil($exception->secondsUntilAvailable / 60),
+ ]),
+ ]);
+ }
+
+ $this->user->update([
+ 'password' => Hash::make(data_get($this->form->getState(), 'password')),
+ ]);
+
+ $this->user->markPasswordAsSet();
+
+ Filament::auth()->login($this->user);
+
+ return app(LoginResponse::class);
+ }
+
+ protected function getFormSchema(): array
+ {
+ return [
+ TextInput::make('email')
+ ->label(__('filament::login.fields.email.label'))
+ ->email()
+ ->disabled(),
+
+ TextInput::make('password')
+ ->label(__('filament::login.fields.password.label'))
+ ->password()
+ ->required()
+ ->confirmed(),
+
+ TextInput::make('password_confirmation')
+ ->label(__('filament::login.fields.password.label'))
+ ->password()
+ ->required(),
+ ];
+ }
+
+ public function render(): View
+ {
+ return view('auth.welcome')
+ ->layout('filament::components.layouts.card', [
+ 'title' => __('filament::login.title'),
+ ]);
+ }
+}
diff --git a/app/Models/User.php b/app/Models/User.php
index 46b6d26f..b5252622 100644
--- a/app/Models/User.php
+++ b/app/Models/User.php
@@ -5,6 +5,7 @@
namespace App\Models;
// use Illuminate\Contracts\Auth\MustVerifyEmail;
+use App\Concerns\MustSetInitialPassword;
use App\Traits\HasRole;
use Filament\Models\Contracts\FilamentUser;
use Illuminate\Database\Eloquent\Factories\HasFactory;
@@ -20,6 +21,7 @@ class User extends Authenticatable implements FilamentUser
use HasFactory;
use Notifiable;
use HasRole;
+ use MustSetInitialPassword;
/**
* The attributes that are mass assignable.
diff --git a/app/Notifications/Admin/WelcomeNotification.php b/app/Notifications/Admin/WelcomeNotification.php
new file mode 100644
index 00000000..9b9c8685
--- /dev/null
+++ b/app/Notifications/Admin/WelcomeNotification.php
@@ -0,0 +1,44 @@
+
+ */
+ public function via(object $notifiable): array
+ {
+ return ['mail'];
+ }
+
+ /**
+ * Get the mail representation of the notification.
+ */
+ public function toMail(object $notifiable): MailMessage
+ {
+ return (new MailMessage)
+ ->subject(__('auth.welcome.subject', ['app' => config('app.name')]))
+ ->greeting(__('auth.welcome.greeting', [
+ 'name' => $notifiable->name,
+ ]))
+ ->line(__('auth.welcome.intro', [
+ 'app' => config('app.name'),
+ ]))
+ ->action(__('auth.welcome.submit'), URL::signedRoute(
+ 'filament.auth.welcome',
+ ['user' => $notifiable->id]
+ ));
+ }
+}
diff --git a/app/Notifications/Ngo/WelcomeNotification.php b/app/Notifications/Ngo/WelcomeNotification.php
new file mode 100644
index 00000000..64f52113
--- /dev/null
+++ b/app/Notifications/Ngo/WelcomeNotification.php
@@ -0,0 +1,44 @@
+
+ */
+ public function via(object $notifiable): array
+ {
+ return ['mail'];
+ }
+
+ /**
+ * Get the mail representation of the notification.
+ */
+ public function toMail(object $notifiable): MailMessage
+ {
+ return (new MailMessage)
+ ->subject(__('auth.welcome.subject', ['app' => config('app.name')]))
+ ->greeting(__('auth.welcome.greeting', [
+ 'name' => $notifiable->name,
+ ]))
+ ->line(__('auth.welcome.intro', [
+ 'app' => config('app.name'),
+ ]))
+ ->action(__('auth.welcome.submit'), URL::signedRoute(
+ 'ngo.user.welcome',
+ ['user' => $notifiable->id]
+ ));
+ }
+}
diff --git a/composer.json b/composer.json
index 0d579ec2..389d56b3 100644
--- a/composer.json
+++ b/composer.json
@@ -15,6 +15,7 @@
"filament/spatie-laravel-translatable-plugin": "^2.17",
"guzzlehttp/guzzle": "^7.8",
"inertiajs/inertia-laravel": "^0.6",
+ "jeffgreco13/filament-breezy": "^1.5",
"laravel/framework": "^10.20",
"laravel/sanctum": "^3.2",
"laravel/tinker": "^2.8",
diff --git a/composer.lock b/composer.lock
index 93048a97..d74f6a7f 100644
--- a/composer.lock
+++ b/composer.lock
@@ -303,6 +303,60 @@
},
"time": "2023-08-25T18:07:43+00:00"
},
+ {
+ "name": "bacon/bacon-qr-code",
+ "version": "2.0.8",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Bacon/BaconQrCode.git",
+ "reference": "8674e51bb65af933a5ffaf1c308a660387c35c22"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/8674e51bb65af933a5ffaf1c308a660387c35c22",
+ "reference": "8674e51bb65af933a5ffaf1c308a660387c35c22",
+ "shasum": ""
+ },
+ "require": {
+ "dasprid/enum": "^1.0.3",
+ "ext-iconv": "*",
+ "php": "^7.1 || ^8.0"
+ },
+ "require-dev": {
+ "phly/keep-a-changelog": "^2.1",
+ "phpunit/phpunit": "^7 | ^8 | ^9",
+ "spatie/phpunit-snapshot-assertions": "^4.2.9",
+ "squizlabs/php_codesniffer": "^3.4"
+ },
+ "suggest": {
+ "ext-imagick": "to generate QR code images"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "BaconQrCode\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-2-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Ben Scholzen 'DASPRiD'",
+ "email": "mail@dasprids.de",
+ "homepage": "https://dasprids.de/",
+ "role": "Developer"
+ }
+ ],
+ "description": "BaconQrCode is a QR code generator for PHP.",
+ "homepage": "https://github.com/Bacon/BaconQrCode",
+ "support": {
+ "issues": "https://github.com/Bacon/BaconQrCode/issues",
+ "source": "https://github.com/Bacon/BaconQrCode/tree/2.0.8"
+ },
+ "time": "2022-12-07T17:46:57+00:00"
+ },
{
"name": "blade-ui-kit/blade-heroicons",
"version": "1.4.0",
@@ -688,6 +742,56 @@
],
"time": "2023-03-12T12:17:29+00:00"
},
+ {
+ "name": "dasprid/enum",
+ "version": "1.0.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/DASPRiD/Enum.git",
+ "reference": "6faf451159fb8ba4126b925ed2d78acfce0dc016"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/DASPRiD/Enum/zipball/6faf451159fb8ba4126b925ed2d78acfce0dc016",
+ "reference": "6faf451159fb8ba4126b925ed2d78acfce0dc016",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1 <9.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^7 | ^8 | ^9",
+ "squizlabs/php_codesniffer": "*"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "DASPRiD\\Enum\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-2-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Ben Scholzen 'DASPRiD'",
+ "email": "mail@dasprids.de",
+ "homepage": "https://dasprids.de/",
+ "role": "Developer"
+ }
+ ],
+ "description": "PHP 7.1 enum implementation",
+ "keywords": [
+ "enum",
+ "map"
+ ],
+ "support": {
+ "issues": "https://github.com/DASPRiD/Enum/issues",
+ "source": "https://github.com/DASPRiD/Enum/tree/1.0.5"
+ },
+ "time": "2023-08-25T16:18:39+00:00"
+ },
{
"name": "dflydev/dot-access-data",
"version": "v3.0.2",
@@ -2116,6 +2220,86 @@
],
"time": "2022-05-21T17:30:32+00:00"
},
+ {
+ "name": "jeffgreco13/filament-breezy",
+ "version": "v1.5.9",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/jeffgreco13/filament-breezy.git",
+ "reference": "20a853f55b5170a65ee1a61682141a7918ee594c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/jeffgreco13/filament-breezy/zipball/20a853f55b5170a65ee1a61682141a7918ee594c",
+ "reference": "20a853f55b5170a65ee1a61682141a7918ee594c",
+ "shasum": ""
+ },
+ "require": {
+ "bacon/bacon-qr-code": "^2.0",
+ "filament/filament": "^2.15",
+ "php": "^8.0|^8.1",
+ "pragmarx/google2fa": "^7.0|^8.0",
+ "spatie/laravel-package-tools": "^1.9.2"
+ },
+ "require-dev": {
+ "nunomaduro/collision": "^5.0|^6.0",
+ "nunomaduro/larastan": "^1.0",
+ "orchestra/testbench": "^6.0|^7.0|^8.0",
+ "pestphp/pest": "^1.21",
+ "pestphp/pest-plugin-laravel": "^1.1",
+ "phpstan/extension-installer": "^1.1",
+ "phpstan/phpstan-deprecation-rules": "^1.0",
+ "phpstan/phpstan-phpunit": "^1.0",
+ "phpunit/phpunit": "^9.5",
+ "spatie/laravel-ray": "^1.26"
+ },
+ "type": "library",
+ "extra": {
+ "laravel": {
+ "providers": [
+ "JeffGreco13\\FilamentBreezy\\FilamentBreezyServiceProvider"
+ ],
+ "aliases": {
+ "FilamentBreezy": "JeffGreco13\\FilamentBreezy\\Facades\\FilamentBreezy"
+ }
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "JeffGreco13\\FilamentBreezy\\": "src",
+ "JeffGreco13\\FilamentBreezy\\Database\\Factories\\": "database/factories"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jeff Greco",
+ "email": "jeff@jeffpgreco.com",
+ "role": "Developer"
+ }
+ ],
+ "description": "A custom package for Filament with login flow, profile and teams support.",
+ "homepage": "https://github.com/jeffgreco13/filament-breezy",
+ "keywords": [
+ "filament-breezy",
+ "jeffgreco13",
+ "laravel"
+ ],
+ "support": {
+ "issues": "https://github.com/jeffgreco13/filament-breezy/issues",
+ "source": "https://github.com/jeffgreco13/filament-breezy/tree/v1.5.9"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/jeffgreco13",
+ "type": "github"
+ }
+ ],
+ "time": "2023-07-22T16:01:05+00:00"
+ },
{
"name": "laravel/framework",
"version": "v10.20.0",
@@ -3936,6 +4120,73 @@
],
"time": "2023-02-08T01:06:31+00:00"
},
+ {
+ "name": "paragonie/constant_time_encoding",
+ "version": "v2.6.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/paragonie/constant_time_encoding.git",
+ "reference": "58c3f47f650c94ec05a151692652a868995d2938"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/58c3f47f650c94ec05a151692652a868995d2938",
+ "reference": "58c3f47f650c94ec05a151692652a868995d2938",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7|^8"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^6|^7|^8|^9",
+ "vimeo/psalm": "^1|^2|^3|^4"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "ParagonIE\\ConstantTime\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Paragon Initiative Enterprises",
+ "email": "security@paragonie.com",
+ "homepage": "https://paragonie.com",
+ "role": "Maintainer"
+ },
+ {
+ "name": "Steve 'Sc00bz' Thomas",
+ "email": "steve@tobtu.com",
+ "homepage": "https://www.tobtu.com",
+ "role": "Original Developer"
+ }
+ ],
+ "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)",
+ "keywords": [
+ "base16",
+ "base32",
+ "base32_decode",
+ "base32_encode",
+ "base64",
+ "base64_decode",
+ "base64_encode",
+ "bin2hex",
+ "encoding",
+ "hex",
+ "hex2bin",
+ "rfc4648"
+ ],
+ "support": {
+ "email": "info@paragonie.com",
+ "issues": "https://github.com/paragonie/constant_time_encoding/issues",
+ "source": "https://github.com/paragonie/constant_time_encoding"
+ },
+ "time": "2022-06-14T06:56:20+00:00"
+ },
{
"name": "phpoption/phpoption",
"version": "1.9.1",
@@ -4011,6 +4262,106 @@
],
"time": "2023-02-25T19:38:58+00:00"
},
+ {
+ "name": "pragmarx/google2fa",
+ "version": "v8.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/antonioribeiro/google2fa.git",
+ "reference": "80c3d801b31fe165f8fe99ea085e0a37834e1be3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/antonioribeiro/google2fa/zipball/80c3d801b31fe165f8fe99ea085e0a37834e1be3",
+ "reference": "80c3d801b31fe165f8fe99ea085e0a37834e1be3",
+ "shasum": ""
+ },
+ "require": {
+ "paragonie/constant_time_encoding": "^1.0|^2.0",
+ "php": "^7.1|^8.0"
+ },
+ "require-dev": {
+ "phpstan/phpstan": "^0.12.18",
+ "phpunit/phpunit": "^7.5.15|^8.5|^9.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "PragmaRX\\Google2FA\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Antonio Carlos Ribeiro",
+ "email": "acr@antoniocarlosribeiro.com",
+ "role": "Creator & Designer"
+ }
+ ],
+ "description": "A One Time Password Authentication package, compatible with Google Authenticator.",
+ "keywords": [
+ "2fa",
+ "Authentication",
+ "Two Factor Authentication",
+ "google2fa"
+ ],
+ "support": {
+ "issues": "https://github.com/antonioribeiro/google2fa/issues",
+ "source": "https://github.com/antonioribeiro/google2fa/tree/v8.0.1"
+ },
+ "time": "2022-06-13T21:57:56+00:00"
+ },
+ {
+ "name": "psr/clock",
+ "version": "1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/clock.git",
+ "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d",
+ "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.0 || ^8.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Psr\\Clock\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for reading the clock.",
+ "homepage": "https://github.com/php-fig/clock",
+ "keywords": [
+ "clock",
+ "now",
+ "psr",
+ "psr-20",
+ "time"
+ ],
+ "support": {
+ "issues": "https://github.com/php-fig/clock/issues",
+ "source": "https://github.com/php-fig/clock/tree/1.0.0"
+ },
+ "time": "2022-11-25T14:36:26+00:00"
+ },
{
"name": "psr/clock",
"version": "1.0.0",
@@ -5411,6 +5762,69 @@
],
"time": "2023-07-19T19:21:38+00:00"
},
+ {
+ "name": "spatie/shiki-php",
+ "version": "1.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/spatie/shiki-php.git",
+ "reference": "34fe61405b405c735c82a9c56feffd3f7c5544ff"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/spatie/shiki-php/zipball/34fe61405b405c735c82a9c56feffd3f7c5544ff",
+ "reference": "34fe61405b405c735c82a9c56feffd3f7c5544ff",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.4|^8.0"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "^v3.0",
+ "pestphp/pest": "^1.8",
+ "phpunit/phpunit": "^9.5",
+ "spatie/pest-plugin-snapshots": "^1.1",
+ "spatie/ray": "^1.10"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Spatie\\ShikiPhp\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Rias Van der Veken",
+ "email": "rias@spatie.be",
+ "role": "Developer"
+ },
+ {
+ "name": "Freek Van der Herten",
+ "email": "freek@spatie.be",
+ "role": "Developer"
+ }
+ ],
+ "description": "Highlight code using Shiki in PHP",
+ "homepage": "https://github.com/spatie/shiki-php",
+ "keywords": [
+ "shiki",
+ "spatie"
+ ],
+ "support": {
+ "source": "https://github.com/spatie/shiki-php/tree/1.3.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/spatie",
+ "type": "github"
+ }
+ ],
+ "time": "2023-07-19T19:21:38+00:00"
+ },
{
"name": "spatie/shiki-php",
"version": "1.3.0",
diff --git a/database/migrations/2023_05_05_142245_update_users.php b/database/migrations/2023_05_05_142245_update_users.php
index 4e1f2f10..2dfd4485 100644
--- a/database/migrations/2023_05_05_142245_update_users.php
+++ b/database/migrations/2023_05_05_142245_update_users.php
@@ -18,6 +18,7 @@ public function up(): void
$table->enum('role', ['donor', 'ngo-admin', 'bb-manager', 'bb-admin']);
$table->string('phone')->nullable();
$table->string('source_of_information')->nullable();
+ $table->timestamp('password_set_at')->nullable();
$table->foreignIdFor(Organization::class)->nullable()->constrained();
});
}
diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php
index 89cb400d..6711e2a5 100644
--- a/database/seeders/DatabaseSeeder.php
+++ b/database/seeders/DatabaseSeeder.php
@@ -78,9 +78,9 @@ public function run(): void
->count(10)
->hasVolunteers(10)
)
- ->has(
- Ticket::factory()
- )
+// ->has(
+//// Ticket::factory()
+// )
->create();
Badge::factory()
diff --git a/lang/ro/auth.php b/lang/ro/auth.php
new file mode 100644
index 00000000..10b506df
--- /dev/null
+++ b/lang/ro/auth.php
@@ -0,0 +1,12 @@
+[
+ 'greeting'=>'Bun venit, :name!',
+ 'subject'=>'Bun venit pe :app',
+ 'intro'=>'Bine ai venit pe platforma :app. Pentru a-ți seta parola, te rugăm să apeși pe butonul de mai jos.',
+ 'submit' =>'Setează parola',
+ 'invalid_signature'=>'Link-ul de setare a parolei este invalid.',
+ 'no_user'=>'Nu există un utilizator cu acest email.',
+ 'already_used'=>'Parola a fost deja setată.',
+ ]
+];
diff --git a/lang/ro/user.php b/lang/ro/user.php
new file mode 100644
index 00000000..afa0080e
--- /dev/null
+++ b/lang/ro/user.php
@@ -0,0 +1,16 @@
+[
+ 'donor'=>'Donator',
+ 'ngo-admin'=>'Administrator ONG',
+ 'bb-manager'=>'Manager Bursa Binelui',
+ 'bb-admin'=>'Administrator Bursa Binelui',
+ ],
+ 'name'=>'Nume',
+ 'email'=>'Email',
+ 'role'=>'Rol',
+ 'organization'=>'Organizație',
+ 'messages'=>[
+ 'set_initial_password_success' => 'Parola a fost setată cu succes!',
+ ]
+];
diff --git a/resources/js/Pages/Auth/SetInitialPassword.vue b/resources/js/Pages/Auth/SetInitialPassword.vue
new file mode 100644
index 00000000..9ad4c5d8
--- /dev/null
+++ b/resources/js/Pages/Auth/SetInitialPassword.vue
@@ -0,0 +1,94 @@
+
+
config('filament.dark_mode')])> + {{$description}} +
+{{ __('filament-breezy::default.profile.2fa.enabled.title') }}
+ {{ __('filament-breezy::default.profile.2fa.enabled.description') ?? __('filament-breezy::default.profile.2fa.enabled.store_codes') }} + @else +{{ __('filament-breezy::default.profile.2fa.finish_enabling.title') }}
+ {{ __('filament-breezy::default.profile.2fa.finish_enabling.description') }} + @endif + +{{ __('filament-breezy::default.profile.2fa.setup_key') }} {{ decrypt($this->user->two_factor_secret) }}
+{{ __('filament-breezy::default.profile.2fa.enabled.store_codes') }}
+{{ __('filament-breezy::default.profile.2fa.not_enabled.title') }}
+ {{ __('filament-breezy::default.profile.2fa.not_enabled.description') }} + + @endif ++ {{ __('filament-breezy::default.or') }} + + {{ __('filament-breezy::default.registration.heading') }} + +
+ @endif ++ {{ __('filament-breezy::default.or') }} + + {{ strtolower(__('filament::login.heading')) }} + +
++ {{ __('filament-breezy::default.or') }} + + {{ strtolower(__('filament::login.heading')) }} + +
++ {{ $this->usingRecoveryCode ? __('filament-breezy::default.two_factor.recovery.description') : __('filament-breezy::default.two_factor.description') }} + {{ __('filament-breezy::default.two_factor.back_to_login_link') }} + +
+