]> BookStack Code Mirror - bookstack/commitdiff
Added user setting system and added user-lang option
authorDan Brown <redacted>
Sun, 15 Jan 2017 16:27:24 +0000 (16:27 +0000)
committerDan Brown <redacted>
Sun, 15 Jan 2017 16:27:24 +0000 (16:27 +0000)
Supports #115

app/Http/Controllers/UserController.php
app/Http/Kernel.php
app/Http/Middleware/Localization.php [new file with mode: 0644]
app/Http/Middleware/RedirectIfAuthenticated.php
app/Providers/AppServiceProvider.php
app/Services/SettingService.php
app/helpers.php
readme.md
resources/lang/en/settings.php
resources/views/users/edit.blade.php
tests/Permissions/RolesTest.php

index b5184c40acace93088c439b0b2eb3383ef4e8a56..c98d5f87eab71ebbf4383b8f77efe43fe17774f0 100644 (file)
@@ -1,13 +1,8 @@
-<?php
+<?php namespace BookStack\Http\Controllers;
 
-namespace BookStack\Http\Controllers;
-
-use BookStack\Activity;
 use Exception;
 use Illuminate\Http\Request;
-
 use Illuminate\Http\Response;
-use BookStack\Http\Requests;
 use BookStack\Repos\UserRepo;
 use BookStack\Services\SocialAuthService;
 use BookStack\User;
@@ -152,7 +147,8 @@ class UserController extends Controller
             'name'             => 'min:2',
             'email'            => 'min:2|email|unique:users,email,' . $id,
             'password'         => 'min:5|required_with:password_confirm',
-            'password-confirm' => 'same:password|required_with:password'
+            'password-confirm' => 'same:password|required_with:password',
+            'setting'          => 'array'
         ]);
 
         $user = $this->user->findOrFail($id);
@@ -175,6 +171,13 @@ class UserController extends Controller
             $user->external_auth_id = $request->get('external_auth_id');
         }
 
+        // Save an user-specific settings
+        if ($request->has('setting')) {
+            foreach ($request->get('setting') as $key => $value) {
+                setting()->putUser($user, $key, $value);
+            }
+        }
+
         $user->save();
         session()->flash('success', trans('settings.users_edit_success'));
 
index f1d95f5c070da381114dad0f3c41a4b69495ec90..c55cc9ab8d47f11caa0ee7bacf9b1cee705b73bf 100644 (file)
@@ -1,6 +1,4 @@
-<?php
-
-namespace BookStack\Http;
+<?php namespace BookStack\Http;
 
 use Illuminate\Foundation\Http\Kernel as HttpKernel;
 
@@ -30,6 +28,7 @@ class Kernel extends HttpKernel
             \Illuminate\View\Middleware\ShareErrorsFromSession::class,
             \BookStack\Http\Middleware\VerifyCsrfToken::class,
             \Illuminate\Routing\Middleware\SubstituteBindings::class,
+            \BookStack\Http\Middleware\Localization::class
         ],
         'api' => [
             'throttle:60,1',
diff --git a/app/Http/Middleware/Localization.php b/app/Http/Middleware/Localization.php
new file mode 100644 (file)
index 0000000..3624e0e
--- /dev/null
@@ -0,0 +1,25 @@
+<?php
+
+namespace BookStack\Http\Middleware;
+
+use Carbon\Carbon;
+use Closure;
+
+class Localization
+{
+    /**
+     * Handle an incoming request.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @param  \Closure  $next
+     * @return mixed
+     */
+    public function handle($request, Closure $next)
+    {
+        $defaultLang = config('app.locale');
+        $locale = setting()->getUser(user(), 'language', $defaultLang);
+        app()->setLocale($locale);
+        Carbon::setLocale($locale);
+        return $next($request);
+    }
+}
index 2b3c64695735d44daf3c6f47f76d4aa59584f4c2..c27df7af4f5434bdbf7d208fbe98f82ddde78bfb 100644 (file)
@@ -1,6 +1,4 @@
-<?php
-
-namespace BookStack\Http\Middleware;
+<?php namespace BookStack\Http\Middleware;
 
 use Closure;
 use Illuminate\Contracts\Auth\Guard;
index 66f40569a7686e6b583e046a3fc7ed0c6bd6c0c9..40a1eef3d81d5ecfdbbf1eb27f41d0b17ceb19b6 100644 (file)
@@ -1,6 +1,5 @@
 <?php namespace BookStack\Providers;
 
-use Carbon\Carbon;
 use Illuminate\Support\ServiceProvider;
 use Validator;
 
@@ -18,8 +17,6 @@ class AppServiceProvider extends ServiceProvider
             $imageMimes = ['image/png', 'image/bmp', 'image/gif', 'image/jpeg', 'image/jpg', 'image/tiff', 'image/webp'];
             return in_array($value->getMimeType(), $imageMimes);
         });
