Browse Source

update

master
dengbiao 2 months ago
parent
commit
f633788be9
55 changed files with 3452 additions and 4358 deletions
  1. +1
    -1
      README.md
  2. +10
    -44
      app/cfg/cfg_app.go
  3. +10
    -20
      app/cfg/init_cfg.go
  4. +0
    -2
      app/cfg/init_task.go
  5. +14
    -0
      app/db/dao/sys_cfg_dao.go
  6. +0
    -112
      app/db/db.go
  7. +0
    -82
      app/db/db_sys_cfg.go
  8. +0
    -104
      app/db/dbs.go
  9. +0
    -194
      app/db/dbs_map.go
  10. +124
    -0
      app/db/implement/sys_cfg_implement.go
  11. +37
    -0
      app/enum/enum_admin.go
  12. +19
    -0
      app/enum/enum_permission_group.go
  13. +19
    -0
      app/enum/enum_role.go
  14. +60
    -0
      app/hdl/hdl_login.go
  15. +205
    -0
      app/hdl/hdl_register.go
  16. +649
    -0
      app/hdl/hdl_role.go
  17. +39
    -0
      app/lib/auth/auth.go
  18. +4
    -8
      app/lib/auth/base.go
  19. +33
    -0
      app/lib/validate/validate_comm.go
  20. +8
    -0
      app/md/app_redis_key.go
  21. +7
    -0
      app/md/md_api_response.go
  22. +11
    -0
      app/md/md_login.go
  23. +13
    -0
      app/md/md_register.go
  24. +91
    -0
      app/md/md_role.go
  25. +5
    -0
      app/md/md_white_uri.go
  26. +14
    -60
      app/mw/mw_auth.go
  27. +0
    -96
      app/mw/mw_auth_jwt.go
  28. +0
    -22
      app/mw/mw_checker.go
  29. +5
    -68
      app/mw/mw_db.go
  30. +28
    -19
      app/router/router.go
  31. +31
    -0
      app/svc/svc_admin.go
  32. +53
    -0
      app/svc/svc_auth.go
  33. +1
    -1
      app/svc/svc_db.go
  34. +33
    -0
      app/svc/svc_login.go
  35. +58
    -0
      app/svc/svc_master.go
  36. +184
    -0
      app/svc/svc_role.go
  37. +1
    -76
      app/svc/svc_sys_cfg_get.go
  38. +0
    -49
      app/utils/aes.go
  39. +0
    -46
      app/utils/auth.go
  40. +5
    -2
      app/utils/cache/redis.go
  41. +146
    -0
      app/utils/ip.go
  42. +28
    -0
      app/utils/rand.go
  43. +16
    -0
      app/utils/url.go
  44. +23
    -0
      cmd_dao.bat
  45. +1
    -1
      cmd_db.bat
  46. +23
    -0
      cmd_implement.bat
  47. +499
    -1208
      docs/docs.go
  48. +485
    -1156
      docs/swagger.json
  49. +353
    -790
      docs/swagger.yaml
  50. +9
    -0
      etc/ps/ConvertToUpperCase.ps1
  51. +14
    -0
      etc/template/template_implement.tpl
  52. +5
    -0
      etc/template/template_interface.tpl
  53. +63
    -33
      go.mod
  54. +15
    -8
      main.go
  55. +0
    -156
      test/zhimeng_api.go

+ 1
- 1
README.md View File

@@ -1,4 +1,4 @@
# applet
# 广告站长平台

## 要看 nginx.conf 和 wap conf



+ 10
- 44
app/cfg/cfg_app.go View File

@@ -5,51 +5,17 @@ import (
)

type Config struct {
Debug bool `yaml:"debug"`
Prd bool `yaml:"prd"`
CurlDebug bool `yaml:"curldebug"`
SrvAddr string `yaml:"srv_addr"`
RedisAddr string `yaml:"redis_addr"`
DB DBCfg `yaml:"db"`
Log LogCfg `yaml:"log"`
ArkID ArkIDCfg `yaml:"arkid"`
Admin AdminCfg `yaml:"admin"`
Official OfficialCfg `yaml:"official"`
WxappletFilepath WxappletFilepathCfg `yaml:"wxapplet_filepath"`
Local bool
AppComm AppCommCfg `yaml:"app_comm"`
Debug bool `yaml:"debug"`
Prd bool `yaml:"prd"`
CurlDebug bool `yaml:"curldebug"`
SrvAddr string `yaml:"srv_addr"`
RedisAddr string `yaml:"redis_addr"`
DB DBCfg `yaml:"db"`
Log LogCfg `yaml:"log"`
Local bool
}

// 公共模块
type AppCommCfg struct {
URL string `yaml:"url"`
}

// OfficialCfg is 官网

type OfficialCfg struct {
URL string `yaml:"url"`
}
type WxappletFilepathCfg struct {
URL string `yaml:"url"`
}

// AdminCfg is 后台接口调用需要
type AdminCfg struct {
URL string `yaml:"url"`
IURL string `yaml:"iurl"`
AesKey string `yaml:"api_aes_key"`
AesIV string `yaml:"api_aes_iv"`
Host string `yaml:"host"`
}

type ArkIDCfg struct {
Admin string `yaml:"admin"`
AdminPassword string `yaml:"admin_password"`
Url string `yaml:"url`
}

