From 8237522e553c7fb6abf97e348328c36cc06e5379 Mon Sep 17 00:00:00 2001 From: Louis Charette Date: Thu, 26 Dec 2024 23:09:08 -0500 Subject: [PATCH] Add User Create, Edit & Delete Action --- .../app/assets/composables/index.ts | 12 ++ .../app/assets/composables/useUserApi.ts | 2 +- .../assets/composables/useUserCreateApi.ts | 46 +++++ .../assets/composables/useUserDeleteApi.ts | 43 +++++ .../app/assets/composables/useUserEditApi.ts | 46 +++++ .../app/assets/interfaces/GroupCreateApi.ts | 4 +- .../app/assets/interfaces/UserCreateApi.ts | 19 +++ .../app/assets/interfaces/UserDeleteApi.ts | 4 + .../app/assets/interfaces/UserEditApi.ts | 19 +++ .../app/assets/interfaces/index.ts | 3 + .../src/Controller/User/UserCreateAction.php | 22 ++- .../src/Controller/User/UserDeleteAction.php | 13 +- .../src/Controller/User/UserEditAction.php | 24 ++- .../Controller/User/UserCreateActionTest.php | 66 +++----- .../Controller/User/UserDeleteActionTest.php | 12 +- .../Controller/User/UserEditActionTest.php | 15 +- .../Pages/Admin/Group/GroupForm.vue | 10 +- .../Pages/Admin/User/UserCreateModal.vue | 75 +++++++++ .../Pages/Admin/User/UserDeleteModal.vue | 60 +++++++ .../Pages/Admin/User/UserEditModal.vue | 103 ++++++++++++ .../components/Pages/Admin/User/UserForm.vue | 157 ++++++++++++++++++ .../components/Pages/Admin/User/UserInfo.vue | 24 ++- .../src/views/Admin/UserPage.vue | 4 +- .../src/views/Admin/UsersPage.vue | 38 ++++- 24 files changed, 711 insertions(+), 110 deletions(-) create mode 100644 packages/sprinkle-admin/app/assets/composables/useUserCreateApi.ts create mode 100644 packages/sprinkle-admin/app/assets/composables/useUserDeleteApi.ts create mode 100644 packages/sprinkle-admin/app/assets/composables/useUserEditApi.ts create mode 100644 packages/sprinkle-admin/app/assets/interfaces/UserCreateApi.ts create mode 100644 packages/sprinkle-admin/app/assets/interfaces/UserDeleteApi.ts create mode 100644 packages/sprinkle-admin/app/assets/interfaces/UserEditApi.ts create mode 100644 packages/theme-pink-cupcake/src/components/Pages/Admin/User/UserCreateModal.vue create mode 100644 packages/theme-pink-cupcake/src/components/Pages/Admin/User/UserDeleteModal.vue create mode 100644 packages/theme-pink-cupcake/src/components/Pages/Admin/User/UserEditModal.vue create mode 100644 packages/theme-pink-cupcake/src/components/Pages/Admin/User/UserForm.vue diff --git a/packages/sprinkle-admin/app/assets/composables/index.ts b/packages/sprinkle-admin/app/assets/composables/index.ts index 70e5203b1..5b5da8a83 100644 --- a/packages/sprinkle-admin/app/assets/composables/index.ts +++ b/packages/sprinkle-admin/app/assets/composables/index.ts @@ -1,8 +1,20 @@ +// Dashboard export { useDashboardApi } from './useDashboardApi' + +// Group export { useGroupApi } from './useGroupApi' export { useGroupCreateApi } from './useGroupCreateApi' export { useGroupDeleteApi } from './useGroupDeleteApi' export { useGroupEditApi } from './useGroupEditApi' + +// Permission export { usePermissionApi } from './usePermissionApi' + +// Role export { useRoleApi } from './useRoleApi' + +// User export { useUserApi } from './useUserApi' +export { useUserCreateApi } from './useUserCreateApi' +export { useUserDeleteApi } from './useUserDeleteApi' +export { useUserEditApi } from './useUserEditApi' diff --git a/packages/sprinkle-admin/app/assets/composables/useUserApi.ts b/packages/sprinkle-admin/app/assets/composables/useUserApi.ts index cc830389b..47d0a90e5 100644 --- a/packages/sprinkle-admin/app/assets/composables/useUserApi.ts +++ b/packages/sprinkle-admin/app/assets/composables/useUserApi.ts @@ -59,5 +59,5 @@ export function useUserApi(route: any) { { immediate: true } ) - return { user, error, loading } + return { user, error, loading, fetchApi } } diff --git a/packages/sprinkle-admin/app/assets/composables/useUserCreateApi.ts b/packages/sprinkle-admin/app/assets/composables/useUserCreateApi.ts new file mode 100644 index 000000000..6b0239100 --- /dev/null +++ b/packages/sprinkle-admin/app/assets/composables/useUserCreateApi.ts @@ -0,0 +1,46 @@ +import { ref } from 'vue' +import axios from 'axios' +import { Severity, type AlertInterface } from '@userfrosting/sprinkle-core/interfaces' +import type { UserCreateForm, UserCreateResponse } from '../interfaces' + +// TODO : Add validation +// 'schema://requests/user/create.yaml' + +/** + * API Composable + */ +export function useUserCreateApi() { + const apiLoading = ref(false) + const apiError = ref(null) + + async function submitUserCreate(data: UserCreateForm) { + apiLoading.value = true + apiError.value = null + return axios + .post('/api/users', data) + .then((response) => { + return { + success: response.data.success, + message: response.data.message, + user: response.data.user + } + }) + .catch((err) => { + apiError.value = { + ...{ + description: 'An error as occurred', + style: Severity.Danger, + closeBtn: true + }, + ...err.response.data + } + + throw apiError.value + }) + .finally(() => { + apiLoading.value = false + }) + } + + return { submitUserCreate, apiLoading, apiError } +} diff --git a/packages/sprinkle-admin/app/assets/composables/useUserDeleteApi.ts b/packages/sprinkle-admin/app/assets/composables/useUserDeleteApi.ts new file mode 100644 index 000000000..79f78d75e --- /dev/null +++ b/packages/sprinkle-admin/app/assets/composables/useUserDeleteApi.ts @@ -0,0 +1,43 @@ +import { ref } from 'vue' +import axios from 'axios' +import { Severity, type AlertInterface } from '@userfrosting/sprinkle-core/interfaces' +import type { UserDeleteResponse } from '../interfaces' + +/** + * API Composable + */ +export function useUserDeleteApi() { + // Form data + const loadingState = ref(false) + const apiError = ref(null) + + async function deleteUser(user_name: string) { + loadingState.value = true + apiError.value = null + return axios + .delete('/api/users/u/' + user_name) + .then((response) => { + return { + success: response.data.success, + message: response.data.message + } + }) + .catch((err) => { + apiError.value = { + ...{ + description: 'An error as occurred', + style: Severity.Danger, + closeBtn: true + }, + ...err.response.data + } + + throw apiError.value + }) + .finally(() => { + loadingState.value = false + }) + } + + return { loadingState, apiError, deleteUser } +} diff --git a/packages/sprinkle-admin/app/assets/composables/useUserEditApi.ts b/packages/sprinkle-admin/app/assets/composables/useUserEditApi.ts new file mode 100644 index 000000000..5dcacd3f6 --- /dev/null +++ b/packages/sprinkle-admin/app/assets/composables/useUserEditApi.ts @@ -0,0 +1,46 @@ +import { ref } from 'vue' +import axios from 'axios' +import { Severity, type AlertInterface } from '@userfrosting/sprinkle-core/interfaces' +import type { UserEditForm, UserEditResponse } from '../interfaces' + +// TODO : Add validation +// 'schema://requests/user/edit-info.yaml' + +/** + * API Composable + */ +export function useUserEditApi() { + const apiLoading = ref(false) + const apiError = ref(null) + + async function submitUserEdit(user_name: string, data: UserEditForm) { + apiLoading.value = true + apiError.value = null + return axios + .put('/api/users/u/' + user_name, data) + .then((response) => { + return { + success: response.data.success, + message: response.data.message, + user: response.data.user + } + }) + .catch((err) => { + apiError.value = { + ...{ + description: 'An error as occurred', + style: Severity.Danger, + closeBtn: true + }, + ...err.response.data + } + + throw apiError.value + }) + .finally(() => { + apiLoading.value = false + }) + } + + return { submitUserEdit, apiLoading, apiError } +} diff --git a/packages/sprinkle-admin/app/assets/interfaces/GroupCreateApi.ts b/packages/sprinkle-admin/app/assets/interfaces/GroupCreateApi.ts index f138ddbd8..3914230ad 100644 --- a/packages/sprinkle-admin/app/assets/interfaces/GroupCreateApi.ts +++ b/packages/sprinkle-admin/app/assets/interfaces/GroupCreateApi.ts @@ -1,3 +1,5 @@ +import type { GroupInterface } from '@userfrosting/sprinkle-account/interfaces' + /** * Interfaces - What the API expects and what it returns */ @@ -11,5 +13,5 @@ export interface GroupCreateForm { export interface GroupCreateResponse { success: boolean message: string - group: GroupCreateForm + group: GroupInterface } diff --git a/packages/sprinkle-admin/app/assets/interfaces/UserCreateApi.ts b/packages/sprinkle-admin/app/assets/interfaces/UserCreateApi.ts new file mode 100644 index 000000000..244e34bc0 --- /dev/null +++ b/packages/sprinkle-admin/app/assets/interfaces/UserCreateApi.ts @@ -0,0 +1,19 @@ +import type { UserInterface } from '@userfrosting/sprinkle-account/interfaces' + +/** + * Interfaces - What the API expects and what it returns + */ +export interface UserCreateForm { + user_name: string + group_id: number + first_name: string + last_name: string + email: string + locale: string +} + +export interface UserCreateResponse { + success: boolean + message: string + user: UserInterface +} diff --git a/packages/sprinkle-admin/app/assets/interfaces/UserDeleteApi.ts b/packages/sprinkle-admin/app/assets/interfaces/UserDeleteApi.ts new file mode 100644 index 000000000..f4e672953 --- /dev/null +++ b/packages/sprinkle-admin/app/assets/interfaces/UserDeleteApi.ts @@ -0,0 +1,4 @@ +export interface UserDeleteResponse { + success: boolean + message: string +} diff --git a/packages/sprinkle-admin/app/assets/interfaces/UserEditApi.ts b/packages/sprinkle-admin/app/assets/interfaces/UserEditApi.ts new file mode 100644 index 000000000..1294389e9 --- /dev/null +++ b/packages/sprinkle-admin/app/assets/interfaces/UserEditApi.ts @@ -0,0 +1,19 @@ +import type { UserInterface } from '@userfrosting/sprinkle-account/interfaces' + +/** + * Interfaces - What the API expects and what it returns + */ +export interface UserEditForm { + user_name: string + group_id: number | null + first_name: string + last_name: string + email: string + locale: string +} + +export interface UserEditResponse { + success: boolean + message: string + user: UserInterface +} diff --git a/packages/sprinkle-admin/app/assets/interfaces/index.ts b/packages/sprinkle-admin/app/assets/interfaces/index.ts index 24d3b9794..76bf636e0 100644 --- a/packages/sprinkle-admin/app/assets/interfaces/index.ts +++ b/packages/sprinkle-admin/app/assets/interfaces/index.ts @@ -6,3 +6,6 @@ export type { GroupEditForm, GroupEditResponse } from './GroupEditApi' export type { PermissionApi } from './PermissionApi' export type { RoleApi } from './RoleApi' export type { UserApi } from './UserApi' +export type { UserCreateForm, UserCreateResponse } from './UserCreateApi' +export type { UserDeleteResponse } from './UserDeleteApi' +export type { UserEditForm, UserEditResponse } from './UserEditApi' diff --git a/packages/sprinkle-admin/app/src/Controller/User/UserCreateAction.php b/packages/sprinkle-admin/app/src/Controller/User/UserCreateAction.php index c77ac2baf..e988d322e 100644 --- a/packages/sprinkle-admin/app/src/Controller/User/UserCreateAction.php +++ b/packages/sprinkle-admin/app/src/Controller/User/UserCreateAction.php @@ -16,12 +16,12 @@ use Psr\EventDispatcher\EventDispatcherInterface; use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; -use UserFrosting\Alert\AlertStream; use UserFrosting\Config\Config; use UserFrosting\Fortress\RequestSchema; use UserFrosting\Fortress\RequestSchema\RequestSchemaInterface; use UserFrosting\Fortress\Transformer\RequestDataTransformer; use UserFrosting\Fortress\Validator\ServerSideValidator; +use UserFrosting\I18n\Translator; use UserFrosting\Sprinkle\Account\Authenticate\Authenticator; use UserFrosting\Sprinkle\Account\Database\Models\Interfaces\GroupInterface; use UserFrosting\Sprinkle\Account\Database\Models\Interfaces\UserInterface; @@ -59,7 +59,7 @@ class UserCreateAction * @param \UserFrosting\Event\EventDispatcher $eventDispatcher */ public function __construct( - protected AlertStream $alert, + protected Translator $translator, protected Authenticator $authenticator, protected Config $config, protected Connection $db, @@ -86,8 +86,12 @@ public function __construct( public function __invoke(Request $request, Response $response): Response { $this->validateAccess(); - $this->handle($request); - $payload = json_encode([], JSON_THROW_ON_ERROR); + $user = $this->handle($request)->toArray(); + $payload = json_encode([ + 'success' => true, + 'message' => $this->translator->translate('USER.CREATED', $user), + 'user' => $user, + ], JSON_THROW_ON_ERROR); $response->getBody()->write($payload); return $response->withHeader('Content-Type', 'application/json'); @@ -97,8 +101,10 @@ public function __invoke(Request $request, Response $response): Response * Handle the request. * * @param Request $request + * + * @return UserInterface */ - protected function handle(Request $request): void + protected function handle(Request $request): UserInterface { // Get POST parameters. $params = (array) $request->getParsedBody(); @@ -156,7 +162,7 @@ protected function handle(Request $request): void $this->userValidation->validate($user); // Ready to save - $this->db->transaction(function () use ($user, $data, $currentUser) { + $user = $this->db->transaction(function () use ($user, $data, $currentUser) { // Store new user to database $user->save(); @@ -175,8 +181,10 @@ protected function handle(Request $request): void $this->passwordEmail->send($user); } - $this->alert->addMessage('success', 'USER.CREATED'); + return $user; }); + + return $user; } /** diff --git a/packages/sprinkle-admin/app/src/Controller/User/UserDeleteAction.php b/packages/sprinkle-admin/app/src/Controller/User/UserDeleteAction.php index c10293671..f9266628b 100644 --- a/packages/sprinkle-admin/app/src/Controller/User/UserDeleteAction.php +++ b/packages/sprinkle-admin/app/src/Controller/User/UserDeleteAction.php @@ -15,8 +15,8 @@ use Illuminate\Database\Connection; use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; -use UserFrosting\Alert\AlertStream; use UserFrosting\Config\Config; +use UserFrosting\I18n\Translator; use UserFrosting\Sprinkle\Account\Authenticate\Authenticator; use UserFrosting\Sprinkle\Account\Database\Models\Interfaces\UserInterface; use UserFrosting\Sprinkle\Account\Exceptions\AccountException; @@ -47,7 +47,7 @@ class UserDeleteAction * Inject dependencies. */ public function __construct( - protected AlertStream $alert, + protected Translator $translator, protected Authenticator $authenticator, protected Config $config, protected Connection $db, @@ -65,7 +65,10 @@ public function __construct( public function __invoke(UserInterface $user, Response $response): Response { $this->handle($user); - $payload = json_encode([], JSON_THROW_ON_ERROR); + $payload = json_encode([ + 'success' => true, + 'message' => $this->translator->translate('DELETION_SUCCESSFUL', $user->toArray()), + ], JSON_THROW_ON_ERROR); $response->getBody()->write($payload); return $response->withHeader('Content-Type', 'application/json'); @@ -107,10 +110,6 @@ protected function handle(UserInterface $user): void 'user_id' => $currentUser->id, ]); }); - - $this->alert->addMessage('success', 'DELETION_SUCCESSFUL', [ - 'user_name' => $username, - ]); } /** diff --git a/packages/sprinkle-admin/app/src/Controller/User/UserEditAction.php b/packages/sprinkle-admin/app/src/Controller/User/UserEditAction.php index d01109ffa..4e4953a0d 100644 --- a/packages/sprinkle-admin/app/src/Controller/User/UserEditAction.php +++ b/packages/sprinkle-admin/app/src/Controller/User/UserEditAction.php @@ -15,12 +15,12 @@ use Illuminate\Database\Connection; use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; -use UserFrosting\Alert\AlertStream; use UserFrosting\Config\Config; use UserFrosting\Fortress\RequestSchema; use UserFrosting\Fortress\RequestSchema\RequestSchemaInterface; use UserFrosting\Fortress\Transformer\RequestDataTransformer; use UserFrosting\Fortress\Validator\ServerSideValidator; +use UserFrosting\I18n\Translator; use UserFrosting\Sprinkle\Account\Authenticate\Authenticator; use UserFrosting\Sprinkle\Account\Database\Models\Interfaces\UserInterface; use UserFrosting\Sprinkle\Account\Exceptions\EmailNotUniqueException; @@ -48,7 +48,7 @@ class UserEditAction * Inject dependencies. */ public function __construct( - protected AlertStream $alert, + protected Translator $translator, protected Authenticator $authenticator, protected Config $config, protected Connection $db, @@ -69,8 +69,12 @@ public function __construct( */ public function __invoke(UserInterface $user, Request $request, Response $response): Response { - $this->handle($user, $request); - $payload = json_encode([], JSON_THROW_ON_ERROR); + $user = $this->handle($user, $request)->toArray(); + $payload = json_encode([ + 'success' => true, + 'message' => $this->translator->translate('DETAILS_UPDATED', $user), + 'user' => $user, + ], JSON_THROW_ON_ERROR); $response->getBody()->write($payload); return $response->withHeader('Content-Type', 'application/json'); @@ -81,8 +85,10 @@ public function __invoke(UserInterface $user, Request $request, Response $respon * * @param UserInterface $user * @param Request $request + * + * @return UserInterface */ - protected function handle(UserInterface $user, Request $request): void + protected function handle(UserInterface $user, Request $request): UserInterface { // Get PUT parameters $params = (array) $request->getParsedBody(); @@ -146,7 +152,7 @@ protected function handle(UserInterface $user, Request $request): void } // Begin transaction - DB will be rolled back if an exception occurs - $this->db->transaction(function () use ($data, $user, $currentUser) { + $newUser = $this->db->transaction(function () use ($data, $user, $currentUser) { // Update the user and generate success messages foreach ($data as $name => $value) { $user->setAttribute($name, $value); @@ -159,11 +165,11 @@ protected function handle(UserInterface $user, Request $request): void 'type' => 'account_update_info', 'user_id' => $user->id, ]); + + return $user; }); - $this->alert->addMessage('success', 'DETAILS_UPDATED', [ - 'user_name' => $user->user_name, - ]); + return $newUser; } /** diff --git a/packages/sprinkle-admin/app/tests/Controller/User/UserCreateActionTest.php b/packages/sprinkle-admin/app/tests/Controller/User/UserCreateActionTest.php index 0b730ac7d..caca4f4c4 100644 --- a/packages/sprinkle-admin/app/tests/Controller/User/UserCreateActionTest.php +++ b/packages/sprinkle-admin/app/tests/Controller/User/UserCreateActionTest.php @@ -14,7 +14,6 @@ use Mockery; use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration; -use UserFrosting\Alert\AlertStream; use UserFrosting\Config\Config; use UserFrosting\Sprinkle\Account\Database\Models\Group; use UserFrosting\Sprinkle\Account\Database\Models\User; @@ -99,19 +98,20 @@ public function testPost(): void // Assert response status & body $this->assertResponseStatus(200, $response); - $this->assertJsonResponse([], $response); + $this->assertJsonStructure([ + 'success', + 'message', + 'user', + ], $response); + $this->assertJsonResponse(true, $response, 'success'); + $this->assertJsonResponse('User foo has been successfully created', $response, 'message'); + $this->assertJsonResponse('Foo', $response, 'user.first_name'); // Make sure the user is added to the db by querying it /** @var User */ $user = User::where('email', 'foo@bar.com')->first(); $this->assertSame('foo', $user['user_name']); $this->assertSame('en_US', $user['locale']); - - // Test message - /** @var AlertStream */ - $ms = $this->ci->get(AlertStream::class); - $messages = $ms->getAndClearMessages(); - $this->assertSame('success', array_reverse($messages)[0]['type']); } /** @@ -154,19 +154,20 @@ public function testPostWithPassword(): void // Assert response status & body $this->assertResponseStatus(200, $response); - $this->assertJsonResponse([], $response); + $this->assertJsonStructure([ + 'success', + 'message', + 'user', + ], $response); + $this->assertJsonResponse(true, $response, 'success'); + $this->assertJsonResponse('User foo has been successfully created', $response, 'message'); + $this->assertJsonResponse('Foo', $response, 'user.first_name'); // Make sure the user is added to the db by querying it /** @var User */ $user = User::where('email', 'foo@bar.com')->first(); $this->assertSame('foo', $user['user_name']); $this->assertSame('en_US', $user['locale']); - - // Test message - /** @var AlertStream */ - $ms = $this->ci->get(AlertStream::class); - $messages = $ms->getAndClearMessages(); - $this->assertSame('success', array_reverse($messages)[0]['type']); } /** @@ -281,19 +282,18 @@ public function testPostForGroup(): void // Assert response status & body $this->assertResponseStatus(200, $response); - $this->assertJsonResponse([], $response); + $this->assertJsonStructure([ + 'success', + 'message', + 'user', + ], $response); + $this->assertJsonResponse($group->id, $response, 'user.group_id'); // Make sure the user is added to the db by querying it /** @var User */ $user = User::where('email', 'foo@bar.com')->first(); $this->assertSame($group->id, $user->group?->id); $this->assertSame('en_US', $user['locale']); // Locale will be default :) - - // Test message - /** @var AlertStream */ - $ms = $this->ci->get(AlertStream::class); - $messages = $ms->getAndClearMessages(); - $this->assertSame('success', array_reverse($messages)[0]['type']); } /** @@ -340,19 +340,13 @@ public function testPostForGroupIsSetAs(): void // Assert response status & body $this->assertResponseStatus(200, $response); - $this->assertJsonResponse([], $response); + $this->assertJsonResponse(true, $response, 'success'); // Make sure the user is added to the db by querying it /** @var User */ $user = User::where('email', 'foo@bar.com')->first(); $this->assertSame($group->id, $user->group?->id); $this->assertSame('en_US', $user['locale']); // Locale will be default :) - - // Test message - /** @var AlertStream */ - $ms = $this->ci->get(AlertStream::class); - $messages = $ms->getAndClearMessages(); - $this->assertSame('success', array_reverse($messages)[0]['type']); } public function testPostForNoGroup(): void @@ -390,20 +384,14 @@ public function testPostForNoGroup(): void $response = $this->handleRequest($request); // Assert response status & body - $this->assertJsonResponse([], $response); $this->assertResponseStatus(200, $response); + $this->assertJsonResponse(true, $response, 'success'); // Make sure the user is added to the db by querying it /** @var User */ $user = User::where('email', 'foo@bar.com')->first(); $this->assertSame('foo', $user['user_name']); $this->assertSame('en_US', $user['locale']); - - // Test message - /** @var AlertStream */ - $ms = $this->ci->get(AlertStream::class); - $messages = $ms->getAndClearMessages(); - $this->assertSame('success', array_reverse($messages)[0]['type']); } /** @@ -476,11 +464,5 @@ public function testPostForInvalidLocale(): void 'status' => 400, ], $response); $this->assertResponseStatus(400, $response); - - // Test message - /** @var AlertStream */ - $ms = $this->ci->get(AlertStream::class); - $messages = $ms->getAndClearMessages(); - $this->assertSame('danger', array_reverse($messages)[0]['type']); } } diff --git a/packages/sprinkle-admin/app/tests/Controller/User/UserDeleteActionTest.php b/packages/sprinkle-admin/app/tests/Controller/User/UserDeleteActionTest.php index 921940416..e37ab2c5d 100644 --- a/packages/sprinkle-admin/app/tests/Controller/User/UserDeleteActionTest.php +++ b/packages/sprinkle-admin/app/tests/Controller/User/UserDeleteActionTest.php @@ -13,7 +13,6 @@ namespace UserFrosting\Sprinkle\Admin\Tests\Controller\User; use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration; -use UserFrosting\Alert\AlertStream; use UserFrosting\Sprinkle\Account\Database\Models\User; use UserFrosting\Sprinkle\Account\Testing\WithTestUser; use UserFrosting\Sprinkle\Admin\Tests\AdminTestCase; @@ -121,17 +120,14 @@ public function testPost(): void // Assert response status & body $this->assertResponseStatus(200, $response); - $this->assertJsonResponse([], $response); + $this->assertJsonResponse([ + 'success' => true, + 'message' => 'User ' . $userToDelete->user_name . ' has been successfully deleted.', + ], $response); // Make sure the user is deleted from the db by querying it $user = User::where('email', $userToDelete->email)->first(); $this->assertNull($user); - - // Test message - /** @var AlertStream */ - $ms = $this->ci->get(AlertStream::class); - $messages = $ms->getAndClearMessages(); - $this->assertSame('success', array_reverse($messages)[0]['type']); } public function testPostForMasterUser(): void diff --git a/packages/sprinkle-admin/app/tests/Controller/User/UserEditActionTest.php b/packages/sprinkle-admin/app/tests/Controller/User/UserEditActionTest.php index f7b827ae3..748babb51 100644 --- a/packages/sprinkle-admin/app/tests/Controller/User/UserEditActionTest.php +++ b/packages/sprinkle-admin/app/tests/Controller/User/UserEditActionTest.php @@ -113,7 +113,14 @@ public function testPage(): void // Assert response status & body $this->assertResponseStatus(200, $response); - $this->assertJsonResponse([], $response); + $this->assertJsonStructure([ + 'success', + 'message', + 'user', + ], $response); + $this->assertJsonResponse(true, $response, 'success'); + $this->assertJsonResponse('Account details updated for user ' . $userToEdit->user_name . '', $response, 'message'); // N.B.: The username CANNOT be changed + $this->assertJsonResponse('Foo', $response, 'user.first_name'); // Test that the user was updated /** @var User */ @@ -121,12 +128,6 @@ public function testPage(): void $this->assertNotSame('foo', $editedUser->user_name); // Username not allowed by schema $this->assertSame('foo@bar.com', $editedUser->email); $this->assertNull($editedUser->group_id); - - // Test message - /** @var AlertStream */ - $ms = $this->ci->get(AlertStream::class); - $messages = $ms->getAndClearMessages(); - $this->assertSame('success', array_reverse($messages)[0]['type']); } public function testPageForEditMasterUser(): void diff --git a/packages/theme-pink-cupcake/src/components/Pages/Admin/Group/GroupForm.vue b/packages/theme-pink-cupcake/src/components/Pages/Admin/Group/GroupForm.vue index e88b3b755..10a3891c1 100644 --- a/packages/theme-pink-cupcake/src/components/Pages/Admin/Group/GroupForm.vue +++ b/packages/theme-pink-cupcake/src/components/Pages/Admin/Group/GroupForm.vue @@ -1,13 +1,5 @@ + + diff --git a/packages/theme-pink-cupcake/src/components/Pages/Admin/User/UserDeleteModal.vue b/packages/theme-pink-cupcake/src/components/Pages/Admin/User/UserDeleteModal.vue new file mode 100644 index 000000000..7b4b1c9eb --- /dev/null +++ b/packages/theme-pink-cupcake/src/components/Pages/Admin/User/UserDeleteModal.vue @@ -0,0 +1,60 @@ + + + diff --git a/packages/theme-pink-cupcake/src/components/Pages/Admin/User/UserEditModal.vue b/packages/theme-pink-cupcake/src/components/Pages/Admin/User/UserEditModal.vue new file mode 100644 index 000000000..276190fe3 --- /dev/null +++ b/packages/theme-pink-cupcake/src/components/Pages/Admin/User/UserEditModal.vue @@ -0,0 +1,103 @@ + + + diff --git a/packages/theme-pink-cupcake/src/components/Pages/Admin/User/UserForm.vue b/packages/theme-pink-cupcake/src/components/Pages/Admin/User/UserForm.vue new file mode 100644 index 000000000..9facb0f31 --- /dev/null +++ b/packages/theme-pink-cupcake/src/components/Pages/Admin/User/UserForm.vue @@ -0,0 +1,157 @@ + + + diff --git a/packages/theme-pink-cupcake/src/components/Pages/Admin/User/UserInfo.vue b/packages/theme-pink-cupcake/src/components/Pages/Admin/User/UserInfo.vue index 6ec8ac9ce..e2dc33599 100644 --- a/packages/theme-pink-cupcake/src/components/Pages/Admin/User/UserInfo.vue +++ b/packages/theme-pink-cupcake/src/components/Pages/Admin/User/UserInfo.vue @@ -1,12 +1,18 @@ diff --git a/packages/theme-pink-cupcake/src/views/Admin/UserPage.vue b/packages/theme-pink-cupcake/src/views/Admin/UserPage.vue index 83c31e2c4..4832dd43e 100644 --- a/packages/theme-pink-cupcake/src/views/Admin/UserPage.vue +++ b/packages/theme-pink-cupcake/src/views/Admin/UserPage.vue @@ -7,7 +7,7 @@ import UserRoles from '../../components/Pages/Admin/User/UserRoles.vue' import UserPermissions from '../../components/Pages/Admin/User/UserPermissions.vue' const route = useRoute() -const { user, error } = useUserApi(route) +const { user, error, fetchApi } = useUserApi(route)