|
|
@@ -0,0 +1,450 @@
|
|
|
+// ==========================================================================
|
|
|
+// GFast自动生成业务逻辑层相关代码,只生成一次,按需修改,再次生成不会覆盖.
|
|
|
+// 生成日期:2021-08-31 17:58:43
|
|
|
+// 生成路径: gfast/app/system/service/plugins_manage.go
|
|
|
+// 生成人:gfast
|
|
|
+// ==========================================================================
|
|
|
+
|
|
|
+package service
|
|
|
+
|
|
|
+import (
|
|
|
+ "context"
|
|
|
+ "encoding/json"
|
|
|
+ "fmt"
|
|
|
+ "gfast/app/common/global"
|
|
|
+ "gfast/app/system/dao"
|
|
|
+ "gfast/app/system/model"
|
|
|
+ "gfast/library"
|
|
|
+ "github.com/gogf/gf/container/garray"
|
|
|
+ "github.com/gogf/gf/container/gmap"
|
|
|
+ "github.com/gogf/gf/encoding/gcompress"
|
|
|
+ "github.com/gogf/gf/encoding/gjson"
|
|
|
+ "github.com/gogf/gf/encoding/gurl"
|
|
|
+ "github.com/gogf/gf/errors/gerror"
|
|
|
+ "github.com/gogf/gf/frame/g"
|
|
|
+ "github.com/gogf/gf/net/ghttp"
|
|
|
+ "github.com/gogf/gf/os/gfile"
|
|
|
+ "github.com/gogf/gf/text/gstr"
|
|
|
+ "github.com/gogf/gf/util/gconv"
|
|
|
+)
|
|
|
+
|
|
|
+type pluginsManage struct {
|
|
|
+}
|
|
|
+
|
|
|
+var PluginsManage = new(pluginsManage)
|
|
|
+
|
|
|
+// GetList 获取列表
|
|
|
+func (s *pluginsManage) GetList(req *dao.PluginsManageSearchReq) (total, page int, list []*dao.CsPluginListRes, err error) {
|
|
|
+ //同步服务端插件商城
|
|
|
+ total, page, list, err = s.syncFromStore(req)
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// GetInfoById 通过id获取
|
|
|
+func (s *pluginsManage) GetInfoById(ctx context.Context, id int64) (info *dao.PluginsManageInfoRes, err error) {
|
|
|
+ if id == 0 {
|
|
|
+ err = gerror.New("参数错误")
|
|
|
+ return
|
|
|
+ }
|
|
|
+ var data *model.PluginsManage
|
|
|
+ err = dao.PluginsManage.Ctx(ctx).Where(dao.PluginsManage.Columns.Id, id).Scan(&data)
|
|
|
+ if err != nil {
|
|
|
+ g.Log().Error(err)
|
|
|
+ }
|
|
|
+ if data == nil || err != nil {
|
|
|
+ err = gerror.New("获取信息失败")
|
|
|
+ }
|
|
|
+ info = &dao.PluginsManageInfoRes{
|
|
|
+ Id: data.Id,
|
|
|
+ StoreId: data.StoreId,
|
|
|
+ PName: data.PName,
|
|
|
+ PTitle: data.PTitle,
|
|
|
+ PDescription: data.PDescription,
|
|
|
+ PAuth: data.PAuth,
|
|
|
+ IsInstall: data.IsInstall,
|
|
|
+ Status: data.Status,
|
|
|
+ Version: data.Version,
|
|
|
+ Price: data.Price,
|
|
|
+ DownloadTimes: data.DownloadTimes,
|
|
|
+ }
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// Add 添加
|
|
|
+func (s *pluginsManage) Add(ctx context.Context, req *dao.PluginsManageAddReq) (err error) {
|
|
|
+ _, err = dao.PluginsManage.Ctx(ctx).Insert(req)
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// Edit 修改
|
|
|
+func (s *pluginsManage) Edit(ctx context.Context, req *dao.PluginsManageEditReq) error {
|
|
|
+ _, err := dao.PluginsManage.Ctx(ctx).FieldsEx(dao.PluginsManage.Columns.Id).Where(dao.PluginsManage.Columns.Id, req.Id).
|
|
|
+ Update(req)
|
|
|
+ return err
|
|
|
+}
|
|
|
+
|
|
|
+// DeleteByIds 删除
|
|
|
+func (s *pluginsManage) DeleteByIds(ctx context.Context, ids []int) (err error) {
|
|
|
+ if len(ids) == 0 {
|
|
|
+ err = gerror.New("参数错误")
|
|
|
+ return
|
|
|
+ }
|
|
|
+ _, err = dao.PluginsManage.Ctx(ctx).Delete(dao.PluginsManage.Columns.Id+" in (?)", ids)
|
|
|
+ if err != nil {
|
|
|
+ g.Log().Error(err)
|
|
|
+ err = gerror.New("删除失败")
|
|
|
+ }
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// ChangeStatus 修改状态
|
|
|
+func (s *pluginsManage) ChangeStatus(ctx context.Context, req *dao.PluginsManageStatusReq) error {
|
|
|
+ _, err := dao.PluginsManage.Ctx(ctx).Where(dao.PluginsManage.Columns.StoreId, req.PluginId).Update(g.Map{
|
|
|
+ dao.PluginsManage.Columns.Status: req.Status,
|
|
|
+ })
|
|
|
+ return err
|
|
|
+}
|
|
|
+
|
|
|
+//同步插件商城中的插件
|
|
|
+func (s *pluginsManage) syncFromStore(req *dao.PluginsManageSearchReq) (total, page int, csPluginList []*dao.CsPluginListRes, err error) {
|
|
|
+ storeUrl := g.Cfg().GetString("plugin.serverUrl") + "/codeStore/pluginList"
|
|
|
+ res := (*ghttp.ClientResponse)(nil)
|
|
|
+ if req.PageNum == 0 {
|
|
|
+ req.PageNum = 1
|
|
|
+ }
|
|
|
+ page = req.PageNum
|
|
|
+ res, err = g.Client().Ctx(req.Ctx).Get(storeUrl, g.MapStrAny{
|
|
|
+ "pageNum": req.PageNum,
|
|
|
+ "PageSize": req.PageSize,
|
|
|
+ "pluginName": req.PTitle,
|
|
|
+ })
|
|
|
+ if err != nil {
|
|
|
+ g.Log().Error(err)
|
|
|
+ err = gerror.New("获取插件数据失败")
|
|
|
+ return
|
|
|
+ }
|
|
|
+ defer res.Close()
|
|
|
+ var data map[string]interface{}
|
|
|
+ b := res.ReadAll()
|
|
|
+ err = json.Unmarshal(b, &data)
|
|
|
+ if err != nil {
|
|
|
+ g.Log().Error(err)
|
|
|
+ err = gerror.New("获取插件数据失败")
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if gconv.Int(data["code"]) == 0 {
|
|
|
+ err = gconv.Structs((data["data"].(g.Map))["list"], &csPluginList)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ csPluginList, err = s.updatePlugins(req.Ctx, csPluginList)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ total = gconv.Int((data["data"].(g.Map))["total"])
|
|
|
+ } else {
|
|
|
+ err = gerror.New(data["msg"].(string))
|
|
|
+ return
|
|
|
+ }
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// 更新插件数据
|
|
|
+func (s *pluginsManage) updatePlugins(ctx context.Context, csList []*dao.CsPluginListRes) (newList []*dao.CsPluginListRes, err error) {
|
|
|
+ ids := make([]uint, len(csList))
|
|
|
+ for k, v := range csList {
|
|
|
+ ids[k] = v.PluginId
|
|
|
+ }
|
|
|
+ //查询插件信息
|
|
|
+ var pluginList []*model.PluginsManage
|
|
|
+ err = dao.PluginsManage.Ctx(ctx).Where(dao.PluginsManage.Columns.StoreId+" in(?)", ids).Scan(&pluginList)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ hasIds := garray.NewArraySize(len(pluginList), 100)
|
|
|
+ gmp := gmap.New()
|
|
|
+ for k, v := range pluginList {
|
|
|
+ hasIds.Set(k, v.StoreId)
|
|
|
+ gmp.Set(v.StoreId, v)
|
|
|
+ }
|
|
|
+ for _, v := range csList {
|
|
|
+ pluginId := gconv.Int(v.PluginId)
|
|
|
+ if hasIds.Len() > 0 && hasIds.Contains(pluginId) {
|
|
|
+ plugin := gmp.Get(pluginId).(*model.PluginsManage)
|
|
|
+ //修改
|
|
|
+ version := plugin.Version
|
|
|
+ if plugin.IsInstall == 0 && len(v.PluginInfo) > 0 {
|
|
|
+ version = v.PluginInfo[0].InfoVersion
|
|
|
+ }
|
|
|
+ err = s.Edit(ctx, &dao.PluginsManageEditReq{
|
|
|
+ Id: plugin.Id,
|
|
|
+ StoreId: pluginId,
|
|
|
+ PName: v.CodeName,
|
|
|
+ PTitle: v.PluginName,
|
|
|
+ PDescription: v.Description,
|
|
|
+ PAuth: v.MemName,
|
|
|
+ Status: plugin.Status,
|
|
|
+ Version: version,
|
|
|
+ Price: v.PluginPrice,
|
|
|
+ DownloadTimes: gconv.Uint(v.DownloadTimes),
|
|
|
+ IsInstall: plugin.IsInstall,
|
|
|
+ })
|
|
|
+ v.Status = plugin.Status
|
|
|
+ v.Version = version
|
|
|
+ v.IsInstall = plugin.IsInstall
|
|
|
+ v.PluginPriceStr = s.Int64ToDecimal(gconv.Int64(v.PluginPrice))
|
|
|
+ } else {
|
|
|
+ //新增
|
|
|
+ version := ""
|
|
|
+ if len(v.PluginInfo) > 0 {
|
|
|
+ version = v.PluginInfo[0].InfoVersion
|
|
|
+ }
|
|
|
+ err = s.Add(ctx, &dao.PluginsManageAddReq{
|
|
|
+ StoreId: pluginId,
|
|
|
+ PName: v.CodeName,
|
|
|
+ PTitle: v.PluginName,
|
|
|
+ PDescription: v.Description,
|
|
|
+ PAuth: v.MemName,
|
|
|
+ Status: 0,
|
|
|
+ Version: version,
|
|
|
+ Price: v.PluginPrice,
|
|
|
+ DownloadTimes: gconv.Uint(v.DownloadTimes),
|
|
|
+ IsInstall: 0,
|
|
|
+ })
|
|
|
+ v.Status = 0
|
|
|
+ v.Version = version
|
|
|
+ v.IsInstall = 0
|
|
|
+ v.PluginPriceStr = s.Int64ToDecimal(gconv.Int64(v.PluginPrice))
|
|
|
+ }
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+ newList = csList
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// DecimalToInt64 元转分
|
|
|
+func (s *pluginsManage) DecimalToInt64(decimal string) (i int64) {
|
|
|
+ pos := gstr.PosR(decimal, ".")
|
|
|
+ integer := gconv.Int64(gstr.SubStr(decimal, 0, pos)) * 100
|
|
|
+ dec := int64(0)
|
|
|
+ if pos > -1 {
|
|
|
+ dec = gconv.Int64(gstr.SubStr(decimal, pos+1, 2))
|
|
|
+ }
|
|
|
+ i = integer + dec
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// Int64ToDecimal 分转元
|
|
|
+func (s *pluginsManage) Int64ToDecimal(i int64) (decimal string) {
|
|
|
+ b := []byte(gconv.String(i))
|
|
|
+ for {
|
|
|
+ if len(b) >= 2 {
|
|
|
+ break
|
|
|
+ }
|
|
|
+ b = append([]byte{'0'}, b...)
|
|
|
+ }
|
|
|
+ integer := b[:len(b)-2]
|
|
|
+ if len(integer) == 0 {
|
|
|
+ integer = []byte{'0'}
|
|
|
+ }
|
|
|
+ dec := b[len(b)-2:]
|
|
|
+ decimal = fmt.Sprintf("%s.%s", integer, dec)
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// Install 插件安装
|
|
|
+func (s *pluginsManage) Install(ctx context.Context, req *dao.PluginsManageInstallReq) (err error) {
|
|
|
+ //生成下载链接
|
|
|
+ storeUrl := g.Cfg().GetString("plugin.serverUrl") + "/codeStoreFrontAdmin/getDownloadInfo"
|
|
|
+ res := (*ghttp.ClientResponse)(nil)
|
|
|
+ res, err = g.Client().Ctx(ctx).Get(fmt.Sprintf("%s?pluginId=%d&version=%s&token=%s", storeUrl, req.PluginId, req.Version,
|
|
|
+ gurl.RawEncode(req.RToken)))
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ defer res.Close()
|
|
|
+ var data map[string]interface{}
|
|
|
+ b := res.ReadAll()
|
|
|
+ err = json.Unmarshal(b, &data)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if gconv.Int(data["code"]) == 0 {
|
|
|
+ url := fmt.Sprintf("%s/%s&token=%s", g.Cfg().GetString("plugin.serverUrl"),
|
|
|
+ (data["data"]).(string), gurl.RawEncode(req.RToken))
|
|
|
+ //下载插件并安装
|
|
|
+ err = s.downloadAndInstall(ctx, url)
|
|
|
+ } else {
|
|
|
+ err = gerror.New(data["msg"].(string))
|
|
|
+ }
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// GetCaptcha 获取验证码
|
|
|
+func (s *pluginsManage) GetCaptcha(ctx context.Context) (idKeyC, base64stringC string, err error) {
|
|
|
+ storeUrl := g.Cfg().GetString("plugin.serverUrl") + "/captcha/get"
|
|
|
+ res := (*ghttp.ClientResponse)(nil)
|
|
|
+ res, err = g.Client().Ctx(ctx).Get(storeUrl)
|
|
|
+ if err != nil {
|
|
|
+ g.Log().Error(err)
|
|
|
+ err = gerror.New("获取验证码失败")
|
|
|
+ return
|
|
|
+ }
|
|
|
+ defer res.Close()
|
|
|
+ var data map[string]interface{}
|
|
|
+ b := res.ReadAll()
|
|
|
+ err = json.Unmarshal(b, &data)
|
|
|
+ if err != nil {
|
|
|
+ g.Log().Error(err)
|
|
|
+ err = gerror.New("获取插件数据失败")
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if gconv.Int(data["code"]) == 0 {
|
|
|
+ data = (data["data"]).(g.Map)
|
|
|
+ idKeyC = gconv.String(data["idKeyC"])
|
|
|
+ base64stringC = gconv.String(data["base64stringC"])
|
|
|
+ } else {
|
|
|
+ err = gerror.New(data["msg"].(string))
|
|
|
+ }
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// LoginR 登录
|
|
|
+func (s *pluginsManage) LoginR(ctx context.Context, loginReq *dao.PluginRLoginFormReq) (userInfo g.Map, err error) {
|
|
|
+ storeUrl := g.Cfg().GetString("plugin.serverUrl") + "/codeStoreFrontAdmin/login"
|
|
|
+ res := (*ghttp.ClientResponse)(nil)
|
|
|
+ res, err = g.Client().Ctx(ctx).Post(storeUrl, loginReq)
|
|
|
+ if err != nil {
|
|
|
+ g.Log().Error(err)
|
|
|
+ err = gerror.New("获取验证码失败")
|
|
|
+ return
|
|
|
+ }
|
|
|
+ defer res.Close()
|
|
|
+ var data map[string]interface{}
|
|
|
+ b := res.ReadAll()
|
|
|
+ err = json.Unmarshal(b, &data)
|
|
|
+ if err != nil {
|
|
|
+ g.Log().Error(err)
|
|
|
+ err = gerror.New("登录失败")
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if gconv.Int(data["code"]) == 0 {
|
|
|
+ userInfo = (data["data"]).(g.Map)
|
|
|
+ } else {
|
|
|
+ err = gerror.New(data["msg"].(string))
|
|
|
+ }
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// 下载并安装插件
|
|
|
+func (s *pluginsManage) downloadAndInstall(ctx context.Context, url string) error {
|
|
|
+ res, err := g.Client().Ctx(ctx).Get(url)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ defer res.Close()
|
|
|
+ ct := res.Header.Get("Content-Type")
|
|
|
+ if gstr.ContainsI(ct, "json") {
|
|
|
+ var data map[string]interface{}
|
|
|
+ b := res.ReadAll()
|
|
|
+ err = json.Unmarshal(b, &data)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ if gconv.Int(data["code"]) != 0 {
|
|
|
+ err = gerror.New(data["msg"].(string))
|
|
|
+ }
|
|
|
+ return err
|
|
|
+ } else {
|
|
|
+ //安装
|
|
|
+ //获取插件名称
|
|
|
+ fileName := res.Header.Get("content-disposition")
|
|
|
+ fileName = gstr.SubStr(fileName, gstr.PosR(fileName, "=")+1,
|
|
|
+ gstr.PosR(fileName, ".")-gstr.PosR(fileName, "=")-1)
|
|
|
+ err = s.InstallFile(ctx, res.ReadAll(), fileName)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// InstallFile 安装插件文件
|
|
|
+func (s *pluginsManage) InstallFile(ctx context.Context, data []byte, fileName string) (err error) {
|
|
|
+ //获取插件下载路径
|
|
|
+ downloadPath := library.GetExcPath() + "/data/installPlugins"
|
|
|
+ if !gfile.IsDir(downloadPath) {
|
|
|
+ err = gfile.Mkdir(downloadPath)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+ g.Log().Debug(downloadPath, fileName)
|
|
|
+ // 删除安装临时文件
|
|
|
+ defer gfile.Remove(downloadPath + "/" + fileName)
|
|
|
+ err = gcompress.UnZipContent(data, downloadPath)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ //获取插件配置信息
|
|
|
+ var installCfg *gjson.Json
|
|
|
+ installCfg, err = gjson.Load(downloadPath + "/" + fileName + "/install.json")
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ mustGfastVersion := installCfg.GetString("minGfastVersion")
|
|
|
+ if gstr.CompareVersion(mustGfastVersion, global.Version) > 0 {
|
|
|
+ err = gerror.New(fmt.Sprintf("您的gfast版本过低,此插件要求gfast版本为:%s", mustGfastVersion))
|
|
|
+ return
|
|
|
+ }
|
|
|
+ //获取本项目安装情况
|
|
|
+ var plugin *model.PluginsManage
|
|
|
+ err = dao.PluginsManage.Ctx(ctx).Where(dao.PluginsManage.Columns.PName, fileName).Limit(1).Scan(&plugin)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if plugin == nil {
|
|
|
+ err = gerror.New("插件信息不存在,请刷新页面后再安装。")
|
|
|
+ return
|
|
|
+ }
|
|
|
+ //复制插件文件到对应目录
|
|
|
+ //1.后端
|
|
|
+ err = gfile.Copy(downloadPath+"/"+fileName+"/go/", library.GetExcPath())
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ //2.前端
|
|
|
+ fontRoot := g.Cfg().GetString("gen.frontDir")
|
|
|
+ if !gfile.IsDir(fontRoot) {
|
|
|
+ err = gerror.New("前端路径不存在,请配置gen.frontDir")
|
|
|
+ return
|
|
|
+ }
|
|
|
+ err = gfile.Copy(downloadPath+"/"+fileName+"/vue/", fontRoot+"/src")
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ // 安装成功后修改插件安装状态及安装路径
|
|
|
+ _, err = dao.PluginsManage.Ctx(ctx).WherePri(plugin.Id).Update(g.Map{
|
|
|
+ dao.PluginsManage.Columns.IsInstall: 1,
|
|
|
+ dao.PluginsManage.Columns.Status: 1,
|
|
|
+ dao.PluginsManage.Columns.InstallPath: installCfg.GetString("installPath"),
|
|
|
+ dao.PluginsManage.Columns.Version: installCfg.GetString("version"),
|
|
|
+ })
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// PluginIsExists 判断插件是否存在
|
|
|
+func (s *pluginsManage) PluginIsExists(ctx context.Context, name string) error {
|
|
|
+ info := (*model.PluginsManage)(nil)
|
|
|
+ err := dao.PluginsManage.Ctx(ctx).Where(dao.PluginsManage.Columns.PName, name).Limit(1).
|
|
|
+ Fields(dao.PluginsManage.Columns.Id).Scan(&info)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ if info == nil {
|
|
|
+ return gerror.New("不属于官方插件,无法安装。")
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|