Kaynağa Gözat

Add a Clear cache feature - Closes #316

Bubka 1 yıl önce
ebeveyn
işleme
edd810cafd

+ 36 - 1
app/Http/Controllers/SystemController.php

@@ -7,6 +7,7 @@ use App\Notifications\TestEmailSettingNotification;
 use App\Services\ReleaseRadarService;
 use Illuminate\Http\Request;
 use Illuminate\Support\Carbon;
+use Illuminate\Support\Facades\Artisan;
 use Illuminate\Support\Facades\DB;
 use Illuminate\Support\Facades\Log;
 
@@ -62,7 +63,7 @@ class SystemController extends Controller
     }
 
     /**
-     * Send a test email.
+     * Send a test email
      *
      * @return \Illuminate\Http\JsonResponse
      */
@@ -76,4 +77,38 @@ class SystemController extends Controller
 
         return response()->json(['message' => 'Ok']);
     }
+
+    /**
+     * Clears all app caches and rebuild them
+     *
+     * @return \Illuminate\Http\JsonResponse
+     */
+    public function optimize(Request $request)
+    {
+        $configCode = Artisan::call('config:cache');
+        $routeCode  = Artisan::call('route:cache');
+        $eventCode  = Artisan::call('event:cache');
+        $viewCode   = Artisan::call('view:cache');
+
+        return response()->json([
+            'config-exit-code' => $configCode,
+            'route-exit-code'  => $routeCode,
+            'event-exit-code'  => $eventCode,
+            'view-exit-code'   => $viewCode,
+        ], 200);
+    }
+
+    /**
+     * Clears application cache
+     *
+     * @return \Illuminate\Http\JsonResponse
+     */
+    public function clear(Request $request)
+    {
+        $exitCode = Artisan::call('optimize:clear');
+
+        return response()->json(['exit-code' => $exitCode], 200);
+    }
+
+    
 }

+ 20 - 4
resources/js/services/systemService.js

@@ -8,7 +8,7 @@ export default {
      * @returns Promise
      */
     getSystemInfos(config = {}) {
-        return webClient.get('infos', { ...config })
+        return webClient.get('system/infos', { ...config })
     },
 
     /**
@@ -16,7 +16,7 @@ export default {
      * @returns Promise
      */
     getLastRelease(config = {}) {
-        return webClient.get('latestRelease', { ...config })
+        return webClient.get('system/latestRelease', { ...config })
     },
 
     /**
@@ -24,7 +24,23 @@ export default {
      * @returns Promise
      */
     sendTestEmail(config = {}) {
-        return webClient.post('testEmail', { ...config })
-    }
+        return webClient.post('system/test-email', { ...config })
+    },
+
+    /**
+     * 
+     * @returns Promise
+     */
+    clearCache(config = {}) {
+        return webClient.get('system/clear-cache', { ...config })
+    },
+
+    /**
+     * 
+     * @returns Promise
+     */
+    optimize(config = {}) {
+        return webClient.get('system/optimize', { ...config })
+    },
     
 }

+ 36 - 1
resources/js/views/admin/AppSetup.vue

@@ -17,6 +17,7 @@
     const infos = ref()
     const listInfos = ref(null)
     const isSendingTestEmail = ref(false)
+    const isClearingCache = ref(false)
     const fieldErrors = ref({
         restrictList: null,
         restrictRule: null,
@@ -91,6 +92,20 @@
         })
     }
 
