diff --git a/Modules/User/Assets/js/UserRoutes.js b/Modules/User/Assets/js/UserRoutes.js index 39d371cbd..24fe2d4ac 100644 --- a/Modules/User/Assets/js/UserRoutes.js +++ b/Modules/User/Assets/js/UserRoutes.js @@ -3,6 +3,7 @@ import RoleForm from './components/RoleForm.vue'; import UserTable from './components/UserTable.vue'; import UserForm from './components/UserForm.vue'; import UserProfile from './components/UserProfile.vue'; +import ApiKeys from './components/ApiKeys.vue'; const locales = window.AsgardCMS.locales; @@ -62,4 +63,9 @@ export default [ name: 'admin.user.users.account', component: UserProfile, }, + { + path: '/account/api-keys', + name: 'admin.user.users.account.api-keys', + component: ApiKeys, + }, ]; diff --git a/Modules/User/Assets/js/components/ApiKeys.vue b/Modules/User/Assets/js/components/ApiKeys.vue new file mode 100644 index 000000000..72573b791 --- /dev/null +++ b/Modules/User/Assets/js/components/ApiKeys.vue @@ -0,0 +1,100 @@ + + + diff --git a/Modules/User/Http/Controllers/Admin/Account/ApiKeysController.php b/Modules/User/Http/Controllers/Admin/Account/ApiKeysController.php index 5be5e6ebe..ec5dff8a7 100644 --- a/Modules/User/Http/Controllers/Admin/Account/ApiKeysController.php +++ b/Modules/User/Http/Controllers/Admin/Account/ApiKeysController.php @@ -28,11 +28,7 @@ public function __construct(Authentication $auth, UserTokenRepository $userToken public function index() { - $tokens = $this->userToken->allForUser($this->auth->id()); - - $this->assetPipeline->requireJs('clipboard.js'); - - return view('user::admin.account.api-keys.index', compact('tokens')); + return view('user::admin.account.api-keys.index'); } public function create() diff --git a/Modules/User/Http/Controllers/Api/ApiKeysController.php b/Modules/User/Http/Controllers/Api/ApiKeysController.php new file mode 100644 index 000000000..406ff40d0 --- /dev/null +++ b/Modules/User/Http/Controllers/Api/ApiKeysController.php @@ -0,0 +1,59 @@ +auth = $auth; + $this->userToken = $userToken; + } + + public function index() + { + $tokens = $this->userToken->allForUser($this->auth->id()); + + return ApiKeysTransformer::collection($tokens); + } + + public function create() + { + $userId = $this->auth->id(); + $this->userToken->generateFor($userId); + $tokens = $this->userToken->allForUser($userId); + + return response()->json([ + 'errors' => false, + 'message' => trans('user::users.token generated'), + 'data' => ApiKeysTransformer::collection($tokens), + ]); + } + + public function destroy(UserToken $userToken) + { + $this->userToken->destroy($userToken); + $tokens = $this->userToken->allForUser($this->auth->id()); + + return response()->json([ + 'errors' => false, + 'message' => trans('user::users.token deleted'), + 'data' => ApiKeysTransformer::collection($tokens), + ]); + } +} diff --git a/Modules/User/Http/apiRoutes.php b/Modules/User/Http/apiRoutes.php index 8845ff147..6ba9024fb 100644 --- a/Modules/User/Http/apiRoutes.php +++ b/Modules/User/Http/apiRoutes.php @@ -95,6 +95,26 @@ 'as' => 'api.account.profile.update', 'uses' => 'ProfileController@update', ]); + + $router->bind('userTokenId', function ($id) { + return app(\Modules\User\Repositories\UserTokenRepository::class)->find($id); + }); + + $router->get('api-keys', [ + 'as' => 'api.account.api.index', + 'uses' => 'ApiKeysController@index', + 'middleware' => 'can:account.api-keys.index', + ]); + $router->get('api-keys/create', [ + 'as' => 'api.account.api.create', + 'uses' => 'ApiKeysController@create', + 'middleware' => 'can:account.api-keys.create', + ]); + $router->delete('api-keys/{userTokenId}', [ + 'as' => 'api.account.api.destroy', + 'uses' => 'ApiKeysController@destroy', + 'middleware' => 'can:account.api-keys.destroy', + ]); }); $router->get('permissions', [ diff --git a/Modules/User/Resources/views/admin/account/api-keys/index.blade.php b/Modules/User/Resources/views/admin/account/api-keys/index.blade.php index 5acaeba24..f48998190 100644 --- a/Modules/User/Resources/views/admin/account/api-keys/index.blade.php +++ b/Modules/User/Resources/views/admin/account/api-keys/index.blade.php @@ -1,73 +1,7 @@ @extends('layouts.master') @section('content-header') -

- {{ trans('user::users.api-keys') }} -

- - @stop @section('content') -
-
- -
-
-

{{ trans('user::users.your api keys') }}

-
-
-
- isEmpty() === false): ?> -
    - -
  • - {!! Form::open(['route' => ['admin.account.api.destroy', $token->id], 'method' => 'delete', 'class' => '']) !!} -
    - - - - - - - - - -
    - {!! Form::close() !!} -
  • - -
- -

{{ trans('user::users.you have no api keys') }} {{ trans('user::users.generate one') }}

- -
-
-
-
- -
- - @include('core::partials.delete-modal') @stop - -@push('js-stack') - -@endpush diff --git a/Modules/User/Transformers/ApiKeysTransformer.php b/Modules/User/Transformers/ApiKeysTransformer.php new file mode 100644 index 000000000..7f005addf --- /dev/null +++ b/Modules/User/Transformers/ApiKeysTransformer.php @@ -0,0 +1,17 @@ + $this->id, + 'access_token' => $this->access_token, + 'created_at' => $this->created_at, + ]; + } +} diff --git a/public/js/app.js b/public/js/app.js index 823a9828e..494987feb 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -101875,6 +101875,13 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de // // // +// +// +// +// +// +// +// exports.default = { mixins: [_Slugify2.default, _ShortcutHelper2.default, _ActiveEditor2.default, _SingleFileSelector2.default], @@ -102610,6 +102617,47 @@ var render = function() { 1 ), _vm._v(" "), + _c( + "el-form-item", + { + class: { + "el-form-item is-error": _vm.form.errors.has( + locale + ".status" + ) + }, + attrs: { label: _vm.trans("page.status") } + }, + [ + _c( + "el-checkbox", + { + model: { + value: _vm.page[locale].status, + callback: function($$v) { + _vm.page[locale].status = $$v + }, + expression: "page[locale].status" + } + }, + [_vm._v(_vm._s(_vm.trans("page.status")))] + ), + _vm._v(" "), + _vm.form.errors.has(locale + ".status") + ? _c("div", { + staticClass: "el-form-item__error", + domProps: { + textContent: _vm._s( + _vm.form.errors.first( + locale + ".status" + ) + ) + } + }) + : _vm._e() + ], + 1 + ), + _vm._v(" "), _c( "div", { staticClass: "panel box box-primary" }, @@ -103026,7 +103074,7 @@ var render = function() { attrs: { zone: "image", entity: "Modules\\Page\\Entities\\Page", - "entity-id": _vm.page.id + "entity-id": _vm.$route.params.pageId }, on: { singleFileSelected: function($event) { @@ -105829,6 +105877,10 @@ var _UserProfile = __webpack_require__(520); var _UserProfile2 = _interopRequireDefault(_UserProfile); +var _ApiKeys = __webpack_require__(562); + +var _ApiKeys2 = _interopRequireDefault(_ApiKeys); + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var locales = window.AsgardCMS.locales; @@ -105883,6 +105935,10 @@ exports.default = [ path: '/account/profile', name: 'admin.user.users.account', component: _UserProfile2.default +}, { + path: '/account/api-keys', + name: 'admin.user.users.account.api-keys', + component: _ApiKeys2.default }]; /***/ }), @@ -109347,7 +109403,7 @@ var render = function() { _vm._v(" "), _c( "el-breadcrumb-item", - { attrs: { to: { name: "admin.user.users.profile" } } }, + { attrs: { to: { name: "admin.user.users.account" } } }, [ _vm._v( _vm._s(_vm.trans("users.breadcrumb.edit-profile")) + @@ -110572,7 +110628,7 @@ exports.default = { props: { zone: { type: String, required: true }, entity: { type: String, required: true }, - entityId: { type: Number }, + entityId: { default: null }, label: { type: String } }, components: { @@ -110636,6 +110692,9 @@ exports.default = { mounted: function mounted() { var _this2 = this; + if (this.entityId) { + this.fetchMedia(); + } this.eventName = 'fileWasSelected' + this.makeId() + Math.floor(Math.random() * 999999); this.$events.listen(this.eventName, function (mediaData) { @@ -110985,5 +111044,313 @@ if (false) { // removed by extract-text-webpack-plugin +/***/ }), +/* 550 */, +/* 551 */, +/* 552 */, +/* 553 */, +/* 554 */, +/* 555 */, +/* 556 */, +/* 557 */, +/* 558 */, +/* 559 */, +/* 560 */, +/* 561 */, +/* 562 */ +/***/ (function(module, exports, __webpack_require__) { + +var disposed = false +var normalizeComponent = __webpack_require__(6) +/* script */ +var __vue_script__ = __webpack_require__(563) +/* template */ +var __vue_template__ = __webpack_require__(564) +/* template functional */ + var __vue_template_functional__ = false +/* styles */ +var __vue_styles__ = null +/* scopeId */ +var __vue_scopeId__ = null +/* moduleIdentifier (server only) */ +var __vue_module_identifier__ = null +var Component = normalizeComponent( + __vue_script__, + __vue_template__, + __vue_template_functional__, + __vue_styles__, + __vue_scopeId__, + __vue_module_identifier__ +) +Component.options.__file = "Modules/User/Assets/js/components/ApiKeys.vue" +if (Component.esModule && Object.keys(Component.esModule).some(function (key) { return key !== "default" && key.substr(0, 2) !== "__"})) { console.error("named exports are not supported in *.vue files.")} + +/* hot reload */ +if (false) {(function () { + var hotAPI = require("vue-hot-reload-api") + hotAPI.install(require("vue"), false) + if (!hotAPI.compatible) return + module.hot.accept() + if (!module.hot.data) { + hotAPI.createRecord("data-v-66a1f586", Component.options) + } else { + hotAPI.reload("data-v-66a1f586", Component.options) +' + ' } + module.hot.dispose(function (data) { + disposed = true + }) +})()} + +module.exports = Component.exports + + +/***/ }), +/* 563 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _axios = __webpack_require__(12); + +var _axios2 = _interopRequireDefault(_axios); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +exports.default = { + data: function data() { + return { + loading: false, + apiKeys: {} + }; + }, + + methods: { + fetchApiKeys: function fetchApiKeys() { + var _this = this; + + this.loading = true; + _axios2.default.get(route('api.account.api.index')).then(function (response) { + _this.loading = false; + _this.apiKeys = response.data.data; + }); + }, + generateKey: function generateKey() { + var _this2 = this; + + _axios2.default.get(route('api.account.api.create')).then(function (response) { + _this2.loading = false; + _this2.apiKeys = response.data.data; + _this2.$message({ + type: 'success', + message: response.data.message + }); + }); + }, + destroyApiKey: function destroyApiKey(apiKey) { + var _this3 = this; + + this.$confirm(this.trans('users.delete api key confirm'), '', { + confirmButtonText: this.trans('core.button.delete'), + cancelButtonText: this.trans('core.button.cancel'), + type: 'warning', + confirmButtonClass: 'el-button--danger' + }).then(function () { + _axios2.default.delete(route('api.account.api.destroy', { userTokenId: apiKey.id })).then(function (response) { + _this3.loading = false; + _this3.apiKeys = response.data.data; + _this3.$message({ + type: 'success', + message: response.data.message + }); + }); + }).catch(function () {}); + } + }, + mounted: function mounted() { + this.fetchApiKeys(); + } +}; // +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// + +/***/ }), +/* 564 */ +/***/ (function(module, exports, __webpack_require__) { + +var render = function() { + var _vm = this + var _h = _vm.$createElement + var _c = _vm._self._c || _h + return _c("div", [ + _c( + "div", + { staticClass: "content-header" }, + [ + _c("h1", [ + _vm._v( + "\n " + + _vm._s(_vm.trans("users.api-keys")) + + "\n " + ) + ]), + _vm._v(" "), + _c( + "el-breadcrumb", + { attrs: { separator: "/" } }, + [ + _c("el-breadcrumb-item", [ + _c("a", { attrs: { href: "/backend" } }, [ + _vm._v(_vm._s(_vm.trans("core.breadcrumb.home"))) + ]) + ]), + _vm._v(" "), + _c( + "el-breadcrumb-item", + { attrs: { to: { name: "admin.user.users.account.api-keys" } } }, + [_vm._v(_vm._s(_vm.trans("users.api-keys")) + "\n ")] + ) + ], + 1 + ) + ], + 1 + ), + _vm._v(" "), + _c("div", { staticClass: "row" }, [ + _c("div", { staticClass: "col-md-12" }, [ + _c("div", { staticClass: "box box-primary" }, [ + _c("div", { staticClass: "box-header with-border" }, [ + _c("h3", { staticClass: "box-title" }, [ + _vm._v(_vm._s(_vm.trans("users.your api keys"))) + ]), + _vm._v(" "), + _c( + "div", + { staticClass: "box-tools pull-right" }, + [ + _c( + "el-button", + { + attrs: { type: "primary", size: "small", icon: "plus" }, + on: { click: _vm.generateKey } + }, + [ + _vm._v( + "\n " + + _vm._s(_vm.trans("users.generate new api key")) + + "\n " + ) + ] + ) + ], + 1 + ) + ]), + _vm._v(" "), + _c("div", { staticClass: "box-body" }, [ + _c( + "ul", + { staticClass: "list-unstyled" }, + _vm._l(_vm.apiKeys, function(key) { + return _c( + "li", + { key: key.id, staticStyle: { "margin-bottom": "20px" } }, + [ + _c( + "el-input", + { + attrs: { disabled: "" }, + model: { + value: key.access_token, + callback: function($$v) { + key.access_token = $$v + }, + expression: "key.access_token" + } + }, + [ + _c( + "el-button", + { + attrs: { slot: "prepend" }, + on: { + click: function($event) { + _vm.destroyApiKey(key) + } + }, + slot: "prepend" + }, + [_c("i", { staticClass: "fa fa-times" })] + ) + ], + 1 + ) + ], + 1 + ) + }) + ) + ]) + ]) + ]) + ]) + ]) +} +var staticRenderFns = [] +render._withStripped = true +module.exports = { render: render, staticRenderFns: staticRenderFns } +if (false) { + module.hot.accept() + if (module.hot.data) { + require("vue-hot-reload-api") .rerender("data-v-66a1f586", module.exports) + } +} + /***/ }) /******/ ]); \ No newline at end of file