]> BookStack Code Mirror - bookstack/commitdiff
Started work on API token controls
authorDan Brown <redacted>
Sun, 29 Dec 2019 13:02:26 +0000 (13:02 +0000)
committerDan Brown <redacted>
Sun, 29 Dec 2019 13:02:26 +0000 (13:02 +0000)
- Added access-api permission.
- Started user profile UI work.
- Created database table and model for tokens.
- Fixed incorrect templates down migration :(

app/Api/ApiToken.php [new file with mode: 0644]
app/Auth/User.php
app/Http/Controllers/UserApiTokenController.php [new file with mode: 0644]
app/Http/Controllers/UserController.php
database/migrations/2019_07_07_112515_add_template_support.php
database/migrations/2019_12_29_120917_add_api_auth.php [new file with mode: 0644]
resources/lang/en/settings.php
resources/views/settings/roles/form.blade.php
resources/views/users/edit.blade.php
routes/web.php

diff --git a/app/Api/ApiToken.php b/app/Api/ApiToken.php
new file mode 100644 (file)
index 0000000..838e70a
--- /dev/null
@@ -0,0 +1,9 @@
+<?php namespace BookStack\Api;
+
+use Illuminate\Database\Eloquent\Model;
+
+class ApiToken extends Model
+{
+    protected $fillable = ['name', 'expires_at'];
+
+}
index bce418a7421fb40ddeb34b0e0dacd192d7048e2a..69f424cac5ec492bb408547735c7856535c274bf 100644 (file)
@@ -1,5 +1,6 @@
 <?php namespace BookStack\Auth;
 
+use BookStack\Api\ApiToken;
 use BookStack\Model;
 use BookStack\Notifications\ResetPassword;
 use BookStack\Uploads\Image;
@@ -9,6 +10,7 @@ use Illuminate\Auth\Passwords\CanResetPassword;
 use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
 use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
 use Illuminate\Database\Eloquent\Relations\BelongsToMany;
+use Illuminate\Database\Eloquent\Relations\HasMany;
 use Illuminate\Notifications\Notifiable;
 
 /**
@@ -217,20 +219,27 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
         return $this->belongsTo(Image::class, 'image_id');
     }
 
+    /**
+     * Get the API tokens assigned to this user.
+     */
+    public function apiTokens(): HasMany
+    {
+        return $this->hasMany(ApiToken::class);
+    }
+
     /**
      * Get the url for editing this user.
-     * @return string
      */
-    public function getEditUrl()
+    public function getEditUrl(string $path = ''): string
     {
-        return url('/settings/users/' . $this->id);
+        $uri = '/settings/users/' . $this->id . '/' . trim($path, '/');
+        return url(rtrim($uri, '/'));
     }
 
     /**
      * Get the url that links to this user's profile.
-     * @return mixed
      */
-    public function getProfileUrl()
+    public function getProfileUrl(): string
     {
         return url('/user/' . $this->id);
     }
diff --git a/app/Http/Controllers/UserApiTokenController.php b/app/Http/Controllers/UserApiTokenController.php
new file mode 100644 (file)
index 0000000..3853520
--- /dev/null
@@ -0,0 +1,20 @@
+<?php namespace BookStack\Http\Controllers;
+
+use Illuminate\Http\Request;
+
+class UserApiTokenController extends Controller
+{
+
+    /**
+     * Show the form to create a new API token.
+     */
+    public function create(int $userId)
+    {
+        $this->checkPermission('access-api');
+
+        // TODO - Form
+        return 'test';
+    }
+
+
+}
index b55398d2f6f644cb35cec75383df75be9dd40b71..207466f388fa5e8faaecdca2838f7186d7ca7cf4 100644 (file)
@@ -116,22 +116,24 @@ class UserController extends Controller
 
     /**
      * Show the form for editing the specified user.
-     * @param  int              $id
-     * @param \BookStack\Auth\Access\SocialAuthService $socialAuthService
-     * @return Response
      */
-    public function edit($id, SocialAuthService $socialAuthService)
+    public function edit(int $id, SocialAuthService $socialAuthService)
     {
         $this->checkPermissionOrCurrentUser('users-manage', $id);
 
-        $user = $this->user->findOrFail($id);
+        $user = $this->user->newQuery()->with(['apiTokens'])->findOrFail($id);
 
         $authMethod = ($user->system_name) ? 'system' : config('auth.method');
 
         $activeSocialDrivers = $socialAuthService->getActiveDrivers();
         $this->setPageTitle(trans('settings.user_profile'));
         $roles = $this->userRepo->getAllRoles();
-        return view('users.edit', ['user' => $user, 'activeSocialDrivers' => $activeSocialDrivers, 'authMethod' => $authMethod, 'roles' => $roles]);
+        return view('users.edit', [
+            'user' => $user,
+            'activeSocialDrivers' => $activeSocialDrivers,
+            'authMethod' => $authMethod,
+            'roles' => $roles
+        ]);
     }
 
     /**
index a545081986a71e1baca7c2c512b4dd006efd4688..3fcc6822751ea926985fbe9573a5a688ba71b7f0 100644 (file)
@@ -46,9 +46,9 @@ class AddTemplateSupport extends Migration
 
         // Remove templates-manage permission
         $templatesManagePermission = DB::table('role_permissions')
-            ->where('name', '=', 'templates_manage')->first();
+            ->where('name', '=', 'templates-manage')->first();
 
         DB::table('permission_role')->where('permission_id', '=', $templatesManagePermission->id)->delete();
-        DB::table('role_permissions')->where('name', '=', 'templates_manage')->delete();
+        DB::table('role_permissions')->where('name', '=', 'templates-manage')->delete();
     }
 }
diff --git a/database/migrations/2019_12_29_120917_add_api_auth.php b/database/migrations/2019_12_29_120917_add_api_auth.php
new file mode 100644 (file)
index 0000000..e80fe3a
--- /dev/null
@@ -0,0 +1,59 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Carbon;
+use Illuminate\Support\Facades\Schema;
+
+class AddApiAuth extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+
+        // Add API tokens table
+        Schema::create('api_tokens', function(Blueprint $table) {
+            $table->increments('id');
+            $table->string('client_id')->index();
+            $table->string('client_secret');
+            $table->integer('user_id')->unsigned()->index();
+            $table->timestamp('expires_at')->index();
+            $table->nullableTimestamps();
+        });
+
+        // Add access-api permission
+        $adminRoleId = DB::table('roles')->where('system_name', '=', 'admin')->first()->id;
+        $permissionId = DB::table('role_permissions')->insertGetId([
+            'name' => 'access-api',
+            'display_name' => 'Access system API',
+            'created_at' => Carbon::now()->toDateTimeString(),
+            'updated_at' => Carbon::now()->toDateTimeString()
+        ]);
+        DB::table('permission_role')->insert([
+            'role_id' => $adminRoleId,
+            'permission_id' => $permissionId
+        ]);
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        // Remove API tokens table
+        Schema::dropIfExists('api_tokens');
+
+        // Remove access-api permission
+        $apiAccessPermission = DB::table('role_permissions')
+            ->where('name', '=', 'access-api')->first();
+
+        DB::table('permission_role')->where('permission_id', '=', $apiAccessPermission->id)->delete();
+        DB::table('role_permissions')->where('name', '=', 'access-api')->delete();
+    }
+}
index 6be7cc9cb18a0f0ab30c373f84dd1b0d5a3a1004..bb750a7804d5bdb6973e89d48c3098259ef03902 100755 (executable)
@@ -103,6 +103,7 @@ return [
     'role_manage_entity_permissions' => 'Manage all book, chapter & page permissions',
     'role_manage_own_entity_permissions' => 'Manage permissions on own book, chapter & pages',
     'role_manage_page_templates' => 'Manage page templates',
+    'role_access_api' => 'Access system API',
     'role_manage_settings' => 'Manage app settings',
     'role_asset' => 'Asset Permissions',
     'role_asset_desc' => 'These permissions control default access to the assets within the system. Permissions on Books, Chapters and Pages will override these permissions.',
@@ -151,6 +152,11 @@ return [
     '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.',
+    'users_api_tokens' => 'API Tokens',
+    'users_api_tokens_none' => 'No API tokens have been created for this user',
+    'users_api_tokens_create' => 'Create Token',
+
+    // API Tokens
 
     //! If editing translations files directly please ignore this in all
     //! languages apart from en. Content will be auto-copied from en.
index 4617b1f520d26bf65fe69b5b15311d06059d192d..1fbc80b1fd1be0f0cbcfacb68869ebfc3bfeadac 100644 (file)
                 <a href="#" permissions-table-toggle-all class="text-small text-primary">{{ trans('common.toggle_all') }}</a>
             </div>
             <div class="toggle-switch-list">
+                <div>@include('settings.roles.checkbox', ['permission' => 'settings-manage', 'label' => trans('settings.role_manage_settings')])</div>
                 <div>@include('settings.roles.checkbox', ['permission' => 'users-manage', 'label' => trans('settings.role_manage_users')])</div>
                 <div>@include('settings.roles.checkbox', ['permission' => 'user-roles-manage', 'label' => trans('settings.role_manage_roles')])</div>
                 <div>@include('settings.roles.checkbox', ['permission' => 'restrictions-manage-all', 'label' => trans('settings.role_manage_entity_permissions')])</div>
                 <div>@include('settings.roles.checkbox', ['permission' => 'restrictions-manage-own', 'label' => trans('settings.role_manage_own_entity_permissions')])</div>
                 <div>@include('settings.roles.checkbox', ['permission' => 'templates-manage', 'label' => trans('settings.role_manage_page_templates')])</div>
-                <div>@include('settings.roles.checkbox', ['permission' => 'settings-manage', 'label' => trans('settings.role_manage_settings')])</div>
+                <div>@include('settings.roles.checkbox', ['permission' => 'access-api', 'label' => trans('settings.role_access_api')])</div>
             </div>
         </div>
 
index ff1e7cbe5d51577e2cd807dc4842aee8b268f1c8..b3f73773b96755995f3738aaa59ecbafa7fd6fd0 100644 (file)
                 </div>
             </section>
         @endif
+
+        {{-- TODO - Review Control--}}
+        @if(($currentUser->id === $user->id && userCan('access-api')) || userCan('manage-users'))
+            <section class="card content-wrap auto-height">
+                <div class="grid half">
+                    <div><h2 class="list-heading">{{ trans('settings.users_api_tokens') }}</h2></div>
+                    <div class="text-right pt-xs">
+                        @if(userCan('access-api'))
+                            <a href="{{ $user->getEditUrl('/create-api-token') }}" class="button outline">{{ trans('settings.users_api_tokens_create') }}</a>
+                        @endif
+                    </div>
+                </div>
+                @if (count($user->apiTokens) > 0)
+
+                @else
+                    <p class="text-muted italic py-m">{{ trans('settings.users_api_tokens_none') }}</p>
+                @endif
+            </section>
+        @endif
     </div>
 
 @stop
index 839e5a256f7684590961377cad9d98928c974580..2a0e85dfe09ca1094a45a18008037c2fc8c6888d 100644 (file)
@@ -187,6 +187,9 @@ Route::group(['middleware' => 'auth'], function () {
         Route::put('/users/{id}', 'UserController@update');
         Route::delete('/users/{id}', 'UserController@destroy');
 
+        // User API Tokens
+        Route::get('/users/{userId}/create-api-token', 'UserApiTokenController@create');
+
         // Roles
         Route::get('/roles', 'PermissionController@listRoles');
         Route::get('/roles/new', 'PermissionController@createRole');