+    /**
+     * clears app cache
+     */
+    function clearCache() {
+        isClearingCache.value = true;
+
+        systemService.clearCache().then(response => {
+            useNotifyStore().success({ type: 'is-success', text: trans('admin.cache_cleared') })
+        })
+        .finally(() => {
+            isClearingCache.value = false;
+        })
+    }
+
     onBeforeRouteLeave((to) => {
         if (! to.name.startsWith('admin.')) {
             notify.clear()
@@ -134,6 +149,7 @@
                     <!-- Check for update -->
                     <FormCheckbox v-model="_settings.checkForUpdate" @update:model-value="val => saveSetting('checkForUpdate', val)" fieldName="checkForUpdate" label="commons.check_for_update" help="commons.check_for_update_help" />
                     <VersionChecker />
+                    <!-- email config test -->
                     <div class="field">
                         <!-- <h5 class="title is-5">{{ $t('settings.security') }}</h5> -->
                         <label class="label"  v-html="$t('admin.forms.test_email.label')" />
@@ -149,7 +165,8 @@
                                 <span>{{ $t('commons.send') }}</span>
                             </button>   
                         </div>
-                    </div>                   
+                    </div>    
+
                     <h4 class="title is-4 pt-4 has-text-grey-light">{{ $t('settings.security') }}</h4>
                     <!-- protect db -->
                     <FormCheckbox v-model="_settings.useEncryption" @update:model-value="val => saveSetting('useEncryption', val)" fieldName="useEncryption" label="admin.forms.use_encryption.label" help="admin.forms.use_encryption.help" />
@@ -165,7 +182,25 @@
                     <!-- disable SSO registration -->
                     <FormCheckbox v-model="_settings.enableSso" @update:model-value="val => saveSetting('enableSso', val)" fieldName="enableSso" label="admin.forms.enable_sso.label" help="admin.forms.enable_sso.help" />
                 </form>
+
                 <h4 class="title is-4 pt-5 has-text-grey-light">{{ $t('commons.environment') }}</h4>
+                <!-- cache management -->
+                <div class="field">
+                    <!-- <h5 class="title is-5">{{ $t('settings.security') }}</h5> -->
+                    <label class="label"  v-html="$t('admin.forms.cache_management.label')" />
+                    <p class="help" v-html="$t('admin.forms.cache_management.help')" />
+                </div>
+                <div class="field mb-5 is-grouped">
+                    <p class="control">
+                        <button type="button" :class="isClearingCache ? 'is-loading' : ''" class="button is-link is-rounded is-small" @click="clearCache">
+                            {{ $t('commons.clear') }}
+                        </button>
+                    </p>
+                </div>
+                <!-- env vars -->
+                <div class="field">
+                    <label class="label"  v-html="$t('admin.variables')" />
+                </div>
                 <div v-if="infos" class="about-debug box is-family-monospace is-size-7">
                     <CopyButton id="btnCopyEnvVars" :token="listInfos?.innerText" />
                     <ul ref="listInfos" id="listInfos">

+ 7 - 0
resources/lang/en/admin.php

@@ -63,6 +63,9 @@ return [
     'user_role_updated' => 'User role updated',
     'pats_succesfully_revoked' => 'User\'s PATs successfully revoked',
     'security_devices_succesfully_revoked' => 'User\'s security devices successfully revoked',
+    'variables' => 'Variables',
+    'cache_cleared' => 'Cache cleared',
+    'cache_optimized' => 'Cache optimized',
     'check_now' => 'Check now',
     'view_on_github' => 'View on Github',
     'x_is_available' => ':version is available',
@@ -99,6 +102,10 @@ return [
             'label' => 'Email configuration test',
             'help' => 'Send a test email to control your instance\'s email configuration. It is important to have a working configuration, otherwise users will not be able to request a reset password.',
             'email_will_be_send_to_x' => 'The email will be send to <span class="is-family-code has-text-info">:email</span>',
+        ],
+        'cache_management' => [
+            'label' => 'Cache management',
+            'help' => 'Sometimes cache needs to be cleared, for instance after a change to environment variables or an update. You can do it from here.',
         ]
     ],
 

+ 1 - 0
resources/lang/en/commons.php

@@ -81,4 +81,5 @@ return [
     'information' => 'Information',
     'permissions' => 'Permissions',
     'send' => 'Send',
+    'optimize' => 'Optimize',
 ];

+ 9 - 8
routes/web.php

@@ -73,20 +73,21 @@ Route::group(['middleware' => ['behind-auth', 'rejectIfReverseProxy']], function
     Route::delete('webauthn/credentials/{credential}', [WebAuthnManageController::class, 'delete'])->name('webauthn.credentials.delete');
 });
 
-Route::get('refresh-csrf', function () {
-    return csrf_token();
-});
-
-
 /**
  * Routes protected by an authentication guard and restricted to administrators
  */
 Route::group(['middleware' => ['behind-auth', 'admin']], function () {   
-    Route::get('infos', [SystemController::class, 'infos'])->name('system.infos');
-    Route::post('testEmail', [SystemController::class, 'testEmail'])->name('system.testEmail');
+    Route::get('system/infos', [SystemController::class, 'infos'])->name('system.infos');
+    Route::post('system/test-email', [SystemController::class, 'testEmail'])->name('system.testEmail');
 });
 
-Route::get('latestRelease', [SystemController::class, 'latestRelease'])->name('system.latestRelease');
+Route::get('system/optimize', [SystemController::class, 'optimize'])->name('system.optimize');
+Route::get('system/clear-cache', [SystemController::class, 'clear'])->name('system.clear');
+Route::get('system/latestRelease', [SystemController::class, 'latestRelease'])->name('system.latestRelease');
+
+Route::get('refresh-csrf', function () {
+    return csrf_token();
+});
 
 /**
  * Route for the main landing view

+ 28 - 8
tests/Feature/Http/SystemControllerTest.php

@@ -37,7 +37,7 @@ class SystemControllerTest extends FeatureTestCase
      */
     public function test_infos_returns_unauthorized()
     {
-        $response = $this->json('GET', '/infos')
+        $response = $this->json('GET', '/system/infos')
             ->assertUnauthorized();
     }
 
@@ -47,7 +47,7 @@ class SystemControllerTest extends FeatureTestCase
     public function test_infos_returns_forbidden()
     {
         $response = $this->actingAs($this->user, 'api-guard')
-            ->json('GET', '/infos')
+            ->json('GET', '/system/infos')
             ->assertForbidden();
     }
 
@@ -57,7 +57,7 @@ class SystemControllerTest extends FeatureTestCase
     public function test_infos_returns_only_base_collection()
     {
         $response = $this->actingAs($this->admin, 'api-guard')
-            ->json('GET', '/infos')
+            ->json('GET', '/system/infos')
             ->assertOk()
             ->assertJsonStructure([
                 'common' => [
@@ -88,7 +88,7 @@ class SystemControllerTest extends FeatureTestCase
     public function test_infos_returns_proxy_collection_when_signed_in_behind_proxy()
     {
         $response = $this->actingAs($this->admin, 'reverse-proxy-guard')
-            ->json('GET', '/infos')
+            ->json('GET', '/system/infos')
             ->assertOk()
             ->assertJsonStructure([
                 'common' => [
@@ -109,7 +109,7 @@ class SystemControllerTest extends FeatureTestCase
             ->once()
             ->andReturn('new_release');
 
-        $response = $this->json('GET', '/latestRelease')
+        $response = $this->json('GET', '/system/latestRelease')
             ->assertOk()
             ->assertJson([
                 'newRelease' => 'new_release',
@@ -124,7 +124,7 @@ class SystemControllerTest extends FeatureTestCase
         Notification::fake();
 
         $response = $this->actingAs($this->admin, 'web-guard')
-            ->json('POST', '/testEmail', []);
+            ->json('POST', '/system/test-email', []);
 
         $response->assertStatus(200);
 
@@ -136,7 +136,7 @@ class SystemControllerTest extends FeatureTestCase
      */
     public function test_testEmail_returns_unauthorized()
     {
-        $response = $this->json('GET', '/infos')
+        $response = $this->json('GET', '/system/infos')
             ->assertUnauthorized();
     }
 
@@ -146,7 +146,27 @@ class SystemControllerTest extends FeatureTestCase
     public function test_testEmail_returns_forbidden()
     {
         $response = $this->actingAs($this->user, 'api-guard')
-            ->json('GET', '/infos')
+            ->json('GET', '/system/infos')
             ->assertForbidden();
     }
+
+    /**
+     * @test
+     */
+    public function test_clearCache_returns_success()
+    {
+        $response = $this->json('GET', '/system/clear-cache');
+
+        $response->assertStatus(200);
+    }
+
+    /**
+     * @test
+     */
+    public function test_optimize_returns_success()
+    {
+        $response = $this->json('GET', '/system/optimize');
+
+        $response->assertStatus(200);
+    }
 }