From 26a35c9738f23ad175eb09c9355790c240492496 Mon Sep 17 00:00:00 2001
From: Karson <karsonzhang@163.com>
Date: Sun, 4 Feb 2018 00:36:17 +0800
Subject: [PATCH] 新增插件在线一键升级功能 新增安装指定插件版本 修复二级管理员无法添加管理员的BUG 优化require-table在add_url的ids替换

---
 application/admin/controller/Addon.php      | 53 +++++++++++++++++++++++++++++++++++++++++++++++++----
 application/admin/controller/auth/Admin.php | 26 +++++++++++++++++---------
 application/admin/lang/zh-cn/addon.php      |  3 +++
 application/admin/view/addon/index.html     | 50 ++++++++++++++++++++++++++++++++++++++++++++------
 application/config.php                      |  2 +-
 public/assets/js/backend/addon.js           | 52 ++++++++++++++++++++++++++++++++++++++++++++++++----
 public/assets/js/require-backend.min.js     |  4 +++-
 public/assets/js/require-table.js           |  4 +++-
 8 files changed, 168 insertions(+), 26 deletions(-)

diff --git a/application/admin/controller/Addon.php b/application/admin/controller/Addon.php
index 4abe86f..7f914c6 100644
--- a/application/admin/controller/Addon.php
+++ b/application/admin/controller/Addon.php
@@ -62,7 +62,6 @@ class Addon extends Backend
             $params = $this->request->post("row/a");
             if ($params)
             {
-                $configList = [];
                 foreach ($config as $k => &$v)
                 {
                     if (isset($params[$v['name']]))
@@ -124,9 +123,18 @@ class Addon extends Backend
         {
             $uid = $this->request->post("uid");
             $token = $this->request->post("token");
-            Service::install($name, $force, ['uid' => $uid, 'token' => $token]);
+            $version = $this->request->post("version");
+            $faversion = $this->request->post("faversion");
+            $extend = [
+                'uid'       => $uid,
+                'token'     => $token,
+                'version'   => $version,
+                'faversion' => $faversion
+            ];
+            Service::install($name, $force, $extend);
             $info = get_addon_info($name);
             $info['config'] = get_addon_config($name) ? 1 : 0;
+            $info['state'] = 1;
             $this->success(__('Install successful'), null, ['addon' => $info]);
         }
         catch (AddonException $e)
@@ -283,6 +291,42 @@ class Addon extends Backend
     }
 
     /**
+     * 更新插件
+     */
+    public function upgrade()
+    {
+        $name = $this->request->post("name");
+        if (!$name)
+        {
+            $this->error(__('Parameter %s can not be empty', 'name'));
+        }
+        try
+        {
+            $uid = $this->request->post("uid");
+            $token = $this->request->post("token");
+            $version = $this->request->post("version");
+            $faversion = $this->request->post("faversion");
+            $extend = [
+                'uid'       => $uid,
+                'token'     => $token,
+                'version'   => $version,
+                'faversion' => $faversion
+            ];
+            //调用更新的方法
+            Service::upgrade($name, $extend);
+            $this->success(__('Operate successful'));
+        }
+        catch (AddonException $e)
+        {
+            $this->result($e->getData(), $e->getCode(), $e->getMessage());
+        }
+        catch (Exception $e)
+        {
+            $this->error($e->getMessage());
+        }
+    }
+
+    /**
      * 刷新缓存
      */
     public function refresh()
@@ -314,14 +358,15 @@ class Addon extends Backend
         {
             if ($search && stripos($v['name'], $search) === FALSE && stripos($v['intro'], $search) === FALSE)
                 continue;
+
             $v['flag'] = '';
             $v['banner'] = '';
             $v['image'] = '';
             $v['donateimage'] = '';
             $v['demourl'] = '';
             $v['price'] = '0.00';
-            $v['url'] = '/addons/' . $v['name'];
-            $v['createtime'] = 0;
+            $v['url'] = addon_url($v['name']);
+            $v['createtime'] = filemtime(ADDON_PATH . $v['name']);
             $list[] = $v;
         }
         $total = count($list);
diff --git a/application/admin/controller/auth/Admin.php b/application/admin/controller/auth/Admin.php
index 4c7431e..c3747b5 100644
--- a/application/admin/controller/auth/Admin.php
+++ b/application/admin/controller/auth/Admin.php
@@ -27,30 +27,38 @@ class Admin extends Backend
         $this->model = model('Admin');
 
         $this->childrenAdminIds = $this->auth->getChildrenAdminIds(true);
-        $this->childrenGroupIds = $this->auth->getChildrenGroupIds($this->auth->isSuperAdmin() ? true : false);
+        $this->childrenGroupIds = $this->auth->getChildrenGroupIds(true);
 
         $groupList = collection(AuthGroup::where('id', 'in', $this->childrenGroupIds)->select())->toArray();
+
         Tree::instance()->init($groupList);
-        $result = [];
+        $groupdata = [];
         if ($this->auth->isSuperAdmin())
         {
             $result = Tree::instance()->getTreeList(Tree::instance()->getTreeArray(0));
+            foreach ($result as $k => $v)
+            {
+                $groupdata[$v['id']] = $v['name'];
+            }
         }
         else
         {
+            $result = [];
             $groups = $this->auth->getGroups();
             foreach ($groups as $m => $n)
             {
-                $result = array_merge($result, Tree::instance()->getTreeList(Tree::instance()->getTreeArray($n['pid'])));
+                $childlist = Tree::instance()->getTreeList(Tree::instance()->getTreeArray($n['id']));
+                $temp = [];
+                foreach ($childlist as $k => $v)
+                {
+                    $temp[$v['id']] = $v['name'];
+                }
+                $result[__($n['name'])] = $temp;
             }
-        }
-        $groupName = [];
-        foreach ($result as $k => $v)
-        {
-            $groupName[$v['id']] = $v['name'];
+            $groupdata = $result;
         }
 
-        $this->view->assign('groupdata', $groupName);
+        $this->view->assign('groupdata', $groupdata);
         $this->assignconfig("admin", ['id' => $this->auth->id]);
     }
 
