working on framework of plugins
This commit is contained in:
parent
688bf668e8
commit
55414072e7
|
|
@ -9,6 +9,7 @@ use App\Models\Player;
|
|||
use App\Models\Texture;
|
||||
use App\Models\UserModel;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Services\PluginManager;
|
||||
use App\Exceptions\PrettyPageException;
|
||||
|
||||
class AdminController extends Controller
|
||||
|
|
@ -63,6 +64,47 @@ class AdminController extends Controller
|
|||
}
|
||||
}
|
||||
|
||||
public function plugins(Request $request, PluginManager $plugins)
|
||||
{
|
||||
if ($request->has('action') && $request->has('id')) {
|
||||
$id = $request->get('id');
|
||||
|
||||
if ($plugins->getPlugins()->has($id)) {
|
||||
switch ($request->get('action')) {
|
||||
case 'enable':
|
||||
$plugins->enable($id);
|
||||
break;
|
||||
|
||||
case 'disable':
|
||||
$plugins->disable($id);
|
||||
break;
|
||||
|
||||
case 'delete':
|
||||
if ($request->isMethod('post')) {
|
||||
$plugins->uninstall($id);
|
||||
|
||||
return json('插件已被成功删除', 0);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
# code...
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$data = [
|
||||
'installed' => $plugins->getPlugins(),
|
||||
'enabled' => $plugins->getEnabledPlugins()
|
||||
];
|
||||
|
||||
// dd($data);
|
||||
|
||||
return view('admin.plugins', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show Manage Page of Users.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@ Route::group(['middleware' => 'admin', 'prefix' => 'admin'], function()
|
|||
{
|
||||
Route::get('/', 'AdminController@index');
|
||||
|
||||
Route::any('/plugins', 'AdminController@plugins');
|
||||
Route::any('/customize', 'AdminController@customize');
|
||||
Route::any('/score', 'AdminController@score');
|
||||
Route::any('/options', 'AdminController@options');
|
||||
|
|
|
|||
37
app/Providers/PluginServiceProvider.php
Normal file
37
app/Providers/PluginServiceProvider.php
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class PluginServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Bootstrap any application services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Register any application services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
$this->app->bind('plugins', 'App\Services\PluginManager');
|
||||
|
||||
$bootstrappers = $this->app->make('plugins')->getEnabledBootstrappers();
|
||||
|
||||
foreach ($bootstrappers as $file) {
|
||||
// bootstraper is a closure
|
||||
$bootstrapper = require $file;
|
||||
|
||||
$this->app->call($bootstrapper);
|
||||
}
|
||||
}
|
||||
}
|
||||
183
app/Services/Plugin.php
Normal file
183
app/Services/Plugin.php
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use Illuminate\Contracts\Support\Arrayable;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* @property string $name
|
||||
* @property string $description
|
||||
* @property string $type
|
||||
* @property array $keywords
|
||||
* @property string $homepage
|
||||
* @property string $time
|
||||
* @property string $license
|
||||
* @property array $authors
|
||||
* @property array $support
|
||||
* @property array $require
|
||||
* @property array $requireDev
|
||||
* @property array $autoload
|
||||
* @property array $autoloadDev
|
||||
* @property array $conflict
|
||||
* @property array $replace
|
||||
* @property array $provide
|
||||
* @property array $suggest
|
||||
* @property array $extra
|
||||
*/
|
||||
class Plugin implements Arrayable
|
||||
{
|
||||
/**
|
||||
* The directory of this plugin.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $path;
|
||||
|
||||
/**
|
||||
* package.json of the package.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $packageInfo;
|
||||
|
||||
/**
|
||||
* Whether the plugin is installed.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $installed = true;
|
||||
|
||||
/**
|
||||
* The installed version of the plugin.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $version;
|
||||
|
||||
/**
|
||||
* Whether the plugin is enabled.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $enabled = false;
|
||||
|
||||
/**
|
||||
* @param $path
|
||||
* @param array $packageInfo
|
||||
*/
|
||||
public function __construct($path, $packageInfo)
|
||||
{
|
||||
$this->path = $path;
|
||||
$this->packageInfo = $packageInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
return $this->packageInfoAttribute(Str::snake($name, '-'));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __isset($name)
|
||||
{
|
||||
return isset($this->{$name}) || $this->packageInfoAttribute(Str::snake($name, '-'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Dot notation getter for composer.json attributes.
|
||||
*
|
||||
* @see https://laravel.com/docs/5.1/helpers#arrays
|
||||
*
|
||||
* @param $name
|
||||
* @return mixed
|
||||
*/
|
||||
public function packageInfoAttribute($name)
|
||||
{
|
||||
return Arr::get($this->packageInfo, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $installed
|
||||
* @return Plugin
|
||||
*/
|
||||
public function setInstalled($installed)
|
||||
{
|
||||
$this->installed = $installed;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isInstalled()
|
||||
{
|
||||
return $this->installed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $version
|
||||
* @return Plugin
|
||||
*/
|
||||
public function setVersion($version)
|
||||
{
|
||||
$this->version = $version;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getVersion()
|
||||
{
|
||||
return $this->version;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $enabled
|
||||
* @return Plugin
|
||||
*/
|
||||
public function setEnabled($enabled)
|
||||
{
|
||||
$this->enabled = $enabled;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isEnabled()
|
||||
{
|
||||
return $this->enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getPath()
|
||||
{
|
||||
return $this->path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an array result for the object.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
return (array) array_merge([
|
||||
'name' => $this->name,
|
||||
'version' => $this->getVersion(),
|
||||
'path' => $this->path
|
||||
], $this->packageInfo);
|
||||
}
|
||||
}
|
||||
|
|
@ -2,10 +2,250 @@
|
|||
|
||||
namespace App\Services;
|
||||
|
||||
use Illuminate\Contracts\Foundation\Application;
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
use Illuminate\Filesystem\Filesystem;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
use App\Events\PluginWasDisabled;
|
||||
use App\Events\PluginWasEnabled;
|
||||
use App\Events\PluginWasUninstalled;
|
||||
|
||||
class PluginManager
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
protected $option;
|
||||
|
||||
protected $app;
|
||||
|
||||
/**
|
||||
* @var Dispatcher
|
||||
*/
|
||||
protected $dispatcher;
|
||||
|
||||
/**
|
||||
* @var Filesystem
|
||||
*/
|
||||
protected $filesystem;
|
||||
|
||||
/**
|
||||
* @var Collection|null
|
||||
*/
|
||||
protected $plugins;
|
||||
|
||||
public function __construct(
|
||||
OptionRepository $option,
|
||||
Application $app,
|
||||
Dispatcher $dispatcher,
|
||||
Filesystem $filesystem
|
||||
) {
|
||||
$this->option = $option;
|
||||
$this->app = $app;
|
||||
$this->dispatcher = $dispatcher;
|
||||
$this->filesystem = $filesystem;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getPlugins()
|
||||
{
|
||||
if (is_null($this->plugins)) {
|
||||
$plugins = new Collection();
|
||||
|
||||
$installed = [];
|
||||
|
||||
$resource = opendir(base_path('plugins'));
|
||||
// traverse plugins dir
|
||||
while($filename = @readdir($resource)) {
|
||||
if ($filename == "." || $filename == "..")
|
||||
continue;
|
||||
|
||||
$path = base_path('plugins')."/".$filename;
|
||||
|
||||
if (is_dir($path)) {
|
||||
if (file_exists($path."/package.json")) {
|
||||
// load packages installed
|
||||
$installed[$filename] = json_decode($this->filesystem->get($path."/package.json"), true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
closedir($resource);
|
||||
|
||||
foreach ($installed as $path => $package) {
|
||||
|
||||
// Instantiates an Plugin object using the package path and package.json file.
|
||||
$plugin = new Plugin($this->getPluginsDir().'/'.$path, $package);
|
||||
|
||||
// Per default all plugins are installed if they are registered in composer.
|
||||
$plugin->setInstalled(true);
|
||||
$plugin->setVersion(Arr::get($package, 'version'));
|
||||
$plugin->setEnabled($this->isEnabled($plugin->name));
|
||||
|
||||
$plugins->put($plugin->name, $plugin);
|
||||
}
|
||||
|
||||
$this->plugins = $plugins->sortBy(function ($plugin, $name) {
|
||||
return $plugin->name;
|
||||
});
|
||||
}
|
||||
|
||||
return $this->plugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads an Plugin with all information.
|
||||
*
|
||||
* @param string $name
|
||||
* @return Plugin|null
|
||||
*/
|
||||
public function getPlugin($name)
|
||||
{
|
||||
return $this->getPlugins()->get($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables the plugin.
|
||||
*
|
||||
* @param string $name
|
||||
*/
|
||||
public function enable($name)
|
||||
{
|
||||
if (! $this->isEnabled($name)) {
|
||||
$plugin = $this->getPlugin($name);
|
||||
|
||||
$enabled = $this->getEnabled();
|
||||
|
||||
$enabled[] = $name;
|
||||
|
||||
// $this->migrate($plugin);
|
||||
|
||||
// $this->publishAssets($plugin);
|
||||
|
||||
$this->setEnabled($enabled);
|
||||
|
||||
$plugin->setEnabled(true);
|
||||
|
||||
// $this->dispatcher->fire(new PluginWasEnabled($plugin));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables an plugin.
|
||||
*
|
||||
* @param string $name
|
||||
*/
|
||||
public function disable($name)
|
||||
{
|
||||
$enabled = $this->getEnabled();
|
||||
|
||||
if (($k = array_search($name, $enabled)) !== false) {
|
||||
unset($enabled[$k]);
|
||||
|
||||
$plugin = $this->getPlugin($name);
|
||||
|
||||
$this->setEnabled($enabled);
|
||||
|
||||
$plugin->setEnabled(false);
|
||||
|
||||
// $this->dispatcher->fire(new PluginWasDisabled($plugin));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstalls an plugin.
|
||||
*
|
||||
* @param string $name
|
||||
*/
|
||||
public function uninstall($name)
|
||||
{
|
||||
$plugin = $this->getPlugin($name);
|
||||
|
||||
$this->disable($name);
|
||||
|
||||
// $this->migrateDown($plugin);
|
||||
|
||||
// $this->unpublishAssets($plugin);
|
||||
|
||||
// $plugin->setInstalled(false);
|
||||
|
||||
$this->filesystem->deleteDirectory($plugin->getPath());
|
||||
|
||||
// refresh plugin list
|
||||
$this->plugins = null;
|
||||
|
||||
// $this->dispatcher->fire(new PluginWasUninstalled($plugin));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get only enabled plugins.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getEnabledPlugins()
|
||||
{
|
||||
return $this->getPlugins()->only($this->getEnabled());
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all bootstrap.php files of the enabled plugins.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getEnabledBootstrappers()
|
||||
{
|
||||
$bootstrappers = new Collection;
|
||||
|
||||
foreach ($this->getEnabledPlugins() as $plugin) {
|
||||
if ($this->filesystem->exists($file = $plugin->getPath().'/bootstrap.php')) {
|
||||
$bootstrappers->push($file);
|
||||
}
|
||||
}
|
||||
|
||||
return $bootstrappers;
|
||||
}
|
||||
|
||||
/**
|
||||
* The id's of the enabled plugins.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getEnabled()
|
||||
{
|
||||
return json_decode($this->option->get('plugins_enabled'), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Persist the currently enabled plugins.
|
||||
*
|
||||
* @param array $enabled
|
||||
*/
|
||||
protected function setEnabled(array $enabled)
|
||||
{
|
||||
$enabled = array_values(array_unique($enabled));
|
||||
|
||||
$this->option->set('plugins_enabled', json_encode($enabled));
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the plugin is enabled.
|
||||
*
|
||||
* @param $plugin
|
||||
* @return bool
|
||||
*/
|
||||
public function isEnabled($plugin)
|
||||
{
|
||||
return in_array($plugin, $this->getEnabled());
|
||||
}
|
||||
|
||||
/**
|
||||
* The plugins path.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getPluginsDir()
|
||||
{
|
||||
return $this->app->basePath().'/plugins';
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -162,6 +162,7 @@ return [
|
|||
*/
|
||||
App\Providers\BootServiceProvider::class,
|
||||
App\Providers\AppServiceProvider::class,
|
||||
App\Providers\PluginServiceProvider::class,
|
||||
App\Providers\EventServiceProvider::class,
|
||||
App\Providers\RouteServiceProvider::class,
|
||||
App\Providers\ResponseMacroServiceProvider::class,
|
||||
|
|
|
|||
|
|
@ -17,14 +17,15 @@ $menu['user'] = array(
|
|||
);
|
||||
|
||||
$menu['admin'] = array(
|
||||
['title' => 'general.dashboard', 'link' => 'admin', 'icon' => 'fa-dashboard'],
|
||||
['title' => 'general.user-manage', 'link' => 'admin/users', 'icon' => 'fa-users'],
|
||||
['title' => 'general.player-manage', 'link' => 'admin/players', 'icon' => 'fa-gamepad'],
|
||||
['title' => 'general.customize', 'link' => 'admin/customize', 'icon' => 'fa-paint-brush'],
|
||||
['title' => 'general.score-options', 'link' => 'admin/score', 'icon' => 'fa-credit-card'],
|
||||
['title' => 'general.options', 'link' => 'admin/options', 'icon' => 'fa-cog'],
|
||||
['title' => 'general.import-v2', 'link' => 'setup/migrations', 'icon' => 'fa-undo'],
|
||||
['title' => 'general.check-update', 'link' => 'admin/update', 'icon' => 'fa-arrow-up']
|
||||
['title' => 'general.dashboard', 'link' => 'admin', 'icon' => 'fa-dashboard'],
|
||||
['title' => 'general.user-manage', 'link' => 'admin/users', 'icon' => 'fa-users'],
|
||||
['title' => 'general.player-manage', 'link' => 'admin/players', 'icon' => 'fa-gamepad'],
|
||||
['title' => 'general.plugin-manage', 'link' => 'admin/plugins', 'icon' => 'fa-plug'],
|
||||
['title' => 'general.customize', 'link' => 'admin/customize', 'icon' => 'fa-paint-brush'],
|
||||
['title' => 'general.score-options', 'link' => 'admin/score', 'icon' => 'fa-credit-card'],
|
||||
['title' => 'general.options', 'link' => 'admin/options', 'icon' => 'fa-cog'],
|
||||
['title' => 'general.import-v2', 'link' => 'setup/migrations', 'icon' => 'fa-undo'],
|
||||
['title' => 'general.check-update', 'link' => 'admin/update', 'icon' => 'fa-arrow-up']
|
||||
);
|
||||
|
||||
return $menu;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
* @Author: printempw
|
||||
* @Date: 2016-07-29 11:53:11
|
||||
* @Last Modified by: printempw
|
||||
* @Last Modified time: 2016-10-17 09:40:16
|
||||
* @Last Modified time: 2016-10-17 11:11:52
|
||||
*/
|
||||
|
||||
return [
|
||||
|
|
@ -37,5 +37,6 @@ return [
|
|||
'return_200_when_notfound' => '0',
|
||||
'cache_expire_time' => '31536000',
|
||||
'max_upload_file_size' => '1024',
|
||||
'auto_detect_asset_url' => '1'
|
||||
'auto_detect_asset_url' => '1',
|
||||
'plugins_enabled' => ''
|
||||
];
|
||||
|
|
|
|||
2
plugins/.gitignore
vendored
Normal file
2
plugins/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
*
|
||||
!.gitignore
|
||||
|
|
@ -16,6 +16,7 @@ my-closet: Closet
|
|||
player-manage: Player Manage
|
||||
user-manage: User Manage
|
||||
generate-config: Generate Config
|
||||
plugin-manage: Plugin Manage
|
||||
customize: Customize
|
||||
options: Options
|
||||
import-v2: Import Data
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ my-closet: 我的衣柜
|
|||
player-manage: 角色管理
|
||||
user-manage: 用户管理
|
||||
generate-config: 配置生成
|
||||
plugin-manage: 插件管理
|
||||
customize: 个性化
|
||||
options: 站点配置
|
||||
import-v2: 导入数据
|
||||
|
|
|
|||
125
resources/views/admin/plugins.tpl
Normal file
125
resources/views/admin/plugins.tpl
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
@extends('admin.master')
|
||||
|
||||
@section('title', trans('general.plugin-manage'))
|
||||
|
||||
@section('style')
|
||||
<style>
|
||||
.btn {
|
||||
margin-right: 4px;
|
||||
}
|
||||
</style>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
|
||||
<!-- Content Wrapper. Contains page content -->
|
||||
<div class="content-wrapper">
|
||||
<!-- Content Header (Page header) -->
|
||||
<section class="content-header">
|
||||
<h1>
|
||||
{{ trans('general.plugin-manage') }}
|
||||
<small>Plugin Manage</small>
|
||||
</h1>
|
||||
</section>
|
||||
|
||||
<!-- Main content -->
|
||||
<section class="content">
|
||||
<div class="box">
|
||||
<div class="box-body table-responsive no-padding">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>名称</th>
|
||||
<th>描述</th>
|
||||
<th>作者</th>
|
||||
<th>版本</th>
|
||||
<th>状态</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
@forelse($installed as $plugin)
|
||||
<tr id="plugin-{{ $plugin->name }}">
|
||||
<td>{{ $plugin->title }}</td>
|
||||
<td id="description">{{ $plugin->description }}</td>
|
||||
<td id="author">{{ $plugin->author }}</td>
|
||||
<td id="version">{{ $plugin->version }}</td>
|
||||
<td id="status">
|
||||
@if ($plugin->isEnabled())
|
||||
已启用
|
||||
@else
|
||||
已禁用
|
||||
@endif
|
||||
</td>
|
||||
|
||||
<td>
|
||||
@if ($plugin->isEnabled())
|
||||
<a class="btn btn-warning btn-sm" href="?action=disable&id={{ $plugin->name }}">禁用插件</a>
|
||||
@else
|
||||
<a class="btn btn-primary btn-sm" href="?action=enable&id={{ $plugin->name }}">启用插件</a>
|
||||
@endif
|
||||
|
||||
<a class="btn btn-default btn-sm" href="?action=config&id={{ $plugin->name }}">插件配置</a>
|
||||
<a class="btn btn-danger btn-sm" href="javascript:deletePlugin('{{ $plugin->name }}');">删除插件</a>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td>0</td>
|
||||
<td>无结果</td>
|
||||
<td>(´・ω・`)</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section><!-- /.content -->
|
||||
</div><!-- /.content-wrapper -->
|
||||
|
||||
@endsection
|
||||
|
||||
@section('style')
|
||||
<style>
|
||||
@media (max-width: 767px) {
|
||||
.content-header > h1 > small {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@endsection
|
||||
|
||||
@section('script')
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
$('.box-body').css('min-height', $('.content-wrapper').height() - $('.content-header').outerHeight() - 120);
|
||||
});
|
||||
|
||||
function deletePlugin(name) {
|
||||
swal({
|
||||
text: '真的要删除这个插件吗?',
|
||||
type: 'warning',
|
||||
showCancelButton: true
|
||||
}).then(function() {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "?action=delete&id=" + name,
|
||||
dataType: "json",
|
||||
success: function(json) {
|
||||
if (json.errno == 0) {
|
||||
toastr.success(json.msg);
|
||||
|
||||
$('tr[id=plugin-'+name+']').remove();
|
||||
} else {
|
||||
toastr.warning(json.msg);
|
||||
}
|
||||
},
|
||||
error: showAjaxError
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
@endsection
|
||||
Loading…
Reference in New Issue
Block a user