后台插件管理器

This commit is contained in:
yxh
2021-12-22 10:16:49 +08:00
parent 1653898e5c
commit 879744e273
9 changed files with 899 additions and 1 deletions
+142
View File
@@ -0,0 +1,142 @@
// ==========================================================================
// GFast自动生成控制器相关代码,只生成一次,按需修改,再次生成不会覆盖.
// 生成日期:2021-08-31 17:58:43
// 生成路径: gfast/app/system/api/plugins_manage.go
// 生成人:gfast
// ==========================================================================
package api
import (
"gfast/app/system/dao"
"gfast/app/system/service"
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/net/ghttp"
"github.com/gogf/gf/text/gstr"
"github.com/gogf/gf/util/gvalid"
)
type pluginsManage struct {
SystemBase
}
var PluginsManage = new(pluginsManage)
// List 列表
func (c *pluginsManage) List(r *ghttp.Request) {
var req *dao.PluginsManageSearchReq
//获取参数
if err := r.Parse(&req); err != nil {
c.FailJsonExit(r, err.(gvalid.Error).FirstString())
}
req.Ctx = r.GetCtx()
total, page, list, err := service.PluginsManage.GetList(req)
if err != nil {
c.FailJsonExit(r, err.Error())
}
result := g.Map{
"currentPage": page,
"total": total,
"list": list,
}
c.SusJsonExit(r, result)
}
// Get 获取
func (c *pluginsManage) Get(r *ghttp.Request) {
id := r.GetInt64("id")
info, err := service.PluginsManage.GetInfoById(r.GetCtx(), id)
if err != nil {
c.FailJsonExit(r, err.Error())
}
c.SusJsonExit(r, info)
}
// ChangeStatus 修改状态
func (c *pluginsManage) ChangeStatus(r *ghttp.Request) {
var req *dao.PluginsManageStatusReq
//获取参数
if err := r.Parse(&req); err != nil {
c.FailJsonExit(r, err.(gvalid.Error).FirstString())
}
if err := service.PluginsManage.ChangeStatus(r.GetCtx(), req); err != nil {
c.FailJsonExit(r, err.Error())
} else {
c.SusJsonExit(r, "状态设置成功")
}
}
// Install 插件安装
func (c *pluginsManage) Install(r *ghttp.Request) {
var req *dao.PluginsManageInstallReq
//获取参数
if err := r.Parse(&req); err != nil {
c.FailJsonExit(r, err.(gvalid.Error).FirstString())
}
if req.RToken == "" {
c.SusJsonExit(r, g.Map{
"code": -401,
"msg": "请登录",
})
}
err := service.PluginsManage.Install(r.GetCtx(), req)
if err != nil {
c.FailJsonExit(r, err.Error())
}
c.SusJsonExit(r, "安装成功")
}
// Captcha 获取验证码
func (c *pluginsManage) Captcha(r *ghttp.Request) {
idKeyC, base64stringC, err := service.PluginsManage.GetCaptcha(r.GetCtx())
if err != nil {
c.FailJsonExit(r, err.Error())
}
c.SusJsonExit(r, g.Map{
"base64stringC": base64stringC,
"idKeyC": idKeyC,
})
}
// LoginR 登录插件服务
func (c *pluginsManage) LoginR(r *ghttp.Request) {
var req *dao.PluginRLoginFormReq
// 通过Parse方法解析获取参数
err := r.Parse(&req)
if err != nil {
c.FailJsonExit(r, err.(gvalid.Error).FirstString())
}
var userInfo g.Map
userInfo, err = service.PluginsManage.LoginR(r.GetCtx(), req)
if err != nil {
c.FailJsonExit(r, err.Error())
}
c.SusJsonExit(r, userInfo)
}
// InstallOffLine 离线安装
func (c *pluginsManage) InstallOffLine(r *ghttp.Request) {
upFile := r.GetUploadFile("file")
f, err := upFile.Open()
if err != nil {
c.FailJsonExit(r, err.Error())
}
defer f.Close()
d := make([]byte, upFile.Size)
_, err = f.Read(d)
if err != nil {
c.FailJsonExit(r, err.Error())
}
fileName := upFile.Filename
fileName = gstr.SubStr(fileName, gstr.PosR(fileName, "=")+1,
gstr.PosR(fileName, ".")-gstr.PosR(fileName, "=")-1)
err = service.PluginsManage.PluginIsExists(r.GetCtx(), fileName)
if err != nil {
c.FailJsonExit(r, err.Error())
}
err = service.PluginsManage.InstallFile(r.GetCtx(), d, fileName)
if err != nil {
c.FailJsonExit(r, err.Error())
}
c.SusJsonExit(r)
}
+81
View File
@@ -0,0 +1,81 @@
// ==========================================================================
// GFast自动生成dao internal操作代码,无需手动修改,重新生成会自动覆盖.
// 生成日期:2021-08-31 17:58:43
// 生成路径: gfast/app/system/dao/internal/plugins_manage.go
// 生成人:gfast
// ==========================================================================
package internal
import (
"context"
"github.com/gogf/gf/database/gdb"
"github.com/gogf/gf/frame/g"
)
// PluginsManageDao is the manager for logic model data accessing and custom defined data operations functions management.
type PluginsManageDao struct {
Table string // Table is the underlying table name of the DAO.
Group string // Group is the database configuration group name of current DAO.
Columns PluginsManageColumns // Columns is the short type for Columns, which contains all the column names of Table for convenient usage.
}
// PluginsManageColumns defines and stores column names for table plugins_manage.
type PluginsManageColumns struct {
Id string // ID
StoreId string // 插件在商城中的id
PName string // 插件名称英文
PTitle string // 插件名称
PDescription string // 插件介绍
PAuth string // 作者
IsInstall string // 是否安装
Status string // 状态
Version string // 当前版本
Price string // 价格
DownloadTimes string // 下载次数
InstallPath string // 安装路径
}
var pluginsManageColumns = PluginsManageColumns{
Id: "id",
StoreId: "store_id",
PName: "p_name",
PTitle: "p_title",
PDescription: "p_description",
PAuth: "p_auth",
IsInstall: "is_install",
Status: "status",
Version: "version",
Price: "price",
DownloadTimes: "download_times",
InstallPath: "install_path",
}
// NewPluginsManageDao creates and returns a new DAO object for table data access.
func NewPluginsManageDao() *PluginsManageDao {
return &PluginsManageDao{
Group: "default",
Table: "plugins_manage",
Columns: pluginsManageColumns,
}
}
// DB retrieves and returns the underlying raw database management object of current DAO.
func (dao *PluginsManageDao) DB() gdb.DB {
return g.DB(dao.Group)
}
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
func (dao *PluginsManageDao) Ctx(ctx context.Context) *gdb.Model {
return dao.DB().Model(dao.Table).Safe().Ctx(ctx)
}
// Transaction wraps the transaction logic using function f.
// It rollbacks the transaction and returns the error from function f if it returns non-nil error.
// It commits the transaction and returns nil if function f returns nil.
//
// Note that, you should not Commit or Rollback the transaction in function f
// as it is automatically handled by this function.
func (dao *PluginsManageDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) {
return dao.Ctx(ctx).Transaction(ctx, f)
}
+146
View File
@@ -0,0 +1,146 @@
// ==========================================================================
// GFast自动生成dao操作代码,无需手动修改,重新生成不会自动覆盖.
// 生成日期:2021-08-31 17:58:43
// 生成路径: gfast/app/system/dao/plugins_manage.go
// 生成人:gfast
// ==========================================================================
package dao
import (
comModel "gfast/app/common/model"
"gfast/app/system/dao/internal"
"github.com/gogf/gf/os/gtime"
)
// pluginsManageDao is the manager for logic model data accessing and custom defined data operations functions management.
// You can define custom methods on it to extend its functionality as you wish.
type pluginsManageDao struct {
*internal.PluginsManageDao
}
var (
// PluginsManage is globally public accessible object for table tools_gen_table operations.
PluginsManage = pluginsManageDao{
internal.NewPluginsManageDao(),
}
)
// Fill with you ideas below.
// PluginsManageSearchReq 分页请求参数
type PluginsManageSearchReq struct {
PName string `p:"pName"` //插件名称英文
PTitle string `p:"pTitle"` //插件名称
PAuth string `p:"pAuth"` //作者
Status string `p:"status"` //状态
comModel.PageReq
}
// PluginsManageAddReq 添加操作请求参数
type PluginsManageAddReq struct {
StoreId int `p:"storeId" `
PName string `p:"pName" v:"required#插件名称英文不能为空"`
PTitle string `p:"pTitle" `
PDescription string `p:"pDescription" `
PAuth string `p:"pAuth" `
Status int `p:"status" v:"required#状态不能为空"`
Version string `p:"version" `
Price uint `p:"price" v:"required#价格不能为空"`
DownloadTimes uint `p:"downloadTimes" v:"required#下载次数不能为空"`
IsInstall int `p:"isInstall" v:"required#是否安装不能为空"`
}
// PluginsManageEditReq 修改操作请求参数
type PluginsManageEditReq struct {
Id uint `p:"id" v:"required#主键ID不能为空"`
StoreId int `p:"storeId" `
PName string `p:"pName" v:"required#插件名称英文不能为空"`
PTitle string `p:"pTitle" `
PDescription string `p:"pDescription" `
PAuth string `p:"pAuth" `
Status int `p:"status" v:"required#状态不能为空"`
Version string `p:"version" `
Price uint `p:"price" v:"required#价格不能为空"`
DownloadTimes uint `p:"downloadTimes" v:"required#下载次数不能为空"`
IsInstall int `p:"isInstall" v:"required#是否安装不能为空"`
}
// PluginsManageStatusReq 设置状态参数
type PluginsManageStatusReq struct {
PluginId uint `p:"pluginId" v:"required#pluginId不能为空"`
Status int `p:"status" v:"required#状态不能为空"`
}
// PluginsManageListRes 列表返回结果
type PluginsManageListRes struct {
Id uint `json:"id" `
PName string `json:"pName" v:"required#插件名称英文不能为空"`
PTitle string `json:"pTitle" `
PDescription string `json:"pDescription" `
PAuth string `json:"pAuth" `
Status int `json:"status" v:"required#状态不能为空"`
Version string `json:"version" `
Price uint `json:"price" v:"required#价格不能为空"`
DownloadTimes uint `json:"downloadTimes" v:"required#下载次数不能为空"`
}
// PluginsManageInfoRes 数据返回结果
type PluginsManageInfoRes struct {
Id uint `json:"id" `
StoreId int `json:"storeId" `
PName string `json:"pName" v:"required#插件名称英文不能为空"`
PTitle string `json:"pTitle" `
PDescription string `json:"pDescription" `
PAuth string `json:"pAuth" `
IsInstall int `json:"isInstall" v:"required#是否安装不能为空"`
Status int `json:"status" v:"required#状态不能为空"`
Version string `json:"version" `
Price uint `json:"price" v:"required#价格不能为空"`
DownloadTimes uint `json:"downloadTimes" v:"required#下载次数不能为空"`
}
// CsPluginListRes 插件商城获取的插件数据
type CsPluginListRes struct {
PluginId uint `orm:"plugin_id,primary" json:"pluginId"` // ID
PluginCateId uint `orm:"plugin_cate_id" json:"pluginCateId"` // 分类ID
PluginName string `orm:"plugin_name" json:"pluginName"` // 插件名称
CodeName string `orm:"code_name" json:"CodeName"` // 代码名称
PluginPrice uint `orm:"plugin_price" json:"pluginPrice"` // 售价
PluginPriceStr string `json:"pluginPriceStr"` // 售价decimal
PluginDiscount uint `orm:"plugin_discount" json:"pluginDiscount"` // 折扣
PluginCreater uint `orm:"plugin_creater" json:"pluginCreater"` // 开发人员ID
PublishDate *gtime.Time `orm:"publish_date" json:"publishDate"` // 发布日期
PluginThumb string `orm:"plugin_thumb" json:"pluginThumb"` // 插件封面
PluginImgs string `orm:"plugin_imgs" json:"pluginImgs"` // 插件预览图
CreatedBy uint64 `orm:"created_by" json:"createdBy"` // 创建人
CreatedAt *gtime.Time `orm:"created_at" json:"createdAt"` // 创建日期
UpdatedAt *gtime.Time `orm:"updated_at" json:"updatedAt"` // 修改日期
DeletedAt *gtime.Time `orm:"deleted_at" json:"deletedAt"` // 删除日期
DownloadTimes uint64 `orm:"download_times" json:"downloadTimes"` //下载次数
Description string `orm:"description" json:"description"` //插件描述
PluginInfo []*struct {
InfoId uint `json:"infoId"` // ID
PluginId uint `json:"pluginId"` // 插件ID
InfoVersion string `json:"infoVersion"` // 版本号
} `json:"pluginInfo"`
MemName string `json:"memName" orm:"mem_name"`
Status int `json:"status"`
Version string `json:"version" `
IsInstall int `json:"isInstall"`
}
// PluginsManageInstallReq 插件安装操作参数
type PluginsManageInstallReq struct {
PluginId uint `p:"pluginId" v:"required#插件ID不能为空"`
Version string `p:"version"`
RToken string `p:"rToken"`
}
// PluginRLoginFormReq 远端登录请求参数
type PluginRLoginFormReq struct {
Username string `p:"username" v:"required#账号必须" json:"username"`
Password string `p:"password" v:"required#密码不能为空" json:"password"`
VerifyCode string `p:"verifyCode" v:"required#验证码不能为空" json:"verifyCode"`
VerifyKey string `p:"verifyKey" json:"verifyKey"`
}
+24
View File
@@ -0,0 +1,24 @@
// ==========================================================================
// GFast自动生成model代码,无需手动修改,重新生成会自动覆盖.
// 生成日期:2021-08-31 17:58:43
// 生成路径: gfast/app/system/model/plugins_manage.go
// 生成人:gfast
// ==========================================================================
package model
// PluginsManage is the golang structure for table plugins_manage.
type PluginsManage struct {
Id uint `orm:"id,primary" json:"id"` // ID
StoreId int `orm:"store_id" json:"storeId"` // 插件在商城中的id
PName string `orm:"p_name" json:"pName"` // 插件名称英文
PTitle string `orm:"p_title" json:"pTitle"` // 插件名称
PDescription string `orm:"p_description" json:"pDescription"` // 插件介绍
PAuth string `orm:"p_auth" json:"pAuth"` // 作者
IsInstall int `orm:"is_install" json:"isInstall"` // 是否安装
Status int `orm:"status" json:"status"` // 状态
Version string `orm:"version" json:"version"` // 当前版本
Price uint `orm:"price" json:"price"` // 价格
DownloadTimes uint `orm:"download_times" json:"downloadTimes"` // 下载次数
InstallPath string `orm:"install_oath" json:"installPath"` // 安装路径
}
+37
View File
@@ -0,0 +1,37 @@
// ==========================================================================
// GFast自动生成路由代码,只生成一次,按需修改,再次生成不会覆盖.
// 生成日期:2021-08-31 17:58:43
// 生成路径: gfast/app/system/router/plugins_manage.go
// 生成人:gfast
// ==========================================================================
package router
import (
"gfast/app/system/api"
"gfast/middleware"
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/net/ghttp"
)
//加载路由
func init() {
s := g.Server()
s.Group("/", func(group *ghttp.RouterGroup) {
group.Group("/system", func(group *ghttp.RouterGroup) {
group.Group("/pluginsManage", func(group *ghttp.RouterGroup) {
//gToken拦截器
api.GfToken.AuthMiddleware(group)
//context拦截器
group.Middleware(middleware.Ctx, middleware.Auth)
group.GET("list", api.PluginsManage.List)
group.GET("get", api.PluginsManage.Get)
group.PUT("changeStatus", api.PluginsManage.ChangeStatus)
group.POST("install", api.PluginsManage.Install)
group.GET("captcha", api.PluginsManage.Captcha)
group.POST("loginR", api.PluginsManage.LoginR)
group.POST("installOffLine", api.PluginsManage.InstallOffLine)
})
})
})
}
+450
View File
@@ -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
}
+5
View File
@@ -88,3 +88,8 @@
SecretKey = "填写您的SecretKey"
[upload.local] #本地上传配置
UpPath = "/pub_upload/" #上传路径
# 插件管理
[plugin]
serverUrl = "http://localhost:8199" #获取插件商城插件列表
+13
View File
@@ -14,6 +14,9 @@ import (
"github.com/gogf/gf/text/gstr"
"github.com/gogf/gf/util/gconv"
"net"
"os"
"os/exec"
"path/filepath"
"strings"
)
@@ -247,3 +250,13 @@ func CurrencyLong(currency interface{}) int64 {
}
return 0
}
func GetExcPath() string {
file, _ := exec.LookPath(os.Args[0])
// 获取包含可执行文件名称的路径
path, _ := filepath.Abs(file)
// 获取可执行文件所在目录
index := strings.LastIndex(path, string(os.PathSeparator))
ret := path[:index]
return strings.Replace(ret, "\\", "/", -1)
}
+1 -1
View File
@@ -3,7 +3,7 @@ package packed
import "github.com/gogf/gf/os/gres"
func init() {
if err := gres.Add("H4sIAAAAAAAC/wrwZmYRYeBg4GCoCVQMZkACIgycDMXlienpqUX6UFovqzg/LzSElYHxbaB+4pvIs3m33QT2PdfsyO1vU/mxIrl72Yml7f8WtN9oF7Vctk3w5Nl3m9ZmcXRcPGafm7vUN1eZY1bUi4VOgUf4Lmj4vl2mrzzpWbTIEo92ofpNXcnRWicmWxif/vns9kx+7aKvsxZpcD3KEuZ5sGLdHR7ehRs1WVy5H3+Xaf1+mvviLv0N65idS1l1w7ICDZSedbW+OvXq9FKpgqmCWh2pbBvfxx+PsfheNufdxO87nt+NLq9+/W6xo9FMhUWs6Rs9+7NmMq1W8rjgOcOe/dji4+wBTu5P3EW61eTdQ0INRbOEw0sFkuddmJ3KIysTMlvwolyyVuXS60fEua7ppO+y1nz9ycnqO0vncuvzc97N+//7+/L27HsHZ33+0Lp9q+Gf7c/XyS7qucr02kbctOjdv4d3apuWFBTcNjDI3s/GxjYnSo19nmeeRNDpUk1JmTV6ilcvJXBenXo0Ktcx0klKzGLH3siVIdOsJRXOyYl+s9HzET+292yC6omvYaHNokmTFMzXb/NoTry2rkZi6pRlevsuzZ6dK7t9zx5vs8qp23cyLM66PK1166qq17a9HN21Tpd1fXTtftv+yQtpKN9U/usR+3PH+h/Xtx+ezPz/oPnhxweXln68oqGRdoOBUUe+u4b/9herTMfA5bNuMOz0ELLbmJj5dpEG2/bcQw7Opa4G0vcO9HSY8QoWHexYOb9ebJPZGpF+ptfZHe5XfD9rypz7tm73dkMbuR63r5eWOCm9lxZtF/XMrAiN0eQJnhDHxZyZusFS/tSDPNvv5rsWf5TpfbW0sznmVZC8UOFSuydHzm6xu2Pw5X+zTc+/dXGdNk+W6z1VFAw/5ex3x+cUM3tY7kQewRmLv2fe868t/zxz8876W6/91/Msvrq4fFbw62aZhs8vDx9xEC159ER+3WTrc/n3d/5mrv/vL+ma2eB3pr9TUVF7e27C2zdhb1P093Uw/V3/+1/d/Ayjo5kOR3sPneBew2Pcxp06g8Pg09E3Ojp1coasLw5wbXGa51L+uu/zk0Cfpburn+TZT1OfEi+4OPh7V3nN/b8/xX8mMgTPfhnYUXiv6dtysdnzawvK60r+vdtVfX7u5HU+tWKXG/YG29iIh8fZZHz6avn/Tvm2bX/vBb9P8F1m11X644DZs2V23ze8/j5v1273TUdrXfbN+qu5yPc0y2UzqaMxZ1jC9DZsOG/5XjO78lTfuuL5mw7Hfwx/w9Jm+EKDVaP0X5/04awatlUzFrAFpgUmND3J8TtR/G+b75vTH35cr9k66QoXS3xSc5u8ulj2VpNYyb+iOftMjl08eKR+xz+tGYLxQRw8604zS+Sk1SuFGx2ruFW289pPfQaG//8DvNk5ZMLCYo4xMzBcU2RggBUIDAy1aAUCO6JAAJcB7wP1E0G6kdUEeDMyiTAjChRkk0EFCgxsawSReIsXhFHYnQIBAgz/HQVZGLA4jJUNJM/EwMTQycDA4M8C4gECAAD//+GYqUjuBAAA"); err != nil {
if err := gres.Add("H4sIAAAAAAAC/wrwZmYRYeBg4GA4xzstmAEJiDBwMhSXJ6anpxbpQ2m9rOL8vNAQVgbG0uZDiW8iz+bddhPY91yzI7e/TeXHiuTuZRwBXy7IfxH4vUHp+BUzpZ03Y7eF8jIa3vqxfO3aLStzWRyDuW1DNLpuMEotXXn3S6rLqZpuJ+1LE4/Ir31jMY3pk8q5M0X7fpY9u+wVs3dZ5qy2HXGs3BZa2eZLHaVWOwVsMag6P3FPfBzH9dpOX2EJreyMjQFczYIbw2VCroXF65k2vO4JcJTZLf/7X+mZ1vL849lyX+W2V32/9vfarv8rjOf4CAQ2b76R2P/uBtPrRfMXGKb8Y5Lgl7/friS7UD5QZ1WNSGDg8ZAXoTEmjj0VS8xPasjKlEwXDJRPzPrRtb5T70r85jkv8o6sOc398U6yyrx3Np9nVR+Ut58jt+4r37U97fpV0dJ3/0f9u6XoFaG74WRwoPL7d/Pv3VX34GQv1+Xe/MvSwODBlY2WH1yKUj00ry5VLdiwq6XkeINqyDUx76WsuZySEQ/+vT3rtHDDHQ+Gwm8aNz9bGM/tqZ590Mv+erQrc1iH76+dlRvdtHg2Vz1cvGGJRelF0ft3Ul6vePr0bsFk8cq53Bu6boheXXS6sdbhR8z2/PfPt+3/eeb2Hfvcrcvf3zr4qrFlzuZydcYFMxK5WTaUSEjO6bSaqnSMVXnbzKu9yW8q1Mv33N///bv1wX/xkadzck6yiBp0/uXcqKA944T7/bLGq5Nvb52454cRF8++TPbfuUkrRNIZRM2NlPU3Gp2RWJf+TCxhKfetyIgvNkncL+pTl7ktd7gq5PFl+7sKfznXkF+73f99Sy51+ilqaFW6/kvf+9/7/6yy40mQNrblEjwXHfD/TOLnzfz/zvnfs/etf7+z/FLIyvOJbBvKN7U//3Sqm813r937+7/vXSu7UHXLOiJ4ZX+SsF3J2p0rz9vnsK1d/u/dxKxC+cnr0+u7Mq5uPFi21stM3LhxKrfOHe5z1WdmlZw76X9L8lqm3y29tZY3NF5tv2fcUXBjuUndrWV+hyRjqtJe7PibF+HwPuX9l6P995rLvr9/v0ud/WBz/u7jc1/633v+Z6+FaVe37P7jFgUvS4NOi2zJ8FN353u25ZHEzPh8nrzdLY2Np2Yl6O1pkpS8PIf7vJOe3MOlXjcsjyi/WfZThC+/+vr92y/kytkW/7q1xEnxvbZou6hr5gyR6dyHRZY8P+SQxZlzrt3oR/T55t5nCTbsi3/dOuKoW7qO37lwp92SI2e32N3ZcMbcUY5Nv22di9yl4OefDESmn3b2ujP1dPMfkb0n5Q4ZMMkeZTjqonwrcfknyxdJPVIuM50bOSdtspz0/Euu9O3p7z7mv6xfqPWvsfOBdk7gz82ZG0O6Lk9VcYhYkp/hM+/J7UkPHv5SmaEY78Whk7eK+UWO2n616yHPCp12x2T/kWdg+P8/wJudo1B/1aqHzAwMtxQZGGBlBQPDRbSygh1RVoCLh+rmQ4kg3chqArwZmUSYEWUNssmgsgYGtjWCSLwlD8Io7E6BAAGG/446LAxYHMbKBpJnYmBi6GRgYMhiAfEAAQAA//8tF7e5CQUAAA=="); err != nil {
panic("add binary content to resource manager failed: " + err.Error())
}
}