-
-        Carbon::setLocale(config('app.locale'));
     }
 
     /**
index 1dc30f8a001e901500486add7266e0dad3ce0bdb..40094a513ed33deefb705b578b5903f2ae9174a8 100644 (file)
@@ -1,6 +1,7 @@
 <?php namespace BookStack\Services;
 
 use BookStack\Setting;
+use BookStack\User;
 use Illuminate\Contracts\Cache\Repository as Cache;
 
 /**
@@ -43,6 +44,18 @@ class SettingService
         return $this->formatValue($value, $default);
     }
 
+    /**
+     * Get a user-specific setting from the database or cache.
+     * @param User $user
+     * @param $key
+     * @param bool $default
+     * @return bool|string
+     */
+    public function getUser($user, $key, $default = false)
+    {
+        return $this->get($this->userKey($user->id, $key), $default);
+    }
+
     /**
      * Gets a setting value from the cache or database.
      * Looks at the system defaults if not cached or in database.
@@ -111,6 +124,16 @@ class SettingService
         return $setting !== null;
     }
 
+    /**
+     * Check if a user setting is in the database.
+     * @param $key
+     * @return bool
+     */
+    public function hasUser($key)
+    {
+        return $this->has($this->userKey($key));
+    }
+
     /**
      * Add a setting to the database.
      * @param $key
@@ -128,6 +151,28 @@ class SettingService
         return true;
     }
 
+    /**
+     * Put a user-specific setting into the database.
+     * @param User $user
+     * @param $key
+     * @param $value
+     * @return bool
+     */
+    public function putUser($user, $key, $value)
+    {
+        return $this->put($this->userKey($user->id, $key), $value);
+    }
+
+    /**
+     * Convert a setting key into a user-specific key.
+     * @param $key
+     * @return string
+     */
+    protected function userKey($userId, $key = '')
+    {
+        return 'user:' . $userId . ':' . $key;
+    }
+
     /**
      * Removes a setting from the database.
      * @param $key
@@ -143,6 +188,16 @@ class SettingService
         return true;
     }
 
+    /**
+     * Delete settings for a given user id.
+     * @param $userId
+     * @return mixed
+     */
+    public function deleteUserSettings($userId)
+    {
+        return $this->setting->where('setting_key', 'like', $this->userKey($userId) . '%')->delete();
+    }
+
     /**
      * Gets a setting model from the database for the given key.
      * @param $key
index b5be0fd11bae196ccd085eb8e127ea3f0045d466..6decb08e96517233086eb9fe2e76ad002ce892fa 100644 (file)
@@ -60,11 +60,12 @@ function userCan($permission, Ownable $ownable = null)
  * Helper to access system settings.
  * @param $key
  * @param bool $default
- * @return mixed
+ * @return bool|string|\BookStack\Services\SettingService
  */
-function setting($key, $default = false)
+function setting($key = null, $default = false)
 {
     $settingService = app(\BookStack\Services\SettingService::class);
+    if (is_null($key)) return $settingService;
     return $settingService->get($key, $default);
 }
 
index fa5c48fe08b97159cf4e4b527f2cd9f3ca4ce1ce..63d43e4b792f818b546e6e0ccc56408b8e5c128e 100644 (file)
--- a/readme.md
+++ b/readme.md
@@ -40,13 +40,19 @@ php artisan db:seed --class=DummyContentSeeder --database=mysql_testing
 
 Once done you can run `phpunit` in the application root directory to run all tests.
 
