]> BookStack Code Mirror - bookstack/commitdiff
Added user ownership migrate to delete screen.
authorDan Brown <redacted>
Fri, 1 Jan 2021 18:31:01 +0000 (18:31 +0000)
committerDan Brown <redacted>
Fri, 1 Jan 2021 18:31:01 +0000 (18:31 +0000)
app/Auth/UserRepo.php
app/Entities/EntityProvider.php
app/Http/Controllers/UserController.php
resources/lang/en/settings.php
resources/views/components/user-select.blade.php
resources/views/users/delete.blade.php

index 6b7de325998a10e8dbd4a530a475d91d0c1f3458..6fb5dfa0fb48af6467a24c19bf360ca15a3d913e 100644 (file)
@@ -1,6 +1,7 @@
 <?php namespace BookStack\Auth;
 
 use Activity;
 <?php namespace BookStack\Auth;
 
 use Activity;
+use BookStack\Entities\EntityProvider;
 use BookStack\Entities\Models\Book;
 use BookStack\Entities\Models\Bookshelf;
 use BookStack\Entities\Models\Chapter;
 use BookStack\Entities\Models\Book;
 use BookStack\Entities\Models\Bookshelf;
 use BookStack\Entities\Models\Chapter;
@@ -169,7 +170,7 @@ class UserRepo
      * Remove the given user from storage, Delete all related content.
      * @throws Exception
      */
      * Remove the given user from storage, Delete all related content.
      * @throws Exception
      */
