diff --git a/dcat-admin-extensions/dcat-admin/operation-log/LICENSE b/dcat-admin-extensions/dcat-admin/operation-log/LICENSE new file mode 100644 index 0000000..6c0a95a --- /dev/null +++ b/dcat-admin-extensions/dcat-admin/operation-log/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Dcat Admin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dcat-admin-extensions/dcat-admin/operation-log/README.md b/dcat-admin-extensions/dcat-admin/operation-log/README.md new file mode 100644 index 0000000..bf116d2 --- /dev/null +++ b/dcat-admin-extensions/dcat-admin/operation-log/README.md @@ -0,0 +1,12 @@ +
$v
";
+ })->filterByValue();
+
+ $grid->column('ip', 'IP')->filterByValue();
+
+ $grid->column('input')->display(function ($input) {
+ $input = json_decode($input, true);
+
+ if (empty($input)) {
+ return;
+ }
+
+ $input = Arr::except($input, ['_pjax', '_token', '_method', '_previous_']);
+
+ if (empty($input)) {
+ return;
+ }
+
+ return ''.json_encode($input, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE).''; + }); + + $grid->column('created_at', trans('admin.created_at')); + + $grid->model()->orderBy('id', 'DESC'); + + $grid->disableCreateButton(); + $grid->disableQuickEditButton(); + $grid->disableEditButton(); + $grid->disableViewButton(); + $grid->showColumnSelector(); + $grid->setActionClass(Grid\Displayers\Actions::class); + + $grid->filter(function (Grid\Filter $filter) { + $userModel = config('admin.database.users_model'); + + $filter->in('user_id', trans('admin.user')) + ->multipleSelect($userModel::pluck('name', 'id')); + + $filter->equal('method', trans('admin.method')) + ->select( + array_combine(OperationLog::$methods, OperationLog::$methods) + ); + + $filter->like('path', trans('admin.uri')); + $filter->equal('ip', 'IP'); + $filter->between('created_at')->datetime(); + }); + }); + } + + public function destroy($id) + { + $ids = explode(',', $id); + + OperationLog::destroy(array_filter($ids)); + + return JsonResponse::make() + ->success(trans('admin.delete_succeeded')) + ->refresh() + ->send(); + } +} diff --git a/dcat-admin-extensions/dcat-admin/operation-log/src/Http/Middleware/LogOperation.php b/dcat-admin-extensions/dcat-admin/operation-log/src/Http/Middleware/LogOperation.php new file mode 100644 index 0000000..151f770 --- /dev/null +++ b/dcat-admin-extensions/dcat-admin/operation-log/src/Http/Middleware/LogOperation.php @@ -0,0 +1,160 @@ +shouldLogOperation($request)) { + $user = Admin::user(); + + $log = [ + 'user_id' => $user ? $user->id : 0, + 'path' => substr($request->path(), 0, 255), + 'method' => $request->method(), + 'ip' => $request->getClientIp(), + 'input' => $this->formatInput($request->input()), + ]; + + try { + OperationLogModel::create($log); + } catch (\Exception $exception) { + // pass + } + } + + return $next($request); + } + + /** + * @param array $input + * + * @return string + */ + protected function formatInput(array $input) + { + foreach ($this->getSecretFields() as $field) { + if ($field && ! empty($input[$field])) { + $input[$field] = Str::limit($input[$field], 3, '******'); + } + } + + return json_encode($input, JSON_UNESCAPED_UNICODE); + } + + /** + * @param string $key + * @param mixed $default + * + * @return mixed + */ + protected function setting($key, $default = null) + { + return OperationLogServiceProvider::setting($key, $default); + } + + /** + * @param Request $request + * + * @return bool + */ + protected function shouldLogOperation(Request $request) + { + return ! $this->inExceptArray($request) + && $this->inAllowedMethods($request->method()); + } + + /** + * Whether requests using this method are allowed to be logged. + * + * @param string $method + * + * @return bool + */ + protected function inAllowedMethods($method) + { + $allowedMethods = collect($this->getAllowedMethods())->filter(); + + if ($allowedMethods->isEmpty()) { + return true; + } + + return $allowedMethods->map(function ($method) { + return strtoupper($method); + })->contains($method); + } + + /** + * Determine if the request has a URI that should pass through CSRF verification. + * + * @param \Illuminate\Http\Request $request + * + * @return bool + */ + protected function inExceptArray($request) + { + if ($request->routeIs(admin_api_route_name('value'))) { + return true; + } + + foreach ($this->except() as $except) { + if ($request->routeIs($except)) { + return true; + } + + $except = admin_base_path($except); + + if ($except !== '/') { + $except = trim($except, '/'); + } + + if (Helper::matchRequestPath($except)) { + return true; + } + } + + return false; + } + + protected function except() + { + return array_merge((array) $this->setting('except'), $this->except); + } + + protected function getSecretFields() + { + return array_merge((array) $this->setting('secret_fields'), $this->secretFields); + } + + protected function getAllowedMethods() + { + return (array) ($this->setting('allowed_methods') ?: $this->defaultAllowedMethods); + } +} diff --git a/dcat-admin-extensions/dcat-admin/operation-log/src/Http/routes.php b/dcat-admin-extensions/dcat-admin/operation-log/src/Http/routes.php new file mode 100644 index 0000000..970f57a --- /dev/null +++ b/dcat-admin-extensions/dcat-admin/operation-log/src/Http/routes.php @@ -0,0 +1,7 @@ +name('dcat-admin.operation-log.index'); +Route::delete('auth/operation-logs/{id}', Controllers\LogController::class.'@destroy')->name('dcat-admin.operation-log.destroy'); \ No newline at end of file diff --git a/dcat-admin-extensions/dcat-admin/operation-log/src/Models/OperationLog.php b/dcat-admin-extensions/dcat-admin/operation-log/src/Models/OperationLog.php new file mode 100644 index 0000000..347974b --- /dev/null +++ b/dcat-admin-extensions/dcat-admin/operation-log/src/Models/OperationLog.php @@ -0,0 +1,44 @@ + 'primary', + 'POST' => 'success', + 'PUT' => 'blue', + 'DELETE' => 'danger', + ]; + + public static $methods = [ + 'GET', 'POST', 'PUT', 'DELETE', 'OPTIONS', 'PATCH', + 'LINK', 'UNLINK', 'COPY', 'HEAD', 'PURGE', + ]; + + public function __construct(array $attributes = []) + { + $this->connection = config('database.connection') ?: config('database.default'); + + parent::__construct($attributes); + } + + /** + * Log belongs to users. + * + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function user() + { + return $this->belongsTo(config('admin.database.users_model')); + } +} diff --git a/dcat-admin-extensions/dcat-admin/operation-log/src/OperationLogServiceProvider.php b/dcat-admin-extensions/dcat-admin/operation-log/src/OperationLogServiceProvider.php new file mode 100644 index 0000000..596827b --- /dev/null +++ b/dcat-admin-extensions/dcat-admin/operation-log/src/OperationLogServiceProvider.php @@ -0,0 +1,27 @@ + [ + LogOperation::class, + ], + ]; + + protected $menu = [ + [ + 'title' => 'Operation Log', + 'uri' => 'auth/operation-logs', + ], + ]; + + public function settingForm() + { + return new Setting($this); + } +} diff --git a/dcat-admin-extensions/dcat-admin/operation-log/src/Setting.php b/dcat-admin-extensions/dcat-admin/operation-log/src/Setting.php new file mode 100644 index 0000000..f50c4fe --- /dev/null +++ b/dcat-admin-extensions/dcat-admin/operation-log/src/Setting.php @@ -0,0 +1,31 @@ +trans('log.title'); + } + + protected function formatInput(array $input) + { + $input['except'] = Helper::array($input['except']); + $input['allowed_methods'] = Helper::array($input['allowed_methods']); + + return $input; + } + + public function form() + { + $this->tags('except'); + $this->multipleSelect('allowed_methods') + ->options(array_combine(OperationLog::$methods, OperationLog::$methods)); + $this->tags('secret_fields'); + } +} diff --git a/dcat-admin-extensions/dcat-admin/operation-log/updates/create_opration_log_table.php b/dcat-admin-extensions/dcat-admin/operation-log/updates/create_opration_log_table.php new file mode 100644 index 0000000..97ce3b3 --- /dev/null +++ b/dcat-admin-extensions/dcat-admin/operation-log/updates/create_opration_log_table.php @@ -0,0 +1,34 @@ +bigIncrements('id')->unsigned(); + $table->bigInteger('user_id'); + $table->string('path'); + $table->string('method', 10); + $table->string('ip'); + $table->text('input'); + $table->index('user_id'); + $table->timestamps(); + }); + } + } + + public function down() + { + Schema::dropIfExists('admin_operation_log'); + } +} diff --git a/dcat-admin-extensions/dcat-admin/operation-log/version.php b/dcat-admin-extensions/dcat-admin/operation-log/version.php new file mode 100644 index 0000000..1517a63 --- /dev/null +++ b/dcat-admin-extensions/dcat-admin/operation-log/version.php @@ -0,0 +1,8 @@ + [ + 'Initialize extension.', + 'create_opration_log_table.php', + ], +];