//数据库配置结构体
// 数据库配置结构体
type DBCfg struct {
Host string `yaml:"host"` //ip及端口
Name string `yaml:"name"` //库名
@@ -62,7 +28,7 @@ type DBCfg struct {
Path string `yaml:"path"` //日志文件存放路径
}

//日志配置结构体
// 日志配置结构体
type LogCfg struct {
AppName string `yaml:"app_name" `
Level string `yaml:"level"`


+ 10
- 20
app/cfg/init_cfg.go View File

@@ -7,24 +7,19 @@ import (
"gopkg.in/yaml.v2"
)

//配置文件数据,全局变量
// 配置文件数据,全局变量
var (
Debug bool
Prd bool
CurlDebug bool
SrvAddr string
RedisAddr string
DB *DBCfg
Log *LogCfg
ArkID *ArkIDCfg
Admin *AdminCfg
Official *OfficialCfg
WxappletFilepath *WxappletFilepathCfg
Local bool
AppComm *AppCommCfg
Debug bool
Prd bool
CurlDebug bool
SrvAddr string
RedisAddr string
DB *DBCfg
Log *LogCfg
Local bool
)

//初始化配置文件,将cfg.yml读入到内存
// 初始化配置文件,将cfg.yml读入到内存
func InitCfg() {
//用指定的名称、默认值、使用信息注册一个string类型flag。
path := flag.String("c", "etc/cfg.yml", "config file")
@@ -50,11 +45,6 @@ func InitCfg() {
CurlDebug = conf.CurlDebug
DB = &conf.DB
Log = &conf.Log
ArkID = &conf.ArkID
RedisAddr = conf.RedisAddr
SrvAddr = conf.SrvAddr
Admin = &conf.Admin
Official = &conf.Official
WxappletFilepath = &conf.WxappletFilepath
AppComm = &conf.AppComm
}

+ 0
- 2
app/cfg/init_task.go View File

@@ -28,10 +28,8 @@ func InitTaskCfg() {
Debug = conf.Debug
DB = &conf.DB
Log = &conf.Log
Admin = &conf.Admin
RedisAddr = conf.RedisAddr
Local = conf.Local
AppComm = &conf.AppComm
}

var MemCache mc.Cache


+ 14
- 0
app/db/dao/sys_cfg_dao.go View File

@@ -0,0 +1,14 @@
package dao

import "applet/app/db/model"

type SysCfgDao interface {
SysCfgGetAll() (*[]model.SysCfg, error)
SysCfgGetOneNoDataNoErr(key string) (*model.SysCfg, error)
SysCfgGetOne(key string) (*model.SysCfg, error)
SysCfgInsert(key, val, memo string) bool
SysCfgUpdate(key, val string) bool
SysCfgGetWithDb(HKey string) string
SysCfgDel(HKey string) error
SysCfgFindWithDb(keys ...string) map[string]string
}

+ 0
- 112
app/db/db.go View File

@@ -1,112 +0,0 @@
package db

import (
"database/sql"
"fmt"
"os"
"time"

_ "github.com/go-sql-driver/mysql" //必须导入mysql驱动,否则会panic
"xorm.io/xorm"
"xorm.io/xorm/log"

"applet/app/cfg"
"applet/app/utils/logx"
)

var Db *xorm.Engine

//根据DB配置文件初始化数据库
func InitDB(c *cfg.DBCfg) error {
var (
err error
f *os.File
)
//创建Orm引擎
if Db, err = xorm.NewEngine("mysql", fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4", c.User, c.Psw, c.Host, c.Name)); err != nil {
return err
}
Db.SetConnMaxLifetime(c.MaxLifetime * time.Second) //设置最长连接时间
Db.SetMaxOpenConns(c.MaxOpenConns) //设置最大打开连接数
Db.SetMaxIdleConns(c.MaxIdleConns) //设置连接池的空闲数大小
if err = Db.Ping(); err != nil { //尝试ping数据库
return err
}
if c.ShowLog { //根据配置文件设置日志
Db.ShowSQL(true) //设置是否打印sql
Db.Logger().SetLevel(0) //设置日志等级
//修改日志文件存放路径文件名是%s.log
path := fmt.Sprintf(c.Path, c.Name)
f, err = os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0777)
if err != nil {
os.RemoveAll(c.Path)
if f, err = os.OpenFile(c.Path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0777); err != nil {
return err
}
}
logger := log.NewSimpleLogger(f)
logger.ShowSQL(true)
Db.SetLogger(logger)
}
return nil
}

/********************************************* 公用方法 *********************************************/

// 数据批量插入
func DbInsertBatch(Db *xorm.Engine, m ...interface{}) error {
if len(m) == 0 {
return nil
}
id, err := Db.Insert(m...)
if id == 0 || err != nil {
return logx.Warn("cannot insert data :", err)
}
return nil
}

// QueryNativeString 查询原生sql
func QueryNativeString(Db *xorm.Engine, sql string, args ...interface{}) ([]map[string]string, error) {
results, err := Db.SQL(sql, args...).QueryString()
return results, err
}

// UpdateComm common update
func UpdateComm(Db *xorm.Engine, id interface{}, model interface{}) (int64, error) {
row, err := Db.ID(id).Update(model)
return row, err
}

// InsertComm common insert
func InsertComm(Db *xorm.Engine, model interface{}) (int64, error) {
row, err := Db.InsertOne(model)
return row, err
}

// ExecuteOriginalSql 执行原生sql
func ExecuteOriginalSql(session *xorm.Session, sql string) (sql.Result, error) {
result, err := session.Exec(sql)
if err != nil {
_ = logx.Warn(err)
return nil, err
}
return result, nil
}

// GetComm
// payload *model
// return *model,has,err
func GetComm(Db *xorm.Engine, model interface{}) (interface{}, bool, error) {
has, err := Db.Get(model)
if err != nil {
_ = logx.Warn(err)
return nil, false, err
}
return model, has, nil
}

// InsertCommWithSession common insert
func InsertCommWithSession(session *xorm.Session, model interface{}) (int64, error) {
row, err := session.InsertOne(model)
return row, err
}

+ 0
- 82
app/db/db_sys_cfg.go View File

@@ -1,82 +0,0 @@
package db

import (
"applet/app/db/model"
"applet/app/md"
"applet/app/utils/cache"
"applet/app/utils/logx"
"fmt"
"xorm.io/xorm"
)

// 系统配置get
func SysCfgGetAll(Db *xorm.Engine) (*[]model.SysCfg, error) {
var cfgList []model.SysCfg
if err := Db.Cols("key,val,memo").Find(&cfgList); err != nil {
return nil, logx.Error(err)
}
return &cfgList, nil
}

// 获取一条记录
func SysCfgGetOne(Db *xorm.Engine, key string) (*model.SysCfg, error) {
var cfgList model.SysCfg
if has, err := Db.Where("`key`=?", key).Get(&cfgList); err != nil || has == false {
return nil, logx.Error(err)
}
return &cfgList, nil
}

// 返回最后插入id
func SysCfgInsert(Db *xorm.Engine, key, val, memo string) bool {
cfg := model.SysCfg{Key: key, Val: val, Memo: memo}
_, err := Db.InsertOne(&cfg)
if err != nil {
logx.Error(err)
return false
}
return true
}

func SysCfgUpdate(Db *xorm.Engine, key, val, memo string) bool {
cfg := model.SysCfg{Key: key, Val: val, Memo: memo}
_, err := Db.Where("`key`=?", key).Cols("val,memo").Update(&cfg)
if err != nil {
logx.Error(err)
return false
}
return true
}
func SysCfgGetWithDb(eg *xorm.Engine, masterId string, HKey string) string {
cacheKey := fmt.Sprintf(md.AppCfgCacheKey, masterId) + HKey
get, err := cache.GetString(cacheKey)
if err != nil || get == "" {
cfg, err := SysCfgGetOne(eg, HKey)
if err != nil || cfg == nil {
_ = logx.Error(err)
return ""
}

// key是否存在
cacheKeyExist := false
if cache.Exists(cacheKey) {
cacheKeyExist = true
}

// 设置缓存
_, err = cache.SetEx(cacheKey, cfg.Val, 30)
if err != nil {
_ = logx.Error(err)
return ""
}
if !cacheKeyExist { // 如果是首次设置 设置过期时间
_, err := cache.Expire(cacheKey, md.CfgCacheTime)
if err != nil {
_ = logx.Error(err)
return ""
}
}
return cfg.Val
}
return get
}

+ 0
- 104
app/db/dbs.go View File

@@ -1,104 +0,0 @@
package db

import (
"fmt"
"os"
"time"

"xorm.io/xorm"
"xorm.io/xorm/log"

"applet/app/cfg"
"applet/app/db/model"
"applet/app/utils/logx"
)

var DBs map[string]*xorm.Engine

// 每个站长都要有自己的syscfg 缓存, 键是站长id,值是缓存名
// var SysCfgMapKey map[string]string

func NewDB(c *cfg.DBCfg) (*xorm.Engine, error) {
db, err := xorm.NewEngine("mysql", fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4", c.User, c.Psw, c.Host, c.Name))
if err != nil {
return nil, err
}
db.SetConnMaxLifetime(c.MaxLifetime * time.Second)
db.SetMaxOpenConns(c.MaxOpenConns)
db.SetMaxIdleConns(c.MaxIdleConns)
err = db.Ping()
if err != nil {
return nil, err
}
if c.ShowLog {
db.ShowSQL(true)
db.Logger().SetLevel(log.LOG_DEBUG)
f, err := os.OpenFile(c.Path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0777)
if err != nil {
os.RemoveAll(c.Path)
if f, err = os.OpenFile(c.Path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0777); err != nil {
return nil, err
}
}
logger := log.NewSimpleLogger(f)
logger.ShowSQL(true)
db.SetLogger(logger)
}
return db, nil
}

// InitDBs is 初始化多数据库
func InitDBs(ch chan int) {
// 初始化多数据库
var tables *[]model.DbMapping
InitMapDbs(cfg.DB, cfg.Prd)
ch <- 1
// 每10s 查询一次模板数据库的db mapping 表,如果有新增数据库记录,则添加到 DBs中
ticker := time.NewTicker(time.Duration(time.Second * 120))
for range ticker.C {
if cfg.Prd {
tables = GetAllDatabasePrd() //默认获取全部
} else {
tables = GetAllDatabaseDev() //默认获取全部
}
if tables == nil {
logx.Warn("no database tables data")
continue
}
for _, item := range *tables {
_, ok := DBs[item.DbMasterId]
if !ok {
// 不在db.DBs 则添加进去
dbCfg := cfg.DBCfg{
Name: item.DbName,
ShowLog: cfg.DB.ShowLog,
MaxLifetime: cfg.DB.MaxLifetime,
MaxOpenConns: cfg.DB.MaxOpenConns,
MaxIdleConns: cfg.DB.MaxIdleConns,
Path: fmt.Sprintf(cfg.DB.Path, item.DbName),
}
if item.DbHost != "" && item.DbUsername != "" && item.DbPassword != "" {
dbCfg.Host = item.DbHost
dbCfg.User = item.DbUsername
dbCfg.Psw = item.DbPassword
} else {
dbCfg.Host = cfg.DB.Host
dbCfg.User = cfg.DB.User
dbCfg.Psw = cfg.DB.Psw
}
e, err := NewDB(&dbCfg)
if err != nil || e == nil {
logx.Warnf("db engine can't create, please check config, params[host:%s, user:%s, psw: %s, name: %s], err: %v", dbCfg.Host, dbCfg.User, dbCfg.Psw, dbCfg.Name, err)
} else {
DBs[item.DbMasterId] = e
}
}
// 如果 被禁用则删除
if item.DeletedAt == 1 {
logx.Infof("%s have been removed", item.DbMasterId)
delete(DBs, item.DbMasterId)
}
}
}

}

+ 0
- 194
app/db/dbs_map.go View File

@@ -1,194 +0,0 @@
package db

import (
"errors"
"fmt"

"xorm.io/xorm"

"applet/app/cfg"
"applet/app/db/model"
"applet/app/utils/logx"
)

func MapBaseExists() (bool, error) {
return Db.IsTableExist("db_mapping")
}

func InitMapDbs(c *cfg.DBCfg, prd bool) {
var tables *[]model.DbMapping
exists, err := MapBaseExists()
if !exists || err != nil {
logx.Fatalf("db_mapping not exists : %v", err)
}
// tables := MapAllDatabases(debug)
if prd {
tables = GetAllDatabasePrd() //debug 获取生产
} else {
tables = GetAllDatabaseDev() //debug 获取开发
}

if tables == nil {
logx.Fatal("no database tables data")
}
var e *xorm.Engine
DBs = map[string]*xorm.Engine{}
for _, v := range *tables {
if v.DbName != "" && v.DeletedAt == 0 && v.DbName != c.Name {
dbCfg := cfg.DBCfg{
Name: v.DbName,
ShowLog: c.ShowLog,
MaxLifetime: c.MaxLifetime,
MaxOpenConns: c.MaxOpenConns,
MaxIdleConns: c.MaxIdleConns,
Path: fmt.Sprintf(c.Path, v.DbName),
}
if v.DbHost != "" && v.DbUsername != "" && v.DbPassword != "" {
dbCfg.Host = v.DbHost
dbCfg.User = v.DbUsername
dbCfg.Psw = v.DbPassword
} else {
dbCfg.Host = c.Host
dbCfg.User = c.User
dbCfg.Psw = c.Psw
}
e, err = NewDB(&dbCfg)
if err != nil || e == nil {
logx.Warnf("db engine can't create, please check config, params[host:%s, user:%s, psw: %s, name: %s], err: %v", dbCfg.Host, dbCfg.User, dbCfg.Psw, dbCfg.Name, err)
} else {
DBs[v.DbMasterId] = e
}
}
}
}

func MapAllDatabases(debug bool) *[]model.DbMapping {
sql := "`db_name` != ?"
if debug {
sql = "`db_name` = ?"
}
var m []model.DbMapping
if err := Db.Where(sql, cfg.DB.Name).Find(&m); err != nil || len(m) == 0 {
logx.Warn(err)
return nil
}
return &m
}

// GetAllDatabasePrd is 获取生成库 所有db 除了 deleted_at = 1 的
func GetAllDatabasePrd() *[]model.DbMapping {
var m []model.DbMapping
if err := Db.Where("deleted_at != ? AND is_dev = '0' ", 1).Find(&m); err != nil || len(m) == 0 {
logx.Warn(err)
return nil
}
return &m
}

// GetAllDatabaseDev is 获取开发库 所有db 除了 deleted_at = 1 的
func GetAllDatabaseDev() *[]model.DbMapping {
var m []model.DbMapping
var err error
fmt.Println("cfg.Local is: ", cfg.Local)
if cfg.Local { // 本地调试 加快速度
fmt.Println("notice:LOCAL TEST, only masterId:** 123456 ** available!")
err = Db.Where("deleted_at != ? AND is_dev = '1' AND db_master_id=?", 1, 123456).Find(&m)
} else {
err = Db.Where("deleted_at != ? AND is_dev = '1' ", 1).Find(&m)
}

//err := Db.Where("deleted_at != ? AND is_dev = '1' and db_master_id='123456'", 1).Find(&m)
if err != nil || len(m) == 0 {
logx.Warn(err)
return nil
}
return &m
}

//GetDatabaseByMasterID is 根据站长id 获取对应的的数据库信息
func GetDatabaseByMasterID(Db *xorm.Engine, id string) (*model.DbMapping, error) {
var m model.DbMapping
has, err := Db.Where("db_master_id=?", id).Get(&m)
if !has {
return nil, errors.New("Not Found DB data by " + id)
}
if err != nil {
return nil, err
}
if m.DbHost == "" {
m.DbHost = cfg.DB.Host
m.DbUsername = cfg.DB.User
m.DbPassword = cfg.DB.Psw
}
return &m, nil
}

//SessionGetDatabaseByMasterID is 根据站长id 获取对应的的数据库信息
func SessionGetDatabaseByMasterID(Db *xorm.Session, id string) (*model.DbMapping, error) {
var m model.DbMapping
has, err := Db.Where("db_master_id=?", id).Get(&m)
if !has {
return nil, errors.New("Not Found DB data by " + id)
}
if err != nil {
return nil, err
}
if m.DbHost == "" {
m.DbHost = cfg.DB.Host
m.DbName = cfg.DB.Name
m.DbUsername = cfg.DB.User
m.DbPassword = cfg.DB.Psw
}
return &m, nil
}

// 获取自动任务队列
func MapCrontabCfg(eg *xorm.Engine) *[]model.SysCfg {
var c []model.SysCfg
// 数据库查询如果有下划线会认为是一个任意字符
if err := eg.Where("`key` LIKE 'mall_cron\\_%' AND val != ''").Cols("`key`,`val`").Find(&c); err != nil || len(c) == 0 {
logx.Warn(err)
return nil
}
return &c
}

// 获取官方域名
func GetOfficialDomainInfoByType(Db *xorm.Engine, masterId, key string) (string, error) {
type SysCfg struct {
K string
V string
Memo string
}
var domainBase SysCfg

has, err := Db.Where("k=?", "domain_base").Get(&domainBase)
if err != nil {
return "", err
}
if has == false {
return "", errors.New("can not find key by : domain_base")
}

if key == "wap" {
return "h5." + masterId + "." + domainBase.V, nil
}

if key == "api" {
var apiDomain SysCfg
has, err = Db.Where("k=?", "domain_api_base").Get(&apiDomain)
if err != nil {
return "", err
}
if has == false {
return "", errors.New("can not find key by : domain_api_base")
}
return apiDomain.V, nil
}

if key == "admin" {
return "admin." + masterId + "." + domainBase.V, nil
}
// 默认返回H5的
return "h5." + masterId + "." + domainBase.V, nil
}

+ 124
- 0
app/db/implement/sys_cfg_implement.go View File

@@ -0,0 +1,124 @@
package implement

import (
"applet/app/db/dao"
"applet/app/db/model"
"applet/app/md"
"applet/app/utils/cache"
"applet/app/utils/logx"
"fmt"
"xorm.io/xorm"
)

func NewSysCfgDb(engine *xorm.Engine, masterId string) dao.SysCfgDao {
return &SysCfgDb{
Db: engine,
MasterId: masterId,
}
}

type SysCfgDb struct {
Db *xorm.Engine
MasterId string
}

func (s SysCfgDb) SysCfgGetAll() (*[]model.SysCfg, error) {
var cfgList []model.SysCfg
if err := s.Db.Cols("key,val,memo").Find(&cfgList); err != nil {
return nil, logx.Error(err)
}
return &cfgList, nil
}

func (s SysCfgDb) SysCfgGetOneNoDataNoErr(key string) (*model.SysCfg, error) {
var cfgList model.SysCfg
has, err := s.Db.Where("`key`=?", key).Get(&cfgList)
if err != nil {
return nil, logx.Error(err)
}
if !has {
return nil, nil
}
return &cfgList, nil
}

func (s SysCfgDb) SysCfgGetOne(key string) (*model.SysCfg, error) {
var cfgList model.SysCfg
if has, err := s.Db.Where("`key`=?", key).Get(&cfgList); err != nil || has == false {
return nil, logx.Error(err)
}
return &cfgList, nil
}

func (s SysCfgDb) SysCfgInsert(key, val, memo string) bool {
cfg := model.SysCfg{Key: key, Val: val, Memo: memo}
_, err := s.Db.InsertOne(&cfg)
if err != nil {
logx.Error(err)
return false
}
return true
}

func (s SysCfgDb) SysCfgUpdate(key, val string) bool {
cfg := model.SysCfg{Key: key, Val: val}
_, err := s.Db.Where("`key`=?", key).Cols("val").Update(&cfg)
if err != nil {
logx.Error(err)
return false
}
s.SysCfgDel(key)
return true
}

func (s SysCfgDb) SysCfgGetWithDb(HKey string) string {
cacheKey := fmt.Sprintf(md.AppCfgCacheKey, s.MasterId, HKey[0:1])
get, err := cache.HGetString(cacheKey, HKey)
if err != nil || get == "" {
cfg, err := s.SysCfgGetOne(HKey)
if err != nil || cfg == nil {
_ = logx.Error(err)
return ""
}

// key是否存在
cacheKeyExist := false
if cache.Exists(cacheKey) {
cacheKeyExist = true
}

// 设置缓存
_, err = cache.HSet(cacheKey, HKey, cfg.Val)
if err != nil {
_ = logx.Error(err)
return ""
}
if !cacheKeyExist { // 如果是首次设置 设置过期时间
_, err := cache.Expire(cacheKey, md.CfgCacheTime)
if err != nil {
_ = logx.Error(err)
return ""
}
}
return cfg.Val
}
return get
}

func (s SysCfgDb) SysCfgDel(HKey string) error {
cacheKey := fmt.Sprintf(md.AppCfgCacheKey, s.MasterId, HKey[0:1])
_, err := cache.HDel(cacheKey, HKey)
if err != nil {
return err
}
return nil
}

func (s SysCfgDb) SysCfgFindWithDb(keys ...string) map[string]string {
res := map[string]string{}
for _, v := range keys {
val := s.SysCfgGetWithDb(v)
res[v] = val
}
return res
}

+ 37
- 0
app/enum/enum_admin.go View File

@@ -0,0 +1,37 @@
package enum

type AdminState int32

const (
AdminStateForNormal = 1
AdminStateForFreeze = 2
)

func (gt AdminState) String() string {
switch gt {
case AdminStateForNormal:
return "正常"
case AdminStateForFreeze:
return "冻结"
default:
return "未知"
}
}

type IsSuperAdministrator int32

const (
IsSuperAdministratorTure = 1
IsSuperAdministratorFalse = 2
)

func (gt IsSuperAdministrator) String() string {
switch gt {
case IsSuperAdministratorTure:
return "超管"
case IsSuperAdministratorFalse:
return "非超管"
default:
return "未知"
}
}

+ 19
- 0
app/enum/enum_permission_group.go View File

@@ -0,0 +1,19 @@
package enum

type PermissionGroupState int32

const (
PermissionGroupStateForNormal = 1
PermissionGroupStateForDiscard = 2
)

func (gt PermissionGroupState) String() string {
switch gt {
case PermissionGroupStateForNormal:
return "正常"
case PermissionGroupStateForDiscard:
return "废弃"
default:
return "未知"
}
}

+ 19
- 0
app/enum/enum_role.go View File

@@ -0,0 +1,19 @@
package enum

type RoleState int32

const (
RoleStateForNormal = 1
RoleStateForFreeze = 2
)

func (gt RoleState) String() string {
switch gt {
case RoleStateForNormal:
return "正常"
case RoleStateForFreeze:
return "冻结"
default:
return "未知"
}
}

+ 60
- 0
app/hdl/hdl_login.go View File

@@ -0,0 +1,60 @@
package hdl

import (
"applet/app/e"
"applet/app/lib/validate"
"applet/app/md"
"applet/app/svc"
"applet/app/utils"
db "code.fnuoos.com/zhimeng/model.git/src"
"code.fnuoos.com/zhimeng/model.git/src/implement"
"fmt"
"github.com/gin-gonic/gin"
)

// Login 登陆
// @Summary 登陆
// @Tags 登录
// @Description 登入
// @Accept json
// @Produce json
// @Param req body md.LoginReq true "用户名密码"
// @Success 200 {object} md.LoginResponse "token"
// @Failure 400 {object} md.Response "具体错误"
// @Router /login [post]
func Login(c *gin.Context) {
var req md.LoginReq
err := c.ShouldBindJSON(&req)
if err != nil {
err = validate.HandleValidateErr(err)
err1 := err.(e.E)
e.OutErr(c, err1.Code, err1.Error())
return
}
engine := db.DBs[svc.GetMasterId(c)]
adminDb := implement.NewAdminDb(engine)
admin, err := adminDb.GetAdminByUserName(req.UserName)
if err != nil {
e.OutErr(c, e.ERR_DB_ORM, err)
return
}
if admin == nil {
e.OutErr(c, e.ERR_NO_DATA, "账号不存在!")
return
}
if utils.Md5(req.PassWord) != admin.Password {
e.OutErr(c, e.ERR_INVALID_ARGS, "密码错误")
return
}
ip := utils.GetIP(c.Request)
key := fmt.Sprintf(md.JwtTokenKey, ip, utils.AnyToString(admin.AdmId))
token, err := svc.HandleLoginToken(key, admin)
if err != nil {
e.OutErr(c, e.ERR, err.Error())
return
}
e.OutSuc(c, md.LoginResponse{
Token: token,
}, nil)
return
}

+ 205
- 0
app/hdl/hdl_register.go View File

@@ -0,0 +1,205 @@
package hdl

import (
"applet/app/e"
"applet/app/lib/validate"
"applet/app/md"
"applet/app/svc"
"applet/app/utils"
db "code.fnuoos.com/zhimeng/model.git/src"
"code.fnuoos.com/zhimeng/model.git/src/implement"
model2 "code.fnuoos.com/zhimeng/model.git/src/model"
implement2 "code.fnuoos.com/zhimeng/model.git/src/super/implement"
"code.fnuoos.com/zhimeng/model.git/src/super/model"
"github.com/gin-gonic/gin"
"time"
)

// RegisterForMedium
// @Summary 媒体注册
// @Tags 注册模块
// @Description 注册模块-媒体注册
// @Accept json
// @Produce json
// @Param req body md.RegisterForMediumReq true "用户名密码"
// @Success 200 string "success"
// @Failure 400 {object} md.Response "具体错误"
// @Router /registerForMedium [post]
func RegisterForMedium(c *gin.Context) {
var req md.RegisterForMediumReq
err := c.ShouldBindJSON(&req)
if err != nil {
err = validate.HandleValidateErr(err)
err1 := err.(e.E)
e.OutErr(c, err1.Code, err1.Error())
return
}
masterId := svc.GetMasterId(c)
engine := db.DBs[masterId]
now := time.Now()

//1、判断当前账号是否已存在
mediumDb := implement.NewMediumDb(engine)
medium, err := mediumDb.GetMediumByUsername(req.Phone)
if err != nil {
e.OutErr(c, e.ERR_DB_ORM, err)
return
}
if medium != nil {
e.OutErr(c, e.ERR_NO_DATA, "账号已存在!")
return
}

//2、生成 medium_list 记录
mediumListDb := implement2.NewMediumListDb(db.Db)
mediumId := utils.GenerateUniqueRandomNumbers(8)
mediumList := model.MediumList{
Uuid: utils.StrToInt(masterId),
MediumId: utils.StrToInt(mediumId),
Kind: 1,
CompanyName: "",
CompanyAbbreviation: "",
UnifiedSocialCreditCode: "",
CertificateType: 1,
BusinessLicenseImgUrl: "",
LegalRepresentative: "",
CountryRegionId: 1,
CountryRegion: "",
RegisteredAddressProvinceId: 0,
RegisteredAddressCityId: 0,
RegisteredAddressCountyId: 0,
RegisteredAddress: "",
BusinessLicenseAddress: "",
CertificateValidity: "",
State: 0,
CreateAt: now.Format("2006-01-02 15:04:05"),
UpdateAt: now.Format("2006-01-02 15:04:05"),
}
insertAffected, err := mediumListDb.MediumListInsert(&mediumList)
if err != nil {
e.OutErr(c, e.ERR_DB_ORM, err.Error())
return
}
if insertAffected <= 0 {
e.OutErr(c, e.ERR_DB_ORM, "生成 medium_list 记录失败")
return
}

//3、新增 medium 记录
mediumModel := model2.Medium{
MediumId: utils.StrToInt(mediumId),
Username: req.Phone,
Password: utils.Md5(req.PassWord),
State: 1,
IsSuperAdministrator: 1,
Memo: "",
CreateAt: now.Format("2006-01-02 15:04:05"),
UpdateAt: now.Format("2006-01-02 15:04:05"),
}
insertAffected, err = mediumDb.MediumInsert(&mediumModel)
if err != nil {
return
}
if insertAffected <= 0 {
e.OutErr(c, e.ERR_DB_ORM, "新增 medium 记录失败")
return
}

e.OutSuc(c, "success", nil)
return
}

// RegisterForAgent
// @Summary 渠道代理注册
// @Tags 注册模块
// @Description 注册模块-渠道代理注册
// @Accept json
// @Produce json
// @Param req body md.RegisterForAgentReq true "用户名密码"
// @Success 200 string "success"
// @Failure 400 {object} md.Response "具体错误"
// @Router /registerForAgent [post]
func RegisterForAgent(c *gin.Context) {
var req md.RegisterForAgentReq
err := c.ShouldBindJSON(&req)
if err != nil {
err = validate.HandleValidateErr(err)
err1 := err.(e.E)
e.OutErr(c, err1.Code, err1.Error())
return
}
masterId := svc.GetMasterId(c)
engine := db.DBs[masterId]
now := time.Now()

//1、判断当前账号是否已存在
agentDb := implement.NewAgentDb(engine)
agent, err := agentDb.GetAgentByUsername(req.Phone)
if err != nil {
e.OutErr(c, e.ERR_DB_ORM, err)
return
}
if agent != nil {
e.OutErr(c, e.ERR_NO_DATA, "账号已存在!")
return
}

//2、生成 agent_list 记录
agentListDb := implement2.NewAgentListDb(db.Db)
agentId := utils.GenerateUniqueRandomNumbers(8)
agentList := model.AgentList{
Uuid: utils.StrToInt(masterId),
AgentId: utils.StrToInt(agentId),
Kind: 1,
CompanyName: "",
CompanyAbbreviation: "",
UnifiedSocialCreditCode: "",
CertificateType: 1,
BusinessLicenseImgUrl: "",
LegalRepresentative: "",
CountryRegionId: 1,
CountryRegion: "",
RegisteredAddressProvinceId: 0,
RegisteredAddressCityId: 0,
RegisteredAddressCountyId: 0,
RegisteredAddress: "",
BusinessLicenseAddress: "",
CertificateValidity: "",
State: 0,
CreateAt: now.Format("2006-01-02 15:04:05"),
UpdateAt: now.Format("2006-01-02 15:04:05"),
}
insertAffected, err := agentListDb.AgentListInsert(&agentList)
if err != nil {
e.OutErr(c, e.ERR_DB_ORM, err.Error())
return
}
if insertAffected <= 0 {
e.OutErr(c, e.ERR_DB_ORM, "生成 medium_list 记录失败")
return
}

//3、新增 agent 记录
agentModel := model2.Agent{
AgentId: utils.StrToInt(agentId),
Username: req.Phone,
Password: utils.Md5(req.PassWord),
State: 1,
IsSuperAdministrator: 1,
Memo: "",
CreateAt: now.Format("2006-01-02 15:04:05"),
UpdateAt: now.Format("2006-01-02 15:04:05"),
}
insertAffected, err = agentDb.AgentInsert(&agentModel)
if err != nil {
e.OutErr(c, e.ERR_DB_ORM, err.Error())
return
}
if insertAffected <= 0 {
e.OutErr(c, e.ERR_DB_ORM, "新增 medium 记录失败")
return
}

e.OutSuc(c, "success", nil)
return
}

+ 649
- 0
app/hdl/hdl_role.go View File

@@ -0,0 +1,649 @@
package hdl

import (
"applet/app/e"
"applet/app/enum"
"applet/app/lib/validate"
"applet/app/md"
"applet/app/svc"
"applet/app/utils"
db "code.fnuoos.com/zhimeng/model.git/src"
"code.fnuoos.com/zhimeng/model.git/src/implement"
"code.fnuoos.com/zhimeng/model.git/src/model"
"github.com/gin-gonic/gin"
"time"
)

// PermissionGroupList
// @Summary 权限组列表
// @Tags 权限管理
// @Description 权限管理-权限组列表
// @param Authorization header string true "验证参数Bearer和token空格拼接"
// @Accept json
// @Produce json
// @param adm_id query string true "管理员id"
// @Success 200 {string} "具体看返回内容"
// @Failure 400 {object} md.Response "具体错误"
// @Router /role/permissionGroupList [GET]
func PermissionGroupList(c *gin.Context) {
roleId := c.DefaultQuery("role_id", "")
engine := db.DBs[svc.GetMasterId(c)]
qrcodeWithBatchRecordsDb := implement.NewPermissionGroupDb(engine)
groupList, err := qrcodeWithBatchRecordsDb.FindPermissionGroup()
if err != nil {
e.OutErr(c, e.ERR_DB_ORM, err.Error())
return
}

roleDb := implement.NewRoleDb(engine, utils.StrToInt(roleId))
list, _, err := roleDb.FindPermissionGroupByRole(utils.StrToInt(roleId))
if err != nil {
e.OutErr(c, e.ERR_DB_ORM, err.Error())
return
}
var isHasPermissionGroupId []string
for _, v := range list {
isHasPermissionGroupId = append(isHasPermissionGroupId, utils.IntToStr(v.PermissionGroup.Id))
}

var tempRespMap = map[string]*md.PermissionGroupListResp{}
var tempRespMapKeys []string
for _, v := range *groupList {
isCheck := false
if utils.InArr(utils.IntToStr(v.Id), isHasPermissionGroupId) {
isCheck = true
}
tempRespMap[utils.IntToStr(v.Id)] = &md.PermissionGroupListResp{
Id: v.Id,
Name: v.Name,
Key: v.Key,
State: v.State,
ParentId: v.ParentId,
CreateAt: v.CreateAt,
UpdateAt: v.UpdateAt,
IsCheck: isCheck,
}
tempRespMapKeys = append(tempRespMapKeys, utils.IntToStr(v.Id))
}
for _, v := range tempRespMap {
if v.ParentId != 0 && tempRespMap[utils.IntToStr(v.ParentId)].ParentId != 0 {
tempRespMap[utils.IntToStr(v.ParentId)].SubPermissionGroupList = append(tempRespMap[utils.IntToStr(v.ParentId)].SubPermissionGroupList, *v)
}
}
for _, v := range tempRespMap {
if v.ParentId != 0 && tempRespMap[utils.IntToStr(v.ParentId)].ParentId == 0 {
tempRespMap[utils.IntToStr(v.ParentId)].SubPermissionGroupList = append(tempRespMap[utils.IntToStr(v.ParentId)].SubPermissionGroupList, *v)
}
}

var resp []*md.PermissionGroupListResp
for _, v := range tempRespMapKeys {
if tempRespMap[v].ParentId == 0 {
resp = append(resp, tempRespMap[v])
}
}

e.OutSuc(c, map[string]interface{}{
"list": resp,
"state": []map[string]interface{}{
{
"name": enum.PermissionGroupState(enum.PermissionGroupStateForNormal).String(),
"value": enum.PermissionGroupStateForNormal,
},
{
"name": enum.PermissionGroupState(enum.PermissionGroupStateForDiscard).String(),
"value": enum.PermissionGroupStateForDiscard,
},
},
}, nil)
return
}

// RoleList
// @Summary 角色列表
// @Tags 权限管理
// @Description 权限管理-角色列表
// @param Authorization header string true "验证参数Bearer和token空格拼接"
// @Accept json
// @Produce json
// @Success 200 {string} "具体看返回内容"
// @Failure 400 {object} md.Response "具体错误"
// @Router /role/roleList [GET]
func RoleList(c *gin.Context) {
engine := db.DBs[svc.GetMasterId(c)]
roleDb := implement.NewRoleDb(engine, 0)
roleList, err := roleDb.FindRole()
if err != nil {
e.OutErr(c, e.ERR_DB_ORM, err.Error())
return
}

adminRoleDb := implement.NewAdminRoleDb(engine)
adminDb := implement.NewAdminDb(engine)
var result []*md.RoleListResp
for _, v := range *roleList {
var temp md.RoleListResp
temp.Data = v
adminRoles, err1 := adminRoleDb.FindAdminRoleByRoleId(v.Id)
if err1 != nil {
e.OutErr(c, e.ERR_DB_ORM, err1.Error())
return
}
for _, adminRole := range *adminRoles {
admin, err2 := adminDb.GetAdmin(adminRole.AdmId)
if err2 != nil {
e.OutErr(c, e.ERR_DB_ORM, err2.Error())
return
}
temp.AdminList = append(temp.AdminList, struct {
Name string `json:"name"`
}{
Name: admin.Username,
})
}
result = append(result, &temp)
}
e.OutSuc(c, map[string]interface{}{
"list": result,
"state": []map[string]interface{}{
{
"name": enum.RoleState(enum.RoleStateForNormal).String(),
"value": enum.RoleStateForNormal,
},
{
"name": enum.RoleState(enum.RoleStateForFreeze).String(),
"value": enum.RoleStateForFreeze,
},
},
}, nil)
return
}

// AddRole
// @Summary 添加角色
// @Tags 权限管理
// @Description 权限管理-添加角色
// @param Authorization header string true "验证参数Bearer和token空格拼接"
// @Accept json
// @Produce json
// @Param args body md.AddRoleReq true "请求参数"
// @Success 200 {string} "success"
// @Failure 400 {object} md.Response "具体错误"
// @Router /role/addRole [POST]
func AddRole(c *gin.Context) {
var req md.AddRoleReq
err := c.ShouldBindJSON(&req)
if err != nil {
err = validate.HandleValidateErr(err)
err1 := err.(e.E)
e.OutErr(c, err1.Code, err1.Error())
return
}
engine := db.DBs[svc.GetMasterId(c)]
roleDb := implement.NewRoleDb(engine, 0)
now := time.Now()
_, err = roleDb.RoleInsert(&model.Role{
Name: req.Name,
State: enum.RoleStateForNormal,
Memo: req.Memo,
CreateAt: now.Format("2006-01-02 15:04:05"),
UpdateAt: now.Format("2006-01-02 15:04:05"),
})
if err != nil {
e.OutErr(c, e.ERR_DB_ORM, err.Error())
return
}

e.OutSuc(c, "success", nil)
return
}

// UpdateRole
// @Summary 修改角色
// @Tags 权限管理
// @Description 权限管理-修改角色
// @param Authorization header string true "验证参数Bearer和token空格拼接"
// @Accept json
// @Produce json
// @Param args body md.UpdateRoleReq true "请求参数"
// @Success 200 {string} "success"
// @Failure 400 {object} md.Response "具体错误"
// @Router /role/updateRole [POST]
func UpdateRole(c *gin.Context) {
var req md.UpdateRoleReq
err := c.ShouldBindJSON(&req)
if err != nil {
err = validate.HandleValidateErr(err)
err1 := err.(e.E)
e.OutErr(c, err1.Code, err1.Error())
return
}
engine := db.DBs[svc.GetMasterId(c)]
roleDb := implement.NewRoleDb(engine, req.RoleId)
role, err := roleDb.GetRole()
if err != nil {
e.OutErr(c, e.ERR_DB_ORM, err.Error())
return
}
if role == nil {
e.OutErr(c, e.ERR_NO_DATA, "未查询到相应记录")
return
}
role.Name = req.Name
role.Memo = req.Memo
_, err = roleDb.UpdateRole(role, "name", "memo")
if err != nil {
e.OutErr(c, e.ERR_DB_ORM, err.Error())
return
}
e.OutSuc(c, "success", nil)
return
}

// RoleBindPermissionGroup
// @Summary 角色绑定权限组
// @Tags 权限管理
// @Description 权限管理-角色绑定权限组
// @param Authorization header string true "验证参数Bearer和token空格拼接"
// @Accept json
// @Produce json
// @Param args body md.RoleBindPermissionGroupReq true "请求参数"
// @Success 200 {string} "success"
// @Failure 400 {object} md.Response "具体错误"
// @Router /role/roleBindPermissionGroup [POST]
func RoleBindPermissionGroup(c *gin.Context) {
var req md.RoleBindPermissionGroupReq
err := c.ShouldBindJSON(&req)
if err != nil {
err = validate.HandleValidateErr(err)
err1 := err.(e.E)
e.OutErr(c, err1.Code, err1.Error())
return
}
err = svc.RoleBindPermissionGroup(c, req)
if err != nil {
e.OutErr(c, e.ERR, err.Error())
return
}

e.OutSuc(c, "success", nil)
return
}

// UpdateRoleState
// @Summary 修改角色状态
// @Tags 权限管理
// @Description 权限管理-修改角色状态
// @param Authorization header string true "验证参数Bearer和token空格拼接"
// @Accept json
// @Produce json
// @Param args body md.UpdateRoleStateReq true "请求参数"
// @Success 200 {string} "success"
// @Failure 400 {object} md.Response "具体错误"
// @Router /role/updateRole [POST]
func UpdateRoleState(c *gin.Context) {
var req md.UpdateRoleStateReq
err := c.ShouldBindJSON(&req)
if err != nil {
err = validate.HandleValidateErr(err)
err1 := err.(e.E)
e.OutErr(c, err1.Code, err1.Error())
return
}
engine := db.DBs[svc.GetMasterId(c)]
roleDb := implement.NewRoleDb(engine, req.RoleId)
role, err := roleDb.GetRole()
if err != nil {
e.OutErr(c, e.ERR_DB_ORM, err.Error())
return
}
if role == nil {
e.OutErr(c, e.ERR_NO_DATA, "未查询到相应记录")
return
}
role.State = req.State
_, err = roleDb.UpdateRole(role, "state")
if err != nil {
e.OutErr(c, e.ERR_DB_ORM, err.Error())
return
}
e.OutSuc(c, "success", nil)
return
}

// DeleteRole
// @Summary 删除角色
// @Tags 权限管理
// @Description 权限管理-删除角色
// @param Authorization header string true "验证参数Bearer和token空格拼接"
// @Accept json
// @Produce json
// @Param args body md.UpdateRoleStateReq true "请求参数"
// @Success 200 {string} "success"
// @Failure 400 {object} md.Response "具体错误"
// @Router /role/deleteRole/{$id} [DELETE]
func DeleteRole(c *gin.Context) {
id := c.Param("id")
engine := db.DBs[svc.GetMasterId(c)]
roleDb := implement.NewRoleDb(engine, utils.StrToInt(id))
role, err := roleDb.GetRole()
if err != nil {
e.OutErr(c, e.ERR_DB_ORM, err.Error())
return
}
if role == nil {
e.OutErr(c, e.ERR_NO_DATA, "未查询到相应记录")
return
}

err = svc.DeleteRole(c, utils.StrToInt(id))
if err != nil {
e.OutErr(c, e.ERR, err.Error())
return
}

e.OutSuc(c, "success", nil)
return
}

// AdminList
// @Summary 管理员列表
// @Tags 权限管理
// @Description 权限管理-管理员列表
// @param Authorization header string true "验证参数Bearer和token空格拼接"
// @Accept json
// @Produce json
// @Param args body md.AdminListReq true "请求参数"
// @Success 200 {string} "具体看返回内容"
// @Failure 400 {object} md.Response "具体错误"
// @Router /role/adminList [POST]
func AdminList(c *gin.Context) {
var req md.AdminListReq
err := c.ShouldBindJSON(&req)
if err != nil {
err = validate.HandleValidateErr(err)
err1 := err.(e.E)
e.OutErr(c, err1.Code, err1.Error())
return
}
if req.Limit == 0 {
req.Limit = 10
}
if req.Page == 0 {
req.Page = 10
}
engine := db.DBs[svc.GetMasterId(c)]
adminDb := implement.NewAdminDb(engine)
adminList, total, err := adminDb.FindAdmin(req.UserName, req.State, req.Page, req.Limit)
if err != nil {
e.OutErr(c, e.ERR_DB_ORM, err.Error())
return
}
var result []md.AdminListResp
for _, v := range adminList {
permissionGroupList, _, err1 := adminDb.FindAdminRolePermissionGroup(v.AdmId)
if err1 != nil {
e.OutErr(c, e.ERR_DB_ORM, err1.Error())
return
}
var roleList []string
for _, v1 := range permissionGroupList {
roleList = append(roleList, v1.Role.Name)
}

result = append(result, md.AdminListResp{
AdmId: v.AdmId,
Username: v.Username,
State: v.State,
IsSuperAdministrator: v.IsSuperAdministrator,
Memo: v.Memo,
CreateAt: v.CreateAt,
UpdateAt: v.UpdateAt,
RoleList: roleList,
})
}

e.OutSuc(c, map[string]interface{}{
"list": result,
"total": total,
"state": []map[string]interface{}{
{
"name": enum.RoleState(enum.RoleStateForNormal).String(),
"value": enum.RoleStateForNormal,
},
{
"name": enum.RoleState(enum.RoleStateForFreeze).String(),
"value": enum.RoleStateForFreeze,
},
},
}, nil)
return
}

// UpdateAdminState
// @Summary 修改管理员状态
// @Tags 权限管理
// @Description 权限管理-修改管理员状态
// @param Authorization header string true "验证参数Bearer和token空格拼接"
// @Accept json
// @Produce json
// @Param args body md.UpdateAdminStateReq true "请求参数"
// @Success 200 {string} "success"
// @Failure 400 {object} md.Response "具体错误"
// @Router /role/updateAdminState [POST]
func UpdateAdminState(c *gin.Context) {
var req md.UpdateAdminStateReq
err := c.ShouldBindJSON(&req)
if err != nil {
err = validate.HandleValidateErr(err)
err1 := err.(e.E)
e.OutErr(c, err1.Code, err1.Error())
return
}

engine := db.DBs[svc.GetMasterId(c)]
admDb := implement.NewAdminDb(engine)
admin, err := admDb.GetAdmin(req.AdmId)
if err != nil {
e.OutErr(c, e.ERR_DB_ORM, err.Error())
return
}
if admin == nil {
e.OutErr(c, e.ERR_NO_DATA, "未查询到相应记录")
return
}
admin.State = req.State
_, err = admDb.UpdateAdmin(admin, "state")
if err != nil {
e.OutErr(c, e.ERR_DB_ORM, err.Error())
return
}
e.OutSuc(c, "success", nil)
return
}

// UpdateAdmin
// @Summary 修改管理员信息
// @Tags 权限管理
// @Description 权限管理-修改管理员信息
// @param Authorization header string true "验证参数Bearer和token空格拼接"
// @Accept json
// @Produce json
// @Param args body md.UpdateAdminReq true "请求参数"
// @Success 200 {string} "success"
// @Failure 400 {object} md.Response "具体错误"
// @Router /role/updateAdmin [POST]
func UpdateAdmin(c *gin.Context) {
var req md.UpdateAdminReq
err := c.ShouldBindJSON(&req)
if err != nil {
err = validate.HandleValidateErr(err)
err1 := err.(e.E)
e.OutErr(c, err1.Code, err1.Error())
return
}
engine := db.DBs[svc.GetMasterId(c)]
admDb := implement.NewAdminDb(engine)
admin, err := admDb.GetAdmin(req.AdmId)
if err != nil {
e.OutErr(c, e.ERR_DB_ORM, err.Error())
return
}
if admin == nil {
e.OutErr(c, e.ERR_NO_DATA, "未查询到相应记录")
return
}
admin.Username = req.Username
admin.Memo = req.Memo
admin.Password = utils.Md5(req.Password)
_, err = admDb.UpdateAdmin(admin, "username", "memo", "password")
if err != nil {
e.OutErr(c, e.ERR_DB_ORM, err.Error())
return
}
e.OutSuc(c, "success", nil)
return
}

// AddAdmin
// @Summary 新增管理员
// @Tags 权限管理
// @Description 权限管理-新增管理员
// @param Authorization header string true "验证参数Bearer和token空格拼接"
// @Accept json
// @Produce json
// @Param args body md.AddAdminReq true "请求参数"
// @Success 200 {string} "success"
// @Failure 400 {object} md.Response "具体错误"
// @Router /role/addAdmin [POST]
func AddAdmin(c *gin.Context) {
var req md.AddAdminReq
err := c.ShouldBindJSON(&req)
if err != nil {
err = validate.HandleValidateErr(err)
err1 := err.(e.E)
e.OutErr(c, err1.Code, err1.Error())
return
}
engine := db.DBs[svc.GetMasterId(c)]
admDb := implement.NewAdminDb(engine)
isHasAdmin, err := admDb.GetAdminByUserName(req.Username)
if err != nil {
e.OutErr(c, e.ERR_DB_ORM, err.Error())
return
}
if isHasAdmin != nil {
e.OutErr(c, e.ERR, "当前用户名已存在,请勿重复添加")
return
}

admId, err := admDb.CreateAdminId()
if err != nil {
e.OutErr(c, e.ERR_DB_ORM, err.Error())
return
}
admin := model.Admin{
AdmId: admId,
Username: req.Username,
Password: utils.Md5(req.Password),
State: enum.AdminStateForNormal,
IsSuperAdministrator: 0,
Memo: req.Memo,
CreateAt: time.Now().Format("2006-01-02 15:04:05"),
UpdateAt: time.Now().Format("2006-01-02 15:04:05"),
}
_, err = admDb.AdminInsert(&admin)
if err != nil {
e.OutErr(c, e.ERR_DB_ORM, err.Error())
return
}
e.OutSuc(c, "success", nil)
return
}

// DeleteAdmin
// @Summary 删除管理员
// @Tags 权限管理
// @Description 权限管理-删除管理员
// @param Authorization header string true "验证参数Bearer和token空格拼接"
// @Accept json
// @Produce json
// @Success 200 {string} "success"
// @Failure 400 {object} md.Response "具体错误"
// @Router /role/deleteAdmin/{$adm_id} [DELETE]
func DeleteAdmin(c *gin.Context) {
admId := c.Param("adm_id")
err := svc.AdminDelete(c, []int{utils.StrToInt(admId)})
if err != nil {
e.OutErr(c, e.ERR_DB_ORM, err.Error())
return
}
e.OutSuc(c, "success", nil)
return
}

// BindAdminRole
// @Summary 管理员绑定角色
// @Tags 权限管理
// @Description 权限管理-管理员绑定角色
// @param Authorization header string true "验证参数Bearer和token空格拼接"
// @Accept json
// @Produce json
// @Param args body md.BindAdminRoleReq true "请求参数"
// @Success 200 {string} "success"
// @Failure 400 {object} md.Response "具体错误"
// @Router /role/bindAdminRole/ [POST]
func BindAdminRole(c *gin.Context) {
var req md.BindAdminRoleReq
err := c.ShouldBindJSON(&req)
if err != nil {
err = validate.HandleValidateErr(err)
err1 := err.(e.E)
e.OutErr(c, err1.Code, err1.Error())
return
}
err = svc.BindAdminRole(c, req)
if err != nil {
e.OutErr(c, e.ERR, err.Error())
return
}
e.OutSuc(c, "success", nil)
return
}

// AdminInfo
// @Summary 管理员信息
// @Tags 权限管理
// @Description 权限管理-管理员信息
// @param Authorization header string true "验证参数Bearer和token空格拼接"
// @Accept json
// @Produce json
// @param adm_id query string true "管理员id"
// @Success 200 {string} "具体看返回内容"
// @Failure 400 {object} md.Response "具体错误"
// @Router /role/adminInfo [GET]
func AdminInfo(c *gin.Context) {
admId := c.DefaultQuery("adm_id", "")
engine := db.DBs[svc.GetMasterId(c)]
admDb := implement.NewAdminDb(engine)
admin, err := admDb.GetAdmin(utils.StrToInt(admId))
if err != nil {
e.OutErr(c, e.ERR_DB_ORM, err.Error())
return
}
admin.Password = ""
e.OutSuc(c, map[string]interface{}{
"info": admin,
"state": []map[string]interface{}{
{
"name": enum.RoleState(enum.RoleStateForNormal).String(),
"value": enum.RoleStateForNormal,
},
{
"name": enum.RoleState(enum.RoleStateForFreeze).String(),
"value": enum.RoleStateForFreeze,
},
},
}, nil)
return
}

+ 39
- 0
app/lib/auth/auth.go View File

@@ -0,0 +1,39 @@
package auth

import (
"errors"
"github.com/dgrijalva/jwt-go"
"time"
)

// GenToken 生成JWT
func GenToken(admId int, username string) (string, error) {
// 创建一个我们自己的声明
c := JWTUser{
AdmId: admId,
Username: username,
StandardClaims: jwt.StandardClaims{
ExpiresAt: time.Now().Add(TokenExpireDuration).Unix(), // 过期时间
Issuer: "advertisement", // 签发人
},
}
// 使用指定的签名方法创建签名对象
token := jwt.NewWithClaims(jwt.SigningMethodHS256, c)
// 使用指定的secret签名并获得完整的编码后的字符串token
return token.SignedString(Secret)
}

// ParseToken 解析JWT
func ParseToken(tokenString string) (*JWTUser, error) {
// 解析token
token, err := jwt.ParseWithClaims(tokenString, &JWTUser{}, func(token *jwt.Token) (i interface{}, err error) {
return Secret, nil
})
if err != nil {
return nil, err
}
if claims, ok := token.Claims.(*JWTUser); ok && token.Valid { // 校验token
return claims, nil
}
return nil, errors.New("invalid token")
}

+ 4
- 8
app/lib/auth/base.go View File

@@ -7,17 +7,13 @@ import (
)

// TokenExpireDuration is jwt 过期时间
const TokenExpireDuration = time.Hour * 4380
const TokenExpireDuration = time.Hour * 24

var Secret = []byte("zyos")
var Secret = []byte("micro_group_admin")

// JWTUser 如果想要保存更多信息,都可以添加到这个结构体中
type JWTUser struct {
UID int `json:"uid"`
Username string `json:"username"`
Phone string `json:"phone"`
AppName string `json:"app_name"`
MiniOpenID string `json:"mini_open_id"` // 小程序的open_id
MiniSK string `json:"mini_session_key"` // 小程序的session_key
AdmId int `json:"adm_id"`
Username string `json:"username"`
jwt.StandardClaims
}

+ 33
- 0
app/lib/validate/validate_comm.go View File

@@ -0,0 +1,33 @@
package validate

import (
"applet/app/e"
"applet/app/utils"
"applet/app/utils/logx"
"encoding/json"
"fmt"
"github.com/go-playground/validator/v10"
)

func HandleValidateErr(err error) error {
switch err.(type) {
case *json.UnmarshalTypeError:
return e.NewErr(e.ERR_UNMARSHAL, "参数格式错误")
case validator.ValidationErrors:
errs := err.(validator.ValidationErrors)
transMsgMap := errs.Translate(utils.ValidatorTrans) // utils.ValidatorTrans \app\utils\validator_err_trans.go::ValidatorTransInit初始化获得
transMsgOne := transMsgMap[GetOneKeyOfMapString(transMsgMap)]
return e.NewErr(e.ERR_INVALID_ARGS, transMsgOne)
default:
_ = logx.Error(err)
return e.NewErr(e.ERR, fmt.Sprintf("validate request params, err:%v\n", err))
}
}

// GetOneKeyOfMapString 取出Map的一个key
func GetOneKeyOfMapString(collection map[string]string) string {
for k := range collection {
return k
}
return ""
}

+ 8
- 0
app/md/app_redis_key.go View File

@@ -2,9 +2,17 @@ package md

// 缓存key统一管理, %s格式化为masterId
const (
JwtTokenKey = "%s:advertisement_jwt_token:%s" // jwt, 占位符:ip, admin:id

JwtTokenCacheTime = 3600 * 24

AppCfgCacheKey = "%s:cfg_cache:%s" // 占位符: masterId, key的第一个字母

UserFinValidUpdateLock = "%s:user_fin_valid_update_lock:%s" // 用户余额更新锁(能拿到锁才能更新余额)

AdminRolePermissionCacheTime = 3600 * 24 * 0.5

KEY_SYS_CFG_CACHE = "sys_cfg_cache"

CfgCacheTime = 86400
)

+ 7
- 0
app/md/md_api_response.go View File

@@ -0,0 +1,7 @@
package md

type Response struct {
Code string `json:"code" example:"响应码"`
Data interface{} `json:"data" ` //内容
Msg string `json:"msg" example:"具体错误原因"`
}

+ 11
- 0
app/md/md_login.go View File

@@ -0,0 +1,11 @@
package md

type LoginReq struct {
UserName string `json:"username" binding:"required" example:"登录账号"`
PassWord string `json:"password" binding:"required" example:"登录密码"`
Code string `json:"code" example:"验证码"`
}

type LoginResponse struct {
Token string `json:"token"`
}

+ 13
- 0
app/md/md_register.go View File

@@ -0,0 +1,13 @@
package md

type RegisterForMediumReq struct {
Phone string `json:"phone" binding:"required" example:"登录账号"`
PassWord string `json:"password" binding:"required" example:"登录密码"`
Code string `json:"code" example:"验证码"`
}

type RegisterForAgentReq struct {
Phone string `json:"phone" binding:"required" example:"登录账号"`
PassWord string `json:"password" binding:"required" example:"登录密码"`
Code string `json:"code" example:"验证码"`
}

+ 91
- 0
app/md/md_role.go View File

@@ -0,0 +1,91 @@
package md

import (
"code.fnuoos.com/zhimeng/model.git/src/model"
)

type RoleListResp struct {
Data model.Role `json:"data"`
AdminList []struct {
Name string `json:"name"`
} `json:"admin_list"`
}

type UpdateRoleStateReq struct {
RoleId int `json:"role_id" binding:"required" label:"id"`
State int `json:"state" binding:"required" label:"状态"`
}

type AddRoleReq struct {
Name string `json:"name" binding:"required" label:"名称"`
Memo string `json:"memo" binding:"required" label:"备注"`
}

type UpdateRoleReq struct {
RoleId int `json:"role_id" binding:"required" label:"id"`
Name string `json:"name" binding:"required" label:"名称"`
Memo string `json:"memo" binding:"required" label:"备注"`
}

type RoleBindPermissionGroupReq struct {
RoleId int `json:"role_id" binding:"required" label:"id"`
PermissionIds []int `json:"permission_ids" label:"权限组id"`
}

type PermissionGroupListResp struct {
Id int `json:"id"`
Name string `json:"name"` //菜单名称
Key string `json:"key"` //唯一标识符
State int `json:"state"`
ParentId int `json:"parent_id"` //父级id,为0则代表没有父级
CreateAt string `json:"create_at"`
UpdateAt string `json:"update_at"`
IsCheck bool `json:"is_check"` //是否用用
SubPermissionGroupList []PermissionGroupListResp `json:"sub_permission_group_list"` //子集菜单
}

type AdminListReq struct {
Limit int `json:"limit"`
Page int `json:"page" `
UserName string `json:"username"`
State int `json:"state"`
}

type AdminListResp struct {
AdmId int `json:"adm_id"`
Username string `json:"username"`
State int `json:"state"`
IsSuperAdministrator int `json:"is_super_administrator"`
Memo string `json:"memo"`
CreateAt string `json:"create_at"`
UpdateAt string `json:"update_at"`
RoleList []string `json:"role_list"`
}

type UpdateAdminStateReq struct {
AdmId int `json:"adm_id" binding:"required" label:"管理员id"`
State int `json:"state" binding:"required" label:"状态"`
}

type AddAdminReq struct {
Username string `json:"username" binding:"required" label:"名称"`
Password string `json:"password" binding:"required" label:"密码"`
Memo string `json:"memo" label:"备注"`
}

type UpdateAdminReq struct {
AdmId int `json:"adm_id" binding:"required" label:"管理员id"`
Username string `json:"username" binding:"required" label:"名称"`
Password string `json:"password" binding:"required" label:"密码"`
Memo string `json:"memo" label:"备注"`
}

type BindAdminRoleReq struct {
AdmId int `json:"adm_id" binding:"required" label:"管理员id"`
RoleIds []int `json:"role_ids" label:"角色id"`
}

type BindAdminWithEnterpriseReq struct {
AdmId int `json:"adm_id" binding:"required" label:"管理员id"`
Ids []int `json:"ids" label:"记录id"`
}

+ 5
- 0
app/md/md_white_uri.go View File

@@ -0,0 +1,5 @@
package md

var WhiteUri = []string{
"/api/admin/comm/getMenuList",
}

+ 14
- 60
app/mw/mw_auth.go View File

@@ -1,72 +1,26 @@
package mw

import (
"errors"

"applet/app/db"
"applet/app/e"
"applet/app/lib/arkid"
"applet/app/md"
"applet/app/utils"

"applet/app/svc"
"github.com/gin-gonic/gin"
)

// 检查权限, 签名等等
func Auth(c *gin.Context) {

for k, v := range c.Request.Header {
c.Set(k, v[0])
}
token, ok := c.Get("Token")
if !ok {
e.OutErr(c, e.ERR_UNAUTHORIZED, errors.New("没有找到token"))
return
}
if token == "" {
e.OutErr(c, e.ERR_UNAUTHORIZED, errors.New("token 不能为空"))
return
}
tokenStr := utils.AnyToString(token)
arkIdSdk := arkid.NewArkID()
var err error
signUser := &md.User{}
arkIdUser := new(arkid.ArkIDUser)
if err = arkIdSdk.SelectFunction("arkid_user_info").
WithArgs(arkid.RequestBody{Token: tokenStr}).
Result(arkIdUser); err != nil {
e.OutErr(c, e.ERR_TOKEN_AUTH, err) //token 不存在
return
}
if arkIdUser.Username == "" {
e.OutErr(c, e.ERR_UNAUTHORIZED, errors.New("Token error"))
return
}
if err = arkIdSdk.SelectFunction("arkid_login").
WithArgs(arkid.RequestBody{Username: arkIdUser.Username, Password: utils.Md5(arkIdUser.Username)}).
Result(arkIdUser); err != nil {
e.OutErr(c, e.ERR_TOKEN_AUTH, err)
return
}
signUser.Ark = arkIdUser
if signUser.Ark == nil {
e.OutErr(c, e.ERR_TOKEN_AUTH, errors.New("无效token"))
return
}
signUser.Info, err = db.UserFindByArkidUserName(db.DBs[c.GetString("mid")], arkIdUser.Username)
admin, err := svc.CheckUser(c)
if err != nil {
e.OutErr(c, e.ERR_TOKEN_AUTH, err)
return
}
if signUser.Info == nil {
e.OutErr(c, e.ERR_TOKEN_AUTH, errors.New("无效token"))
return
}
signUser.Profile, err = db.UserProfileFindByArkID(db.DBs[c.GetString("mid")], utils.IntToStr(arkIdUser.UserID))
if err != nil {
e.OutErr(c, e.ERR_TOKEN_AUTH, err)
return
}
c.Set("user", signUser)
switch err.(type) {
case e.E:
err1 := err.(e.E)
e.OutErr(c, err1.Code, err1.Error())
return
default:
e.OutErr(c, e.ERR_TOKEN_AUTH, err.Error())
return
}
}
// 将当前请求的username信息保存到请求的上下文c上
c.Set("admin", admin)
c.Next()
}

+ 0
- 96
app/mw/mw_auth_jwt.go View File

@@ -1,96 +0,0 @@
package mw

import (
"applet/app/db"
"applet/app/e"
"applet/app/md"
"applet/app/utils"
"applet/app/utils/cache"
"applet/app/utils/logx"
"errors"
"fmt"
"strings"

"github.com/gin-gonic/gin"
)

// AuthJWT is jwt middleware
func AuthJWT(c *gin.Context) {

authHeader := c.Request.Header.Get("Authorization")
if authHeader == "" {
e.OutErr(c, e.ERR_UNAUTHORIZED, errors.New("token 不能为空"))
return
}

// 按空格分割
parts := strings.SplitN(authHeader, " ", 2)
if !(len(parts) == 2 && parts[0] == "Bearer") {
e.OutErr(c, e.ERR_TOKEN_FORMAT, errors.New("token 格式不对"))
return
}
// parts[1]是token
mc, err := utils.ParseToken(parts[1])
if err != nil {
e.OutErr(c, e.ERR_UNAUTHORIZED, errors.New("token 过期或无效"))
return
}
//fmt.Println(mc.UID)
// 获取user
u, err := db.UserFindByID(db.DBs[c.GetString("mid")], mc.UID)
if err != nil {
e.OutErr(c, e.ERR_DB_ORM, err)
return
}
if u == nil {
e.OutErr(c, e.ERR_UNAUTHORIZED, errors.New("token 过期或无效"))
return
}
// 检验账号是否未激活或被冻结
switch u.State {
case 0:
e.OutErr(c, e.ERR_USER_NO_ACTIVE)
return
case 2:
e.OutErr(c, e.ERR_USER_IS_BAN)
return
}

// 校验是否和缓存的token一致,只能有一个token 是真实有效
key := fmt.Sprintf("%s:token:%s", c.GetString("mid"), u.Username)
//fmt.Println(key)
cjwt, err := cache.GetString(key)
//fmt.Println(cjwt)
if err != nil {
logx.Warn(err)
goto NOCACHE
}
if parts[1] != cjwt {
e.OutErr(c, e.ERR_TOKEN_AUTH, errors.New("token expired"))
return
}
NOCACHE:
// 获取user profile
up, err := db.UserProfileFindByID(db.DBs[c.GetString("mid")], mc.UID)
if err != nil {
e.OutErr(c, e.ERR_DB_ORM, err)
return
}
// 获取user 等级
ul, err := db.UserLevelByID(db.DBs[c.GetString("mid")], u.Level)
if err != nil {
e.OutErr(c, e.ERR_DB_ORM, err)
return
}
user := &md.User{
Info: u,
Profile: up,
Level: ul,
}

// 将当前请求的username信息保存到请求的上下文c上
c.Set("user", user)
// 异步处理 有效会员和新会员
c.Next() // 后续的处理函数可以用过c.Get("user")来获取当前请求的用户信息

}

+ 0
- 22
app/mw/mw_checker.go View File

@@ -1,22 +0,0 @@
package mw

import (
"strings"

"github.com/gin-gonic/gin"

"applet/app/e"
"applet/app/md"
)

// 检查设备等, 把头部信息下放到hdl可以获取
func Checker(c *gin.Context) {
// 校验平台支持
platform := strings.ToLower(c.GetHeader("Platform"))
//fmt.Println(platform)
if _, ok := md.PlatformList[platform]; !ok {
e.OutErr(c, e.ERR_PLATFORM)
return
}
c.Next()
}

+ 5
- 68
app/mw/mw_db.go View File

@@ -1,71 +1,22 @@
package mw

import (
"applet/app/e"
"applet/app/svc"
db "code.fnuoos.com/zhimeng/model.git/src"
"errors"
"fmt"
"github.com/gin-gonic/gin"
"strings"

"applet/app/db"
"applet/app/e"
"applet/app/md"
)

// DB is 中间件 用来检查master_id是否有对应的数据库engine
func DB(c *gin.Context) {
fmt.Println(c.Request.Header)
masterID := c.GetHeader("master_id")
masterID := svc.GetMasterId(c)
fmt.Println("master_id", masterID)
if masterID == "" {
fmt.Println("not found master_id found MasterId start")
masterID = c.GetHeader("MasterId")
fmt.Println("MasterId", masterID)
// if masterID still emtpy
if masterID == "" {
platform := c.GetHeader("Platform")
if platform == md.PLATFORM_WAP {
// H5 要根据域名去获取mid
hostList := strings.Split(c.Request.Host, ".")
if len(hostList) == 4 && (hostList[2]+"."+hostList[3] == "zhiyingos.com" || hostList[2]+"."+hostList[3] == "izhyin.com") {
// 官方域名
masterID = hostList[1]
} else {
// 自定义域名
masterID = svc.GetWebSiteDomainMasterId(md.PLATFORM_WAP, c.Request.Host)
}
//requestURL := cfg.Official.URL + "/api/user/check"
//fmt.Println(c.Request.Host)
//client := &http.Client{
// Timeout: time.Duration(time.Second * 2),
//}
//data := []byte(fmt.Sprintf(`{"domain":"%s"}`, c.Request.Host))
//body := bytes.NewReader(data)
//request, err := http.NewRequest("POST", requestURL, body)
//if err != nil {
// e.OutErr(c, e.ERR_MASTER_ID, errors.New("not found master_id in DBs"))
// return
//}
//request.Header.Set("Content-Type", "application/json;charset=UTF-8")
//resp, err := client.Do(request.WithContext(context.TODO()))
//if err != nil {
// e.OutErr(c, e.ERR_MASTER_ID, err)
// return
//}
//defer resp.Body.Close()
//respBytes, err := ioutil.ReadAll(resp.Body)
//if err != nil {
// e.OutErr(c, e.ERR_MASTER_ID, err)
// return
//}
//mid := gjson.GetBytes(respBytes, "data.db_master_id").String()
//if mid == "" {
// e.OutErr(c, e.ERR_MASTER_ID, errors.New("not found master_id in DBs"))
// return
//}
//masterID = mid
}
}
e.OutErr(c, e.ERR_MASTER_ID, errors.New("not found master_id"))
return
}

_, ok := db.DBs[masterID]
@@ -75,19 +26,5 @@ func DB(c *gin.Context) {
}
fmt.Println("master_id", masterID)
c.Set("mid", masterID)
//判断是否有独立域名
domain_wap_base := svc.GetWebSiteDomainInfo(c, "wap")

httpStr := "http://"
if c.GetHeader("Platform") == md.PLATFORM_WX_APPLET || c.GetHeader("Platform") == md.PLATFORM_ALIPAY_APPLET || c.GetHeader("Platform") == md.PLATFORM_BAIDU_APPLET || c.GetHeader("Platform") == md.PLATFORM_TOUTIAO_APPLET || c.GetHeader("Platform") == md.PLATFORM_TIKTOK_APPLET {
httpStr = "https://"
domain_wap_base = strings.Replace(domain_wap_base, "http://", httpStr, 1)
}
c.Set("domain_wap_base", domain_wap_base)
c.Set("http_host", httpStr)

c.Set("h5_api_secret_key", svc.SysCfgGet(c, "h5_api_secret_key"))
c.Set("app_api_secret_key", svc.SysCfgGet(c, "app_api_secret_key"))
c.Set("applet_api_secret_key", svc.SysCfgGet(c, "applet_api_secret_key"))
c.Next()
}

+ 28
- 19
app/router/router.go View File

@@ -6,6 +6,8 @@ import (
"applet/app/mw"
_ "applet/docs"
"github.com/gin-gonic/gin"
swaggerFiles "github.com/swaggo/files"
ginSwagger "github.com/swaggo/gin-swagger"
)

// 初始化路由
@@ -18,6 +20,11 @@ func Init() *gin.Engine {
gin.SetMode(mode)
//创建一个新的启动器
r := gin.New()
r.GET("/api/swagger/*any", func(c *gin.Context) {
//r.Use(mw.SwagAuth())
ginSwagger.DisablingWrapHandler(swaggerFiles.Handler, "SWAGGER")(c)
})

r.Use(mw.ChangeHeader)

// 是否打印访问日志, 在非正式环境都打印
@@ -38,8 +45,7 @@ func Init() *gin.Engine {
c.JSON(405, gin.H{"code": 405, "msg": "method not allowed", "data": []struct{}{}})
})
r.Use(mw.Cors)
route(r.Group("/api/v1/mall"))
rInApi(r.Group("/inapi/mall"))
route(r.Group("/api"))
return r
}

@@ -48,27 +54,30 @@ func route(r *gin.RouterGroup) {

r.Use(mw.DB) // 以下接口需要用到数据库
{
r.POST("/login", hdl.Login)
}
r.Use(mw.CheckBody) //body参数转换
r.Use(mw.CheckSign) //签名校验
r.Use(mw.Checker) // 以下接口需要检查Header: platform
{
}
r.POST("/registerForMedium", hdl.RegisterForMedium)
r.POST("/registerForAgent", hdl.RegisterForAgent)

r.Use(mw.AuthJWT) // 以下接口需要JWT验证
{

}
r.Use(mw.Auth) // 以下接口需要JWT验证
rRole(r.Group("/role")) //权限管理
}

func rInApi(r *gin.RouterGroup) {
//TODO::该分组中所有的接口,支持开放平台调用
r.Use(mw.DB) // 以下接口需要用到数据库
{

}
r.Use(mw.AuthJWT) // 以下接口需要JWT验证
{

}
func rRole(r *gin.RouterGroup) {
r.GET("/roleList", hdl.RoleList) //角色列表
r.POST("/addRole", hdl.AddRole) //角色添加
r.POST("/roleBindPermissionGroup", hdl.RoleBindPermissionGroup) //角色绑定权限组
r.POST("/updateRoleState", hdl.UpdateRoleState) //修改角色状态
r.POST("/updateRole", hdl.UpdateRole) //修改角色状态
r.DELETE("/deleteRole/:id", hdl.DeleteRole) //删除角色
r.GET("/permissionGroupList", hdl.PermissionGroupList) //权限组列表
r.POST("/adminList", hdl.AdminList) //管理员列表
r.POST("/updateAdminState", hdl.UpdateAdminState) //修改管理员状态
r.POST("/updateAdmin", hdl.UpdateAdmin) //修改管理员信息
r.POST("/addAdmin", hdl.AddAdmin) //新增管理员
r.DELETE("/deleteAdmin/:adm_id", hdl.DeleteAdmin) //删除管理员
r.GET("/adminInfo", hdl.AdminInfo) //获取管理员信息
r.POST("/bindAdminRole", hdl.BindAdminRole) //绑定角色
}

+ 31
- 0
app/svc/svc_admin.go View File

@@ -0,0 +1,31 @@
package svc

import (
db "code.fnuoos.com/zhimeng/model.git/src"
"code.fnuoos.com/zhimeng/model.git/src/implement"
"github.com/gin-gonic/gin"
)

func AdminDelete(c *gin.Context, admIds []int) (err error) {
engine := db.DBs[GetMasterId(c)]
session := engine.NewSession()
defer session.Close()
session.Begin()
//1、删除 `admin`
adminDb := implement.NewAdminDb(engine)
_, err = adminDb.AdminDeleteBySession(session, admIds)
if err != nil {
_ = session.Rollback()
return
}

//2、删除 `admin_role`
adminRoleDb := implement.NewAdminRoleDb(engine)
_, err = adminRoleDb.AdminDeleteBySessionForAdmId(session, admIds)
if err != nil {
_ = session.Rollback()
return
}

return session.Commit()
}

+ 53
- 0
app/svc/svc_auth.go View File

@@ -0,0 +1,53 @@
package svc

import (
"applet/app/lib/auth"
db "code.fnuoos.com/zhimeng/model.git/src"
"code.fnuoos.com/zhimeng/model.git/src/implement"
"code.fnuoos.com/zhimeng/model.git/src/model"
"errors"
"github.com/gin-gonic/gin"
"strings"
)

func GetUser(c *gin.Context) *model.Admin {
user, _ := c.Get("admin")
if user == nil {
return &model.Admin{
AdmId: 0,
Username: "",
Password: "",
State: 0,
IsSuperAdministrator: 0,
Memo: "",
CreateAt: "",
UpdateAt: "",
}
}
return user.(*model.Admin)
}

func CheckUser(c *gin.Context) (*model.Admin, error) {
token := c.GetHeader("Authorization")
if token == "" {
return nil, errors.New("token not exist")
}
// 按空格分割
parts := strings.SplitN(token, " ", 2)
if !(len(parts) == 2 && parts[0] == "Bearer") {
return nil, errors.New("token format error")
}
// parts[1]是获取到的tokenString,我们使用之前定义好的解析JWT的函数来解析它
mc, err := auth.ParseToken(parts[1])
if err != nil {
return nil, err
}

// 获取admin
adminDb := implement.NewAdminDb(db.DBs[GetMasterId(c)])
admin, err := adminDb.GetAdmin(mc.AdmId)
if err != nil {
return nil, err
}
return admin, nil
}

+ 1
- 1
app/svc/svc_db.go View File

@@ -1,7 +1,7 @@
package svc

import (
"applet/app/db"
db "code.fnuoos.com/zhimeng/model.git/src"
"github.com/gin-gonic/gin"
"xorm.io/xorm"
)


+ 33
- 0
app/svc/svc_login.go View File

@@ -0,0 +1,33 @@
package svc

import (
"applet/app/lib/auth"
"applet/app/md"
"applet/app/utils/cache"
"applet/app/utils/logx"
"code.fnuoos.com/zhimeng/model.git/src/model"
)

func HandleLoginToken(cacheKey string, admin *model.Admin) (string, error) {
// 获取之前生成的token
token, err := cache.GetString(cacheKey)
if err != nil {
_ = logx.Error(err)
}
// 没有获取到
if err != nil || token == "" {
// 生成token
token, err = auth.GenToken(admin.AdmId, admin.Username)
if err != nil {
return "", err
}
// 缓存token
_, err = cache.SetEx(cacheKey, token, md.JwtTokenCacheTime)
if err != nil {
return "", err
}
return token, nil
}

return token, nil
}

+ 58
- 0
app/svc/svc_master.go View File

@@ -0,0 +1,58 @@
package svc

import (
"fmt"
"github.com/gin-gonic/gin"
"strconv"
)

func GetMasterId(c *gin.Context) (masterId string) {
masterId = c.GetHeader("master_id")
if masterId != "" {
return
}

masterId = c.GetString("master_id")
if masterId == "" {
//TODO::通过域名查找masterId
//host := c.Request.Host

//fmt.Println("not found master_id found MasterId start")
//masterId = c.GetHeader("MasterId")
//if masterId == "" && c.GetHeader("Platform") == md.PLATFORM_WAP { // H5 要根据域名去获取mid
// hostList := strings.Split(c.Request.Host, ".")
// if isNumeric(hostList[0]) {
// masterId = hostList[0]
// } else if isNumeric(hostList[1]) {
// masterId = hostList[1]
// } else {
// // 自定义域名
// masterId = svc.GetWebSiteDomainMasterId(baseDb, md.PLATFORM_WAP, c.Request.Host)
// }
//}
//if masterId == "" && c.GetHeader("Platform") == md.PLATFORM_PC { // H5 要根据域名去获取mid
// hostList := strings.Split(c.Request.Host, ".")
// if isNumeric(hostList[0]) {
// masterId = hostList[0]
// } else if isNumeric(hostList[1]) {
// masterId = hostList[1]
// } else {
// // 自定义域名
// masterId = svc.GetWebSiteDomainMasterId(baseDb, md.PLATFORM_PC, c.Request.Host)
// }
//}
//if masterId == "" && c.GetHeader("Platform") == "" { // 无平台访问
// hostList := strings.Split(c.Request.Host, ".")
// if isNumeric(hostList[0]) {
// masterId = hostList[0]
// }
//}
}
fmt.Println("master_id:::::::", masterId)
return
}

func isNumeric(str string) bool {
_, err := strconv.ParseFloat(str, 64)
return err == nil
}

+ 184
- 0
app/svc/svc_role.go View File

@@ -0,0 +1,184 @@
package svc

import (
"applet/app/md"
"applet/app/utils"
"applet/app/utils/cache"
db "code.fnuoos.com/zhimeng/model.git/src"
"code.fnuoos.com/zhimeng/model.git/src/implement"
"code.fnuoos.com/zhimeng/model.git/src/model"
"encoding/json"
"errors"
"github.com/gin-gonic/gin"
"regexp"
"strings"
"time"
)

func CheckUserRole(c *gin.Context, cacheKey, uri string, admId int) (isHasPermission bool, err error) {
uri = utils.UriFilterExcludeQueryString(uri) //去除uri中?后的query参数
isHasPermission = false
var rolePermission []string
var rolePermissionString string
rolePermissionString, _ = cache.GetString(cacheKey)

//TODO::判断是否在白名单中
if utils.InArr(uri, md.WhiteUri) {
isHasPermission = true
return
}

if rolePermissionString != "" {
//if false {
if err = json.Unmarshal([]byte(rolePermissionString), &rolePermission); err != nil {
return
}
} else {
adminDb := implement.NewAdminDb(db.DBs[GetMasterId(c)])
list, _, err1 := adminDb.GetAdminRolePermission(admId)
if err1 != nil {
return isHasPermission, err1
}
for _, v := range list {
rolePermission = append(rolePermission, v.Permission.Action)
}
marshal, err1 := json.Marshal(rolePermission)
if err1 != nil {
return isHasPermission, err1
}
rolePermissionString = string(marshal)
_, err = cache.SetEx(cacheKey, rolePermissionString, md.AdminRolePermissionCacheTime)
}

if utils.InArr(uri, rolePermission) {
isHasPermission = true
} else {
//正则匹配占位符情况
compileRegex := regexp.MustCompile("[0-9]+")
matchArr := compileRegex.FindAllString(uri, -1)
if len(matchArr) > 0 {
uri = strings.Replace(uri, matchArr[len(matchArr)-1], ":id", 1)
if utils.InArr(uri, rolePermission) {
isHasPermission = true
}
}
}
return
}

func DeleteRole(c *gin.Context, roleId int) (err error) {
session := db.Db.NewSession()
defer session.Close()
session.Begin()

//1、删除 `role`
roleDb := implement.NewRoleDb(db.DBs[GetMasterId(c)], roleId)
_, err = roleDb.RoleDeleteBySession(session, roleId)
if err != nil {
_ = session.Rollback()
return
}

//2、删除 `role_permission_group`
rolePermissionGroupDb := implement.NewRolePermissionGroupDb(db.DBs[GetMasterId(c)])
_, err = rolePermissionGroupDb.RolePermissionGroupDeleteForRoleBySession(session, roleId)
if err != nil {
_ = session.Rollback()
return
}

//3、删除 `admin_role`
adminRoleDb := implement.NewAdminRoleDb(db.DBs[GetMasterId(c)])
_, err = adminRoleDb.AdminRoleDeleteForRoleBySession(session, roleId)
if err != nil {
_ = session.Rollback()
return
}

return session.Commit()
}

func RoleBindPermissionGroup(c *gin.Context, req md.RoleBindPermissionGroupReq) (err error) {
session := db.Db.NewSession()
defer session.Close()
session.Begin()
//1、查询 `role`
roleDb := implement.NewRoleDb(db.DBs[GetMasterId(c)], req.RoleId)
role, err := roleDb.GetRole()
if err != nil {
return
}
if role == nil {
return errors.New("未查询到相应记录")
}

//1、删除 `role_permission_group`
rolePermissionGroupDb := implement.NewRolePermissionGroupDb(db.DBs[GetMasterId(c)])
_, err = rolePermissionGroupDb.RolePermissionGroupDeleteForRoleBySession(session, req.RoleId)
if err != nil {
_ = session.Rollback()
return
}

//2、新增 `role_permission_group``
var mm []*model.RolePermissionGroup
now := time.Now()
for _, v := range req.PermissionIds {
mm = append(mm, &model.RolePermissionGroup{
RoleId: role.Id,
GroupId: v,
CreateAt: now.Format("2006-01-02 15:04:05"),
UpdateAt: now.Format("2006-01-02 15:04:05"),
})
}
_, err = rolePermissionGroupDb.BatchAddRolePermissionGroupBySession(session, mm)
if err != nil {
_ = session.Rollback()
return
}

return session.Commit()
}

func BindAdminRole(c *gin.Context, req md.BindAdminRoleReq) (err error) {
session := db.Db.NewSession()
defer session.Close()
session.Begin()
//1、查询 `role`
adminDb := implement.NewAdminDb(db.DBs[GetMasterId(c)])
role, err := adminDb.GetAdmin(req.AdmId)
if err != nil {
return
}
if role == nil {
return errors.New("未查询到相应记录")
}

//1、删除 `admin_role`
adminRoleDb := implement.NewAdminRoleDb(db.DBs[GetMasterId(c)])
_, err = adminRoleDb.AdminRoleDeleteBySession(session, req.AdmId)
if err != nil {
_ = session.Rollback()
return
}

//2、新增 `删除 `admin_role``
var mm []*model.AdminRole
now := time.Now()
for _, v := range req.RoleIds {
mm = append(mm, &model.AdminRole{
AdmId: req.AdmId,
RoleId: v,
State: 1,
CreateAt: now.Format("2006-01-02 15:04:05"),
UpdateAt: now.Format("2006-01-02 15:04:05"),
})
}
_, err = adminRoleDb.BatchAddAdminRoleBySession(session, mm)
if err != nil {
_ = session.Rollback()
return
}

return session.Commit()
}

+ 1
- 76
app/svc/svc_sys_cfg_get.go View File

@@ -1,15 +1,11 @@
package svc

import (
"errors"
db "code.fnuoos.com/zhimeng/model.git/src"
"github.com/gin-gonic/gin"
"strings"
"xorm.io/xorm"

"applet/app/cfg"
"applet/app/db"
"applet/app/md"
"applet/app/utils"
"applet/app/utils/cache"
)

@@ -102,74 +98,3 @@ func SysCfgSet(c *gin.Context, key, val, memo string) bool {
SysCfgCleanCache()
return db.SysCfgUpdate(db.DBs[c.GetString("mid")], key, val, cfg.Memo)
}

// 多条记录获取
func SysCfgFindByIds(eg *xorm.Engine, keys ...string) map[string]string {
key := utils.Md5(eg.DataSourceName() + md.KEY_SYS_CFG_CACHE)
res := map[string]string{}
c, ok := cfg.MemCache.Get(key).(map[string]string)
if !ok || len(c) == 0 {
cfgList, _ := db.DbsSysCfgGetAll(eg)
if cfgList == nil {
return nil
}
for _, v := range *cfgList {
res[v.Key] = v.Val
}
cfg.MemCache.Put(key, res, 10)
} else {
res = c
}
if len(keys) == 0 {
return res
}
tmp := map[string]string{}
for _, v := range keys {
if val, ok := res[v]; ok {
tmp[v] = val
} else {
tmp[v] = ""
}
}
return tmp
}

// 支付配置
func SysCfgFindPayment(c *gin.Context) ([]map[string]string, error) {
platform := c.GetHeader("platform")
payCfg := SysCfgFind(c, "pay_wx_pay_img", "pay_ali_pay_img", "pay_balance_img", "pay_type")
if payCfg["pay_wx_pay_img"] == "" || payCfg["pay_ali_pay_img"] == "" || payCfg["pay_balance_img"] == "" || payCfg["pay_type"] == "" {
return nil, errors.New("lack of payment config")
}
payCfg["pay_wx_pay_img"] = ImageFormat(c, payCfg["pay_wx_pay_img"])
payCfg["pay_ali_pay_img"] = ImageFormat(c, payCfg["pay_ali_pay_img"])
payCfg["pay_balance_img"] = ImageFormat(c, payCfg["pay_balance_img"])

var result []map[string]string

if strings.Contains(payCfg["pay_type"], "aliPay") && platform != md.PLATFORM_WX_APPLET {
item := make(map[string]string)
item["pay_channel"] = "alipay"
item["img"] = payCfg["pay_ali_pay_img"]
item["name"] = "支付宝支付"
result = append(result, item)
}

if strings.Contains(payCfg["pay_type"], "wxPay") {
item := make(map[string]string)
item["pay_channel"] = "wx"
item["img"] = payCfg["pay_wx_pay_img"]
item["name"] = "微信支付"
result = append(result, item)
}

if strings.Contains(payCfg["pay_type"], "walletPay") {
item := make(map[string]string)
item["pay_channel"] = "fin"
item["img"] = payCfg["pay_balance_img"]
item["name"] = "余额支付"
result = append(result, item)
}

return result, nil
}

+ 0
- 49
app/utils/aes.go View File

@@ -1,12 +1,9 @@
package utils

import (
"applet/app/cfg"
"bytes"
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"encoding/json"
"fmt"
)

@@ -124,49 +121,3 @@ func pKCS5Trimming(encrypt []byte) []byte {
padding := encrypt[len(encrypt)-1]
return encrypt[:len(encrypt)-int(padding)]
}

// AesAdminCurlPOST is 与后台接口加密交互
func AesAdminCurlPOST(aesData string, url string) ([]byte, error) {
adminKey := cfg.Admin.AesKey
adminVI := cfg.Admin.AesIV
crypto := AesCrypt{
Key: []byte(adminKey),
Iv: []byte(adminVI),
}

encrypt, err := crypto.Encrypt([]byte(aesData))
if err != nil {
return nil, err
}

// 发送请求到后台
postData := map[string]string{
"postData": base64.StdEncoding.EncodeToString(encrypt),
}
fmt.Println(adminKey)
fmt.Println(adminVI)
fmt.Println("=======ADMIN请求=====")
fmt.Println(postData)
postDataByte, _ := json.Marshal(postData)
rdata, err := CurlPost(url, postDataByte, nil)
fmt.Println(err)

if err != nil {
return nil, err
}
fmt.Println(rdata)

pass, err := base64.StdEncoding.DecodeString(string(rdata))
if err != nil {
return nil, err
}
fmt.Println(pass)

decrypt, err := crypto.Decrypt(pass)
fmt.Println(err)

if err != nil {
return nil, err
}
return decrypt, nil
}

+ 0
- 46
app/utils/auth.go View File

@@ -1,46 +0,0 @@
package utils

import (
"errors"
"time"

"applet/app/lib/auth"

"github.com/dgrijalva/jwt-go"
)

// GenToken 生成JWT
func GenToken(uid int, username, phone, appname, MiniOpenID, MiniSK string) (string, error) {
// 创建一个我们自己的声明
c := auth.JWTUser{
uid,
username,
phone,
appname,
MiniOpenID,
MiniSK,
jwt.StandardClaims{
ExpiresAt: time.Now().Add(auth.TokenExpireDuration).Unix(), // 过期时间
Issuer: "zyos", // 签发人
},
}
// 使用指定的签名方法创建签名对象
token := jwt.NewWithClaims(jwt.SigningMethodHS256, c)
// 使用指定的secret签名并获得完整的编码后的字符串token
return token.SignedString(auth.Secret)
}

// ParseToken 解析JWT
func ParseToken(tokenString string) (*auth.JWTUser, error) {
// 解析token
token, err := jwt.ParseWithClaims(tokenString, &auth.JWTUser{}, func(token *jwt.Token) (i interface{}, err error) {
return auth.Secret, nil
})
if err != nil {
return nil, err
}
if claims, ok := token.Claims.(*auth.JWTUser); ok && token.Valid { // 校验token
return claims, nil
}
return nil, errors.New("invalid token")
}

+ 5
- 2
app/utils/cache/redis.go View File

@@ -402,8 +402,11 @@ func Scan(cursor int64, pattern string, count int64) (int64, []string, error) {
return newCursor, items, nil
}


func LPushMax(key string, data ...interface{}) (interface{}, error) {
// set
return Do("LPUSH", key, data)
}
}

func SelectDb(db int) (interface{}, error) {
return Do("SELECT", db)
}

+ 146
- 0
app/utils/ip.go View File

@@ -0,0 +1,146 @@
package utils

import (
"errors"
"math"
"net"
"net/http"
"strings"
)

func GetIP(r *http.Request) string {
ip := ClientPublicIP(r)
if ip == "" {
ip = ClientIP(r)
}
if ip == "" {
ip = "0000"
}
return ip
}

// HasLocalIPddr 检测 IP 地址字符串是否是内网地址
// Deprecated: 此为一个错误名称错误拼写的函数,计划在将来移除,请使用 HasLocalIPAddr 函数
func HasLocalIPddr(ip string) bool {
return HasLocalIPAddr(ip)
}

// HasLocalIPAddr 检测 IP 地址字符串是否是内网地址
func HasLocalIPAddr(ip string) bool {
return HasLocalIP(net.ParseIP(ip))
}

// HasLocalIP 检测 IP 地址是否是内网地址
// 通过直接对比ip段范围效率更高,详见:https://github.com/thinkeridea/go-extend/issues/2
func HasLocalIP(ip net.IP) bool {
if ip.IsLoopback() {
return true
}

ip4 := ip.To4()
if ip4 == nil {
return false
}

return ip4[0] == 10 || // 10.0.0.0/8
(ip4[0] == 172 && ip4[1] >= 16 && ip4[1] <= 31) || // 172.16.0.0/12
(ip4[0] == 169 && ip4[1] == 254) || // 169.254.0.0/16
(ip4[0] == 192 && ip4[1] == 168) // 192.168.0.0/16
}

// ClientIP 尽最大努力实现获取客户端 IP 的算法。
// 解析 X-Real-IP 和 X-Forwarded-For 以便于反向代理(nginx 或 haproxy)可以正常工作。
func ClientIP(r *http.Request) string {
ip := strings.TrimSpace(strings.Split(r.Header.Get("X-Forwarded-For"), ",")[0])
if ip != "" {
return ip
}

ip = strings.TrimSpace(r.Header.Get("X-Real-Ip"))
if ip != "" {
return ip
}

if ip, _, err := net.SplitHostPort(strings.TrimSpace(r.RemoteAddr)); err == nil {
return ip
}

return ""
}

// ClientPublicIP 尽最大努力实现获取客户端公网 IP 的算法。
// 解析 X-Real-IP 和 X-Forwarded-For 以便于反向代理(nginx 或 haproxy)可以正常工作。
func ClientPublicIP(r *http.Request) string {
var ip string
for _, ip = range strings.Split(r.Header.Get("X-Forwarded-For"), ",") {
if ip = strings.TrimSpace(ip); ip != "" && !HasLocalIPAddr(ip) {
return ip
}
}

if ip = strings.TrimSpace(r.Header.Get("X-Real-Ip")); ip != "" && !HasLocalIPAddr(ip) {
return ip
}

if ip = RemoteIP(r); !HasLocalIPAddr(ip) {
return ip
}

return ""
}

// RemoteIP 通过 RemoteAddr 获取 IP 地址, 只是一个快速解析方法。
func RemoteIP(r *http.Request) string {
ip, _, _ := net.SplitHostPort(r.RemoteAddr)
return ip
}

// IPString2Long 把ip字符串转为数值
func IPString2Long(ip string) (uint, error) {
b := net.ParseIP(ip).To4()
if b == nil {
return 0, errors.New("invalid ipv4 format")
}

return uint(b[3]) | uint(b[2])<<8 | uint(b[1])<<16 | uint(b[0])<<24, nil
}

// Long2IPString 把数值转为ip字符串
func Long2IPString(i uint) (string, error) {
if i > math.MaxUint32 {
return "", errors.New("beyond the scope of ipv4")
}

ip := make(net.IP, net.IPv4len)
ip[0] = byte(i >> 24)
ip[1] = byte(i >> 16)
ip[2] = byte(i >> 8)
ip[3] = byte(i)

return ip.String(), nil
}

// IP2Long 把net.IP转为数值
func IP2Long(ip net.IP) (uint, error) {
b := ip.To4()
if b == nil {
return 0, errors.New("invalid ipv4 format")
}

return uint(b[3]) | uint(b[2])<<8 | uint(b[1])<<16 | uint(b[0])<<24, nil
}

// Long2IP 把数值转为net.IP
func Long2IP(i uint) (net.IP, error) {
if i > math.MaxUint32 {
return nil, errors.New("beyond the scope of ipv4")
}

ip := make(net.IP, net.IPv4len)
ip[0] = byte(i >> 24)
ip[1] = byte(i >> 16)
ip[2] = byte(i >> 8)
ip[3] = byte(i)

return ip, nil
}

+ 28
- 0
app/utils/rand.go View File

@@ -5,6 +5,7 @@ import (
"fmt"
"math/big"
"math/rand"
"strconv"
"time"
)

@@ -29,3 +30,30 @@ func RandNum() string {
seed := time.Now().UnixNano() + rand.Int63()
return fmt.Sprintf("%05v", rand.New(rand.NewSource(seed)).Int31n(1000000))
}

func GenerateUniqueRandomNumbers(n int) string {
rand.Seed(time.Now().UnixNano()) // 初始化随机种子
numbers := make([]int, n) // 创建一个切片来保存随机数
for i := range numbers {
j := 0
for {
b := rand.Intn(10) // 生成0-9之间的随机数
numbers[i] = b
for _, num := range numbers[:i] {
if num == b {
j++
break
}
}
if j == 0 {
break
}
}
}

var numbersStr string
for _, v := range numbers {
numbersStr += strconv.Itoa(v)
}
return numbersStr
}

+ 16
- 0
app/utils/url.go View File

@@ -0,0 +1,16 @@
package utils

import (
"net/url"
"strings"
)

func UriFilterExcludeQueryString(uri string) string {
URL, _ := url.Parse(uri)

clearUri := strings.ReplaceAll(uri, URL.RawQuery, "")

clearUri = strings.TrimRight(clearUri, "?")

return strings.TrimRight(clearUri, "/")
}

+ 23
- 0
cmd_dao.bat View File

@@ -0,0 +1,23 @@
@echo off
setlocal

set "BasePath=./"

REM 假设已经提供了文件名作为参数
set "FileName=%~1"

REM 将参数设置最终文件名
set "FinalFile=%BasePath%app\db\dao\%FileName%_dao.go"

REM 将文件名转换成大驼峰格式并设置成最终接口名
for /f "delims=" %%i in ('powershell -File "%BasePath%etc\ps\ConvertToUpperCase.ps1" -inputString "%FileName%"') do set "InterfaceName=%%i"

REM 使用 PowerShell 替换接口名称,并指定 UTF-8 编码
powershell -Command "(Get-Content '%BasePath%etc\template\template_interface.tpl') -replace 'DemoInterface', '%InterfaceName%' | Out-File -FilePath '%BasePath%temp_interface.go' -Encoding UTF8"

REM 如果需要,将临时文件重命名为最终文件(取决于move Y?N)
move /Y "%BasePath%temp_interface.go" "%FinalFile%"

echo Interface file %FileName%_dao.go generated successfully.

endlocal

+ 1
- 1
cmd_db.bat View File

@@ -12,7 +12,7 @@ if "%one%" NEQ "" (
set BasePath="./"
set DBUSER="root"
set DBPSW="Fnuo123com@"
set DBNAME="fnuoos_test1"
set DBNAME="advertisement"
set DBHOST="119.23.182.117"
set DBPORT="3306"



+ 23
- 0
cmd_implement.bat View File

@@ -0,0 +1,23 @@
@echo off
setlocal

set "BasePath=./"

REM 假设已经提供了文件名作为参数
set "FileName=%~1"

REM 将参数设置最终文件名
set "FinalFile=%BasePath%app\db\implement\%FileName%_implement.go"

REM 将文件名转换成大驼峰格式并设置成最终实现类名
for /f "delims=" %%i in ('powershell -File "%BasePath%etc\ps\ConvertToUpperCase.ps1" -inputString "%FileName%"') do set "ImplementName=%%i"

REM 使用 PowerShell 替换接口名称,并指定 UTF-8 编码
powershell -Command "(Get-Content '%BasePath%etc\template\template_implement.tpl') -replace 'DemoImplement', '%ImplementName%' | Out-File -FilePath '%BasePath%temp_implement.go' -Encoding UTF8"

REM 如果需要,将临时文件重命名为最终文件(取决于move Y?N)
move /Y "%BasePath%temp_implement.go" "%FinalFile%"

echo Implement file %FileName%_implement.go generated successfully.

endlocal

+ 499
- 1208
docs/docs.go
File diff suppressed because it is too large
View File


+ 485
- 1156
docs/swagger.json
File diff suppressed because it is too large
View File


+ 353
- 790
docs/swagger.yaml
File diff suppressed because it is too large
View File


+ 9
- 0
etc/ps/ConvertToUpperCase.ps1 View File

@@ -0,0 +1,9 @@
param($inputString)
$words = $inputString.Split('_')
$outputString = ""
foreach ($word in $words) {
$outputString += $word.Substring(0,1).ToUpper() + $word.Substring(1).ToLower() + ""
}
$outputString = $outputString.TrimEnd()
$outputString -replace ' ', '' # 如果想要没有空格的字符串,取消注释这行代码
$outputString

+ 14
- 0
etc/template/template_implement.tpl View File

@@ -0,0 +1,14 @@
package implement

import (
"applet/app/db/dao"
"xorm.io/xorm"
)

func NewDemoImplementDb(engine *xorm.Engine) dao.DemoImplementDao {
return &DemoImplementDb{Db: engine}
}

type DemoImplementDb struct {
Db *xorm.Engine
}

+ 5
- 0
etc/template/template_interface.tpl View File

@@ -0,0 +1,5 @@
package dao

type DemoInterfaceDao interface {
//TODO:: You can add specific method definitions here
}

+ 63
- 33
go.mod View File

@@ -2,54 +2,84 @@ module applet

go 1.18

replace code.fnuoos.com/zhimeng/model.git => E:/company/ad/models

require (
code.fnuoos.com/zhimeng/model.git v0.0.2
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751
github.com/antchfx/htmlquery v1.3.2 // indirect
github.com/antchfx/xmlquery v1.4.1 // indirect
github.com/boombuler/barcode v1.0.1
github.com/dchest/uniuri v0.0.0-20200228104902-7aecb25e1fe5
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/forgoer/openssl v0.0.0-20201023062029-c3112b0c8700
github.com/gin-contrib/sessions v0.0.3
github.com/gin-gonic/gin v1.6.3
github.com/go-openapi/spec v0.20.3 // indirect
github.com/go-openapi/swag v0.19.15 // indirect
github.com/go-playground/locales v0.13.0
github.com/go-playground/universal-translator v0.17.0
github.com/go-playground/validator/v10 v10.4.2
github.com/gin-gonic/gin v1.9.0
github.com/go-playground/locales v0.14.1
github.com/go-playground/universal-translator v0.18.1
github.com/go-playground/validator/v10 v10.11.2
github.com/go-redis/redis v6.15.9+incompatible
github.com/go-sql-driver/mysql v1.6.0
github.com/gobwas/glob v0.2.3 // indirect
github.com/gocolly/colly v1.2.0
github.com/golang/protobuf v1.5.2 // indirect
github.com/golang/snappy v0.0.3 // indirect
github.com/gomodule/redigo v2.0.0+incompatible
github.com/gookit/color v1.3.8 // indirect
github.com/gorilla/sessions v1.2.1 // indirect
github.com/iGoogle-ink/gopay v1.5.36
github.com/iGoogle-ink/gotil v1.0.20
github.com/json-iterator/go v1.1.10 // indirect
github.com/kennygrant/sanitize v1.2.4 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/makiuchi-d/gozxing v0.0.0-20210324052758-57132e828831
github.com/pkg/errors v0.9.1
github.com/qiniu/api.v7/v7 v7.8.2
github.com/robfig/cron/v3 v3.0.1
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d // indirect
github.com/sony/sonyflake v1.0.0
github.com/swaggo/swag v1.7.0
github.com/syyongx/php2go v0.9.4
github.com/temoto/robotstxt v1.1.2 // indirect
github.com/tidwall/gjson v1.7.4
github.com/ugorji/go v1.2.5 // indirect
go.uber.org/multierr v1.6.0 // indirect
github.com/swaggo/files v1.0.1
github.com/swaggo/gin-swagger v1.6.0
github.com/swaggo/swag v1.8.12
github.com/syyongx/php2go v0.9.8
go.uber.org/zap v1.16.0
golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1
gopkg.in/yaml.v2 v2.4.0
xorm.io/xorm v1.3.1
)

require (
filippo.io/edwards25519 v1.1.0 // indirect
github.com/KyleBanks/depth v1.2.1 // indirect
github.com/PuerkitoBio/purell v1.1.1 // indirect
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
github.com/bytedance/sonic v1.8.0 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.19.6 // indirect
github.com/go-openapi/spec v0.20.4 // indirect
github.com/go-openapi/swag v0.19.15 // indirect
github.com/go-sql-driver/mysql v1.8.1 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/gookit/color v1.3.8 // indirect
github.com/gorilla/context v1.1.1 // indirect
github.com/gorilla/securecookie v1.1.1 // indirect
github.com/gorilla/sessions v1.2.1 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/onsi/ginkgo v1.15.0 // indirect
github.com/onsi/gomega v1.10.5 // indirect
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/syndtr/goleveldb v1.0.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.9 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect
golang.org/x/crypto v0.5.0 // indirect
golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect
golang.org/x/net v0.10.0 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.8.0 // indirect
golang.org/x/text v0.9.0 // indirect
golang.org/x/tools v0.7.0 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
honnef.co/go/tools v0.0.1-2020.1.4 // indirect
xorm.io/builder v0.3.9 // indirect
xorm.io/xorm v1.0.7
xorm.io/builder v0.3.11-0.20220531020008-1bd24a7dc978 // indirect
)

+ 15
- 8
main.go View File

@@ -1,6 +1,7 @@
package main

import (
db "code.fnuoos.com/zhimeng/model.git/src"
"context"
"fmt"
"log"
@@ -11,12 +12,11 @@ import (
"time"

"applet/app/cfg"
"applet/app/db"
"applet/app/router"
"applet/app/utils"
)

//系统初始化
// 系统初始化
func init() {
cfg.InitCfg() //配置初始化
cfg.InitLog() //日志初始化
@@ -33,16 +33,23 @@ func init() {

}

// @title 智莺生活移动端接口
// @title 广告联盟-站长平台
// @version 1.0
// @description 移动端接口
// @termsOfService 智莺生活后端组
// @contact.name sherlockwhite
// @host localhost:5000
// @description 站长后台接口
// @termsOfService http://swagger.io/terms/

// @contact.name dengbiao
// @contact.url http://www.swagger.io/support
// @contact.email 1239118001@qq.com

// @license.name Apache 2.0
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html

// @host localhost:1002 or xxxx.advertisement.dengbiao.top
// @securityDefinitions.apikey MasterID
// @in header
// @name MasterID
// @BasePath /
// @BasePath /api
func main() {
// 启动获取所有品牌
//go taoke.GetAllBrand()


+ 0
- 156
test/zhimeng_api.go View File

@@ -1,156 +0,0 @@
package test

import (
"fmt"
"github.com/gocolly/colly"
"github.com/gocolly/colly/extensions"
"github.com/tidwall/gjson"
"net/http"
"regexp"
"strings"
)

/*
目前可用接口
[商品查询]https://www.showdoc.com.cn/59349170678610?page_id=339616554551473
[商品详情]https://www.showdoc.com.cn/59349170678610?page_id=339687047645094

*/

// Response is SDK Response
type Response struct {
Msg string `json:"msg"`
Success int `json:"success"`
Data interface{} `json:"data"`
}

func main() {
// // JD
// postData := map[string]string{"keyword": "联想", "p": "1", "size": "10"}
// fmt.Println(postData["time"])
// res, _ := zhimeng.Send("jd", "getgoods", postData)
// fmt.Println(string(res))
// p := Response{}
// json.Unmarshal(res, &p)
// fmt.Println(p)
// // VIP
// postData = map[string]string{"keyword": "联想", "p": "1", "size": "10", "order": "0"}
// fmt.Println(postData["time"])
// res, _ = zhimeng.Send("wph", "seach_goods", postData)
// fmt.Println(string(res))
// p = Response{}
// json.Unmarshal(res, &p)
// fmt.Println(p)
// // PDD
// postData = map[string]string{"keyword": "联想", "p": "1", "size": "10", "sort": "goods_price asc"}
// res, _ = zhimeng.Send("pdd", "getgoods", postData)
// fmt.Println(string(res))
// p = Response{}
// json.Unmarshal(res, &p)
// fmt.Println(p)
for i := 0; i < 1000; i++ {
fmt.Println(i)
scrapPDD()
}
}

func scrapJD() {
c := colly.NewCollector(func(collector *colly.Collector) {
extensions.RandomUserAgent(collector)
})
c.OnResponse(func(r *colly.Response) {
re, _ := regexp.Compile(`[(]//[^\s]*[)]`)
body := r.Body
fmt.Println(string(body))
urls := re.FindAllString(string(body), -1)
fmt.Println(urls)
for _, url := range urls {
url = strip(url, "()")
url = "https:" + url
fmt.Println(url)
}
})
c.Visit("https://wqsitem.jd.com/detail/100008309360_d100008309360_normal.html")
}

func scrapPDD() {
var cookies = []*http.Cookie{}
var mapcookies = make(map[string]string)
url := fmt.Sprintf("https://mobile.yangkeduo.com/goods.html?goods_id=%s", "156632692649")
cs := "api_uid=CiHUKl9DZKpL6QBVK4qWAg==; _nano_fp=Xpdbl0PyX5Pxn0TynT_DTGXbst0kz5cjzGAQDnBR; ua=Mozilla%2F5.0%20(Windows%20NT%2010.0%3B%20Win64%3B%20x64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F84.0.4147.135%20Safari%2F537.36; webp=1; quick_entrance_click_record=20200824%2C1; PDDAccessToken=XRC6FNX7FRBL6AJRMRBRN4CDG2PZXO3YJZYHFUA4O2PLDAWVYXHA1125821; pdd_user_id=9622705741400; pdd_user_uin=F27EAZ4V5S7EGEVMCJI2P7RFLE_GEXDA; chat_config={'host_whitelist':['.yangkeduo.com','.pinduoduo.com','.10010.com/queen/tencent/pinduoduo-fill.html','.ha.10086.cn/pay/card-sale!toforward.action','wap.ha.10086.cn','m.10010.com']}; pdd_vds=gaLMNqmfGfyYEpyYiZGWopaCicNHbXGWtDNcOZnWLqiDNfLHOXnZaqtCLDiX"
csList := strings.Split(cs, ";")
for _, c := range csList {
s := strings.Trim(c, " ")
sList := strings.SplitN(s, "=", 2)

mapcookies[sList[len(sList)-len(sList)]] = sList[(len(sList) - len(sList) + 1)]

}
fmt.Println(mapcookies)
for key, value := range mapcookies {
if key == "ua" {
continue
}
cookies = append(cookies, &http.Cookie{Name: key, Value: value})
}
c := colly.NewCollector(
colly.UserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36"),
)

c.OnResponse(func(r *colly.Response) {
re, _ := regexp.Compile(`window.rawData=.*}`)
body := r.Body
fmt.Println(string(body))
result := re.FindString(string(body))
// fmt.Println(result)
result = strings.SplitN(result, "=", 2)[1]
// fmt.Println(result)
value := gjson.Get(result, "store.initDataObj.goods.detailGallery")
// fmt.Println(value)
list := value.Array()
imageList := []string{}
for _, v := range list {
nv := gjson.Get(v.String(), "url")
imageList = append(imageList, nv.String())
}
fmt.Println(imageList)
ck := c.Cookies("https://mobile.yangkeduo.com")
fmt.Println(ck)
cookies = ck
})

c.SetCookies("https://mobile.yangkeduo.com", cookies)

c.Visit(url)
}

func strip(ss string, charss string) string {
s, chars := []rune(ss), []rune(charss)
length := len(s)
max := len(s) - 1
l, r := true, true //标记当左端或者右端找到正常字符后就停止继续寻找
start, end := 0, max
tmpEnd := 0
charset := make(map[rune]bool) //创建字符集,也就是唯一的字符,方便后面判断是否存在
for i := 0; i < len(chars); i++ {
charset[chars[i]] = true
}
for i := 0; i < length; i++ {
if _, exist := charset[s[i]]; l && !exist {
start = i
l = false
}
tmpEnd = max - i
if _, exist := charset[s[tmpEnd]]; r && !exist {
end = tmpEnd
r = false
}
if !l && !r {
break
}
}
if l && r { // 如果左端和右端都没找到正常字符,那么表示该字符串没有正常字符
return ""
}
return string(s[start : end+1])
}

Loading…
Cancel
Save