-    public function destroy(User $user)
+    public function destroy(User $user, ?int $newOwnerId = null)
     {
         $user->socialAccounts()->delete();
         $user->apiTokens()->delete();
     {
         $user->socialAccounts()->delete();
         $user->apiTokens()->delete();
@@ -183,6 +184,25 @@ class UserRepo
         foreach ($profileImages as $image) {
             Images::destroy($image);
         }
         foreach ($profileImages as $image) {
             Images::destroy($image);
         }
+
+        if (!empty($newOwnerId)) {
+            $newOwner = User::query()->find($newOwnerId);
+            if (!is_null($newOwner)) {
+                $this->migrateOwnership($user, $newOwner);
+            }
+        }
+    }
+
+    /**
+     * Migrate ownership of items in the system from one user to another.
+     */
+    protected function migrateOwnership(User $fromUser, User $toUser)
+    {
+        $entities = (new EntityProvider)->all();
+        foreach ($entities as $instance) {
+            $instance->newQuery()->where('owned_by', '=', $fromUser->id)
+                ->update(['owned_by' => $toUser->id]);
+        }
     }
 
     /**
     }
 
     /**
index ef1935a0f0fa9891aec03f7b7010317feedf8b0c..c77a57d61a5710edf652082839492a394c21a341 100644 (file)
@@ -55,7 +55,7 @@ class EntityProvider
     /**
      * Fetch all core entity types as an associated array
      * with their basic names as the keys.
     /**
      * Fetch all core entity types as an associated array
      * with their basic names as the keys.
-     * @return [string => Entity]
+     * @return array<Entity>
      */
     public function all(): array
     {
      */
     public function all(): array
     {
index 8d688ed8479309550f5dc83e188a27fdfc639f0d..852d507c1dcea5ed16b53ea7a9d306107a74c0ff 100644 (file)
@@ -217,12 +217,13 @@ class UserController extends Controller
      * Remove the specified user from storage.
      * @throws \Exception
      */
      * Remove the specified user from storage.
      * @throws \Exception
      */
-    public function destroy(int $id)
+    public function destroy(Request $request, int $id)
     {
         $this->preventAccessInDemoMode();
         $this->checkPermissionOrCurrentUser('users-manage', $id);
 
         $user = $this->userRepo->getById($id);
     {
         $this->preventAccessInDemoMode();
         $this->checkPermissionOrCurrentUser('users-manage', $id);
 
         $user = $this->userRepo->getById($id);
+        $newOwnerId = $request->get('new_owner_id', null);
 
         if ($this->userRepo->isOnlyAdmin($user)) {
             $this->showErrorNotification(trans('errors.users_cannot_delete_only_admin'));
 
         if ($this->userRepo->isOnlyAdmin($user)) {
             $this->showErrorNotification(trans('errors.users_cannot_delete_only_admin'));
@@ -234,7 +235,7 @@ class UserController extends Controller
             return redirect($user->getEditUrl());
         }
 
             return redirect($user->getEditUrl());
         }
 
-        $this->userRepo->destroy($user);
+        $this->userRepo->destroy($user, $newOwnerId);
         $this->showSuccessNotification(trans('settings.users_delete_success'));
         $this->logActivity(ActivityType::USER_DELETE, $user);
 
         $this->showSuccessNotification(trans('settings.users_delete_success'));
         $this->logActivity(ActivityType::USER_DELETE, $user);
 
index 3e043e3c6646232cce34329658cfa87213006ea2..fe7ebc61295c29d03a2e900d009bfcd4e9494e31 100755 (executable)
@@ -175,7 +175,10 @@ return [
     'users_delete_named' => 'Delete user :userName',
     'users_delete_warning' => 'This will fully delete this user with the name \':userName\' from the system.',
     'users_delete_confirm' => 'Are you sure you want to delete this user?',
     'users_delete_named' => 'Delete user :userName',
     'users_delete_warning' => 'This will fully delete this user with the name \':userName\' from the system.',
     'users_delete_confirm' => 'Are you sure you want to delete this user?',
-    'users_delete_success' => 'Users successfully removed',
+    'users_migrate_ownership' => 'Migrate Ownership',
+    'users_migrate_ownership_desc' => 'Select a user here if you want another user to become the owner of all items currently owned by this user.',
+    'users_none_selected' => 'No user selected',
+    'users_delete_success' => 'User successfully removed',
     'users_edit' => 'Edit User',
     'users_edit_profile' => 'Edit Profile',
     'users_edit_success' => 'User successfully updated',
     'users_edit' => 'Edit User',
     'users_edit_profile' => 'Edit Profile',
     'users_edit_success' => 'User successfully updated',
index c6a30f53dfe81616f17c5b5d7ed205a017a86e4c..2a07f0bde5044e03aa00e7eaaff724b2deffce63 100644 (file)
@@ -1,13 +1,17 @@
 <div class="dropdown-search custom-select-input" components="dropdown dropdown-search user-select"
      option:dropdown-search:url="/search/users/select"
 >
 <div class="dropdown-search custom-select-input" components="dropdown dropdown-search user-select"
      option:dropdown-search:url="/search/users/select"
 >
-    <input refs="user-select@input" type="hidden" name="{{ $name }}" value="{{ $user->id }}">
+    <input refs="user-select@input" type="hidden" name="{{ $name }}" value="{{ $user->id ?? '' }}">
     <div refs="dropdown@toggle"
          class="dropdown-search-toggle flex-container-row items-center"
          aria-haspopup="true" aria-expanded="false" tabindex="0">
         <div refs="user-select@user-info" class="flex-container-row items-center px-s">
     <div refs="dropdown@toggle"
          class="dropdown-search-toggle flex-container-row items-center"
          aria-haspopup="true" aria-expanded="false" tabindex="0">
         <div refs="user-select@user-info" class="flex-container-row items-center px-s">
-            <img class="avatar mr-m" src="{{ $user->getAvatar(30) }}" alt="{{ $user->name }}">
-            <span>{{ $user->name }}</span>
+            @if($user)
+                <img class="avatar mr-m" src="{{ $user->getAvatar(30) }}" alt="{{ $user->name }}">
+                <span>{{ $user->name }}</span>
+            @else
+                <span>{{ trans('settings.users_none_selected') }}</span>
+            @endif
         </div>
         <span style="font-size: 1.5rem; margin-left: auto;">
             @icon('caret-down')
         </div>
         <span style="font-size: 1.5rem; margin-left: auto;">
             @icon('caret-down')
index d3349c2f3fc29b93e6b10319e95d0cefc97df7e5..aba6f5cc1f6de6cee8da0beec9b64a51fc563eab 100644 (file)
 
             <p>{{ trans('settings.users_delete_warning', ['userName' => $user->name]) }}</p>
 
 
             <p>{{ trans('settings.users_delete_warning', ['userName' => $user->name]) }}</p>
 
+            <hr class="my-l">
+
+            <div class="grid half gap-xl v-center">
+                <div>
+                    <label class="setting-list-label">{{ trans('settings.users_migrate_ownership') }}</label>
+                    <p class="small">{{ trans('settings.users_migrate_ownership_desc') }}</p>
+                </div>
+                <div>
+                    @include('components.user-select', ['name' => 'new_owner_id', 'user' => null])
+                </div>
+            </div>
+
+            <hr class="my-l">
+
             <div class="grid half">
                 <p class="text-neg"><strong>{{ trans('settings.users_delete_confirm') }}</strong></p>
                 <div>
             <div class="grid half">
                 <p class="text-neg"><strong>{{ trans('settings.users_delete_confirm') }}</strong></p>
                 <div>