commit dd96cce40e53b1fab8b77984c68422346abd73eb Author: zze <49554487+zze326@users.noreply.github.com> Date: Fri Sep 22 16:55:57 2023 +0800 Initial commit diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1fbf887 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* linguist-language=GO \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2f4f842 --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +.buildpath +.hgignore.swp +.project +.orig +.swp +.idea/ +.settings/ +.vscode/ +bin/ +**/.DS_Store +gf +main +main.exe +output/ +manifest/output/ +temp/ +temp.yaml +bin +**/config/config-prod.yaml +dist \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b822f69 --- /dev/null +++ b/Makefile @@ -0,0 +1,6 @@ +ROOT_DIR = $(shell pwd) +NAMESPACE = "default" +DEPLOY_NAME = "zze-admin-go" +DOCKER_NAME = "zze-admin-go" + +include ./hack/hack.mk \ No newline at end of file diff --git a/README.MD b/README.MD new file mode 100644 index 0000000..4d86b0b --- /dev/null +++ b/README.MD @@ -0,0 +1,42 @@ +# zze Admin go + +## 功能 + +本项目主要用来作为新项目启动时的模板,如果你想要使用 Golang 来新开发一个后台管理系统,那么选我就对了。 + +- 已实现后台管理系统最基础的用户管理、角色管理、权限管理,基于它来开发可以让你可以更聚焦业务的实现。 +- 选用了相对成熟、稳定、功能齐全的的框架,后端基于 **[GoFrame](https://goframe.org/pages/viewpage.action?pageId=1114119)** + ,前端基于 **[PureAdmin](https://yiming_chang.gitee.io/pure-admin-doc/pages/introduction/)**; +- 支持一套权限管理逻辑控制前后端路由、按钮级别权限; + +## 预览地址 + +[点我预览](http://admin.zze.xyz) + +- 管理员:`admin`,密码:`devops.zze`; +- 测试账号:`test`,密码:`devops.zze`; + +效果图: + +![用户管理](https://raw.githubusercontent.com/zze326/zze-admin-go/main/resource/imgs/user-manage.png) +![角色管理](https://raw.githubusercontent.com/zze326/zze-admin-go/main/resource/imgs/role-manage.png) +![权限管理](https://raw.githubusercontent.com/zze326/zze-admin-go/main/resource/imgs/permission-manage.png) +![部门管理](https://raw.githubusercontent.com/zze326/zze-admin-go/main/resource/imgs/dept-manage.png) + +## 技术栈 + +- 语言:Golang、Typescript; +- 后端:GoFrame、Casbin; +- 前端:Vue3、Vite、Element-Plus、TypeScript、Pinia 等; + +## 项目运行 +1、在 MySQL 中执行 `manifest/db/zze_admin_go.sql` 创建好数据库以及初始化数据; + +2、然后修改 `manifest/config/config.yaml` 中的数据库连接地址(`database.default.link`),格式如下: +```sql +mysql:<用户名>:<密码>@tcp(<数据库地址>)/<库名>?loc=Local&parseTime=true +-- 例:mysql:zze:zze.admin@tcp(127.0.0.1:3306)/zze_admin_go?loc=Local&parseTime=true +``` +3、直接运行项目根目录的 `main.go` 就可以跑起来啦~ +## 前端项目 +本仓库是后端项目,对应前端项目地址为:。 \ No newline at end of file diff --git a/api/common.go b/api/common.go new file mode 100644 index 0000000..a5ced09 --- /dev/null +++ b/api/common.go @@ -0,0 +1,29 @@ +package api + +import ( + "github.com/gogf/gf/v2/encoding/gjson" +) + +type PageLstReq struct { + Page int `p:"page" v:"page @integer|min:1#页码必填" dc:"页码"` // 页码 + PageSize int `p:"pageSize" v:"pageSize @integer|min:1#每页数量必填" dc:"每页数量"` // 每页数量 + Search string `p:"search" dc:"模糊搜索内容"` // 搜索内容 + Wheres *gjson.Json `p:"wheres" dc:"搜索条件"` +} + +func (r *PageLstReq) Offset() int { + return (r.Page - 1) * r.PageSize +} + +func (r *PageLstReq) Limit() int { + return r.PageSize +} + +func (r *PageLstReq) SearchStr() string { + return "%" + r.Search + "%" +} + +type PageLstRes[T any] struct { + Total int `json:"total" dc:"总数"` // 总数 + List []T `json:"list" dc:"列表"` // 列表 +} diff --git a/api/dept/dept.go b/api/dept/dept.go new file mode 100644 index 0000000..7d0d1a0 --- /dev/null +++ b/api/dept/dept.go @@ -0,0 +1,18 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package dept + +import ( + "context" + + "devops-super/api/dept/v1" +) + +type IDeptV1 interface { + Add(ctx context.Context, req *v1.AddReq) (res *v1.AddRes, err error) + GetLst(ctx context.Context, req *v1.GetLstReq) (res *v1.GetLstRes, err error) + Upt(ctx context.Context, req *v1.UptReq) (res *v1.UptRes, err error) + Del(ctx context.Context, req *v1.DelReq) (res *v1.DelRes, err error) +} diff --git a/api/dept/v1/dept.go b/api/dept/v1/dept.go new file mode 100644 index 0000000..8943415 --- /dev/null +++ b/api/dept/v1/dept.go @@ -0,0 +1,38 @@ +package v1 + +import ( + "devops-super/internal/model/entity" + "devops-super/internal/model/mid" + "github.com/gogf/gf/v2/frame/g" +) + +type AddReq struct { + g.Meta `path:"/dept" method:"post" tags:"部门" summary:"新增部门"` + *mid.Dept +} + +type AddRes struct{} + +type GetLstReq struct { + g.Meta `path:"/dept/list" method:"get" tags:"部门" summary:"获取部门列表"` + Search string `p:"search"` +} + +type GetLstRes struct { + List []*entity.Dept `json:"list"` +} + +type UptReq struct { + g.Meta `path:"/dept/{id}" method:"put" tags:"部门" summary:"更新部门"` + Id int ` v:"min:1#id必须" path:"id"` + *mid.Dept +} + +type UptRes struct{} + +type DelReq struct { + g.Meta `path:"/dept/{id}" method:"delete" tags:"部门" summary:"删除部门"` + Id int `v:"min:1#id必须" path:"id" ` +} + +type DelRes struct{} diff --git a/api/permission/permission.go b/api/permission/permission.go new file mode 100644 index 0000000..0598cfb --- /dev/null +++ b/api/permission/permission.go @@ -0,0 +1,22 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package permission + +import ( + "context" + + "devops-super/api/permission/v1" +) + +type IPermissionV1 interface { + Add(ctx context.Context, req *v1.AddReq) (res *v1.AddRes, err error) + GetLst(ctx context.Context, req *v1.GetLstReq) (res *v1.GetLstRes, err error) + Upt(ctx context.Context, req *v1.UptReq) (res *v1.UptRes, err error) + UptShowLink(ctx context.Context, req *v1.UptShowLinkReq) (res *v1.UptShowLinkRes, err error) + Del(ctx context.Context, req *v1.DelReq) (res *v1.DelRes, err error) + GetRouteLst(ctx context.Context, req *v1.GetRouteLstReq) (res *v1.GetRouteLstRes, err error) +} + + diff --git a/api/permission/v1/permission.go b/api/permission/v1/permission.go new file mode 100644 index 0000000..690517a --- /dev/null +++ b/api/permission/v1/permission.go @@ -0,0 +1,54 @@ +package v1 + +import ( + "devops-super/internal/model/entity" + "devops-super/internal/model/mid" + "github.com/gogf/gf/v2/frame/g" +) + +type AddReq struct { + g.Meta `path:"/permission" method:"post" tags:"权限" summary:"创建权限"` + *mid.Permission +} + +type AddRes struct{} + +type GetLstReq struct { + g.Meta `path:"/permission/list" method:"get" tags:"权限" summary:"获取权限列表"` + Search string `p:"search"` +} + +type GetLstRes struct { + List []*entity.Permission `json:"list"` +} + +type UptReq struct { + g.Meta `path:"/permission/{id}" method:"put" tags:"权限" summary:"更新权限"` + Id int ` v:"min:1#id必须" path:"id"` + *mid.Permission +} + +type UptRes struct{} + +type UptShowLinkReq struct { + g.Meta `path:"/permission/{id}/show-link" method:"patch" tags:"权限" summary:"更新是否显示在菜单"` + Id int `v:"min:1#id必须" path:"id" ` + Enabled bool `v:"required" json:"enabled"` +} + +type UptShowLinkRes struct{} + +type DelReq struct { + g.Meta `path:"/permission/{id}" method:"delete" tags:"权限" summary:"删除权限"` + Id int `v:"min:1#id必须" path:"id" ` +} + +type DelRes struct{} + +type GetRouteLstReq struct { + g.Meta `path:"/permission/route-list" method:"get" tags:"权限" summary:"获取前端路由列表"` +} + +type GetRouteLstRes struct { + List []*mid.Route `json:"list"` +} diff --git a/api/public/public.go b/api/public/public.go new file mode 100644 index 0000000..de2422f --- /dev/null +++ b/api/public/public.go @@ -0,0 +1,18 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package public + +import ( + "context" + + "devops-super/api/public/v1" +) + +type IPublicV1 interface { + Login(ctx context.Context, req *v1.LoginReq) (res *v1.LoginRes, err error) + RefreshToken(ctx context.Context, req *v1.RefreshTokenReq) (res *v1.RefreshTokenRes, err error) + Logout(ctx context.Context, req *v1.LogoutReq) (res *v1.LogoutRes, err error) + Ping(ctx context.Context, req *v1.PingReq) (res *v1.PingRes, err error) +} diff --git a/api/public/v1/login.go b/api/public/v1/login.go new file mode 100644 index 0000000..33603ec --- /dev/null +++ b/api/public/v1/login.go @@ -0,0 +1,37 @@ +package v1 + +import "github.com/gogf/gf/v2/frame/g" + +type LoginReq struct { + g.Meta `path:"/login" tags:"用户" method:"post" summary:"登录"` + Username string `v:"required#请输入用户名" json:"username" dc:"用户名"` + Password string `v:"required#请输入密码" json:"password" dc:"密码"` +} + +type LoginRes struct { + Username string `json:"username"` + RealName string `json:"realName"` + Token string `json:"token"` + Expires int64 `json:"expires"` + RefreshAfter int64 `json:"refreshAfter"` + Roles []string `json:"roles"` +} + +type RefreshTokenReq struct { + g.Meta `path:"/refresh-token" method:"post" tags:"用户" summary:"刷新 Token"` +} + +type RefreshTokenRes struct { + Username string `json:"username"` + RealName string `json:"realName"` + Token string `json:"token"` + Expire int64 `json:"expire"` + RefreshAfter int64 `json:"refreshAfter"` + Roles []string `json:"roles"` +} + +type LogoutReq struct { + g.Meta `path:"/logout" method:"post" tags:"用户" summary:"用户登出"` +} + +type LogoutRes struct{} diff --git a/api/public/v1/public.go b/api/public/v1/public.go new file mode 100644 index 0000000..4916033 --- /dev/null +++ b/api/public/v1/public.go @@ -0,0 +1,9 @@ +package v1 + +import "github.com/gogf/gf/v2/frame/g" + +type PingReq struct { + g.Meta `path:"/ping" method:"get" tags:"健康检查" summary:"ping"` +} + +type PingRes struct{} diff --git a/api/role/role.go b/api/role/role.go new file mode 100644 index 0000000..16bb3bc --- /dev/null +++ b/api/role/role.go @@ -0,0 +1,22 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package role + +import ( + "context" + + "devops-super/api/role/v1" +) + +type IRoleV1 interface { + UptPermission(ctx context.Context, req *v1.UptPermissionReq) (res *v1.UptPermissionRes, err error) + GetPageLst(ctx context.Context, req *v1.GetPageLstReq) (res *v1.GetPageLstRes, err error) + Add(ctx context.Context, req *v1.AddReq) (res *v1.AddRes, err error) + Upt(ctx context.Context, req *v1.UptReq) (res *v1.UptRes, err error) + Del(ctx context.Context, req *v1.DelReq) (res *v1.DelRes, err error) + GetLst(ctx context.Context, req *v1.GetLstReq) (res *v1.GetLstRes, err error) +} + + diff --git a/api/role/v1/permission.go b/api/role/v1/permission.go new file mode 100644 index 0000000..dc4829e --- /dev/null +++ b/api/role/v1/permission.go @@ -0,0 +1,14 @@ +package v1 + +import ( + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/frame/g" +) + +type UptPermissionReq struct { + g.Meta `method:"patch" path:"/role/{id}/permission" summary:"更新角色关联的权限" tags:"角色"` + Id int `v:"min:1#id必须" path:"id"` + PermissionIds *gjson.Json `json:"permissionIds"` +} + +type UptPermissionRes struct{} diff --git a/api/role/v1/role.go b/api/role/v1/role.go new file mode 100644 index 0000000..66db2ec --- /dev/null +++ b/api/role/v1/role.go @@ -0,0 +1,48 @@ +package v1 + +import ( + "devops-super/api" + "devops-super/internal/model/entity" + "devops-super/internal/model/mid" + "github.com/gogf/gf/v2/frame/g" +) + +type GetPageLstReq struct { + g.Meta `method:"get" path:"/role/page-list" summary:"分页获取角色列表" tags:"角色"` + *api.PageLstReq +} + +type GetPageLstRes struct { + *api.PageLstRes[*entity.Role] +} + +type AddReq struct { + g.Meta `method:"post" path:"/role" summary:"添加角色" tags:"角色"` + *mid.Role +} + +type AddRes struct{} + +type UptReq struct { + g.Meta `method:"put" path:"/role/{id}" summary:"更新角色" tags:"角色"` + Id int ` v:"min:1#id必须" path:"id"` + *mid.Role +} + +type UptRes struct{} + +type DelReq struct { + g.Meta `method:"delete" path:"/role/{id}" summary:"删除角色" tags:"角色"` + Id int ` v:"min:1#id必须" path:"id"` +} + +type DelRes struct{} + +type GetLstReq struct { + g.Meta `method:"get" path:"/role/list" summary:"获取所有角色列表" tags:"角色"` + *api.PageLstReq +} + +type GetLstRes struct { + List []*entity.Role `json:"list"` +} diff --git a/api/user/user.go b/api/user/user.go new file mode 100644 index 0000000..714cb64 --- /dev/null +++ b/api/user/user.go @@ -0,0 +1,22 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package user + +import ( + "context" + + "devops-super/api/user/v1" +) + +type IUserV1 interface { + GetPageLst(ctx context.Context, req *v1.GetPageLstReq) (res *v1.GetPageLstRes, err error) + Add(ctx context.Context, req *v1.AddReq) (res *v1.AddRes, err error) + Upt(ctx context.Context, req *v1.UptReq) (res *v1.UptRes, err error) + UptPassword(ctx context.Context, req *v1.UptPasswordReq) (res *v1.UptPasswordRes, err error) + UptEnabled(ctx context.Context, req *v1.UptEnabledReq) (res *v1.UptEnabledRes, err error) + Del(ctx context.Context, req *v1.DelReq) (res *v1.DelRes, err error) +} + + diff --git a/api/user/v1/user.go b/api/user/v1/user.go new file mode 100644 index 0000000..444ce12 --- /dev/null +++ b/api/user/v1/user.go @@ -0,0 +1,55 @@ +package v1 + +import ( + "devops-super/api" + "devops-super/internal/model/entity" + "devops-super/internal/model/mid" + "github.com/gogf/gf/v2/frame/g" +) + +type GetPageLstReq struct { + g.Meta `method:"get" path:"/user/page-list" summary:"分页获取用户列表" tags:"用户"` + *api.PageLstReq +} + +type GetPageLstRes struct { + *api.PageLstRes[*entity.User] +} + +type AddReq struct { + g.Meta `method:"post" path:"/user" summary:"新增用户" tags:"用户"` + *mid.User +} + +type AddRes struct{} + +type UptReq struct { + g.Meta `method:"put" path:"/user/{id}" summary:"更新用户" tags:"用户"` + Id int ` v:"min:1#id必须" path:"id"` + *mid.User +} + +type UptRes struct{} + +type UptPasswordReq struct { + g.Meta `method:"patch" path:"/user/{id}/password" summary:"更新用户密码" tags:"用户"` + Id int ` v:"min:1#id必须" path:"id"` + Password string `v:"required|length:6,30#请输入密码|密码长度为:{min}到:{max}位"` +} + +type UptPasswordRes struct{} + +type UptEnabledReq struct { + g.Meta `method:"patch" path:"/user/{id}/enabled" summary:"更新用户密码" tags:"用户"` + Id int `v:"min:1#id必须" path:"id"` + Enabled bool `v:"required" json:"enabled"` +} + +type UptEnabledRes struct{} + +type DelReq struct { + g.Meta `method:"delete" path:"/user/{id}" summary:"删除用户" tags:"用户"` + Id int ` v:"min:1#id必须" path:"id"` +} + +type DelRes struct{} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..6f83cb1 --- /dev/null +++ b/go.mod @@ -0,0 +1,45 @@ +module devops-super + +go 1.18 + +require ( + github.com/casbin/casbin/v2 v2.77.2 + github.com/gogf/gf-jwt/v2 v2.1.0 + github.com/gogf/gf/contrib/drivers/mysql/v2 v2.5.4 + github.com/gogf/gf/contrib/nosql/redis/v2 v2.5.4 + github.com/gogf/gf/v2 v2.5.4 + golang.org/x/crypto v0.11.0 +) + +require ( + github.com/BurntSushi/toml v1.2.0 // indirect + github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/clbanning/mxj/v2 v2.7.0 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/fatih/color v1.15.0 // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/go-logr/logr v1.2.4 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-sql-driver/mysql v1.7.1 // indirect + github.com/golang-jwt/jwt/v4 v4.3.0 // indirect + github.com/gorilla/websocket v1.5.0 // indirect + github.com/grokify/html-strip-tags-go v0.0.1 // indirect + github.com/magiconair/properties v1.8.6 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/olekukonko/tablewriter v0.0.5 // indirect + github.com/redis/go-redis/v9 v9.0.5 // indirect + github.com/rivo/uniseg v0.4.4 // indirect + github.com/tidwall/gjson v1.14.4 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.0 // indirect + go.opentelemetry.io/otel v1.14.0 // indirect + go.opentelemetry.io/otel/sdk v1.14.0 // indirect + go.opentelemetry.io/otel/trace v1.14.0 // indirect + golang.org/x/net v0.12.0 // indirect + golang.org/x/sys v0.10.0 // indirect + golang.org/x/text v0.11.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..c660fbb --- /dev/null +++ b/go.sum @@ -0,0 +1,202 @@ +github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.2.0 h1:Rt8g24XnyGTyglgET/PRUNlrUeu9F5L+7FilkXfZgs0= +github.com/BurntSushi/toml v1.2.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw= +github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/bsm/ginkgo/v2 v2.7.0 h1:ItPMPH90RbmZJt5GtkcNvIRuGEdwlBItdNVoyzaNQao= +github.com/bsm/gomega v1.26.0 h1:LhQm+AFcgV2M0WyKroMASzAzCAJVpAxQXv4SaI9a69Y= +github.com/casbin/casbin/v2 v2.77.2 h1:yQinn/w9x8AswiwqwtrXz93VU48R1aYTXdHEx4RI3jM= +github.com/casbin/casbin/v2 v2.77.2/go.mod h1:mzGx0hYW9/ksOSpw3wNjk3NRAroq5VMFYUQ6G43iGPk= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= +github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME= +github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= +github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Pxt6RJr792+w= +github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= +github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/gogf/gf-jwt/v2 v2.1.0 h1:79/KH6vo3IAtHTvRubE8/NXKDF6/UisItLVpdsTTIjE= +github.com/gogf/gf-jwt/v2 v2.1.0/go.mod h1:AGEJOkG64G8ZYOi50ObYgJ+D7L3W4GcTW65m6VVGbmI= +github.com/gogf/gf/contrib/drivers/mysql/v2 v2.5.4 h1:xAmYQZEDBDoce/q5s7UTibYHHW0DSTApfmXVC/i0/zI= +github.com/gogf/gf/contrib/drivers/mysql/v2 v2.5.4/go.mod h1:lEgzJw5PLBOEJ4gZHgs1GwsbjyBLBttN2sN63rYRNhk= +github.com/gogf/gf/contrib/nosql/redis/v2 v2.5.4 h1:t4Ls/E022VMk5hc3a4IgWO3xGNEQRXicCTOrFymZdDg= +github.com/gogf/gf/contrib/nosql/redis/v2 v2.5.4/go.mod h1:1P7id3OWFb3lkp1zBKdGqRoVXgYAjATzky++tGh2vxc= +github.com/gogf/gf/v2 v2.0.0-rc3/go.mod h1:apktt6TleWtCIwpz63vBqUnw8MX8gWKoZyxgDpXFtgM= +github.com/gogf/gf/v2 v2.5.4 h1:UBCSw8mInkHmEqL0E1LYc6QhSpaNFY/wHcFrTI/rzTk= +github.com/gogf/gf/v2 v2.5.4/go.mod h1:7yf5qp0BznfsYx7Sw49m3mQvBsHpwAjJk3Q9ZnKoUEc= +github.com/golang-jwt/jwt/v4 v4.3.0 h1:kHL1vqdqWNfATmA0FNMdmZNMyZI1U6O31X4rlIPoBog= +github.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grokify/html-strip-tags-go v0.0.1 h1:0fThFwLbW7P/kOiTBs03FsJSV9RM2M/Q/MOnCQxKMo0= +github.com/grokify/html-strip-tags-go v0.0.1/go.mod h1:2Su6romC5/1VXOQMaWL2yb618ARB8iVo6/DR99A6d78= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= +github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/redis/go-redis/v9 v9.0.5 h1:CuQcn5HIEeK7BgElubPP8CGtE0KakrnbBSTLjathl5o= +github.com/redis/go-redis/v9 v9.0.5/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= +github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= +github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.opentelemetry.io/otel v1.0.0/go.mod h1:AjRVh9A5/5DE7S+mZtTR6t8vpKKryam+0lREnfmS4cg= +go.opentelemetry.io/otel v1.14.0 h1:/79Huy8wbf5DnIPhemGB+zEPVwnN6fuQybr/SRXa6hM= +go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU= +go.opentelemetry.io/otel/sdk v1.0.0/go.mod h1:PCrDHlSy5x1kjezSdL37PhbFUMjrsLRshJ2zCzeXwbM= +go.opentelemetry.io/otel/sdk v1.14.0 h1:PDCppFRDq8A1jL9v6KMI6dYesaq+DFcDZvjsoGvxGzY= +go.opentelemetry.io/otel/sdk v1.14.0/go.mod h1:bwIC5TjrNG6QDCHNWvW4HLHtUQ4I+VQDsnjhvyZCALM= +go.opentelemetry.io/otel/trace v1.0.0/go.mod h1:PXTWqayeFUlJV1YDNhsJYB184+IvAH814St6o6ajzIs= +go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyKcFq/M= +go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= +golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= +golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0= +golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/hack/config.yaml b/hack/config.yaml new file mode 100644 index 0000000..0076752 --- /dev/null +++ b/hack/config.yaml @@ -0,0 +1,19 @@ + +# CLI tool, only in development environment. +# https://goframe.org/pages/viewpage.action?pageId=3673173 +gfcli: + docker: + build: "-a amd64 -s linux -p temp -ew" + tagPrefixes: + - zze326/ + gen: + dao: + - link: "mysql:zze:devops.zze@tcp(192.168.2.231:3306)/zze_admin_go?loc=Local&parseTime=true" + group: default + tables: "user, permission, role, dept" + withTime: false + gJsonSupport: true + overwriteDao: true + descriptionTag: true +# jsonCase: Snake + clear: true \ No newline at end of file diff --git a/hack/hack-cli.mk b/hack/hack-cli.mk new file mode 100644 index 0000000..7ba0d72 --- /dev/null +++ b/hack/hack-cli.mk @@ -0,0 +1,19 @@ + +# Install/Update to the latest CLI tool. +.PHONY: cli +cli: + @set -e; \ + wget -O gf https://github.com/gogf/gf/releases/latest/download/gf_$(shell go env GOOS)_$(shell go env GOARCH) && \ + chmod +x gf && \ + ./gf install -y && \ + rm ./gf + + +# Check and install CLI tool. +.PHONY: cli.install +cli.install: + @set -e; \ + gf -v > /dev/null 2>&1 || if [[ "$?" -ne "0" ]]; then \ + echo "GoFame CLI is not installed, start proceeding auto installation..."; \ + make cli; \ + fi; \ No newline at end of file diff --git a/hack/hack.mk b/hack/hack.mk new file mode 100644 index 0000000..9ca4f84 --- /dev/null +++ b/hack/hack.mk @@ -0,0 +1,77 @@ +include ./hack/hack-cli.mk +DATE := $(shell date '+%Y%m%d%H%M') + +# Update GoFrame and its CLI to latest stable version. +.PHONY: up +up: cli.install + @gf up -a + +# Build binary using configuration from hack/config.yaml. +.PHONY: build +build: cli.install + @gf build -ew + +# Parse api and generate controller/sdk. +.PHONY: ctrl +ctrl: cli.install + @gf gen ctrl + +# Generate Go files for DAO/DO/Entity. +.PHONY: dao +dao: cli.install + @gf gen dao + +# Parse current project go files and generate enums go file. +.PHONY: enums +enums: cli.install + @gf gen enums + +# Generate Go files for Service. +.PHONY: service +service: cli.install + @gf gen service + + +# Build docker image. +.PHONY: image +image: cli.install +# $(eval _TAG = $(shell git describe --dirty --always --tags --abbrev=8 --match 'v*' | sed 's/-/./2' | sed 's/-/./2')) + $(eval _TAG = $(DATE)) +#ifneq (, $(shell git status --porcelain 2>/dev/null)) +# $(eval _TAG = $(_TAG).dirty) +#endif + $(eval _TAG = $(if ${TAG}, ${TAG}, $(_TAG))) + $(eval _PUSH = $(if ${PUSH}, ${PUSH}, )) + @gf docker ${_PUSH} -tn $(DOCKER_NAME):${_TAG}; + + +# Build docker image and automatically push to docker repo. +.PHONY: image.push +image.push: + @make image PUSH=-p; + + +# Deploy image and yaml to current kubectl environment. +.PHONY: deploy +deploy: + $(eval _TAG = $(if ${TAG}, ${TAG}, develop)) + + @set -e; \ + mkdir -p $(ROOT_DIR)/temp/kustomize;\ + cd $(ROOT_DIR)/manifest/deploy/kustomize/overlays/${_ENV};\ + kustomize build > $(ROOT_DIR)/temp/kustomize.yaml;\ + kubectl apply -f $(ROOT_DIR)/temp/kustomize.yaml; \ + if [ $(DEPLOY_NAME) != "" ]; then \ + kubectl patch -n $(NAMESPACE) deployment/$(DEPLOY_NAME) -p "{\"spec\":{\"template\":{\"metadata\":{\"labels\":{\"date\":\"$(shell date +%s)\"}}}}}"; \ + fi; + + +# Parsing protobuf files and generating go files. +.PHONY: pb +pb: cli.install + @gf gen pb + +# Generate protobuf files for database tables. +.PHONY: pbentity +pbentity: cli.install + @gf gen pbentity \ No newline at end of file diff --git a/internal/cmd/cmd.go b/internal/cmd/cmd.go new file mode 100644 index 0000000..0df3132 --- /dev/null +++ b/internal/cmd/cmd.go @@ -0,0 +1,51 @@ +package cmd + +import ( + "context" + "devops-super/internal/controller/dept" + "devops-super/internal/controller/permission" + "devops-super/internal/controller/public" + "devops-super/internal/controller/role" + "devops-super/internal/controller/user" + "devops-super/internal/service" + + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/net/ghttp" + "github.com/gogf/gf/v2/os/gcmd" +) + +var ( + Main = gcmd.Command{ + Name: "main", + Usage: "main", + Brief: "start http server", + Func: func(ctx context.Context, parser *gcmd.Parser) (err error) { + s := g.Server() + s.Group("/", func(group *ghttp.RouterGroup) { + group.Middleware(ghttp.MiddlewareCORS) + group.Middleware(ghttp.MiddlewareHandlerResponse) + group.Bind( + public.NewV1(), + ) + + // 权限控制路由 + group.Group("/", func(group *ghttp.RouterGroup) { + group.Middleware(service.Middleware().Auth) + group.Bind( + user.NewV1(), + permission.NewV1(), + role.NewV1(), + dept.NewV1(), + ) + }) + }) + + // 初始化 + if err = service.Context().Init(ctx); err != nil { + g.Log().Fatal(ctx, err) + } + s.Run() + return nil + }, + } +) diff --git a/internal/consts/consts.go b/internal/consts/consts.go new file mode 100644 index 0000000..8922b4b --- /dev/null +++ b/internal/consts/consts.go @@ -0,0 +1,11 @@ +package consts + +// 权限类型 +const ( + PERMISSION_TYPE_DIR = 1 // 目录 + PERMISSION_TYPE_MENU = 2 // 菜单 + PERMISSION_TYPE_ABLE = 3 // 功能 +) + +// 系统必须权限名称 +const PERMISSION_SYSTEM_REQUIRED_NAME = "system-required" diff --git a/internal/controller/dept/dept.go b/internal/controller/dept/dept.go new file mode 100644 index 0000000..4719bd2 --- /dev/null +++ b/internal/controller/dept/dept.go @@ -0,0 +1,5 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dept diff --git a/internal/controller/dept/dept_new.go b/internal/controller/dept/dept_new.go new file mode 100644 index 0000000..765d4ac --- /dev/null +++ b/internal/controller/dept/dept_new.go @@ -0,0 +1,15 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package dept + +import ( + "devops-super/api/dept" +) + +type ControllerV1 struct{} + +func NewV1() dept.IDeptV1 { + return &ControllerV1{} +} diff --git a/internal/controller/dept/dept_v1_add.go b/internal/controller/dept/dept_v1_add.go new file mode 100644 index 0000000..25d257e --- /dev/null +++ b/internal/controller/dept/dept_v1_add.go @@ -0,0 +1,20 @@ +package dept + +import ( + "context" + "devops-super/internal/model/entity" + "devops-super/internal/service" + "github.com/gogf/gf/v2/util/gconv" + + "devops-super/api/dept/v1" +) + +func (c *ControllerV1) Add(ctx context.Context, req *v1.AddReq) (res *v1.AddRes, err error) { + in := new(entity.Dept) + if err = gconv.Struct(req, in); err != nil { + return + } + + err = service.Dept().Add(ctx, in) + return +} diff --git a/internal/controller/dept/dept_v1_del.go b/internal/controller/dept/dept_v1_del.go new file mode 100644 index 0000000..ec3ed8d --- /dev/null +++ b/internal/controller/dept/dept_v1_del.go @@ -0,0 +1,14 @@ +package dept + +import ( + "context" + "devops-super/internal/model/do" + "devops-super/internal/service" + + "devops-super/api/dept/v1" +) + +func (c *ControllerV1) Del(ctx context.Context, req *v1.DelReq) (res *v1.DelRes, err error) { + err = service.Role().Del(ctx, &do.Role{Id: req.Id}) + return +} diff --git a/internal/controller/dept/dept_v1_get_lst.go b/internal/controller/dept/dept_v1_get_lst.go new file mode 100644 index 0000000..dff1cdf --- /dev/null +++ b/internal/controller/dept/dept_v1_get_lst.go @@ -0,0 +1,14 @@ +package dept + +import ( + "context" + "devops-super/internal/service" + + "devops-super/api/dept/v1" +) + +func (c *ControllerV1) GetLst(ctx context.Context, req *v1.GetLstReq) (res *v1.GetLstRes, err error) { + res = new(v1.GetLstRes) + res.List, err = service.Dept().GetLst(ctx, req.Search) + return +} diff --git a/internal/controller/dept/dept_v1_upt.go b/internal/controller/dept/dept_v1_upt.go new file mode 100644 index 0000000..3306da7 --- /dev/null +++ b/internal/controller/dept/dept_v1_upt.go @@ -0,0 +1,19 @@ +package dept + +import ( + "context" + "devops-super/internal/model/do" + "devops-super/internal/service" + "github.com/gogf/gf/v2/util/gconv" + + "devops-super/api/dept/v1" +) + +func (c *ControllerV1) Upt(ctx context.Context, req *v1.UptReq) (res *v1.UptRes, err error) { + in := new(do.Dept) + if err = gconv.Struct(req, in); err != nil { + return + } + err = service.Dept().Upt(ctx, in) + return +} diff --git a/internal/controller/permission/permission.go b/internal/controller/permission/permission.go new file mode 100644 index 0000000..8cc591b --- /dev/null +++ b/internal/controller/permission/permission.go @@ -0,0 +1,6 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package permission + diff --git a/internal/controller/permission/permission_new.go b/internal/controller/permission/permission_new.go new file mode 100644 index 0000000..976f3fe --- /dev/null +++ b/internal/controller/permission/permission_new.go @@ -0,0 +1,16 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package permission + +import ( + "devops-super/api/permission" +) + +type ControllerV1 struct{} + +func NewV1() permission.IPermissionV1 { + return &ControllerV1{} +} + diff --git a/internal/controller/permission/permission_v1_add.go b/internal/controller/permission/permission_v1_add.go new file mode 100644 index 0000000..f29fb6a --- /dev/null +++ b/internal/controller/permission/permission_v1_add.go @@ -0,0 +1,19 @@ +package permission + +import ( + "context" + "devops-super/internal/model/entity" + "devops-super/internal/service" + "github.com/gogf/gf/v2/util/gconv" + + "devops-super/api/permission/v1" +) + +func (c *ControllerV1) Add(ctx context.Context, req *v1.AddReq) (res *v1.AddRes, err error) { + ePermission := new(entity.Permission) + if err = gconv.Struct(req, ePermission); err != nil { + return + } + err = service.Permission().Add(ctx, ePermission) + return +} diff --git a/internal/controller/permission/permission_v1_del.go b/internal/controller/permission/permission_v1_del.go new file mode 100644 index 0000000..4df6531 --- /dev/null +++ b/internal/controller/permission/permission_v1_del.go @@ -0,0 +1,14 @@ +package permission + +import ( + "context" + "devops-super/internal/model/do" + "devops-super/internal/service" + + "devops-super/api/permission/v1" +) + +func (c *ControllerV1) Del(ctx context.Context, req *v1.DelReq) (res *v1.DelRes, err error) { + err = service.Permission().Del(ctx, &do.Permission{Id: req.Id}) + return +} diff --git a/internal/controller/permission/permission_v1_get_lst.go b/internal/controller/permission/permission_v1_get_lst.go new file mode 100644 index 0000000..50caeb2 --- /dev/null +++ b/internal/controller/permission/permission_v1_get_lst.go @@ -0,0 +1,14 @@ +package permission + +import ( + "context" + "devops-super/internal/service" + + "devops-super/api/permission/v1" +) + +func (c *ControllerV1) GetLst(ctx context.Context, req *v1.GetLstReq) (res *v1.GetLstRes, err error) { + res = new(v1.GetLstRes) + res.List, err = service.Permission().GetLst(ctx, req.Search) + return +} diff --git a/internal/controller/permission/permission_v1_get_route_lst.go b/internal/controller/permission/permission_v1_get_route_lst.go new file mode 100644 index 0000000..5dc22b5 --- /dev/null +++ b/internal/controller/permission/permission_v1_get_route_lst.go @@ -0,0 +1,14 @@ +package permission + +import ( + "context" + "devops-super/internal/service" + + "devops-super/api/permission/v1" +) + +func (c *ControllerV1) GetRouteLst(ctx context.Context, req *v1.GetRouteLstReq) (res *v1.GetRouteLstRes, err error) { + res = new(v1.GetRouteLstRes) + res.List, err = service.Permission().GetRouteLst(ctx) + return +} diff --git a/internal/controller/permission/permission_v1_upt.go b/internal/controller/permission/permission_v1_upt.go new file mode 100644 index 0000000..4f08aec --- /dev/null +++ b/internal/controller/permission/permission_v1_upt.go @@ -0,0 +1,19 @@ +package permission + +import ( + "context" + "devops-super/internal/model/do" + "devops-super/internal/service" + "github.com/gogf/gf/v2/util/gconv" + + "devops-super/api/permission/v1" +) + +func (c *ControllerV1) Upt(ctx context.Context, req *v1.UptReq) (res *v1.UptRes, err error) { + uptDo := new(do.Permission) + if err = gconv.Struct(req, uptDo); err != nil { + return + } + err = service.Permission().Upt(ctx, uptDo) + return +} diff --git a/internal/controller/permission/permission_v1_upt_show_link.go b/internal/controller/permission/permission_v1_upt_show_link.go new file mode 100644 index 0000000..e12d2df --- /dev/null +++ b/internal/controller/permission/permission_v1_upt_show_link.go @@ -0,0 +1,14 @@ +package permission + +import ( + "context" + "devops-super/internal/model/do" + "devops-super/internal/service" + + "devops-super/api/permission/v1" +) + +func (c *ControllerV1) UptShowLink(ctx context.Context, req *v1.UptShowLinkReq) (res *v1.UptShowLinkRes, err error) { + err = service.Permission().Upt(ctx, &do.Permission{Id: req.Id, ShowLink: req.Enabled}) + return +} diff --git a/internal/controller/public/public.go b/internal/controller/public/public.go new file mode 100644 index 0000000..7ae4232 --- /dev/null +++ b/internal/controller/public/public.go @@ -0,0 +1,6 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package public + diff --git a/internal/controller/public/public_new.go b/internal/controller/public/public_new.go new file mode 100644 index 0000000..01e7562 --- /dev/null +++ b/internal/controller/public/public_new.go @@ -0,0 +1,16 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package public + +import ( + "devops-super/api/public" +) + +type ControllerV1 struct{} + +func NewV1() public.IPublicV1 { + return &ControllerV1{} +} + diff --git a/internal/controller/public/public_v1_login.go b/internal/controller/public/public_v1_login.go new file mode 100644 index 0000000..0be800f --- /dev/null +++ b/internal/controller/public/public_v1_login.go @@ -0,0 +1,28 @@ +package public + +import ( + "context" + "devops-super/internal/model/do" + "devops-super/internal/service" + "time" + + "devops-super/api/public/v1" +) + +func (c *ControllerV1) Login(ctx context.Context, req *v1.LoginReq) (res *v1.LoginRes, err error) { + token, expires := service.Auth().LoginHandler(ctx) + refreshAfter := time.Now().Add(expires.Sub(time.Now()) / 2).UnixMilli() + eUser, err := service.User().GetComb(ctx, &do.User{Username: req.Username}) + if err != nil { + return nil, err + } + res = &v1.LoginRes{ + Username: eUser.Username, + RealName: eUser.RealName, + Token: token, + Expires: expires.UnixMilli(), + RefreshAfter: refreshAfter, + Roles: eUser.RoleCodes(), + } + return +} diff --git a/internal/controller/public/public_v1_logout.go b/internal/controller/public/public_v1_logout.go new file mode 100644 index 0000000..d550c37 --- /dev/null +++ b/internal/controller/public/public_v1_logout.go @@ -0,0 +1,13 @@ +package public + +import ( + "context" + "devops-super/internal/service" + + "devops-super/api/public/v1" +) + +func (c *ControllerV1) Logout(ctx context.Context, _ *v1.LogoutReq) (res *v1.LogoutRes, err error) { + service.Auth().LogoutHandler(ctx) + return +} diff --git a/internal/controller/public/public_v1_ping.go b/internal/controller/public/public_v1_ping.go new file mode 100644 index 0000000..7204556 --- /dev/null +++ b/internal/controller/public/public_v1_ping.go @@ -0,0 +1,11 @@ +package public + +import ( + "context" + + "devops-super/api/public/v1" +) + +func (c *ControllerV1) Ping(ctx context.Context, req *v1.PingReq) (res *v1.PingRes, err error) { + return +} diff --git a/internal/controller/public/public_v1_refresh_token.go b/internal/controller/public/public_v1_refresh_token.go new file mode 100644 index 0000000..1aa32af --- /dev/null +++ b/internal/controller/public/public_v1_refresh_token.go @@ -0,0 +1,28 @@ +package public + +import ( + "context" + "devops-super/internal/model/do" + "devops-super/internal/service" + "time" + + "devops-super/api/public/v1" +) + +func (c *ControllerV1) RefreshToken(ctx context.Context, req *v1.RefreshTokenReq) (res *v1.RefreshTokenRes, err error) { + token, expire := service.Auth().RefreshHandler(ctx) + refreshAfter := time.Now().Add(expire.Sub(time.Now()) / 2).UnixMilli() + eUser, err := service.User().GetComb(ctx, &do.User{Id: service.Auth().GetIdentity(ctx)}) + if err != nil { + return nil, err + } + res = &v1.RefreshTokenRes{ + Username: eUser.Username, + RealName: eUser.RealName, + Token: token, + Expire: expire.UnixMilli(), + RefreshAfter: refreshAfter, + Roles: eUser.RoleCodes(), + } + return +} diff --git a/internal/controller/role/role.go b/internal/controller/role/role.go new file mode 100644 index 0000000..e33045e --- /dev/null +++ b/internal/controller/role/role.go @@ -0,0 +1,6 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package role + diff --git a/internal/controller/role/role_new.go b/internal/controller/role/role_new.go new file mode 100644 index 0000000..f9caab9 --- /dev/null +++ b/internal/controller/role/role_new.go @@ -0,0 +1,16 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package role + +import ( + "devops-super/api/role" +) + +type ControllerV1 struct{} + +func NewV1() role.IRoleV1 { + return &ControllerV1{} +} + diff --git a/internal/controller/role/role_v1_add.go b/internal/controller/role/role_v1_add.go new file mode 100644 index 0000000..66cf76f --- /dev/null +++ b/internal/controller/role/role_v1_add.go @@ -0,0 +1,20 @@ +package role + +import ( + "context" + "devops-super/internal/model/entity" + "devops-super/internal/service" + "github.com/gogf/gf/v2/util/gconv" + + "devops-super/api/role/v1" +) + +func (c *ControllerV1) Add(ctx context.Context, req *v1.AddReq) (res *v1.AddRes, err error) { + in := new(entity.Role) + if err = gconv.Struct(req, in); err != nil { + return + } + + err = service.Role().Add(ctx, in) + return +} diff --git a/internal/controller/role/role_v1_del.go b/internal/controller/role/role_v1_del.go new file mode 100644 index 0000000..f1c5b2b --- /dev/null +++ b/internal/controller/role/role_v1_del.go @@ -0,0 +1,14 @@ +package role + +import ( + "context" + "devops-super/internal/model/do" + "devops-super/internal/service" + + "devops-super/api/role/v1" +) + +func (c *ControllerV1) Del(ctx context.Context, req *v1.DelReq) (res *v1.DelRes, err error) { + err = service.Role().Del(ctx, &do.Role{Id: req.Id}) + return +} diff --git a/internal/controller/role/role_v1_get_lst.go b/internal/controller/role/role_v1_get_lst.go new file mode 100644 index 0000000..1f74042 --- /dev/null +++ b/internal/controller/role/role_v1_get_lst.go @@ -0,0 +1,14 @@ +package role + +import ( + "context" + "devops-super/internal/service" + + "devops-super/api/role/v1" +) + +func (c *ControllerV1) GetLst(ctx context.Context, req *v1.GetLstReq) (res *v1.GetLstRes, err error) { + res = new(v1.GetLstRes) + res.List, err = service.Role().GetLst(ctx) + return +} diff --git a/internal/controller/role/role_v1_get_page_lst.go b/internal/controller/role/role_v1_get_page_lst.go new file mode 100644 index 0000000..9a18305 --- /dev/null +++ b/internal/controller/role/role_v1_get_page_lst.go @@ -0,0 +1,14 @@ +package role + +import ( + "context" + "devops-super/internal/service" + + "devops-super/api/role/v1" +) + +func (c *ControllerV1) GetPageLst(ctx context.Context, req *v1.GetPageLstReq) (res *v1.GetPageLstRes, err error) { + res = new(v1.GetPageLstRes) + res.PageLstRes, err = service.Role().GetPageLst(ctx, req.PageLstReq) + return +} diff --git a/internal/controller/role/role_v1_upt.go b/internal/controller/role/role_v1_upt.go new file mode 100644 index 0000000..9bbd9f6 --- /dev/null +++ b/internal/controller/role/role_v1_upt.go @@ -0,0 +1,19 @@ +package role + +import ( + "context" + "devops-super/internal/model/do" + "devops-super/internal/service" + "github.com/gogf/gf/v2/util/gconv" + + "devops-super/api/role/v1" +) + +func (c *ControllerV1) Upt(ctx context.Context, req *v1.UptReq) (res *v1.UptRes, err error) { + in := new(do.Role) + if err = gconv.Struct(req, in); err != nil { + return + } + err = service.Role().Upt(ctx, in) + return +} diff --git a/internal/controller/role/role_v1_upt_permission.go b/internal/controller/role/role_v1_upt_permission.go new file mode 100644 index 0000000..26f08bf --- /dev/null +++ b/internal/controller/role/role_v1_upt_permission.go @@ -0,0 +1,14 @@ +package role + +import ( + "context" + "devops-super/internal/model/do" + "devops-super/internal/service" + + "devops-super/api/role/v1" +) + +func (c *ControllerV1) UptPermission(ctx context.Context, req *v1.UptPermissionReq) (res *v1.UptPermissionRes, err error) { + err = service.Role().Upt(ctx, &do.Role{Id: req.Id, Permission: req.PermissionIds}) + return +} diff --git a/internal/controller/user/user.go b/internal/controller/user/user.go new file mode 100644 index 0000000..47f94e2 --- /dev/null +++ b/internal/controller/user/user.go @@ -0,0 +1,6 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package user + diff --git a/internal/controller/user/user_new.go b/internal/controller/user/user_new.go new file mode 100644 index 0000000..2f40b76 --- /dev/null +++ b/internal/controller/user/user_new.go @@ -0,0 +1,16 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package user + +import ( + "devops-super/api/user" +) + +type ControllerV1 struct{} + +func NewV1() user.IUserV1 { + return &ControllerV1{} +} + diff --git a/internal/controller/user/user_v1_add.go b/internal/controller/user/user_v1_add.go new file mode 100644 index 0000000..19fad0b --- /dev/null +++ b/internal/controller/user/user_v1_add.go @@ -0,0 +1,21 @@ +package user + +import ( + "context" + "devops-super/internal/model/entity" + "devops-super/internal/service" + "github.com/gogf/gf/v2/util/gconv" + + "devops-super/api/user/v1" +) + +func (c *ControllerV1) Add(ctx context.Context, req *v1.AddReq) (res *v1.AddRes, err error) { + eUser := new(entity.User) + if err = gconv.Struct(req, eUser); err != nil { + return + } + + eUser.Password = "devops.zze" + err = service.User().Add(ctx, eUser) + return +} diff --git a/internal/controller/user/user_v1_del.go b/internal/controller/user/user_v1_del.go new file mode 100644 index 0000000..899f3ee --- /dev/null +++ b/internal/controller/user/user_v1_del.go @@ -0,0 +1,13 @@ +package user + +import ( + "context" + "devops-super/api/user/v1" + "devops-super/internal/model/do" + "devops-super/internal/service" +) + +func (c *ControllerV1) Del(ctx context.Context, req *v1.DelReq) (res *v1.DelRes, err error) { + err = service.User().Del(ctx, &do.User{Id: req.Id}) + return +} diff --git a/internal/controller/user/user_v1_get_page_lst.go b/internal/controller/user/user_v1_get_page_lst.go new file mode 100644 index 0000000..1929d22 --- /dev/null +++ b/internal/controller/user/user_v1_get_page_lst.go @@ -0,0 +1,14 @@ +package user + +import ( + "context" + "devops-super/internal/service" + + "devops-super/api/user/v1" +) + +func (c *ControllerV1) GetPageLst(ctx context.Context, req *v1.GetPageLstReq) (res *v1.GetPageLstRes, err error) { + res = new(v1.GetPageLstRes) + res.PageLstRes, err = service.User().GetPageLst(ctx, req.PageLstReq) + return +} diff --git a/internal/controller/user/user_v1_upt.go b/internal/controller/user/user_v1_upt.go new file mode 100644 index 0000000..b2890e4 --- /dev/null +++ b/internal/controller/user/user_v1_upt.go @@ -0,0 +1,19 @@ +package user + +import ( + "context" + "devops-super/internal/model/do" + "devops-super/internal/service" + "github.com/gogf/gf/v2/util/gconv" + + "devops-super/api/user/v1" +) + +func (c *ControllerV1) Upt(ctx context.Context, req *v1.UptReq) (res *v1.UptRes, err error) { + uptDo := new(do.User) + if err = gconv.Struct(req, uptDo); err != nil { + return + } + err = service.User().Upt(ctx, uptDo) + return +} diff --git a/internal/controller/user/user_v1_upt_enabled.go b/internal/controller/user/user_v1_upt_enabled.go new file mode 100644 index 0000000..d72f6e6 --- /dev/null +++ b/internal/controller/user/user_v1_upt_enabled.go @@ -0,0 +1,14 @@ +package user + +import ( + "context" + "devops-super/internal/model/do" + "devops-super/internal/service" + + "devops-super/api/user/v1" +) + +func (c *ControllerV1) UptEnabled(ctx context.Context, req *v1.UptEnabledReq) (res *v1.UptEnabledRes, err error) { + err = service.User().Upt(ctx, &do.User{Id: req.Id, Enabled: req.Enabled}) + return +} diff --git a/internal/controller/user/user_v1_upt_password.go b/internal/controller/user/user_v1_upt_password.go new file mode 100644 index 0000000..fb909bd --- /dev/null +++ b/internal/controller/user/user_v1_upt_password.go @@ -0,0 +1,13 @@ +package user + +import ( + "context" + "devops-super/api/user/v1" + "devops-super/internal/model/do" + "devops-super/internal/service" +) + +func (c *ControllerV1) UptPassword(ctx context.Context, req *v1.UptPasswordReq) (res *v1.UptPasswordRes, err error) { + err = service.User().Upt(ctx, &do.User{Id: req.Id, Password: req.Password}) + return +} diff --git a/internal/dao/.gitkeep b/internal/dao/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/internal/dao/dept.go b/internal/dao/dept.go new file mode 100644 index 0000000..94460e9 --- /dev/null +++ b/internal/dao/dept.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "devops-super/internal/dao/internal" +) + +// internalDeptDao is internal type for wrapping internal DAO implements. +type internalDeptDao = *internal.DeptDao + +// deptDao is the data access object for table dept. +// You can define custom methods on it to extend its functionality as you wish. +type deptDao struct { + internalDeptDao +} + +var ( + // Dept is globally public accessible object for table dept operations. + Dept = deptDao{ + internal.NewDeptDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/internal/dept.go b/internal/dao/internal/dept.go new file mode 100644 index 0000000..d059740 --- /dev/null +++ b/internal/dao/internal/dept.go @@ -0,0 +1,81 @@ +// ========================================================================== +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// DeptDao is the data access object for table dept. +type DeptDao 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 DeptColumns // columns contains all the column names of Table for convenient usage. +} + +// DeptColumns defines and stores column names for table dept. +type DeptColumns struct { + Id string // + Name string // 部门名称 + Rank string // 排序 + ParentId string // 上级部门 id + UpdatedAt string // 更新时间 +} + +// deptColumns holds the columns for table dept. +var deptColumns = DeptColumns{ + Id: "id", + Name: "name", + Rank: "rank", + ParentId: "parent_id", + UpdatedAt: "updated_at", +} + +// NewDeptDao creates and returns a new DAO object for table data access. +func NewDeptDao() *DeptDao { + return &DeptDao{ + group: "default", + table: "dept", + columns: deptColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *DeptDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *DeptDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *DeptDao) Columns() DeptColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *DeptDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *DeptDao) 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 *DeptDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/permission.go b/internal/dao/internal/permission.go new file mode 100644 index 0000000..b7d606a --- /dev/null +++ b/internal/dao/internal/permission.go @@ -0,0 +1,97 @@ +// ========================================================================== +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// PermissionDao is the data access object for table permission. +type PermissionDao 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 PermissionColumns // columns contains all the column names of Table for convenient usage. +} + +// PermissionColumns defines and stores column names for table permission. +type PermissionColumns struct { + Id string // + Title string // 标题 + Name string // 路由名称 + Type string // 类型:1-目录,2-菜单,3-功能 + FRoute string // 前端路由路径 + BRoutes string // 后端路由路径 + Redirect string // 重定向路径 + Icon string // 图标 + Rank string // 排序 + ShowLink string // 是否在菜单中展示 + ShowParent string // 是否展示父级菜单 + KeepAlive string // 页面缓存 + ParentId string // 父级权限 id +} + +// permissionColumns holds the columns for table permission. +var permissionColumns = PermissionColumns{ + Id: "id", + Title: "title", + Name: "name", + Type: "type", + FRoute: "f_route", + BRoutes: "b_routes", + Redirect: "redirect", + Icon: "icon", + Rank: "rank", + ShowLink: "show_link", + ShowParent: "show_parent", + KeepAlive: "keep_alive", + ParentId: "parent_id", +} + +// NewPermissionDao creates and returns a new DAO object for table data access. +func NewPermissionDao() *PermissionDao { + return &PermissionDao{ + group: "default", + table: "permission", + columns: permissionColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *PermissionDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *PermissionDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *PermissionDao) Columns() PermissionColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *PermissionDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *PermissionDao) 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 *PermissionDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/role.go b/internal/dao/internal/role.go new file mode 100644 index 0000000..c0a4ef3 --- /dev/null +++ b/internal/dao/internal/role.go @@ -0,0 +1,81 @@ +// ========================================================================== +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// RoleDao is the data access object for table role. +type RoleDao 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 RoleColumns // columns contains all the column names of Table for convenient usage. +} + +// RoleColumns defines and stores column names for table role. +type RoleColumns struct { + Id string // + Name string // 角色名称 + Code string // 角色代码 + Permission string // 关联权限 + UpdatedAt string // 更新时间 +} + +// roleColumns holds the columns for table role. +var roleColumns = RoleColumns{ + Id: "id", + Name: "name", + Code: "code", + Permission: "permission", + UpdatedAt: "updated_at", +} + +// NewRoleDao creates and returns a new DAO object for table data access. +func NewRoleDao() *RoleDao { + return &RoleDao{ + group: "default", + table: "role", + columns: roleColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *RoleDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *RoleDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *RoleDao) Columns() RoleColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *RoleDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *RoleDao) 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 *RoleDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/user.go b/internal/dao/internal/user.go new file mode 100644 index 0000000..569bbab --- /dev/null +++ b/internal/dao/internal/user.go @@ -0,0 +1,91 @@ +// ========================================================================== +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// UserDao is the data access object for table user. +type UserDao 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 UserColumns // columns contains all the column names of Table for convenient usage. +} + +// UserColumns defines and stores column names for table user. +type UserColumns struct { + Id string // + Username string // 用户名 + Password string // 密码 + Phone string // 手机号码 + Email string // 邮箱 + RealName string // 真实姓名 + Enabled string // 是否启用状态 + RoleIds string // 角色 id + DeptId string // 所属部门 id + UpdatedAt string // 更新时间 +} + +// userColumns holds the columns for table user. +var userColumns = UserColumns{ + Id: "id", + Username: "username", + Password: "password", + Phone: "phone", + Email: "email", + RealName: "real_name", + Enabled: "enabled", + RoleIds: "role_ids", + DeptId: "dept_id", + UpdatedAt: "updated_at", +} + +// NewUserDao creates and returns a new DAO object for table data access. +func NewUserDao() *UserDao { + return &UserDao{ + group: "default", + table: "user", + columns: userColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *UserDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *UserDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *UserDao) Columns() UserColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *UserDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *UserDao) 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 *UserDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/permission.go b/internal/dao/permission.go new file mode 100644 index 0000000..b8fc6fb --- /dev/null +++ b/internal/dao/permission.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "devops-super/internal/dao/internal" +) + +// internalPermissionDao is internal type for wrapping internal DAO implements. +type internalPermissionDao = *internal.PermissionDao + +// permissionDao is the data access object for table permission. +// You can define custom methods on it to extend its functionality as you wish. +type permissionDao struct { + internalPermissionDao +} + +var ( + // Permission is globally public accessible object for table permission operations. + Permission = permissionDao{ + internal.NewPermissionDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/role.go b/internal/dao/role.go new file mode 100644 index 0000000..81a578f --- /dev/null +++ b/internal/dao/role.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "devops-super/internal/dao/internal" +) + +// internalRoleDao is internal type for wrapping internal DAO implements. +type internalRoleDao = *internal.RoleDao + +// roleDao is the data access object for table role. +// You can define custom methods on it to extend its functionality as you wish. +type roleDao struct { + internalRoleDao +} + +var ( + // Role is globally public accessible object for table role operations. + Role = roleDao{ + internal.NewRoleDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/user.go b/internal/dao/user.go new file mode 100644 index 0000000..29d7e74 --- /dev/null +++ b/internal/dao/user.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "devops-super/internal/dao/internal" +) + +// internalUserDao is internal type for wrapping internal DAO implements. +type internalUserDao = *internal.UserDao + +// userDao is the data access object for table user. +// You can define custom methods on it to extend its functionality as you wish. +type userDao struct { + internalUserDao +} + +var ( + // User is globally public accessible object for table user operations. + User = userDao{ + internal.NewUserDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/logic/.gitkeep b/internal/logic/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/internal/logic/context/casbin.go b/internal/logic/context/casbin.go new file mode 100644 index 0000000..3432f40 --- /dev/null +++ b/internal/logic/context/casbin.go @@ -0,0 +1,87 @@ +package context + +import ( + "context" + "devops-super/internal/consts" + "devops-super/internal/model/entity/comb" + "devops-super/internal/service" + "github.com/casbin/casbin/v2" + "github.com/casbin/casbin/v2/model" + "github.com/gogf/gf/v2/frame/g" + "strings" +) + +func (*sContext) initCasbin(ctx context.Context) (*casbin.Enforcer, error) { + g.Log().Debug(ctx, "init casbin enforcer start.") + enforcer, err := casbin.NewEnforcer(newCasbinModel()) + if err != nil { + return nil, err + } + roleList, err := service.Role().GetCombList(ctx) + if err != nil { + return nil, err + } + + type recursiveHandlePermissionsFunc func(roleCode string, permissions []*comb.Permission) error + var recursiveHandlePermissions recursiveHandlePermissionsFunc + + recursiveHandlePermissions = func(roleCode string, permissions []*comb.Permission) error { + for _, permission := range permissions { + if permission.Type == consts.PERMISSION_TYPE_ABLE { + for _, backendRouteInfo := range permission.BRoutes.Array() { + routeInfoArr := strings.SplitN(backendRouteInfo.(string), ":", 2) + method := strings.ToUpper(routeInfoArr[0]) + routePath := routeInfoArr[1] + if enforcer.HasPolicy(roleCode, routePath, method) { + continue + } + if _, err := enforcer.AddPolicy(roleCode, routePath, method); err != nil { + return err + } + g.Log().Debugf(ctx, "casbin policy added: %s, %s, %s", roleCode, routePath, method) + } + } else { + if len(permission.Children) > 0 { + if err = recursiveHandlePermissions(roleCode, permission.Children); err != nil { + return err + } + } + } + } + return nil + } + + for _, role := range roleList { + if err := recursiveHandlePermissions(role.Code, role.Permissions); err != nil { + return nil, err + } + } + + userList, err := service.User().GetCombLst(ctx) + if err != nil { + return nil, err + } + + for _, user := range userList { + var roleCodes []string + for _, role := range user.Roles { + roleCodes = append(roleCodes, role.Code) + } + if _, err := enforcer.AddRolesForUser(user.Username, roleCodes); err != nil { + return nil, err + } + g.Log().Debugf(ctx, "casbin roles added: %s, %v", user.Username, roleCodes) + } + g.Log().Debug(ctx, "init casbin enforcer successful.") + return enforcer, nil +} + +func newCasbinModel() model.Model { + m := model.NewModel() + m.AddDef("r", "r", "sub, obj, act") + m.AddDef("p", "p", "sub, obj, act") + m.AddDef("g", "g", "_, _") + m.AddDef("e", "e", "some(where (p.eft == allow))") + m.AddDef("m", "m", `g(r.sub, p.sub) && keyMatch2(r.obj, p.obj) && regexMatch(r.act, p.act) || g(r.sub, "admin")`) + return m +} diff --git a/internal/logic/context/context.go b/internal/logic/context/context.go new file mode 100644 index 0000000..0030d15 --- /dev/null +++ b/internal/logic/context/context.go @@ -0,0 +1,48 @@ +package context + +import ( + "context" + "devops-super/internal/model" + "devops-super/internal/service" +) + +type sContext struct { + svcCtx *model.ServiceContext + ctx context.Context +} + +func init() { + service.RegisterContext(New()) +} + +func New() *sContext { + return &sContext{} +} + +func (s *sContext) Init(ctx context.Context) error { + s.ctx = ctx + return s.initServiceContext() +} + +func (s *sContext) initServiceContext() (err error) { + s.svcCtx = new(model.ServiceContext) + // 初始化 casbin + err = s.RefreshCasbin(s.ctx) + if err != nil { + return + } + return +} + +func (s *sContext) RefreshCasbin(ctx context.Context) error { + enforcer, err := s.initCasbin(ctx) + if err != nil { + return err + } + s.svcCtx.CasbinEnforcer = enforcer + return nil +} + +func (s *sContext) Ctx() *model.ServiceContext { + return s.svcCtx +} diff --git a/internal/logic/dept/dept.go b/internal/logic/dept/dept.go new file mode 100644 index 0000000..e858926 --- /dev/null +++ b/internal/logic/dept/dept.go @@ -0,0 +1,72 @@ +package permission + +import ( + "context" + "devops-super/internal/dao" + "devops-super/internal/model/do" + "devops-super/internal/model/entity" + "devops-super/internal/service" + "devops-super/utility/util" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/util/gutil" +) + +type sDept struct{} + +var ( + cols = dao.Dept.Columns() +) + +func init() { + service.RegisterDept(New()) +} + +func New() *sDept { + return &sDept{} +} + +func (s *sDept) Add(ctx context.Context, in *entity.Dept) (err error) { + r, err := s.Get(ctx, &do.Dept{Name: in.Name}) + if err != nil { + return err + } + if r != nil { + return gerror.Newf("已存在名称为 %s 部门", in.Name) + } + _, err = dao.Dept.Ctx(ctx).Insert(in) + return +} + +func (*sDept) Get(ctx context.Context, in *do.Dept) (out *entity.Dept, err error) { + err = dao.Dept.Ctx(ctx).Where(in).OmitNilWhere().Limit(1).Scan(&out) + return +} + +func (*sDept) GetLst(ctx context.Context, search string) (out []*entity.Dept, err error) { + m := dao.Dept.Ctx(ctx).Order(dao.Dept.Columns().Rank).Safe(true) + if !gutil.IsEmpty(search) { + m = m.WhereOr(m.Builder().WhereOrLike(cols.Name, util.SqlLikeStr(search))) + } + err = m.Scan(&out) + return +} + +func (*sDept) Upt(ctx context.Context, in *do.Dept) (err error) { + if !gutil.IsEmpty(in.Name) { + r, err := dao.Dept.Ctx(ctx).WhereNot(cols.Id, in.Id).Where(cols.Name, in.Name).One() + if err != nil { + return err + } + + if r != nil { + return gerror.Newf("已存在名称为 %s 部门", in.Name) + } + } + _, err = dao.Dept.Ctx(ctx).WherePri(in.Id).OmitNilData().Data(in).Update() + return +} + +func (*sDept) Del(ctx context.Context, in *do.Dept) (err error) { + _, err = dao.Dept.Ctx(ctx).Where(in).OmitNilWhere().Delete() + return +} diff --git a/internal/logic/logic.go b/internal/logic/logic.go new file mode 100644 index 0000000..36801b5 --- /dev/null +++ b/internal/logic/logic.go @@ -0,0 +1,14 @@ +// ========================================================================== +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package logic + +import ( + _ "devops-super/internal/logic/context" + _ "devops-super/internal/logic/dept" + _ "devops-super/internal/logic/middleware" + _ "devops-super/internal/logic/permission" + _ "devops-super/internal/logic/role" + _ "devops-super/internal/logic/user" +) diff --git a/internal/logic/middleware/middleware.go b/internal/logic/middleware/middleware.go new file mode 100644 index 0000000..1926ef1 --- /dev/null +++ b/internal/logic/middleware/middleware.go @@ -0,0 +1,64 @@ +package middleware + +import ( + "devops-super/internal/service" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/net/ghttp" + "github.com/gogf/gf/v2/text/gstr" + "net/http" +) + +type sMiddleware struct{} + +func init() { + service.RegisterMiddleware(New()) +} + +func New() *sMiddleware { + return &sMiddleware{} +} + +func (*sMiddleware) Auth(r *ghttp.Request) { + service.Auth().MiddlewareFunc()(r) + var ( + requestPath = r.Request.URL.Path + method = r.Request.Method + refreshPermissionPathPrefixes = []string{"/permission", "/role", "/user"} + ) + + pass, err := service.Context().Ctx().CasbinEnforcer.Enforce(service.CurrentUser(r.GetCtx()).Username, requestPath, method) + if err != nil { + r.Response.WriteJson(g.Map{ + "code": http.StatusForbidden, + "message": err, + }) + r.ExitAll() + } + + if !pass { + r.Response.WriteJson(g.Map{ + "code": http.StatusForbidden, + "message": "没有接口权限", + }) + r.ExitAll() + } + + r.Middleware.Next() + + if method != "GET" { + for _, prefix := range refreshPermissionPathPrefixes { + if gstr.HasPrefix(requestPath, prefix) { + if err := service.Context().RefreshCasbin(r.GetCtx()); err != nil { + r.Response.WriteJson(g.Map{ + "code": http.StatusInternalServerError, + "message": gerror.Newf("刷新权限失败: %v", err), + }) + r.ExitAll() + } + break + } + } + } + +} diff --git a/internal/logic/permission/permission.go b/internal/logic/permission/permission.go new file mode 100644 index 0000000..c298dd8 --- /dev/null +++ b/internal/logic/permission/permission.go @@ -0,0 +1,103 @@ +package permission + +import ( + "context" + "devops-super/internal/consts" + "devops-super/internal/dao" + "devops-super/internal/model/do" + "devops-super/internal/model/entity" + "devops-super/internal/service" + "devops-super/utility/util" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/util/gutil" +) + +type sPermission struct{} + +var ( + cols = dao.Permission.Columns() +) + +func init() { + service.RegisterPermission(New()) +} + +func New() *sPermission { + return &sPermission{} +} + +func (s *sPermission) Add(ctx context.Context, in *entity.Permission) (err error) { + r, err := s.Get(ctx, &do.Permission{Name: in.Name}) + if err != nil { + return err + } + if r != nil { + return gerror.Newf("已存在名称为 %s 权限", in.Name) + } + if (in.Type == consts.PERMISSION_TYPE_DIR || in.Type == consts.PERMISSION_TYPE_MENU) && !gutil.IsEmpty(in.FRoute) { + r, err = s.Get(ctx, &do.Permission{FRoute: in.FRoute}) + if err != nil { + return err + } + if r != nil { + return gerror.Newf("已存在前端路由为 %s 权限", in.FRoute) + } + } + _, err = dao.Permission.Ctx(ctx).Insert(in) + return +} + +func (*sPermission) Get(ctx context.Context, in *do.Permission) (out *entity.Permission, err error) { + err = dao.Permission.Ctx(ctx).Where(in).OmitNilWhere().Limit(1).Scan(&out) + return +} + +func (*sPermission) GetLst(ctx context.Context, search string) (out []*entity.Permission, err error) { + m := dao.Permission.Ctx(ctx).Order(dao.Permission.Columns().Rank).Safe(true) + if !gutil.IsEmpty(search) { + m = m.WhereOr(m.Builder().WhereOrLike(cols.Name, util.SqlLikeStr(search)).WhereOrLike(cols.Title, util.SqlLikeStr(search))) + } + err = m.Scan(&out) + return +} + +func (*sPermission) Upt(ctx context.Context, in *do.Permission) (err error) { + if !gutil.IsEmpty(in.Name) { + r, err := dao.Permission.Ctx(ctx).WhereNot(cols.Id, in.Id).Where(cols.Name, in.Name).One() + if err != nil { + return err + } + + if r != nil { + return gerror.Newf("已存在名称为 %s 权限", in.Name) + } + } + if (in.Type == consts.PERMISSION_TYPE_DIR || in.Type == consts.PERMISSION_TYPE_MENU) && !gutil.IsEmpty(in.FRoute) { + r, err := dao.Permission.Ctx(ctx).WhereNot(cols.Id, in.Id).Where(cols.FRoute, in.FRoute).One() + if err != nil { + return err + } + if r != nil { + return gerror.Newf("已存在前端路由为 %s 权限", in.FRoute) + } + } + + _, err = dao.Permission.Ctx(ctx).WherePri(in.Id).OmitNilData().Data(in).Update() + return +} + +func (*sPermission) Del(ctx context.Context, in *do.Permission) (err error) { + _, err = dao.Permission.Ctx(ctx).Where(in).OmitNilWhere().Delete() + return +} + +func (s *sPermission) SystemRequired(ctx context.Context) (ePermission *entity.Permission, err error) { + requiredPermission, err := s.Get(ctx, &do.Permission{Name: consts.PERMISSION_SYSTEM_REQUIRED_NAME}) + if err != nil { + return nil, err + } + if requiredPermission != nil && requiredPermission.Id > 0 { + return requiredPermission, nil + } + return nil, gerror.New("系统必需权限缺失") +} diff --git a/internal/logic/permission/route.go b/internal/logic/permission/route.go new file mode 100644 index 0000000..6073b1d --- /dev/null +++ b/internal/logic/permission/route.go @@ -0,0 +1,137 @@ +package permission + +import ( + "context" + "devops-super/internal/consts" + "devops-super/internal/dao" + "devops-super/internal/model/do" + "devops-super/internal/model/entity" + "devops-super/internal/model/entity/comb" + "devops-super/internal/model/mid" + "devops-super/internal/service" + "github.com/gogf/gf/v2/container/gset" + "github.com/gogf/gf/v2/util/gconv" + "sort" +) + +func (*sPermission) GetRouteLst(ctx context.Context) (out []*mid.Route, err error) { + cUser, err := service.User().GetComb(ctx, &do.User{Id: service.CurrentUser(ctx).UserId}) + if err != nil { + return nil, err + } + + var permissionIdSet = gset.New() + for _, role := range cUser.Roles { + if role.Permission.IsNil() { + continue + } + for _, pId := range role.Permission.Array() { + permissionIdSet.Add(pId) + } + } + + var cPermissions []*comb.Permission + if err = dao.Permission.Ctx(ctx).Order(cols.Rank).WithAll().WhereIn(cols.Id, permissionIdSet.Slice()).Scan(&cPermissions); err != nil { + return + } + + var ePermissionMap = make(map[int]*entity.Permission, len(cPermissions)) + for _, permission := range cPermissions { + ePermissionMap[permission.Id] = permission.Permission + } + + type ( + handleManyFunc = func(children []*comb.Permission) error + handleOneFunc = func(cPermission *comb.Permission) error + handleParentFunc = func(parentId int) (*mid.Route, error) + ) + + var ( + finalRoutes mid.FrontendRouteList + routeMap = make(map[int]*mid.Route) + getOne = func(id int) *entity.Permission { + return ePermissionMap[id] + } + permissionToRoute = func(ePermission *entity.Permission) (route *mid.Route) { + _ = gconv.Struct(ePermission, &route) + return + } + handleMany handleManyFunc + handleOne handleOneFunc + handleParent handleParentFunc + ) + + handleParent = func(parentId int) (*mid.Route, error) { + var ( + parent *mid.Route + ok bool + ) + parent, ok = routeMap[parentId] + if !ok { + ePermission := new(entity.Permission) + if permissionIdSet.Contains(parentId) { + ePermission = getOne(parentId) + } else { + if err := dao.Permission.Ctx(ctx).WherePri(parentId).Scan(ePermission); err != nil { + return nil, err + } + parent = permissionToRoute(ePermission) + routeMap[parentId] = parent + finalRoutes = append(finalRoutes, parent) + } + if parent.ParentId > 0 { + if _, err := handleParent(parent.ParentId); err != nil { + return nil, err + } + } + } + + return parent, nil + } + + handleMany = func(children []*comb.Permission) error { + for _, child := range children { + if err := handleOne(child); err != nil { + return err + } + } + return nil + } + + handleOne = func(cPermission *comb.Permission) error { + switch cPermission.Type { + case consts.PERMISSION_TYPE_DIR, consts.PERMISSION_TYPE_MENU: + route := permissionToRoute(cPermission.Permission) + if cPermission.Type == consts.PERMISSION_TYPE_DIR { + if err := handleMany(cPermission.Children); err != nil { + return err + } + } else { + route.Auths = cPermission.AuthCodes() + } + + if _, ok := routeMap[route.Id]; !ok { + routeMap[route.Id] = route + finalRoutes = append(finalRoutes, route) + } + } + + if parentId := cPermission.ParentId; parentId > 0 { + parent, err := handleParent(parentId) + if err != nil { + return err + } + + if cPermission.Type == consts.PERMISSION_TYPE_ABLE { + parent.Auths = append(parent.Auths, cPermission.Name) + } + } + return nil + } + + if err = handleMany(cPermissions); err != nil { + return + } + sort.Sort(finalRoutes) + return finalRoutes, nil +} diff --git a/internal/logic/role/role.go b/internal/logic/role/role.go new file mode 100644 index 0000000..5949545 --- /dev/null +++ b/internal/logic/role/role.go @@ -0,0 +1,111 @@ +package user + +import ( + "context" + "devops-super/api" + "devops-super/internal/dao" + "devops-super/internal/model/do" + "devops-super/internal/model/entity" + "devops-super/internal/model/entity/comb" + "devops-super/internal/service" + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/util/gutil" +) + +type sRole struct{} + +var cols = dao.Role.Columns() + +func init() { + service.RegisterRole(New()) +} + +func New() *sRole { + return &sRole{} +} + +func (*sRole) Add(ctx context.Context, in *entity.Role) (err error) { + r, err := dao.Role.Ctx(ctx).Where(cols.Code, in.Code).One() + if err != nil { + return err + } + if r != nil { + return gerror.New("已存在该代码的权限") + } + _, err = dao.Role.Ctx(ctx).Insert(in) + return +} + +func (*sRole) Upt(ctx context.Context, in *do.Role) (err error) { + if !gutil.IsEmpty(in.Code) { + r, err := dao.Role.Ctx(ctx).WhereNot(cols.Id, in.Id).Where(cols.Code, in.Code).One() + if err != nil { + return err + } + if r != nil { + return gerror.New("已存在该代码的权限") + } + } + _, err = dao.Role.Ctx(ctx).WherePri(in.Id).OmitNilData().Data(in).Update() + return +} + +func (*sRole) GetPageLst(ctx context.Context, in *api.PageLstReq) (out *api.PageLstRes[*entity.Role], err error) { + out = &api.PageLstRes[*entity.Role]{} + m := dao.Role.Ctx(ctx).Safe(true) + if !gutil.IsEmpty(in.Search) { + m = m.WhereOr(m.Builder().WhereOrLike(cols.Name, in.SearchStr()).WhereOrLike(cols.Code, in.SearchStr())) + } + + err = m.Offset(in.Offset()).Limit(in.Limit()). + ScanAndCount(&out.List, &out.Total, false) + + permission, err := service.Permission().SystemRequired(ctx) + if err != nil { + return nil, err + } + for _, u := range out.List { + u.Permission = gjson.New(append(u.Permission.Array(), permission.Id)) + } + return +} + +func (*sRole) GetLst(ctx context.Context) (out []*entity.Role, err error) { + err = dao.Role.Ctx(ctx).OrderDesc(cols.Id).FieldsEx(cols.Permission).Scan(&out) + return +} + +func (*sRole) GetCombList(ctx context.Context) (out []*comb.Role, err error) { + if err = dao.Role.Ctx(ctx).Scan(&out); err != nil { + return + } + + permission, err := service.Permission().SystemRequired(ctx) + if err != nil { + return nil, err + } + + for _, role := range out { + role.Permission = gjson.New(append(role.Permission.Array(), permission.Id)) + if err = dao.Permission.Ctx(ctx).WithAll().WhereIn(dao.Permission.Columns().Id, role.Permission.Array()).Scan(&role.Permissions); err != nil { + return + } + } + return +} + +func (*sRole) Get(ctx context.Context, in *do.Role) (out *entity.Role, err error) { + err = dao.Role.Ctx(ctx).Where(in).OmitNilWhere().Limit(1).Scan(&out) + permission, err := service.Permission().SystemRequired(ctx) + if err != nil { + return nil, err + } + out.Permission = gjson.New(append(out.Permission.Array(), permission.Id)) + return +} + +func (*sRole) Del(ctx context.Context, in *do.Role) (err error) { + _, err = dao.Role.Ctx(ctx).Where(in).OmitNilWhere().Delete() + return +} diff --git a/internal/logic/user/user.go b/internal/logic/user/user.go new file mode 100644 index 0000000..a912dcc --- /dev/null +++ b/internal/logic/user/user.go @@ -0,0 +1,98 @@ +package user + +import ( + "context" + "devops-super/api" + "devops-super/internal/dao" + "devops-super/internal/model/do" + "devops-super/internal/model/entity" + "devops-super/internal/model/entity/comb" + "devops-super/internal/service" + "devops-super/utility/util" + "github.com/gogf/gf/v2/util/gutil" +) + +type sUser struct{} + +var cols = dao.User.Columns() + +func init() { + service.RegisterUser(New()) +} + +func New() *sUser { + return &sUser{} +} + +func (*sUser) Add(ctx context.Context, in *entity.User) (err error) { + in.Password, err = util.EncryptPassword(in.Password) + if err != nil { + return + } + _, err = dao.User.Ctx(ctx).Insert(in) + return +} + +func (*sUser) Upt(ctx context.Context, in *do.User) (err error) { + if !gutil.IsEmpty(in.Password) { + in.Password, err = util.EncryptPassword(in.Password.(string)) + if err != nil { + return + } + } + _, err = dao.User.Ctx(ctx).WherePri(in.Id).OmitNilData().Data(in).Update() + return +} + +func (*sUser) GetPageLst(ctx context.Context, in *api.PageLstReq) (out *api.PageLstRes[*entity.User], err error) { + out = &api.PageLstRes[*entity.User]{} + m := dao.User.Ctx(ctx).Safe(true) + if !gutil.IsEmpty(in.Search) { + m = m.WhereOr(m.Builder().WhereOrLike(cols.Username, in.SearchStr()).WhereOrLike(cols.RealName, in.SearchStr())) + } + + if enabled := in.Wheres.Get("enabled"); !enabled.IsNil() { + m = m.Where(cols.Enabled, enabled.Bool()) + } + + if deptId := in.Wheres.Get("deptId"); !deptId.IsNil() { + m = m.Where(cols.DeptId, deptId.Int()) + } + + err = m.Offset(in.Offset()).Limit(in.Limit()).FieldsEx(cols.Password). + ScanAndCount(&out.List, &out.Total, false) + return +} + +func (*sUser) Get(ctx context.Context, userDo *do.User) (out *entity.User, err error) { + err = dao.User.Ctx(ctx).Where(userDo).OmitNilWhere().Limit(1).Scan(&out) + return +} + +func (*sUser) GetComb(ctx context.Context, userDo *do.User) (out *comb.User, err error) { + if err = dao.User.Ctx(ctx).Where(userDo).OmitNilWhere().Limit(1).Scan(&out); err != nil { + return + } + if err = dao.Role.Ctx(ctx).WhereIn(dao.Role.Columns().Id, out.RoleIds.Array()).Scan(&out.Roles); err != nil { + return + } + return +} + +func (*sUser) GetCombLst(ctx context.Context) (out []*comb.User, err error) { + if err = dao.User.Ctx(ctx).Where(cols.Enabled, true).Scan(&out); err != nil { + return + } + + for _, user := range out { + if err = dao.Role.Ctx(ctx).WhereIn(dao.Role.Columns().Id, user.RoleIds.Array()).Scan(&user.Roles); err != nil { + return + } + } + return +} + +func (*sUser) Del(ctx context.Context, in *do.User) (err error) { + _, err = dao.User.Ctx(ctx).Where(in).OmitNilWhere().Delete() + return +} diff --git a/internal/model/.gitkeep b/internal/model/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/internal/model/context.go b/internal/model/context.go new file mode 100644 index 0000000..4884abc --- /dev/null +++ b/internal/model/context.go @@ -0,0 +1,13 @@ +package model + +import "github.com/casbin/casbin/v2" + +type ServiceContext struct { + CasbinEnforcer *casbin.Enforcer +} + +type RequestUser struct { + UserId int `json:"userId"` + RealName string `json:"realName"` + Username string `json:"username"` +} diff --git a/internal/model/do/.gitkeep b/internal/model/do/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/internal/model/do/dept.go b/internal/model/do/dept.go new file mode 100644 index 0000000..2df75b0 --- /dev/null +++ b/internal/model/do/dept.go @@ -0,0 +1,20 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// Dept is the golang structure of table dept for DAO operations like Where/Data. +type Dept struct { + g.Meta `orm:"table:dept, do:true"` + Id interface{} // + Name interface{} // 部门名称 + Rank interface{} // 排序 + ParentId interface{} // 上级部门 id + UpdatedAt *gtime.Time // 更新时间 +} diff --git a/internal/model/do/permission.go b/internal/model/do/permission.go new file mode 100644 index 0000000..26b3b71 --- /dev/null +++ b/internal/model/do/permission.go @@ -0,0 +1,28 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/frame/g" +) + +// Permission is the golang structure of table permission for DAO operations like Where/Data. +type Permission struct { + g.Meta `orm:"table:permission, do:true"` + Id interface{} // + Title interface{} // 标题 + Name interface{} // 路由名称 + Type interface{} // 类型:1-目录,2-菜单,3-功能 + FRoute interface{} // 前端路由路径 + BRoutes *gjson.Json // 后端路由路径 + Redirect interface{} // 重定向路径 + Icon interface{} // 图标 + Rank interface{} // 排序 + ShowLink interface{} // 是否在菜单中展示 + ShowParent interface{} // 是否展示父级菜单 + KeepAlive interface{} // 页面缓存 + ParentId interface{} // 父级权限 id +} diff --git a/internal/model/do/role.go b/internal/model/do/role.go new file mode 100644 index 0000000..97e19a0 --- /dev/null +++ b/internal/model/do/role.go @@ -0,0 +1,21 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// Role is the golang structure of table role for DAO operations like Where/Data. +type Role struct { + g.Meta `orm:"table:role, do:true"` + Id interface{} // + Name interface{} // 角色名称 + Code interface{} // 角色代码 + Permission *gjson.Json // 关联权限 + UpdatedAt *gtime.Time // 更新时间 +} diff --git a/internal/model/do/user.go b/internal/model/do/user.go new file mode 100644 index 0000000..7642c7c --- /dev/null +++ b/internal/model/do/user.go @@ -0,0 +1,26 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// User is the golang structure of table user for DAO operations like Where/Data. +type User struct { + g.Meta `orm:"table:user, do:true"` + Id interface{} // + Username interface{} // 用户名 + Password interface{} // 密码 + Phone interface{} // 手机号码 + Email interface{} // 邮箱 + RealName interface{} // 真实姓名 + Enabled interface{} // 是否启用状态 + RoleIds *gjson.Json // 角色 id + DeptId interface{} // 所属部门 id + UpdatedAt *gtime.Time // 更新时间 +} diff --git a/internal/model/entity/.gitkeep b/internal/model/entity/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/internal/model/entity/comb/permission.go b/internal/model/entity/comb/permission.go new file mode 100644 index 0000000..336199a --- /dev/null +++ b/internal/model/entity/comb/permission.go @@ -0,0 +1,21 @@ +package comb + +import ( + "devops-super/internal/consts" + "devops-super/internal/model/entity" +) + +type Permission struct { + *entity.Permission + //Parent *Permission `orm:"with:id=parent_id" json:"parent"` + Children []*Permission `orm:"with:parent_id=id" json:"children"` +} + +func (s *Permission) AuthCodes() (codes []string) { + for _, child := range s.Children { + if child.Type == consts.PERMISSION_TYPE_ABLE { + codes = append(codes, child.Name) + } + } + return +} diff --git a/internal/model/entity/comb/role.go b/internal/model/entity/comb/role.go new file mode 100644 index 0000000..1068092 --- /dev/null +++ b/internal/model/entity/comb/role.go @@ -0,0 +1,8 @@ +package comb + +import "devops-super/internal/model/entity" + +type Role struct { + *entity.Role + Permissions []*Permission +} diff --git a/internal/model/entity/comb/user.go b/internal/model/entity/comb/user.go new file mode 100644 index 0000000..c00fa73 --- /dev/null +++ b/internal/model/entity/comb/user.go @@ -0,0 +1,16 @@ +package comb + +import "devops-super/internal/model/entity" + +type User struct { + *entity.User + Roles []*entity.Role +} + +func (u *User) RoleCodes() []string { + codes := make([]string, 0) + for _, role := range u.Roles { + codes = append(codes, role.Code) + } + return codes +} diff --git a/internal/model/entity/dept.go b/internal/model/entity/dept.go new file mode 100644 index 0000000..df207af --- /dev/null +++ b/internal/model/entity/dept.go @@ -0,0 +1,18 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// Dept is the golang structure for table dept. +type Dept struct { + Id int `json:"id" description:""` // + Name string `json:"name" description:"部门名称"` // 部门名称 + Rank int `json:"rank" description:"排序"` // 排序 + ParentId int `json:"parentId" description:"上级部门 id"` // 上级部门 id + UpdatedAt *gtime.Time `json:"updatedAt" description:"更新时间"` // 更新时间 +} diff --git a/internal/model/entity/permission.go b/internal/model/entity/permission.go new file mode 100644 index 0000000..719f537 --- /dev/null +++ b/internal/model/entity/permission.go @@ -0,0 +1,26 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/encoding/gjson" +) + +// Permission is the golang structure for table permission. +type Permission struct { + Id int `json:"id" description:""` // + Title string `json:"title" description:"标题"` // 标题 + Name string `json:"name" description:"路由名称"` // 路由名称 + Type int `json:"type" description:"类型:1-目录,2-菜单,3-功能"` // 类型:1-目录,2-菜单,3-功能 + FRoute string `json:"fRoute" description:"前端路由路径"` // 前端路由路径 + BRoutes *gjson.Json `json:"bRoutes" description:"后端路由路径"` // 后端路由路径 + Redirect string `json:"redirect" description:"重定向路径"` // 重定向路径 + Icon string `json:"icon" description:"图标"` // 图标 + Rank int `json:"rank" description:"排序"` // 排序 + ShowLink bool `json:"showLink" description:"是否在菜单中展示"` // 是否在菜单中展示 + ShowParent bool `json:"showParent" description:"是否展示父级菜单"` // 是否展示父级菜单 + KeepAlive bool `json:"keepAlive" description:"页面缓存"` // 页面缓存 + ParentId int `json:"parentId" description:"父级权限 id"` // 父级权限 id +} diff --git a/internal/model/entity/role.go b/internal/model/entity/role.go new file mode 100644 index 0000000..b5be416 --- /dev/null +++ b/internal/model/entity/role.go @@ -0,0 +1,19 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/os/gtime" +) + +// Role is the golang structure for table role. +type Role struct { + Id int `json:"id" description:""` // + Name string `json:"name" description:"角色名称"` // 角色名称 + Code string `json:"code" description:"角色代码"` // 角色代码 + Permission *gjson.Json `json:"permission" description:"关联权限"` // 关联权限 + UpdatedAt *gtime.Time `json:"updatedAt" description:"更新时间"` // 更新时间 +} diff --git a/internal/model/entity/user.go b/internal/model/entity/user.go new file mode 100644 index 0000000..5165517 --- /dev/null +++ b/internal/model/entity/user.go @@ -0,0 +1,24 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/os/gtime" +) + +// User is the golang structure for table user. +type User struct { + Id uint `json:"id" description:""` // + Username string `json:"username" description:"用户名"` // 用户名 + Password string `json:"password" description:"密码"` // 密码 + Phone string `json:"phone" description:"手机号码"` // 手机号码 + Email string `json:"email" description:"邮箱"` // 邮箱 + RealName string `json:"realName" description:"真实姓名"` // 真实姓名 + Enabled bool `json:"enabled" description:"是否启用状态"` // 是否启用状态 + RoleIds *gjson.Json `json:"roleIds" description:"角色 id"` // 角色 id + DeptId int `json:"deptId" description:"所属部门 id"` // 所属部门 id + UpdatedAt *gtime.Time `json:"updatedAt" description:"更新时间"` // 更新时间 +} diff --git a/internal/model/mid/dept.go b/internal/model/mid/dept.go new file mode 100644 index 0000000..77d9be6 --- /dev/null +++ b/internal/model/mid/dept.go @@ -0,0 +1,10 @@ +package mid + +import "github.com/gogf/gf/v2/os/gtime" + +type Dept struct { + Name string `v:"required" json:"name"` + Rank int `v:"required" json:"rank"` + ParentId int `json:"parentId"` + CreatedAt *gtime.Time `json:"createdAt"` +} diff --git a/internal/model/mid/permission.go b/internal/model/mid/permission.go new file mode 100644 index 0000000..701e971 --- /dev/null +++ b/internal/model/mid/permission.go @@ -0,0 +1,43 @@ +package mid + +import ( + "github.com/gogf/gf/v2/encoding/gjson" +) + +type Permission struct { + Title string `v:"required" json:"title"` + Name string `v:"required" json:"name"` + Type int `v:"required" json:"type"` + FRoute string `json:"fRoute"` + BRoutes *gjson.Json `json:"bRoutes"` + Redirect string `json:"redirect"` + Icon string `json:"icon"` + Rank int `json:"rank"` + ShowLink bool `v:"required" json:"showLink"` + ShowParent bool `v:"required" json:"showParent"` + KeepAlive bool `v:"required" json:"keepAlive"` + ParentId int `json:"parentId"` +} + +type Route struct { + Id int `json:"id"` + Name string `json:"name"` + Title string `json:"title"` + FRoute string `json:"fRoute"` + Redirect string `json:"redirect"` + Icon string `json:"icon,omitempty"` + ParentId int `json:"parentId"` + Rank int `json:"rank"` + ShowLink bool `json:"showLink"` + ShowParent bool `json:"showParent"` + Auths []string `json:"auths,omitempty"` + KeepAlive bool `json:"keepAlive"` +} + +type FrontendRouteList []*Route + +func (s FrontendRouteList) Len() int { return len(s) } + +func (s FrontendRouteList) Swap(i, j int) { s[i], s[j] = s[j], s[i] } + +func (s FrontendRouteList) Less(i, j int) bool { return s[i].Rank < s[j].Rank } diff --git a/internal/model/mid/role.go b/internal/model/mid/role.go new file mode 100644 index 0000000..a5833bb --- /dev/null +++ b/internal/model/mid/role.go @@ -0,0 +1,6 @@ +package mid + +type Role struct { + Name string `v:"required|max-length:30" json:"name"` + Code string `v:"required|max-length:30" json:"code"` +} diff --git a/internal/model/mid/user.go b/internal/model/mid/user.go new file mode 100644 index 0000000..dfcbc6d --- /dev/null +++ b/internal/model/mid/user.go @@ -0,0 +1,12 @@ +package mid + +import "github.com/gogf/gf/v2/encoding/gjson" + +type User struct { + Username string `v:"required|length:4,30" json:"username"` + Phone string `json:"phone"` + Email string `json:"email"` + RealName string `v:"required" json:"realName"` + RoleIds *gjson.Json `json:"roleIds"` + DeptId int `v:"required" json:"deptId"` +} diff --git a/internal/packed/packed.go b/internal/packed/packed.go new file mode 100644 index 0000000..e20ab1e --- /dev/null +++ b/internal/packed/packed.go @@ -0,0 +1 @@ +package packed diff --git a/internal/service/.gitkeep b/internal/service/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/internal/service/auth.go b/internal/service/auth.go new file mode 100644 index 0000000..e8d3776 --- /dev/null +++ b/internal/service/auth.go @@ -0,0 +1,113 @@ +package service + +import ( + "context" + v1 "devops-super/api/public/v1" + "devops-super/internal/model" + "devops-super/internal/model/do" + "devops-super/internal/model/entity" + "devops-super/utility/util" + "time" + + "github.com/gogf/gf/v2/encoding/gjson" + + jwt "github.com/gogf/gf-jwt/v2" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" +) + +var authService *jwt.GfJWTMiddleware + +func Auth() *jwt.GfJWTMiddleware { + return authService +} + +func CurrentUser(ctx context.Context) (u *model.RequestUser) { + _ = gjson.New(authService.GetPayload(ctx)).Scan(&u) + return +} + +func init() { + ctx := context.Background() + auth := jwt.New(&jwt.GfJWTMiddleware{ + Realm: "devops-super", + Key: g.Cfg().MustGet(context.Background(), "jwt.secret").Bytes(), + Timeout: g.Cfg().MustGet(ctx, "jwt.expire").Duration(), + MaxRefresh: g.Cfg().MustGet(ctx, "jwt.expire").Duration(), + IdentityKey: "userId", + TokenLookup: "header: Authorization, query: token, cookie: jwt", + TokenHeadName: "Bearer", + TimeFunc: time.Now, + Authenticator: Authenticator, + Unauthorized: Unauthorized, + PayloadFunc: PayloadFunc, + IdentityHandler: IdentityHandler, + }) + authService = auth +} + +// PayloadFunc is a callback function that will be called during login. +// Using this function it is possible to add additional payload data to the webtoken. +// The data is then made available during requests via c.Get("JWT_PAYLOAD"). +// Note that the payload is not encrypted. +// The attributes mentioned on jwt.io can't be used as keys for the map. +// Optional, by default no additional data will be set. +func PayloadFunc(data any) jwt.MapClaims { + userInfo := data.(*entity.User) + claims := make(jwt.MapClaims) + claims["userId"] = userInfo.Id + claims["username"] = userInfo.Username + claims["realName"] = userInfo.RealName + return claims +} + +// IdentityHandler get the identity from JWT and set the identity for every request +// Using this function, by r.GetParam("id") get identity +func IdentityHandler(ctx context.Context) interface{} { + claims := jwt.ExtractClaims(ctx) + return claims[authService.IdentityKey] +} + +// Unauthorized is used to define customized Unauthorized callback function. +func Unauthorized(ctx context.Context, code int, message string) { + r := g.RequestFromCtx(ctx) + g.Log().Debug(ctx, message) + r.Response.WriteJson(g.Map{ + "code": code, + "message": message, + }) + r.ExitAll() +} + +// Authenticator is used to validate login parameters. +// It must return user data as user identifier, it will be stored in Claim Array. +// if your identityKey is 'id', your user data must have 'id' +// Check error (e) to determine the appropriate error message. +func Authenticator(ctx context.Context) (interface{}, error) { + var ( + r = g.RequestFromCtx(ctx) + req *v1.LoginReq + ) + if err := r.Parse(&req); err != nil { + return nil, err + } + + eUser, err := User().Get(ctx, &do.User{Username: req.Username}) + if err != nil { + return nil, err + } + + if eUser == nil { + return nil, gerror.New("用户不存在") + } + + if !util.ComparePassword(eUser.Password, req.Password) { + return nil, gerror.New("密码错误") + } + + if !eUser.Enabled { + return nil, gerror.New("该用户处于禁用状态") + } + + return eUser, nil +} diff --git a/internal/service/context.go b/internal/service/context.go new file mode 100644 index 0000000..882f3ad --- /dev/null +++ b/internal/service/context.go @@ -0,0 +1,34 @@ +// ================================================================================ +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// You can delete these comments if you wish manually maintain this interface file. +// ================================================================================ + +package service + +import ( + "context" + model0 "devops-super/internal/model" +) + +type ( + IContext interface { + Init(ctx context.Context) error + RefreshCasbin(ctx context.Context) error + Ctx() *model0.ServiceContext + } +) + +var ( + localContext IContext +) + +func Context() IContext { + if localContext == nil { + panic("implement not found for interface IContext, forgot register?") + } + return localContext +} + +func RegisterContext(i IContext) { + localContext = i +} diff --git a/internal/service/dept.go b/internal/service/dept.go new file mode 100644 index 0000000..71495c1 --- /dev/null +++ b/internal/service/dept.go @@ -0,0 +1,37 @@ +// ================================================================================ +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// You can delete these comments if you wish manually maintain this interface file. +// ================================================================================ + +package service + +import ( + "context" + "devops-super/internal/model/do" + "devops-super/internal/model/entity" +) + +type ( + IDept interface { + Add(ctx context.Context, in *entity.Dept) (err error) + Get(ctx context.Context, in *do.Dept) (out *entity.Dept, err error) + GetLst(ctx context.Context, search string) (out []*entity.Dept, err error) + Upt(ctx context.Context, in *do.Dept) (err error) + Del(ctx context.Context, in *do.Dept) (err error) + } +) + +var ( + localDept IDept +) + +func Dept() IDept { + if localDept == nil { + panic("implement not found for interface IDept, forgot register?") + } + return localDept +} + +func RegisterDept(i IDept) { + localDept = i +} diff --git a/internal/service/middleware.go b/internal/service/middleware.go new file mode 100644 index 0000000..e3202f5 --- /dev/null +++ b/internal/service/middleware.go @@ -0,0 +1,31 @@ +// ================================================================================ +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// You can delete these comments if you wish manually maintain this interface file. +// ================================================================================ + +package service + +import ( + "github.com/gogf/gf/v2/net/ghttp" +) + +type ( + IMiddleware interface { + Auth(r *ghttp.Request) + } +) + +var ( + localMiddleware IMiddleware +) + +func Middleware() IMiddleware { + if localMiddleware == nil { + panic("implement not found for interface IMiddleware, forgot register?") + } + return localMiddleware +} + +func RegisterMiddleware(i IMiddleware) { + localMiddleware = i +} diff --git a/internal/service/permission.go b/internal/service/permission.go new file mode 100644 index 0000000..cdb85e3 --- /dev/null +++ b/internal/service/permission.go @@ -0,0 +1,40 @@ +// ================================================================================ +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// You can delete these comments if you wish manually maintain this interface file. +// ================================================================================ + +package service + +import ( + "context" + "devops-super/internal/model/do" + "devops-super/internal/model/entity" + "devops-super/internal/model/mid" +) + +type ( + IPermission interface { + Add(ctx context.Context, in *entity.Permission) (err error) + Get(ctx context.Context, in *do.Permission) (out *entity.Permission, err error) + GetLst(ctx context.Context, search string) (out []*entity.Permission, err error) + Upt(ctx context.Context, in *do.Permission) (err error) + Del(ctx context.Context, in *do.Permission) (err error) + SystemRequired(ctx context.Context) (ePermission *entity.Permission, err error) + GetRouteLst(ctx context.Context) (out []*mid.Route, err error) + } +) + +var ( + localPermission IPermission +) + +func Permission() IPermission { + if localPermission == nil { + panic("implement not found for interface IPermission, forgot register?") + } + return localPermission +} + +func RegisterPermission(i IPermission) { + localPermission = i +} diff --git a/internal/service/role.go b/internal/service/role.go new file mode 100644 index 0000000..45931c5 --- /dev/null +++ b/internal/service/role.go @@ -0,0 +1,41 @@ +// ================================================================================ +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// You can delete these comments if you wish manually maintain this interface file. +// ================================================================================ + +package service + +import ( + "context" + "devops-super/api" + "devops-super/internal/model/do" + "devops-super/internal/model/entity" + "devops-super/internal/model/entity/comb" +) + +type ( + IRole interface { + Add(ctx context.Context, in *entity.Role) (err error) + Upt(ctx context.Context, in *do.Role) (err error) + GetPageLst(ctx context.Context, in *api.PageLstReq) (out *api.PageLstRes[*entity.Role], err error) + GetLst(ctx context.Context) (out []*entity.Role, err error) + GetCombList(ctx context.Context) (out []*comb.Role, err error) + Get(ctx context.Context, in *do.Role) (out *entity.Role, err error) + Del(ctx context.Context, in *do.Role) (err error) + } +) + +var ( + localRole IRole +) + +func Role() IRole { + if localRole == nil { + panic("implement not found for interface IRole, forgot register?") + } + return localRole +} + +func RegisterRole(i IRole) { + localRole = i +} diff --git a/internal/service/user.go b/internal/service/user.go new file mode 100644 index 0000000..e17f3e3 --- /dev/null +++ b/internal/service/user.go @@ -0,0 +1,41 @@ +// ================================================================================ +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// You can delete these comments if you wish manually maintain this interface file. +// ================================================================================ + +package service + +import ( + "context" + "devops-super/api" + "devops-super/internal/model/do" + "devops-super/internal/model/entity" + "devops-super/internal/model/entity/comb" +) + +type ( + IUser interface { + Add(ctx context.Context, in *entity.User) (err error) + Upt(ctx context.Context, in *do.User) (err error) + GetPageLst(ctx context.Context, in *api.PageLstReq) (out *api.PageLstRes[*entity.User], err error) + Get(ctx context.Context, userDo *do.User) (out *entity.User, err error) + GetComb(ctx context.Context, userDo *do.User) (out *comb.User, err error) + GetCombLst(ctx context.Context) (out []*comb.User, err error) + Del(ctx context.Context, in *do.User) (err error) + } +) + +var ( + localUser IUser +) + +func User() IUser { + if localUser == nil { + panic("implement not found for interface IUser, forgot register?") + } + return localUser +} + +func RegisterUser(i IUser) { + localUser = i +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..6dfbb3e --- /dev/null +++ b/main.go @@ -0,0 +1,16 @@ +package main + +import ( + _ "devops-super/internal/logic" + _ "devops-super/internal/packed" + _ "github.com/gogf/gf/contrib/drivers/mysql/v2" + _ "github.com/gogf/gf/contrib/nosql/redis/v2" + + "github.com/gogf/gf/v2/os/gctx" + + "devops-super/internal/cmd" +) + +func main() { + cmd.Main.Run(gctx.GetInitCtx()) +} diff --git a/manifest/config/config.yaml b/manifest/config/config.yaml new file mode 100644 index 0000000..046b99a --- /dev/null +++ b/manifest/config/config.yaml @@ -0,0 +1,28 @@ +server: + address: ":8000" + openapiPath: "/api.json" + swaggerPath: "/swagger" + accessLogEnabled: true + serverRoot: /Users/zze/Work/code/github/zze-admin-go/resource/dist + indexFiles: [ "index.html", "main.html" ] + + +logger: + level: "all" + stdout: true + +database: + logger: + level: "all" + stdout: "true" + default: + type: mysql + link: "mysql:zze:zze.admin@tcp(127.0.0.1:3306)/zze_admin_go?loc=Local&parseTime=true" + charset: utf8mb4 + maxIdle: "10" + maxOpen: "300" + debug: true + +jwt: + secret: vIIEngfamGZasdkseadgF9fe + expire: 8h diff --git a/manifest/db/zze_admin_go.sql b/manifest/db/zze_admin_go.sql new file mode 100644 index 0000000..5698d09 --- /dev/null +++ b/manifest/db/zze_admin_go.sql @@ -0,0 +1,132 @@ +CREATE DATABASE `zze_admin_go` default charset utf8mb4; +USE `zze_admin_go`; + +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +-- ---------------------------- +-- Table structure for dept +-- ---------------------------- +DROP TABLE IF EXISTS `dept`; +CREATE TABLE `dept` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(64) NOT NULL COMMENT '部门名称', + `rank` int(11) NOT NULL COMMENT '排序', + `parent_id` int(11) NOT NULL DEFAULT '0' COMMENT '上级部门 id', + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4; + +-- ---------------------------- +-- Records of dept +-- ---------------------------- +BEGIN; +INSERT INTO `dept` (`id`, `name`, `rank`, `parent_id`, `updated_at`) VALUES (1, '深圳总公司', 0, 0, '2023-09-22 13:43:26'); +INSERT INTO `dept` (`id`, `name`, `rank`, `parent_id`, `updated_at`) VALUES (2, '研发部', 1, 1, '2023-09-22 13:52:25'); +INSERT INTO `dept` (`id`, `name`, `rank`, `parent_id`, `updated_at`) VALUES (3, '开发部', 1, 2, '2023-09-22 13:52:36'); +INSERT INTO `dept` (`id`, `name`, `rank`, `parent_id`, `updated_at`) VALUES (4, '运维部', 2, 2, '2023-09-22 13:52:41'); +INSERT INTO `dept` (`id`, `name`, `rank`, `parent_id`, `updated_at`) VALUES (5, '运营部', 2, 1, '2023-09-22 13:52:57'); +COMMIT; + +-- ---------------------------- +-- Table structure for permission +-- ---------------------------- +DROP TABLE IF EXISTS `permission`; +CREATE TABLE `permission` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `title` varchar(64) NOT NULL COMMENT '标题', + `name` varchar(64) NOT NULL COMMENT '路由名称', + `type` tinyint(4) NOT NULL COMMENT '类型:1-目录,2-菜单,3-功能', + `f_route` varchar(64) DEFAULT NULL COMMENT '前端路由路径', + `b_routes` json DEFAULT NULL COMMENT '后端路由路径', + `redirect` varchar(64) DEFAULT NULL COMMENT '重定向路径', + `icon` varchar(32) DEFAULT NULL COMMENT '图标', + `rank` int(11) DEFAULT NULL COMMENT '排序', + `show_link` bit(1) NOT NULL COMMENT '是否在菜单中展示', + `show_parent` bit(1) NOT NULL COMMENT '是否展示父级菜单', + `keep_alive` bit(1) NOT NULL COMMENT '页面缓存', + `parent_id` int(11) NOT NULL COMMENT '父级权限 id', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=32 DEFAULT CHARSET=utf8mb4; + +-- ---------------------------- +-- Records of permission +-- ---------------------------- +BEGIN; +INSERT INTO `permission` (`id`, `title`, `name`, `type`, `f_route`, `b_routes`, `redirect`, `icon`, `rank`, `show_link`, `show_parent`, `keep_alive`, `parent_id`) VALUES (1, '系统管理', 'system-manage', 1, '/system', '[]', '/system/user', 'ep:setting', 1, b'1', b'0', b'0', 0); +INSERT INTO `permission` (`id`, `title`, `name`, `type`, `f_route`, `b_routes`, `redirect`, `icon`, `rank`, `show_link`, `show_parent`, `keep_alive`, `parent_id`) VALUES (2, '权限管理', 'permission-manage', 2, '/system/permission', '[]', '', 'fa-solid:allergies', 3, b'1', b'1', b'1', 1); +INSERT INTO `permission` (`id`, `title`, `name`, `type`, `f_route`, `b_routes`, `redirect`, `icon`, `rank`, `show_link`, `show_parent`, `keep_alive`, `parent_id`) VALUES (3, '用户管理', 'user-manage', 2, '/system/user', '[]', '', 'fa:address-card', 1, b'1', b'1', b'1', 1); +INSERT INTO `permission` (`id`, `title`, `name`, `type`, `f_route`, `b_routes`, `redirect`, `icon`, `rank`, `show_link`, `show_parent`, `keep_alive`, `parent_id`) VALUES (4, '新增用户', 'user-add', 3, '/test4', '[\"post:/user\"]', '/test4', '', 2, b'1', b'0', b'0', 3); +INSERT INTO `permission` (`id`, `title`, `name`, `type`, `f_route`, `b_routes`, `redirect`, `icon`, `rank`, `show_link`, `show_parent`, `keep_alive`, `parent_id`) VALUES (5, '角色管理', 'role-manage', 2, '/system/role', '[]', '', 'ep:avatar', 2, b'1', b'1', b'1', 1); +INSERT INTO `permission` (`id`, `title`, `name`, `type`, `f_route`, `b_routes`, `redirect`, `icon`, `rank`, `show_link`, `show_parent`, `keep_alive`, `parent_id`) VALUES (6, '更新用户', 'user-upt', 3, '/test6', '[\"put:/user/:id\"]', '/test6', '', 3, b'1', b'0', b'0', 3); +INSERT INTO `permission` (`id`, `title`, `name`, `type`, `f_route`, `b_routes`, `redirect`, `icon`, `rank`, `show_link`, `show_parent`, `keep_alive`, `parent_id`) VALUES (8, '更新用户密码', 'user-upt-password', 3, '', '[\"patch:/user/:id/password\"]', '', '', 5, b'0', b'0', b'0', 3); +INSERT INTO `permission` (`id`, `title`, `name`, `type`, `f_route`, `b_routes`, `redirect`, `icon`, `rank`, `show_link`, `show_parent`, `keep_alive`, `parent_id`) VALUES (9, '启用、禁用用户', 'user-upt-enable', 3, '', '[\"patch:/user/:id/enabled\"]', '', '', 6, b'0', b'0', b'0', 3); +INSERT INTO `permission` (`id`, `title`, `name`, `type`, `f_route`, `b_routes`, `redirect`, `icon`, `rank`, `show_link`, `show_parent`, `keep_alive`, `parent_id`) VALUES (10, '删除用户', 'user-del', 3, '', '[\"delete:/user/:id\"]', '', '', 4, b'0', b'0', b'0', 3); +INSERT INTO `permission` (`id`, `title`, `name`, `type`, `f_route`, `b_routes`, `redirect`, `icon`, `rank`, `show_link`, `show_parent`, `keep_alive`, `parent_id`) VALUES (11, '查询用户', 'user-read', 3, '', '[\"get:/user/page-list\", \"get:/dept/list\"]', '', '', 1, b'0', b'0', b'0', 3); +INSERT INTO `permission` (`id`, `title`, `name`, `type`, `f_route`, `b_routes`, `redirect`, `icon`, `rank`, `show_link`, `show_parent`, `keep_alive`, `parent_id`) VALUES (14, '查询权限', 'permission-read', 3, '', '[\"get:/permission/list\"]', '', '', 1, b'0', b'0', b'0', 2); +INSERT INTO `permission` (`id`, `title`, `name`, `type`, `f_route`, `b_routes`, `redirect`, `icon`, `rank`, `show_link`, `show_parent`, `keep_alive`, `parent_id`) VALUES (15, '新增权限', 'permission-add', 3, '', '[\"post:/permission\"]', '', '', 2, b'0', b'0', b'0', 2); +INSERT INTO `permission` (`id`, `title`, `name`, `type`, `f_route`, `b_routes`, `redirect`, `icon`, `rank`, `show_link`, `show_parent`, `keep_alive`, `parent_id`) VALUES (16, '更新权限', 'permission-upt', 3, '', '[\"put:/permission/:id\"]', '', '', 3, b'0', b'0', b'0', 2); +INSERT INTO `permission` (`id`, `title`, `name`, `type`, `f_route`, `b_routes`, `redirect`, `icon`, `rank`, `show_link`, `show_parent`, `keep_alive`, `parent_id`) VALUES (17, '删除权限', 'permission-del', 3, '', '[\"delete:/permission/:id\"]', '', '', 4, b'0', b'0', b'0', 2); +INSERT INTO `permission` (`id`, `title`, `name`, `type`, `f_route`, `b_routes`, `redirect`, `icon`, `rank`, `show_link`, `show_parent`, `keep_alive`, `parent_id`) VALUES (18, '更新权限是否展示在菜单', 'permission-upt-show-link', 3, '', '[\"patch:/permission/:id/show-link\"]', '', '', 5, b'0', b'0', b'0', 2); +INSERT INTO `permission` (`id`, `title`, `name`, `type`, `f_route`, `b_routes`, `redirect`, `icon`, `rank`, `show_link`, `show_parent`, `keep_alive`, `parent_id`) VALUES (20, '查询角色', 'role-read', 3, '', '[\"get:/role/page-list\", \"get:/permission/list\"]', '', '', 1, b'0', b'0', b'0', 5); +INSERT INTO `permission` (`id`, `title`, `name`, `type`, `f_route`, `b_routes`, `redirect`, `icon`, `rank`, `show_link`, `show_parent`, `keep_alive`, `parent_id`) VALUES (21, '新增角色', 'role-add', 3, '', '[\"post:/role\"]', '', '', 2, b'0', b'0', b'0', 5); +INSERT INTO `permission` (`id`, `title`, `name`, `type`, `f_route`, `b_routes`, `redirect`, `icon`, `rank`, `show_link`, `show_parent`, `keep_alive`, `parent_id`) VALUES (22, '更新角色', 'role-upt', 3, '', '[\"put:/role:id\"]', '', '', 3, b'0', b'0', b'0', 5); +INSERT INTO `permission` (`id`, `title`, `name`, `type`, `f_route`, `b_routes`, `redirect`, `icon`, `rank`, `show_link`, `show_parent`, `keep_alive`, `parent_id`) VALUES (23, '删除角色', 'role-del', 3, '', '[\"delete:/role/:id\"]', '', '', 4, b'0', b'0', b'0', 5); +INSERT INTO `permission` (`id`, `title`, `name`, `type`, `f_route`, `b_routes`, `redirect`, `icon`, `rank`, `show_link`, `show_parent`, `keep_alive`, `parent_id`) VALUES (24, '保存角色权限信息', 'role-upt-permission', 3, '', '[\"patch:/role/:id/permission\"]', '', '', 5, b'0', b'0', b'0', 5); +INSERT INTO `permission` (`id`, `title`, `name`, `type`, `f_route`, `b_routes`, `redirect`, `icon`, `rank`, `show_link`, `show_parent`, `keep_alive`, `parent_id`) VALUES (25, '系统必需', 'system-required', 3, '', '[\"get:/permission/route-list\"]', '', '', 0, b'0', b'0', b'0', 0); +INSERT INTO `permission` (`id`, `title`, `name`, `type`, `f_route`, `b_routes`, `redirect`, `icon`, `rank`, `show_link`, `show_parent`, `keep_alive`, `parent_id`) VALUES (27, '部门管理', 'dept-manage', 2, '/system/dept', '[]', '', 'fa:group', 4, b'1', b'1', b'1', 1); +INSERT INTO `permission` (`id`, `title`, `name`, `type`, `f_route`, `b_routes`, `redirect`, `icon`, `rank`, `show_link`, `show_parent`, `keep_alive`, `parent_id`) VALUES (28, '查询部门', 'dept-read', 3, '', '[\"get:/dept/list\"]', '', '', 1, b'0', b'0', b'0', 27); +INSERT INTO `permission` (`id`, `title`, `name`, `type`, `f_route`, `b_routes`, `redirect`, `icon`, `rank`, `show_link`, `show_parent`, `keep_alive`, `parent_id`) VALUES (29, '新增部门', 'dept-add', 3, '', '[\"post:/dept\"]', '', '', 2, b'0', b'0', b'0', 27); +INSERT INTO `permission` (`id`, `title`, `name`, `type`, `f_route`, `b_routes`, `redirect`, `icon`, `rank`, `show_link`, `show_parent`, `keep_alive`, `parent_id`) VALUES (30, '更新部门', 'dept-upt', 3, '', '[\"put:/dept/:id\"]', '', '', 3, b'0', b'0', b'0', 27); +INSERT INTO `permission` (`id`, `title`, `name`, `type`, `f_route`, `b_routes`, `redirect`, `icon`, `rank`, `show_link`, `show_parent`, `keep_alive`, `parent_id`) VALUES (31, '删除部门', 'dept-del', 3, '', '[\"delete:/dept/:id\"]', '', '', 4, b'0', b'0', b'0', 27); +COMMIT; + +-- ---------------------------- +-- Table structure for role +-- ---------------------------- +DROP TABLE IF EXISTS `role`; +CREATE TABLE `role` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(128) NOT NULL COMMENT '角色名称', + `code` varchar(30) NOT NULL COMMENT '角色代码', + `permission` json DEFAULT NULL COMMENT '关联权限', + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4; + +-- ---------------------------- +-- Records of role +-- ---------------------------- +BEGIN; +INSERT INTO `role` (`id`, `name`, `code`, `permission`, `updated_at`) VALUES (1, '管理员', 'admin', '[25, 1, 3, 11, 4, 6, 10, 8, 9, 5, 20, 21, 22, 23, 24, 2, 14, 15, 16, 17, 18]', '2023-09-22 11:06:46'); +INSERT INTO `role` (`id`, `name`, `code`, `permission`, `updated_at`) VALUES (2, '测试', 'test', '[25, 11, 5, 20, 21, 22, 23, 24, 16]', '2023-09-22 11:06:46'); +COMMIT; + +-- ---------------------------- +-- Table structure for user +-- ---------------------------- +DROP TABLE IF EXISTS `user`; +CREATE TABLE `user` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `username` varchar(128) NOT NULL COMMENT '用户名', + `password` varchar(128) NOT NULL COMMENT '密码', + `phone` varchar(128) DEFAULT NULL COMMENT '手机号码', + `email` varchar(128) DEFAULT NULL COMMENT '邮箱', + `real_name` varchar(128) DEFAULT NULL COMMENT '真实姓名', + `enabled` bit(1) NOT NULL DEFAULT b'1' COMMENT '是否启用状态', + `role_ids` json DEFAULT NULL COMMENT '角色 id', + `dept_id` int(11) NOT NULL COMMENT '所属部门 id', + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COMMENT='用户表'; + +-- ---------------------------- +-- Records of user +-- ---------------------------- +BEGIN; +INSERT INTO `user` (`id`, `username`, `password`, `phone`, `email`, `real_name`, `enabled`, `role_ids`, `dept_id`, `updated_at`) VALUES (1, 'admin', '$2a$10$4R/ujw20O63gNwBTS0vJmOfAUukGT5pCMll0gsqy6IALPHZC7SDv2', '16666666666', '632404164@qq.com', '管理员', b'1', '[1]', 1, '2023-09-22 16:45:33'); +INSERT INTO `user` (`id`, `username`, `password`, `phone`, `email`, `real_name`, `enabled`, `role_ids`, `dept_id`, `updated_at`) VALUES (2, 'test', '$2a$10$aEX83iCGh/JrxiTImN0PE.0bK/dLE1lFFeZ4ssHdK4/rrXCqMgRHe', '16666666666', '632404164@qq.com', '测试用户', b'1', '[2]', 4, '2023-09-22 16:45:50'); +COMMIT; + +SET FOREIGN_KEY_CHECKS = 1; + diff --git a/manifest/deploy/kustomize/base/deployment.yaml b/manifest/deploy/kustomize/base/deployment.yaml new file mode 100644 index 0000000..28f1d69 --- /dev/null +++ b/manifest/deploy/kustomize/base/deployment.yaml @@ -0,0 +1,21 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: template-single + labels: + app: template-single +spec: + replicas: 1 + selector: + matchLabels: + app: template-single + template: + metadata: + labels: + app: template-single + spec: + containers: + - name : main + image: template-single + imagePullPolicy: Always + diff --git a/manifest/deploy/kustomize/base/kustomization.yaml b/manifest/deploy/kustomize/base/kustomization.yaml new file mode 100644 index 0000000..302d92d --- /dev/null +++ b/manifest/deploy/kustomize/base/kustomization.yaml @@ -0,0 +1,8 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: +- deployment.yaml +- service.yaml + + + diff --git a/manifest/deploy/kustomize/base/service.yaml b/manifest/deploy/kustomize/base/service.yaml new file mode 100644 index 0000000..608771c --- /dev/null +++ b/manifest/deploy/kustomize/base/service.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Service +metadata: + name: template-single +spec: + ports: + - port: 80 + protocol: TCP + targetPort: 8000 + selector: + app: template-single + diff --git a/manifest/deploy/kustomize/overlays/develop/configmap.yaml b/manifest/deploy/kustomize/overlays/develop/configmap.yaml new file mode 100644 index 0000000..3b1d0af --- /dev/null +++ b/manifest/deploy/kustomize/overlays/develop/configmap.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: template-single-configmap +data: + config.yaml: | + server: + address: ":8000" + openapiPath: "/api.json" + swaggerPath: "/swagger" + + logger: + level : "all" + stdout: true diff --git a/manifest/deploy/kustomize/overlays/develop/deployment.yaml b/manifest/deploy/kustomize/overlays/develop/deployment.yaml new file mode 100644 index 0000000..04e4851 --- /dev/null +++ b/manifest/deploy/kustomize/overlays/develop/deployment.yaml @@ -0,0 +1,10 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: template-single +spec: + template: + spec: + containers: + - name : main + image: template-single:develop \ No newline at end of file diff --git a/manifest/deploy/kustomize/overlays/develop/kustomization.yaml b/manifest/deploy/kustomize/overlays/develop/kustomization.yaml new file mode 100644 index 0000000..4731c47 --- /dev/null +++ b/manifest/deploy/kustomize/overlays/develop/kustomization.yaml @@ -0,0 +1,14 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: +- ../../base +- configmap.yaml + +patchesStrategicMerge: +- deployment.yaml + +namespace: default + + + diff --git a/manifest/docker/Dockerfile b/manifest/docker/Dockerfile new file mode 100644 index 0000000..d0e361b --- /dev/null +++ b/manifest/docker/Dockerfile @@ -0,0 +1,17 @@ +FROM loads/alpine:3.8 + +############################################################################### +# INSTALLATION +############################################################################### + +ENV WORKDIR /app +ADD resource $WORKDIR/ +ADD manifest/config $WORKDIR/config +ADD ./temp/linux_amd64/main $WORKDIR/main +RUN chmod +x $WORKDIR/main + +############################################################################### +# START +############################################################################### +WORKDIR $WORKDIR +CMD ./main --gf.gcfg.file=config-prod.yaml diff --git a/manifest/docker/docker.sh b/manifest/docker/docker.sh new file mode 100644 index 0000000..ff393f9 --- /dev/null +++ b/manifest/docker/docker.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +# This shell is executed before docker build. + + + + + diff --git a/manifest/protobuf/.keep-if-necessary b/manifest/protobuf/.keep-if-necessary new file mode 100644 index 0000000..e69de29 diff --git a/resource/i18n/.gitkeep b/resource/i18n/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/resource/imgs/dept-manage.png b/resource/imgs/dept-manage.png new file mode 100644 index 0000000..3dd9cc1 Binary files /dev/null and b/resource/imgs/dept-manage.png differ diff --git a/resource/imgs/permission-manage.png b/resource/imgs/permission-manage.png new file mode 100644 index 0000000..dae6844 Binary files /dev/null and b/resource/imgs/permission-manage.png differ diff --git a/resource/imgs/role-manage.png b/resource/imgs/role-manage.png new file mode 100644 index 0000000..da67b68 Binary files /dev/null and b/resource/imgs/role-manage.png differ diff --git a/resource/imgs/user-manage.png b/resource/imgs/user-manage.png new file mode 100644 index 0000000..edb3f5c Binary files /dev/null and b/resource/imgs/user-manage.png differ diff --git a/resource/public/html/.gitkeep b/resource/public/html/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/resource/public/plugin/.gitkeep b/resource/public/plugin/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/resource/public/resource/css/.gitkeep b/resource/public/resource/css/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/resource/public/resource/image/.gitkeep b/resource/public/resource/image/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/resource/public/resource/js/.gitkeep b/resource/public/resource/js/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/resource/template/.gitkeep b/resource/template/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/1_test.go b/tests/1_test.go new file mode 100644 index 0000000..094c1c7 --- /dev/null +++ b/tests/1_test.go @@ -0,0 +1,39 @@ +package tests + +import ( + "devops-super/utility/util" + "fmt" + "github.com/gogf/gf/v2/os/gtime" + "strings" + "testing" +) + +func Test1_1(t *testing.T) { + t.Log(util.EncryptPassword("admin123")) + //a := "$2a$10$yCU6QndNxyrLGjEMSn.YIOXph2LfaedbnrGKkZJ8vpcpaDhKMSb5K" + b := "$2a$10$lmPQ9aQ287342NpIdZctH.m9vP1gljNGJExhT1TVhbisVia.0cNRC" + t.Log(util.ComparePassword(b, "admin123")) +} + +func Test1(t *testing.T) { + t.Log(gtime.Now().Unix()) + t.Log(gtime.Now().UnixMilli()) + t.Log(gtime.Now().UnixMicro()) + t.Log(gtime.Now().UnixNano()) +} + +func Test1_3(t *testing.T) { + var iv int = 3 + switch iv { + case 1 | 2: + fmt.Println("into 1") + case 4: + fmt.Println("into 4") + } + fmt.Println("testSwitch run end") +} + +func Test1_4(t *testing.T) { + route := "get:/test/:id" + t.Log(strings.SplitN(route, ":", 2)) +} diff --git a/utility/.gitkeep b/utility/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/utility/util/encrypt.go b/utility/util/encrypt.go new file mode 100644 index 0000000..6b969b2 --- /dev/null +++ b/utility/util/encrypt.go @@ -0,0 +1,18 @@ +package util + +import "golang.org/x/crypto/bcrypt" + +func EncryptPassword(password string) (string, error) { + hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), 3) + if err != nil { + return "", err + } + + return string(hashedPassword), nil +} + +func ComparePassword(hashedPassword, password string) bool { + // 比较哈希后的密码和输入的密码是否匹配 + err := bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password)) + return err == nil +} diff --git a/utility/util/generic.go b/utility/util/generic.go new file mode 100644 index 0000000..d34ea12 --- /dev/null +++ b/utility/util/generic.go @@ -0,0 +1,18 @@ +package util + +func GetPointer[T any](v T) *T { + return &v +} + +func SqlLikeStr(str string) string { + return "%" + str + "%" +} + +func InSlice[T comparable](slice []T, v T) bool { + for _, item := range slice { + if item == v { + return true + } + } + return false +}