diff --git a/application/admin/lang/zh-cn/addon.php b/application/admin/lang/zh-cn/addon.php
index 250f7a0..3fb633b 100644
--- a/application/admin/lang/zh-cn/addon.php
+++ b/application/admin/lang/zh-cn/addon.php
@@ -22,11 +22,13 @@ return [
     'Pay click tips'                 => '请点击这里在新窗口中进行支付!',
     'Pay new window tips'            => '请在新弹出的窗口中进行支付,支付完成后再重新点击安装按钮进行安装!',
     'Uninstall tips'                 => '确认卸载插件?<p class="text-danger">卸载将会删除所有插件文件且不可找回!!! 插件如果有创建数据库表请手动删除!!!</p>如有重要数据请备份后再操作!',
+    'Upgrade tips'                   => '确认升级插件?<p class="text-danger">如果之前购买插件时未登录,此次升级可能出现购买后才可以下载的提示!!!<br>升级后可能出现部分冗余数据记录,请根据需要移除即可!!!</p>如有重要数据请备份后再操作!',
     'Offline installed tips'         => '插件安装成功!你需要手动启用该插件,并清除缓存使之生效',
     'Online installed tips'          => '插件安装成功!清除插件缓存和框架缓存后生效!',
     'Not login tips'                 => '你当前未登录FastAdmin,登录后将同步已购买的记录,下载时无需二次付费!',
     'Not installed tips'             => '请安装后再访问插件前台页面!',
     'Not enabled tips'               => '插件已经禁用,请启用后再访问插件前台页面!',
+    'Please disable addon first'     => '请先禁用插件再进行升级',
     'Login now'                      => '立即登录',
     'Continue install'               => '不登录,继续安装',
     'Recommend'                      => '推荐',
@@ -49,6 +51,7 @@ return [
     'Feedback'                       => '反馈BUG',
     'Install'                        => '安装',
     'Uninstall'                      => '卸载',
+    'Upgrade'                        => '升级',
     'Setting'                        => '配置',
     'Disable'                        => '禁用',
     'Enable'                         => '启用',
diff --git a/application/admin/view/addon/index.html b/application/admin/view/addon/index.html
index 5cbea77..ba6aae2 100644
--- a/application/admin/view/addon/index.html
+++ b/application/admin/view/addon/index.html
@@ -2,7 +2,8 @@
     .noimage {width:100%;text-align: center;background:#18bc9c;color:#fff;padding-bottom:66.66%;position:relative;}
     .noimage > div {position: absolute;top:48%;width:100%;text-align:center;}
     .addon {position: relative;}
-    .addon > span {position:absolute;left:15px;top:15px;}
+    .addon > span {position:absolute;left:15px;top:15px;z-index:9;}
+    .addon > span a{opacity: 0.5;border:none;color:#fff;}
     .layui-layer-pay .layui-layer-content {padding:0;height:600px!important;}
     .layui-layer-pay {border:none;}
     .payimg{position:relative;width:800px;height:600px;}
@@ -162,8 +163,14 @@
         <% var label = labelarr[item.id % 5]; %>
         <% var addon = typeof addons[item.name]!= 'undefined' ? addons[item.name] : null; %>
         <div class="thumbnail addon">
-            <!--<span class="btn btn-primary"><%=item.name%></span>-->
-            <a href="<%=addon?addon.url:'javascript:;'%>" class="btn-addonindex" target="_blank">
+            <%if(addon){%>
+            <span>
+                <a href="<%=addon.url%>" target="_blank" class="btn btn-xs">
+                    <i class="fa fa-home"></i>
+                </a>
+            </span>
+            <%}%>
+            <a href="<%=item.url%>" class="btn-addonindex" target="_blank">
                 <%if(item.image){%>
                 <img src="<%=item.image%>" class="img-responsive" alt="<%=item.title%>">
                 <%}else{%>
@@ -190,9 +197,23 @@
                 <p class="text-muted">{:__('Intro')}: <%=item.intro%></p>
                 <p class="text-muted">{:__('Version')}: <%=# addon && item && addon.version!=item.version?'<span class="label label-danger">'+addon.version+'</span> -> <span class="label label-success">'+item.version+'</span>':item.version%></p>
                 <p class="text-muted">{:__('Createtime')}: <%=Moment(item.createtime*1000).format("YYYY-MM-DD HH:mm:ss")%></p>
-                <p class="operate" data-id="<%=item.id%>" data-name="<%=item.name%>">
+                <div class="operate" data-id="<%=item.id%>" data-name="<%=item.name%>">
                     <% if(!addon){ %>
-                    <a href="javascript:;" class="btn btn-primary btn-success btn-install" data-type="<%=item.price<=0?'free':'price';%>" data-donateimage="<%=item.donateimage%>"><i class="fa fa-cloud-download"></i> {:__('Install')}</a> 
+                    <% if(typeof item.releaselist !="undefined" && item.releaselist.length>1){%>
+                    <span class="btn-group">
+                        <a href="javascript:;" class="btn btn-primary btn-success btn-install" data-type="<%=item.price<=0?'free':'price';%>" data-donateimage="<%=item.donateimage%>" data-version="<%=item.version%>"><i class="fa fa-cloud-download"></i> {:__('Install')}</a> 
+                        <a class="btn btn-success dropdown-toggle" data-toggle="dropdown" href="javascript:;">
+                            <span class="fa fa-caret-down"></span>
+                        </a>
+                        <ul class="dropdown-menu">
+                            <% for(var i=0;i< item.releaselist.length;i++){ %>
+                            <li><a href="javascript:;" class="btn-install" data-type="<%=item.price<=0?'free':'price';%>" data-donateimage="<%=item.donateimage%>" data-version="<%=item.releaselist[i].version%>"><%=item.releaselist[i].version%></a></li>
+                            <% } %>
+                        </ul>
+                    </span>
+                    <% }else{%>
+                    <a href="javascript:;" class="btn btn-primary btn-success btn-install" data-type="<%=item.price<=0?'free':'price';%>" data-donateimage="<%=item.donateimage%>" data-version="<%=item.version%>"><i class="fa fa-cloud-download"></i> {:__('Install')}</a> 
+                    <% } %>
                     <% if(item.demourl){ %>
                     <a href="<%=item.demourl%>" class="btn btn-primary btn-info btn-demo" target="_blank"><i class="fa fa-flash"></i> {:__('Demo')}</a> 
                     <% } %>
@@ -209,12 +230,29 @@
                     <a href="javascript:;" class="btn btn-danger btn-uninstall"><i class="fa fa-times"></i> {:__('Uninstall')}</a>
                     <% } %>
                     <% } %>
+                    <% if(addon && item && addon.version!=item.version){%>
+                    <% if(typeof item.releaselist !="undefined" && item.releaselist.length>1){%>
+                    <span class="btn-group">
+                        <a href="javascript:;" class="btn btn-info btn-success btn-upgrade" data-version="<%=item.version%>"><i class="fa fa-cloud"></i> {:__('Upgrade')}</a> 
+                        <a class="btn btn-info dropdown-toggle" data-toggle="dropdown" href="javascript:;">
+                            <span class="fa fa-caret-down"></span>
+                        </a>
+                        <ul class="dropdown-menu">
+                            <% for(var i=0;i< item.releaselist.length;i++){ %>
+                            <li><a href="javascript:;" class="btn-upgrade" data-version="<%=item.releaselist[i].version%>"><%=item.releaselist[i].version%></a></li>
+                            <% } %>
+                        </ul>
+                    </span>
+                    <% }else{%>
+                    <a href="javascript:;" class="btn btn-info btn-upgrade" data-version="<%=item.version%>"><i class="fa fa-cloud"></i> {:__('Upgrade')}</a>
+                    <% }%>
+                    <% }%>
 
                     <span class="pull-right" style="margin-top:10px;">
                         <a href="javascript:;" class="btn-addoninfo text-gray" data-index="<%=i%>" title="<%=item.title?item.title:'{:__('None')}'%>"><i class="fa fa-bars"></i></a>
                     </span>
 
-                </p>
+                </div>
             </div>
         </div>
     </div>
diff --git a/application/config.php b/application/config.php
index 213531a..96299e9 100755
--- a/application/config.php
+++ b/application/config.php
@@ -253,7 +253,7 @@ return [
         //自动检测更新
         'checkupdate'      => false,
         //版本号
-        'version'          => '1.0.0.20180130_beta',
+        'version'          => '1.0.0.20180204_beta',
         'api_url'          => 'http://api.fastadmin.net',
     ],
 ];
diff --git a/public/assets/js/backend/addon.js b/public/assets/js/backend/addon.js
index b499904..631aeab 100644
--- a/public/assets/js/backend/addon.js
+++ b/public/assets/js/backend/addon.js
@@ -22,8 +22,10 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
                     if (e.keyCode == 13) {
                         var that = this;
                         var options = table.bootstrapTable('getOptions');
+                        var queryParams = options.queryParams;
                         options.pageNumber = 1;
                         options.queryParams = function (params) {
+                            var params = queryParams(params);
                             params.search = $(that).val();
                             return params;
                         };
@@ -53,7 +55,16 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
                 showExport: false,
                 commonSearch: false,
                 searchFormVisible: false,
-                pageSize: 12
+                pageSize: 12,
+                queryParams: function (params) {
+                    var filter = params.filter ? JSON.parse(params.filter) : {};
+                    var op = params.op ? JSON.parse(params.op) : {};
+                    filter.faversion = Config.fastadmin.version;
+                    op.faversion = "=";
+                    params.filter = JSON.stringify(filter);
+                    params.op = JSON.stringify(op);
+                    return params;
+                }
             });
 
             // 为表格绑定事件
@@ -64,7 +75,6 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
                 var data = table.bootstrapTable("getData");
                 var item = data[index];
                 var addon = typeof Config.addons[item.name] != 'undefined' ? Config.addons[item.name] : null;
-                console.log(item, addon);
                 Layer.alert(Template("addoninfotpl", {item: item, addon: addon}), {
                     btn: [__('OK'), __('Donate'), __('Feedback'), __('Document')],
                     title: __('Detail'),
@@ -113,7 +123,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
             $(document).on("click", ".btn-addonindex", function () {
                 if ($(this).attr("href") == 'javascript:;') {
                     Layer.msg(__('Not installed tips'), {icon: 7});
-                } else if ($(this).parent().find("a.btn-enable").size() > 0) {
+                } else if ($(this).closest(".operate").find("a.btn-enable").size() > 0) {
                     Layer.msg(__('Not enabled tips'), {icon: 7});
                     return false;
                 }
@@ -187,13 +197,14 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
             $(document).on("click", ".btn-install", function () {
                 var that = this;
                 var name = $(this).closest(".operate").data("name");
+                var version = $(this).data("version");
                 var userinfo = Controller.api.userinfo.get();
                 var uid = userinfo ? userinfo.id : 0;
                 var token = userinfo ? userinfo.token : '';
                 var install = function (name, force) {
                     Fast.api.ajax({
                         url: 'addon/install',
-                        data: {name: name, force: force ? 1 : 0, uid: uid, token: token}
+                        data: {name: name, force: force ? 1 : 0, uid: uid, token: token, version: version, faversion: Config.fastadmin.version}
                     }, function (data, ret) {
                         Layer.closeAll();
                         Config['addons'][data.addon.name] = ret.data.addon;
@@ -367,6 +378,39 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
                 };
                 operate(name, action, false);
             });
+
+            //点击升级
+            $(document).on("click", ".btn-upgrade", function () {
+                if ($(this).closest(".operate").find("a.btn-disable").size() > 0) {
+                    Layer.alert(__('Please disable addon first'), {icon: 7});
+                    return false;
+                }
+                var name = $(this).closest(".operate").data("name");
+                var version = $(this).data("version");
+                var userinfo = Controller.api.userinfo.get();
+                var uid = userinfo ? userinfo.id : 0;
+                var token = userinfo ? userinfo.token : '';
+                var upgrade = function (name) {
+                    Fast.api.ajax({
+                        url: 'addon/upgrade',
+                        data: {name: name, uid: uid, token: token, version: version, faversion: Config.fastadmin.version}
+                    }, function (data, ret) {
+                        Config['addons'][name].version = version;
+                        Layer.closeAll();
+                        $('.btn-refresh').trigger('click');
+                    }, function (data, ret) {
+                        Layer.alert(ret.msg);
+                        return false;
+                    });
+                };
+                Layer.confirm(__('Upgrade tips'), function () {
+                    upgrade(name);
+                });
+            });
+
+            $(document).on("click", ".operate .btn-group .dropdown-toggle", function () {
+                $(this).closest(".btn-group").toggleClass("dropup", $(document).height() - $(this).offset().top <= 200);
+            });
         },
         add: function () {
             Controller.api.bindevent();
diff --git a/public/assets/js/require-backend.min.js b/public/assets/js/require-backend.min.js
index 2d689ca..36b0dae 100644
--- a/public/assets/js/require-backend.min.js
+++ b/public/assets/js/require-backend.min.js
@@ -9758,7 +9758,9 @@ define('table',['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstr
                 $(toolbar).on('click', Table.config.addbtn, function () {
                     var ids = Table.api.selectedids(table);
                     var url = options.extend.add_url;
-                    url = Table.api.replaceurl(url, {ids: ids.length > 0 ? ids.join(",") : 0}, table);
+                    if (url.indexOf("{ids}") !== -1) {
+                        url = Table.api.replaceurl(url, {ids: ids.length > 0 ? ids.join(",") : 0}, table);
+                    }
                     Fast.api.open(url, __('Add'), $(this).data() || {});
                 });
                 // 导入按钮事件
diff --git a/public/assets/js/require-table.js b/public/assets/js/require-table.js
index e4e74a2..e740da5 100644
--- a/public/assets/js/require-table.js
+++ b/public/assets/js/require-table.js
@@ -160,7 +160,9 @@ define(['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstrap-table
                 $(toolbar).on('click', Table.config.addbtn, function () {
                     var ids = Table.api.selectedids(table);
                     var url = options.extend.add_url;
-                    url = Table.api.replaceurl(url, {ids: ids.length > 0 ? ids.join(",") : 0}, table);
+                    if (url.indexOf("{ids}") !== -1) {
+                        url = Table.api.replaceurl(url, {ids: ids.length > 0 ? ids.join(",") : 0}, table);
+                    }
                     Fast.api.open(url, __('Add'), $(this).data() || {});
                 });
                 // 导入按钮事件
--
libgit2 0.24.0