diff --git a/app/Domains/Invoice/Views/CreateInvoice.vue b/app/Domains/Invoice/Views/CreateInvoice.vue new file mode 100644 index 0000000..01f0f5f --- /dev/null +++ b/app/Domains/Invoice/Views/CreateInvoice.vue @@ -0,0 +1,29 @@ + + + + + diff --git a/app/Domains/MessageSystem/Actions/SendMessage/SendMessageCommand.php b/app/Domains/MessageSystem/Actions/SendMessage/SendMessageCommand.php new file mode 100644 index 0000000..64c76c2 --- /dev/null +++ b/app/Domains/MessageSystem/Actions/SendMessage/SendMessageCommand.php @@ -0,0 +1,45 @@ +request = $request; + } + + public function send() : SendMessageResponse { + $response = new SendMessageResponse(); + + foreach ($this->request->messageTypes as $messageType) { + switch (true) { + case $messageType->value === MessageType::EMAIL->value: + $this->sendAsEmail(); + break; + + case $messageType->value === MessageType::INTERNAL->value: + $this->sendAsInternalMessage(); + break; + } + } + + return $response; + } + + private function sendAsEmail() { + foreach ($this->request->recipient->getEmailAddresses() as $emailAddress) { + Mail::html($this->request->message, function ($message) use ($emailAddress) { + $message + ->to($emailAddress->getValue(), $this->request->recipient->getName()) + ->subject($this->request->subject); + }); + } + } + + private function sendAsInternalMessage() { + } +} diff --git a/app/Domains/MessageSystem/Actions/SendMessage/SendMessageRequest.php b/app/Domains/MessageSystem/Actions/SendMessage/SendMessageRequest.php new file mode 100644 index 0000000..dc4ae4d --- /dev/null +++ b/app/Domains/MessageSystem/Actions/SendMessage/SendMessageRequest.php @@ -0,0 +1,30 @@ +message = $message; + $this->recipient = $recipient; + $this->subject = $subject; + $this->messageTypes = $messageTypes; + } +} diff --git a/app/Domains/MessageSystem/Actions/SendMessage/SendMessageResponse.php b/app/Domains/MessageSystem/Actions/SendMessage/SendMessageResponse.php new file mode 100644 index 0000000..98e2dae --- /dev/null +++ b/app/Domains/MessageSystem/Actions/SendMessage/SendMessageResponse.php @@ -0,0 +1,7 @@ +request = $request; + } + + public function execute() : GenerateActivationTokenResponse { + $response = new GenerateActivationTokenResponse; + + $activationCode = Str::password(24,true,true,false,false); + $this->request->user->activation_token = $activationCode; + if (null !== $this->request->expirationDate) { + $this->request->user->activation_token_expires_at = $this->request->expirationDate; + } + $this->request->user->save(); + + $response->activationCode = $activationCode; + + $activationMessage = new activationCodeTemplate(); + $activationMessage->composeMessage(EmailAddress::fromString($this->request->user->email), $activationCode); + + $recipient = new MessageRecipient(); + $recipient->addEmailAddress(EmailAddress::fromString($this->request->user->email)); + $recipient->setName($this->request->user->getFullname()); + + $message = activationCodeTemplate::createForUser(EmailAddress::fromString($this->request->user->email), $activationCode); + + $userMessageRequests = new SendMessageRequest($message->getMessage(), $message->getSubject(), $recipient, [MessageType::EMAIL]); + + $userMessageCommand = new SendMessageCommand($userMessageRequests); + $userMessageCommand->send(); + + return $response; + + } +} diff --git a/app/Domains/UserManagement/Actions/GenerateActivationToken/GenerateActivationTokenRequest.php b/app/Domains/UserManagement/Actions/GenerateActivationToken/GenerateActivationTokenRequest.php new file mode 100644 index 0000000..58220c5 --- /dev/null +++ b/app/Domains/UserManagement/Actions/GenerateActivationToken/GenerateActivationTokenRequest.php @@ -0,0 +1,16 @@ +user = $user; + $this->expirationDate = $expirationDate; + + } +} diff --git a/app/Domains/UserManagement/Actions/GenerateActivationToken/GenerateActivationTokenResponse.php b/app/Domains/UserManagement/Actions/GenerateActivationToken/GenerateActivationTokenResponse.php new file mode 100644 index 0000000..a24b291 --- /dev/null +++ b/app/Domains/UserManagement/Actions/GenerateActivationToken/GenerateActivationTokenResponse.php @@ -0,0 +1,7 @@ +request = $request; + } + + public function execute() : UserActivationResponse { + $response = new UserActivationResponse(); + $this->request->user->active = true; + $this->request->user->activation_token = null; + $this->request->user->activation_token_expires_at = null; + $this->request->user->save(); + $response->success = true; + return $response; + } +} diff --git a/app/Domains/UserManagement/Actions/UserActivation/UserActivationRequest.php b/app/Domains/UserManagement/Actions/UserActivation/UserActivationRequest.php new file mode 100644 index 0000000..f68cfee --- /dev/null +++ b/app/Domains/UserManagement/Actions/UserActivation/UserActivationRequest.php @@ -0,0 +1,14 @@ +user = $user; + + } +} diff --git a/app/Domains/UserManagement/Actions/UserActivation/UserActivationResponse.php b/app/Domains/UserManagement/Actions/UserActivation/UserActivationResponse.php new file mode 100644 index 0000000..859aaa8 --- /dev/null +++ b/app/Domains/UserManagement/Actions/UserActivation/UserActivationResponse.php @@ -0,0 +1,11 @@ +success = false; + } +} diff --git a/app/Domains/UserManagement/Actions/UserChangePassword/UserChangePasswordCommand.php b/app/Domains/UserManagement/Actions/UserChangePassword/UserChangePasswordCommand.php new file mode 100644 index 0000000..ca3eed0 --- /dev/null +++ b/app/Domains/UserManagement/Actions/UserChangePassword/UserChangePasswordCommand.php @@ -0,0 +1,23 @@ +request = $request; + } + + public function execute() : UserChangePasswordResponse { + $response = new UserChangePasswordResponse(); + + $this->request->user->password = $this->request->newPassword; + $this->request->user->save(); + + $response->success = true; + return $response; + } +} diff --git a/app/Domains/UserManagement/Actions/UserChangePassword/UserChangePasswordRequest.php b/app/Domains/UserManagement/Actions/UserChangePassword/UserChangePasswordRequest.php new file mode 100644 index 0000000..e5c6767 --- /dev/null +++ b/app/Domains/UserManagement/Actions/UserChangePassword/UserChangePasswordRequest.php @@ -0,0 +1,15 @@ +user = $user; + $this->newPassword = $newPassword; + } +} diff --git a/app/Domains/UserManagement/Actions/UserChangePassword/UserChangePasswordResponse.php b/app/Domains/UserManagement/Actions/UserChangePassword/UserChangePasswordResponse.php new file mode 100644 index 0000000..7f196e2 --- /dev/null +++ b/app/Domains/UserManagement/Actions/UserChangePassword/UserChangePasswordResponse.php @@ -0,0 +1,11 @@ +success = false; + } +} diff --git a/app/Domains/UserManagement/Actions/UserDeactivation/UserDeactivationCommand.php b/app/Domains/UserManagement/Actions/UserDeactivation/UserDeactivationCommand.php new file mode 100644 index 0000000..791ccff --- /dev/null +++ b/app/Domains/UserManagement/Actions/UserDeactivation/UserDeactivationCommand.php @@ -0,0 +1,21 @@ +request = $request; + } + + public function execute() : UserDeactivationResponse { + $response = new UserDeactivationResponse(); + $this->request->user->active = false; + $this->request->user->password = NULL; + $this->request->user->username = 'deleted-' . $this->request->user->username; + $this->request->user->email = 'null@example.com'; + $this->request->user->save(); + $response->success = true; + return $response; + } +} diff --git a/app/Domains/UserManagement/Actions/UserDeactivation/UserDeactivationRequest.php b/app/Domains/UserManagement/Actions/UserDeactivation/UserDeactivationRequest.php new file mode 100644 index 0000000..0907a26 --- /dev/null +++ b/app/Domains/UserManagement/Actions/UserDeactivation/UserDeactivationRequest.php @@ -0,0 +1,14 @@ +user = $user; + + } +} diff --git a/app/Domains/UserManagement/Actions/UserDeactivation/UserDeactivationResponse.php b/app/Domains/UserManagement/Actions/UserDeactivation/UserDeactivationResponse.php new file mode 100644 index 0000000..5573662 --- /dev/null +++ b/app/Domains/UserManagement/Actions/UserDeactivation/UserDeactivationResponse.php @@ -0,0 +1,11 @@ +success = false; + } +} diff --git a/app/Domains/UserManagement/Actions/UserRegistration/UserRegistrationCommand.php b/app/Domains/UserManagement/Actions/UserRegistration/UserRegistrationCommand.php new file mode 100644 index 0000000..b7df941 --- /dev/null +++ b/app/Domains/UserManagement/Actions/UserRegistration/UserRegistrationCommand.php @@ -0,0 +1,60 @@ +request = $request; + } + + public function execute() : UserRegistrationResponse { + $response = new UserRegistrationResponse; + + $user = User::create([ + 'user_role_main' => $this->request->userRoleMain, + 'user_role_local_group' => $this->request->userRoleLocalGroup, + 'username' => $this->request->email->getValue(), + 'local_group' => $this->request->localGroup, + 'firstname' => $this->request->firstname, + 'lastname' => $this->request->lastname, + 'nickname' => $this->request->nickname !== '' ? $this->request->nickname : null, + 'email' => $this->request->email->getValue(), + ]); + + if ($user === null) { + return $response; + } + + $generateActivationCoedeRequest = new GenerateActivationTokenRequest($user); + $generateActivationCoedeDommand = new GenerateActivationTokenCommand($generateActivationCoedeRequest); + $result = $generateActivationCoedeDommand->execute(); + + $user->activation_token = $result->activationCode; + + $siteAdmin = new MessageRecipient(); + $siteAdmin->addEmailAddress(EmailAddress::fromString(env('APP_ADMIN_MAIL'))); + $siteAdmin->setName(env('APP_ADMIN_NAME')); + + $registrationMessage = InformAdminAboutNewUserTemplate::createNew($user); + + $registrationMessageRequest = new SendMessageRequest($registrationMessage->getMessage(), $registrationMessage->getSubject(), $siteAdmin, [MessageType::EMAIL]); + $registrationMessageCommand = new SendMessageCommand($registrationMessageRequest); + $registrationMessageCommand->send(); + + $response->user = $user; + $response->success = true; + return $response; + } +} diff --git a/app/Domains/UserManagement/Actions/UserRegistration/UserRegistrationRequest.php b/app/Domains/UserManagement/Actions/UserRegistration/UserRegistrationRequest.php new file mode 100644 index 0000000..b3697fa --- /dev/null +++ b/app/Domains/UserManagement/Actions/UserRegistration/UserRegistrationRequest.php @@ -0,0 +1,25 @@ +firstname = $firstname; + $this->lastname = $lastname; + $this->nickname = $nickname; + $this->email = $email; + $this->userRoleMain = $userRoleMain; + $this->userRoleLocalGroup = $userRoleLocalGroup; + $this->localGroup = $localGroup; + } +} diff --git a/app/Domains/UserManagement/Actions/UserRegistration/UserRegistrationResponse.php b/app/Domains/UserManagement/Actions/UserRegistration/UserRegistrationResponse.php new file mode 100644 index 0000000..4c3202b --- /dev/null +++ b/app/Domains/UserManagement/Actions/UserRegistration/UserRegistrationResponse.php @@ -0,0 +1,15 @@ +user = null; + $this->success = false; + } +} diff --git a/app/Domains/UserManagement/Controllers/EmailVerificationController.php b/app/Domains/UserManagement/Controllers/EmailVerificationController.php new file mode 100644 index 0000000..91c4009 --- /dev/null +++ b/app/Domains/UserManagement/Controllers/EmailVerificationController.php @@ -0,0 +1,80 @@ + app('tenant')->name]); + return $inertiaProvider->render(); + } + + public function doVerification(Request $request) : JsonResponse + { + + $user = $this->users->findByUsername($request->get('email')); + if ($user === null) { + return response()->json([ + 'error_types' => [ + 'email' => 'Die E-Mail-Adresse konnte nicht zugeordnet werden.', + ], + ]); + } + + if (new DateTime() > DateTime::createFromFormat('Y-m-d H:i:s', $user->activation_token_expires_at)) { + return response()->json([ + 'error_types' => [ + 'verificationToken' => 'Der Sicherheitsschlüssel ist abgelaufen.', + ], + ]); + } + + if (!$this->users->checkVerificationToken($user, $request->get('verificationToken'))) { + return response()->json([ + 'error_types' => [ + 'verificationToken' => 'Der Sicherheitsschlüssel ist nicht korrekt', + ], + ]); + } + + $userActivationRequest = new UserActivationRequest($user); + $userActivationCommand = new UserActivationCommand($userActivationRequest); + $activationResult = $userActivationCommand->execute(); + + + if (!$activationResult->success) { + return response()->json([ + 'error_types' => [ + 'verificationToken' => 'Ein allgemeiner Fehler ist aufgetreten. Bitte versuche es später noch einmal.', + ], + ]); + } + + $userPasswordResetRequest = new UserChangePasswordRequest($user, $request->get('password')); + $userPasswordResetCommand = new UserChangePasswordCommand($userPasswordResetRequest); + $userPasswordResetCommand->execute(); + + return response()->json([ + 'status' => 'success', + 'message' => 'Dein Account wurde aktiviert.Du kannst dich nun mit deinem neuen Passwort einloggen.' + ]); + } +} diff --git a/app/Domains/UserManagement/Controllers/LoginController.php b/app/Domains/UserManagement/Controllers/LoginController.php index 640cbde..d7270d6 100644 --- a/app/Domains/UserManagement/Controllers/LoginController.php +++ b/app/Domains/UserManagement/Controllers/LoginController.php @@ -3,10 +3,11 @@ namespace App\Domains\UserManagement\Controllers; use App\Providers\InertiaProvider; +use App\Scopes\CommonController; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; -class LoginController { +class LoginController extends CommonController { public function loginForm(Request $request) { $errors = []; @@ -32,6 +33,12 @@ class LoginController { 'password.required' => 'Bitte gib dein Passwort ein.', ]); + $user = $this->users->findByUsername($request->get('username')); + if ($user !== null && $user->password === null) { + return redirect()->intended('/register/verifyEmail'); + } + + #$credentials = ['username' => 'development', 'password' => 'development']; if (!Auth::attempt($credentials)) { diff --git a/app/Domains/UserManagement/Controllers/RegistrationController.php b/app/Domains/UserManagement/Controllers/RegistrationController.php new file mode 100644 index 0000000..986a72b --- /dev/null +++ b/app/Domains/UserManagement/Controllers/RegistrationController.php @@ -0,0 +1,73 @@ +session()->has('errors')) { + $errors = $request->session()->get('errors')->getBag('default')->getMessages(); + } + + + $inertiaProvider = new InertiaProvider('UserManagement/Registration', ['errors' => $errors, 'appName' => app('tenant')->name]); + return $inertiaProvider->render(); + } + + public function doRegistration(Request $request) : JsonResponse { + + $user = $this->users->findByUsername($request->get('email')); + if ($user !== null) { + return response()->json([ + 'status' => 'error', + 'message' => 'Dieser Account existiert bereits.' + ]); + } + + $email = EmailAddress::fromString($request->get('email')); + $userRoleMain = UserRole::USER_ROLE_USER; + $userRoleLocalGroup = UserRole::USER_ROLE_USER; + + $localGroup = app('tenant')->slug === 'lv' ? $request->get('localGroup') : app('tenant')->slug; + + + $registrationRequest = new UserRegistrationRequest( + $request->get('firstname'), + $request->get('lastname'), + $request->get('nickname'), + $email, + $userRoleMain, + $userRoleLocalGroup, + $localGroup + ); + + $registrationCommand = new UserRegistrationCommand($registrationRequest); + $result = $registrationCommand->execute(); + + if (!$result->success) { + return response()->json([ + 'status' => 'error', + 'message' => 'Beim Erstellen des Accounts ist ein Fehler aufgetreten.' + ]); + } + + return response()->json([ + 'status' => 'success', + 'message' => 'Registrierung erfolgreich! Bitte prüfe nun dein E-Mail-Postfach' + ]); + } +} diff --git a/app/Domains/UserManagement/Controllers/ResetPasswordController.php b/app/Domains/UserManagement/Controllers/ResetPasswordController.php new file mode 100644 index 0000000..2c5cead --- /dev/null +++ b/app/Domains/UserManagement/Controllers/ResetPasswordController.php @@ -0,0 +1,39 @@ +render(); + } + + public function doResetPassword(Request $request) : JsonResponse { + $user = $this->users->findByUsername($request->get('email')); + + if (null !== $user) { + $expirationDate = new \DateTime()->modify('+15 Minutes'); + + $resetAccountRequest = new GenerateActivationTokenRequest($user, $expirationDate); + $resetAccountCommand = new GenerateActivationTokenCommand($resetAccountRequest); + $resetAccountCommand->execute(); + } + + + return response()->json([ + 'status' => 'success', + 'message' => 'Falls deine E-Mail-Adresse gefunden wurde, erhältst du nun eine E-Mail mit weiteren Schritten zum Zurücksetzen deines Passwortes.' + ]); + + } +} diff --git a/app/Domains/UserManagement/Routes/api.php b/app/Domains/UserManagement/Routes/api.php new file mode 100644 index 0000000..ed20b73 --- /dev/null +++ b/app/Domains/UserManagement/Routes/api.php @@ -0,0 +1,17 @@ +group(function () { + Route::middleware(IdentifyTenant::class)->group(function () { + Route::post('/register', [RegistrationController::class, 'doRegistration']); + Route::post('/register/confirmEmail', [EmailVerificationController::class, 'doVerification']); + Route::post('/reset-password', [ResetPasswordController::class, 'doResetPassword']); + }); + }); diff --git a/app/Domains/UserManagement/Routes/web.php b/app/Domains/UserManagement/Routes/web.php new file mode 100644 index 0000000..a5dea9c --- /dev/null +++ b/app/Domains/UserManagement/Routes/web.php @@ -0,0 +1,31 @@ +group(function () { + Route::get('/register', [RegistrationController::class, 'loginForm']); + Route::get('/register/verifyEmail', [EmailVerificationController::class, 'verifyEmailForm']); + + Route::get('/reset-password', [ResetPasswordController::class, 'resetPasswordForm']); + + route::get('/logout', LogOutController::class); + route::post('/login', [LoginController::class, 'doLogin']); + route::get('/login', [LoginController::class, 'loginForm']); + + Route::middleware(['auth'])->group(function () { + Route::post('/logout', [LogoutController::class, 'logout']); + + }); +}); + + + diff --git a/app/Domains/UserManagement/Views/Login.vue b/app/Domains/UserManagement/Views/Login.vue index 0616102..ef5d6d2 100644 --- a/app/Domains/UserManagement/Views/Login.vue +++ b/app/Domains/UserManagement/Views/Login.vue @@ -25,6 +25,10 @@ const username = ref('') const password = ref('') const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content') + +function resetPassword() { + window.location.href = '/reset-password'; + }