-## Website and Docs 
+## Translations
 
-The website and project docs are currently stored in the [BookStackApp/website](https://github.com/BookStackApp/website) repo. The docs are stored as markdown files in the `resources/docs` folder
+As part of BookStack v0.14 support for translations has been built in. All text strings can be found in the `resources/lang` folder where each language option has its own folder. To add a new language you should copy the `en` folder to an new folder (eg. `fr` for french) then go through and translate all text strings in those files, leaving the keys and file-names intact. If a language string is missing then the `en` translation will be used. To show the language option in the user preferences language drop-down you will need to add your language to the options found at the bottom of the `resources/lang/en/settings.php` file. A system-wide language can also be set in the `.env` file like so: `APP_LANG=en`.
+ Some strings have colon-prefixed variables in such as `:userName`. Leave these values as they are as they will be replaced at run-time.
+
+## Website, Docs & Blog 
+
+The website project docs & Blog can be found in the [BookStackApp/website](https://github.com/BookStackApp/website) repo.
 
 ## License
 
-BookStack is provided under the MIT License.
+The BookStack source is provided under the MIT License.
 
 ## Attribution
 
index e61df19d91172738d7ef1f3783c7bb847f2e1cf2..e1b544ef931f40c68e2aae5b41156babd72bd7b2 100644 (file)
@@ -101,12 +101,23 @@ return [
     'users_edit_success' => 'User successfully updated',
     'users_avatar' => 'User Avatar',
     'users_avatar_desc' => 'This image should be approx 256px square.',
+    'users_preferred_language' => 'Preferred Language',
     'users_social_accounts' => 'Social Accounts',
     'users_social_accounts_info' => 'Here you can connect your other accounts for quicker and easier login. Disconnecting an account here does not previously authorized access. Revoke access from your profile settings on the connected social account.',
     'users_social_connect' => 'Connect Account',
     'users_social_disconnect' => 'Disconnect Account',
     'users_social_connected' => ':socialAccount account was successfully attached to your profile.',
     'users_social_disconnected' => ':socialAccount account was successfully disconnected from your profile.',
+
+    // Since these labels are already localized this array does not need to be
+    // translated in the language-specific files.
+    // DELETE BELOW IF COPIED FROM EN
+    ///////////////////////////////////
+    'language_select' => [
+        'en' => 'English',
+        'de' => 'Deutsch'
+    ]
+    ///////////////////////////////////
 ];
 
 
index 4db00e31f932fb8157fa63d8c085b25ead1a2b24..c5d512725ba7ab82a952172f85aa791285afb0ab 100644 (file)
@@ -5,8 +5,6 @@
 
     @include('settings/navbar', ['selected' => 'users'])
 
-
-
     <div class="container small">
         <form action="{{ baseUrl("/settings/users/{$user->id}") }}" method="post">
             <div class="row">
                           'name' => 'image_id',
                           'imageClass' => 'avatar large'
                       ])
-
+                </div>
+                <div class="form-group">
+                    <label for="user-language">{{ trans('settings.users_preferred_language') }}</label>
+                    <select name="setting[language]" id="user-language">
+                        @foreach(trans('settings.language_select') as $lang => $label)
+                            <option @if(setting()->getUser($user, 'language') === $lang) selected @endif value="{{ $lang }}">{{ $label }}</option>
+                        @endforeach
+                    </select>
                 </div>
             </div>
         </div>
index 0f6a7a150492c0c4a5845b0f4ae87f39be91766d..7f1895b916d410839938f019a484c8871d460aec 100644 (file)
@@ -583,7 +583,6 @@ class RolesTest extends TestCase
     public function test_image_delete_own_permission()
     {
         $this->giveUserPermissions($this->user, ['image-update-all']);
-//        $admin = $this->getAdmin();
         $page = \BookStack\Page::first();
         $image = factory(\BookStack\Image::class)->create(['uploaded_to' => $page->id, 'created_by' => $this->user->id, 'updated_by' => $this->user->id]);