This commit is contained in:
2025-06-20 17:13:51 +08:00
parent 1b55403cd6
commit fd0345a034
472 changed files with 52560 additions and 77 deletions

1
.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
* linguist-language=GO

31
.gitignore vendored Normal file
View File

@@ -0,0 +1,31 @@
.buildpath
.hgignore.swp
.project
.orig
.swp
.idea/
.settings/
vendor/
composer.lock
gitpush.sh
pkg/
bin/
cbuild
**/.DS_Store
.test/
main
output/
manifest/output/
temp/
data/db.sqlite
public/uploads/
cool.sqlite
node_modules
docs/.vuepress/dist/
cool-tools/cool-tools
go.work
data/mysql/
data/redis/
go.work.sum
data/
__debug_*

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 李栋
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

81
Makefile Normal file
View File

@@ -0,0 +1,81 @@
.PHONY: help
help: ## 查看帮助
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
.PHONY: cli
cli: ## 安装gf-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 && \
rm ./gf
.PHONY: front
front: ## 下载最新cool-admin-vue,并调整参数编译
bash scripts/frontend.sh
.PHONY: docs
docs: ## 打开pkgsite文档
@set -e; \
go install golang.org/x/pkgsite/cmd/pkgsite@latest;\
echo "http://localhost:6060/github.com/cool-team-official/cool-admin-go";\
pkgsite -http=localhost:6060
.PHONY: init
init: ## 初始化环境变量
bash scripts/init.sh
.PHONY: dev
dev: ## 启动开发环境
gf run main.go
.PHONY: clean
clean: ## 清理项目,用于删除开发容器及存储卷,需在本地开发环境执行
@echo "清理项目"
@bash ./scripts/clean.sh
@echo "清理完成"
# 启动mysql
.PHONY: mysql-up
mysql-up: ## 启动mysql
@echo "启动mysql"
@docker-compose -f ./docker-compose.yml up -d mysql
# 停止mysql
.PHONY: mysql-down
mysql-down: ## 停止mysql
@echo "停止mysql"
@docker-compose -f ./docker-compose.yml stop mysql
# 备份mysql
.PHONY: mysql-backup
mysql-backup: ## 备份mysql
@echo "备份mysql"
@bash ./scripts/mysql-backup.sh
# 启动redis
.PHONY: redis-up
redis-up: ## 启动redis
@echo "启动redis"
@docker-compose -f ./docker-compose.yml up -d redis
# 停止redis
.PHONY: redis-down
redis-down: ## 停止redis
@echo "停止redis"
@docker-compose -f ./docker-compose.yml stop redis
# 启动pgsql
.PHONY: pgsql-up
pgsql-up: ## 启动pgsql
@echo "启动pgsql"
@docker-compose -f ./docker-compose.yml up -d pgsql
# 停止pgsql
.PHONY: pgsql-down
pgsql-down: ## 停止pgsql
@echo "停止pgsql"
@docker-compose -f ./docker-compose.yml stop pgsql

View File

@@ -0,0 +1,4 @@
# drivers
数据库驱动包,集合了goframe的gdb驱动 和gorm的驱动

View File

@@ -0,0 +1,18 @@
# cool-admin-go mysql 驱动包
扩展了 GoFrame mysql ,集成了 gorm相关功能.
## 使用方法
引入规则应早于 `modules`相关引入,建议在 main.go 中进行引入
```go
import (
_ "github.com/cool-team-official/cool-admin-go/contrib/drivers/mysql"
// 换行然后再入模块包,防止编辑器自动排序导致引入顺序错乱
_ "github.com/cool-team-official/cool-admin-go/modules/base"
)
```
## 配置

View File

@@ -0,0 +1,41 @@
module github.com/cool-team-official/cool-admin-go/contrib/drivers/mysql
go 1.18
require (
github.com/cool-team-official/cool-admin-go/cool v1.5.9
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.6.3
github.com/gogf/gf/v2 v2.6.3
gorm.io/driver/mysql v1.5.4
gorm.io/gorm v1.25.7
)
require (
github.com/BurntSushi/toml v1.3.2 // indirect
github.com/clbanning/mxj/v2 v2.7.0 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-sql-driver/mysql v1.7.1 // indirect
github.com/gorilla/websocket v1.5.1 // indirect
github.com/grokify/html-strip-tags-go v0.1.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/rogpeppe/go-internal v1.6.1 // indirect
go.opentelemetry.io/otel v1.24.0 // indirect
go.opentelemetry.io/otel/metric v1.24.0 // indirect
go.opentelemetry.io/otel/sdk v1.24.0 // indirect
go.opentelemetry.io/otel/trace v1.24.0 // indirect
golang.org/x/net v0.21.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/text v0.14.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

View File

@@ -0,0 +1,85 @@
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
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/cool-team-official/cool-admin-go/cool v1.5.9 h1:mvZkckumdnhkr8BGRbB+FKmUeP3tbxmyvSxfNyZAlhE=
github.com/cool-team-official/cool-admin-go/cool v1.5.9/go.mod h1:kle9oSJM+yl8ZtQwZFL8PWbz7ByI8Glj1431njGbWPo=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
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-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
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/gogf/gf/contrib/drivers/mysql/v2 v2.6.3 h1:dRGGKKiT9FEnxhfHFerojy34uCKHgReKgpMbAOtqhsY=
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.6.3/go.mod h1:sGdaCPgN1AY0tho+WYAgYdUHJkXwuDf76M3ASgHXWRQ=
github.com/gogf/gf/v2 v2.6.3 h1:DoqeuwU98wotpFoDSQEx8RZbmJdK8KdGiJtzJeqpyIo=
github.com/gogf/gf/v2 v2.6.3/go.mod h1:x2XONYcI4hRQ/4gMNbWHmZrNzSEIg20s2NULbzom5k0=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=
github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
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.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/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/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw=
go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg=
go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/mysql v1.5.4 h1:igQmHfKcbaTVyAIHNhhB888vvxh8EdQ2uSUT0LPcBso=
gorm.io/driver/mysql v1.5.4/go.mod h1:9rYxJph/u9SWkWc9yY4XJ1F/+xO0S/ChOmbk3+Z5Tvs=
gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
gorm.io/gorm v1.25.7 h1:VsD6acwRjz2zFxGO50gPO6AkNs7KKnvfzUjHQhZDz/A=
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=

View File

@@ -0,0 +1,65 @@
// Package mysql 扩展了 GoFrame 的 mysql 包,集成了 gorm相关功能.
package mysql
import (
_ "github.com/gogf/gf/contrib/drivers/mysql/v2"
"fmt"
"net/url"
"github.com/cool-team-official/cool-admin-go/cool/cooldb"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/text/gregex"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
type DriverMysql struct {
}
func NewMysql() cooldb.Driver {
return &DriverMysql{}
}
func (d *DriverMysql) GetConn(config *gdb.ConfigNode) (db *gorm.DB, err error) {
var (
source string
)
if config.Link != "" {
// ============================================================================
// Deprecated from v2.2.0.
// ============================================================================
source = config.Link
// Custom changing the schema in runtime.
if config.Name != "" {
source, _ = gregex.ReplaceString(`/([\w\.\-]+)+`, "/"+config.Name, source)
}
} else {
source = fmt.Sprintf(
"%s:%s@%s(%s:%s)/%s?charset=%s",
config.User, config.Pass, config.Protocol, config.Host, config.Port, config.Name, config.Charset,
)
if config.Timezone != "" {
source = fmt.Sprintf("%s&loc=%s", source, url.QueryEscape(config.Timezone))
}
if config.Extra != "" {
source = fmt.Sprintf("%s&%s", source, config.Extra)
}
}
return gorm.Open(mysql.Open(source), &gorm.Config{})
}
func init() {
var (
err error
driverObj = NewMysql()
driverNames = g.SliceStr{"mysql", "mariadb", "tidb"}
)
for _, driverName := range driverNames {
if err = cooldb.Register(driverName, driverObj); err != nil {
panic(err)
}
}
}

View File

@@ -0,0 +1,47 @@
module github.com/cool-team-official/cool-admin-go/contrib/drivers/pgsql
go 1.18
require (
github.com/cool-team-official/cool-admin-go/cool v1.5.9
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.6.3
github.com/gogf/gf/v2 v2.6.3
gorm.io/driver/postgres v1.5.6
gorm.io/gorm v1.25.7
)
require (
github.com/BurntSushi/toml v1.3.2 // indirect
github.com/clbanning/mxj/v2 v2.7.0 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/gorilla/websocket v1.5.1 // indirect
github.com/grokify/html-strip-tags-go v0.1.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect
github.com/jackc/pgx/v5 v5.5.3 // indirect
github.com/jackc/puddle/v2 v2.2.1 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/lib/pq v1.10.9 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/rogpeppe/go-internal v1.11.0 // indirect
go.opentelemetry.io/otel v1.24.0 // indirect
go.opentelemetry.io/otel/metric v1.24.0 // indirect
go.opentelemetry.io/otel/sdk v1.24.0 // indirect
go.opentelemetry.io/otel/trace v1.24.0 // indirect
golang.org/x/crypto v0.19.0 // indirect
golang.org/x/net v0.21.0 // indirect
golang.org/x/sync v0.6.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/text v0.14.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

View File

@@ -0,0 +1,96 @@
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
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/cool-team-official/cool-admin-go/cool v1.5.9 h1:mvZkckumdnhkr8BGRbB+FKmUeP3tbxmyvSxfNyZAlhE=
github.com/cool-team-official/cool-admin-go/cool v1.5.9/go.mod h1:kle9oSJM+yl8ZtQwZFL8PWbz7ByI8Glj1431njGbWPo=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
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/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
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/gogf/gf/contrib/drivers/pgsql/v2 v2.6.3 h1:Q5wh3EHLksi0ej/KnBZBgr2MU6r3MISaEF341RjsBeI=
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.6.3/go.mod h1:4vzOwG+fZ76cGssHEhwao0Uto1nPpARPqgyZQ9ost/4=
github.com/gogf/gf/v2 v2.6.3 h1:DoqeuwU98wotpFoDSQEx8RZbmJdK8KdGiJtzJeqpyIo=
github.com/gogf/gf/v2 v2.6.3/go.mod h1:x2XONYcI4hRQ/4gMNbWHmZrNzSEIg20s2NULbzom5k0=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=
github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA=
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.5.3 h1:Ces6/M3wbDXYpM8JyyPD57ivTtJACFZJd885pdIaV2s=
github.com/jackc/pgx/v5 v5.5.3/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
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.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/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/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
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/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw=
go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg=
go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/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=
gorm.io/driver/postgres v1.5.6 h1:ydr9xEd5YAM0vxVDY0X139dyzNz10spDiDlC7+ibLeU=
gorm.io/driver/postgres v1.5.6/go.mod h1:3e019WlBaYI5o5LIdNV+LyxCMNtLOQETBXL2h4chKpA=
gorm.io/gorm v1.25.7 h1:VsD6acwRjz2zFxGO50gPO6AkNs7KKnvfzUjHQhZDz/A=
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=

View File

@@ -0,0 +1,82 @@
package pgsql
import (
_ "github.com/gogf/gf/contrib/drivers/pgsql/v2"
"github.com/cool-team-official/cool-admin-go/cool/cooldb"
"github.com/gogf/gf/v2/frame/g"
"fmt"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/text/gregex"
"github.com/gogf/gf/v2/text/gstr"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
type DriverPgsql struct {
}
func NewDriverPgsql() *DriverPgsql {
return &DriverPgsql{}
}
func (d *DriverPgsql) GetConn(config *gdb.ConfigNode) (db *gorm.DB, err error) {
var (
source string
// underlyingDriverName = "postgres"
)
if config.Link != "" {
// ============================================================================
// Deprecated from v2.2.0.
// ============================================================================
source = config.Link
// Custom changing the schema in runtime.
if config.Name != "" {
source, _ = gregex.ReplaceString(`dbname=([\w\.\-]+)+`, "dbname="+config.Name, source)
}
} else {
if config.Name != "" {
source = fmt.Sprintf(
"user=%s password=%s host=%s port=%s dbname=%s sslmode=disable",
config.User, config.Pass, config.Host, config.Port, config.Name,
)
} else {
source = fmt.Sprintf(
"user=%s password=%s host=%s port=%s sslmode=disable",
config.User, config.Pass, config.Host, config.Port,
)
}
if config.Timezone != "" {
source = fmt.Sprintf("%s timezone=%s", source, config.Timezone)
}
if config.Extra != "" {
var extraMap map[string]interface{}
if extraMap, err = gstr.Parse(config.Extra); err != nil {
return nil, err
}
for k, v := range extraMap {
source += fmt.Sprintf(` %s=%s`, k, v)
}
}
}
db, err = gorm.Open(postgres.Open(source), &gorm.Config{})
return
}
func init() {
// Register the driver.
var (
err error
driverObj = NewDriverPgsql()
driverNames = g.SliceStr{"pgsql"}
)
for _, driverName := range driverNames {
if err = cooldb.Register(driverName, driverObj); err != nil {
panic(err)
}
}
}

View File

@@ -0,0 +1,30 @@
# cool-admin-go sqlite 驱动包
扩展了 GoFrame sqlite ,集成了 gorm 相关功能.
## 使用方法
引入规则应早于 `modules`相关引入,建议在 main.go 中进行引入
```go
import (
_ "github.com/cool-team-official/cool-admin-go/contrib/drivers/sqlite"
// 换行然后再入模块包,防止编辑器自动排序导致引入顺序错乱
_ "github.com/cool-team-official/cool-admin-go/modules/base"
)
```
## 配置
```yaml
database:
default:
type: "sqlite" # 数据库类型
name: "cool.sqlite" # 数据库名称,对于sqlite来说就是数据库文件名
extra: busy_timeout=5000 # 扩展参数 如 busy_timeout=5000&journal_mode=ALL
createdAt: "createTime" # 创建时间字段名称
updatedAt: "updateTime" # 更新时间字段名称
debug: true # 开启调试模式,启用后将在控制台打印相关sql语句
```

View File

@@ -0,0 +1,252 @@
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
// Package sqlite implements gdb.Driver, which supports operations for database SQLite.
//
// Note:
// 1. It needs manually import: _ "github.com/glebarez/go-sqlite"
// 2. It does not support Save/Replace features.
package sqlite
import (
"context"
"database/sql"
"fmt"
"strings"
// _ "github.com/glebarez/go-sqlite"
"github.com/gogf/gf/v2/util/gutil"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/encoding/gurl"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
)
// Driver is the driver for sqlite database.
type Driver struct {
*gdb.Core
}
func init() {
if err := gdb.Register(`sqlite`, New()); err != nil {
panic(err)
}
}
// New create and returns a driver that implements gdb.Driver, which supports operations for SQLite.
func New() gdb.Driver {
return &Driver{}
}
// New creates and returns a database object for sqlite.
// It implements the interface of gdb.Driver for extra database driver installation.
func (d *Driver) New(core *gdb.Core, node *gdb.ConfigNode) (gdb.DB, error) {
return &Driver{
Core: core,
}, nil
}
// Open creates and returns a underlying sql.DB object for sqlite.
// https://github.com/glebarez/go-sqlite
func (d *Driver) Open(config *gdb.ConfigNode) (db *sql.DB, err error) {
var (
source string
underlyingDriverName = "sqlite"
)
if config.Link != "" {
// ============================================================================
// Deprecated from v2.2.0.
// ============================================================================
source = config.Link
} else {
source = config.Name
}
// It searches the source file to locate its absolute path..
if absolutePath, _ := gfile.Search(source); absolutePath != "" {
source = absolutePath
}
// Multiple PRAGMAs can be specified, e.g.:
// path/to/some.db?_pragma=busy_timeout(5000)&_pragma=journal_mode(WAL)
if config.Extra != "" {
var (
options string
extraMap map[string]interface{}
)
if extraMap, err = gstr.Parse(config.Extra); err != nil {
return nil, err
}
for k, v := range extraMap {
if options != "" {
options += "&"
}
options += fmt.Sprintf(`_pragma=%s(%s)`, k, gurl.Encode(gconv.String(v)))
}
if len(options) > 1 {
source += "?" + options
}
}
if db, err = sql.Open(underlyingDriverName, source); err != nil {
err = gerror.WrapCodef(
gcode.CodeDbOperationError, err,
`sql.Open failed for driver "%s" by source "%s"`, underlyingDriverName, source,
)
return nil, err
}
return
}
// GetChars returns the security char for this type of database.
func (d *Driver) GetChars() (charLeft string, charRight string) {
return "`", "`"
}
// DoFilter deals with the sql string before commits it to underlying sql driver.
func (d *Driver) DoFilter(ctx context.Context, link gdb.Link, sql string, args []interface{}) (newSql string, newArgs []interface{}, err error) {
return d.Core.DoFilter(ctx, link, sql, args)
}
// Tables retrieves and returns the tables of current schema.
// It's mainly used in cli tool chain for automatically generating the models.
func (d *Driver) Tables(ctx context.Context, schema ...string) (tables []string, err error) {
var result gdb.Result
link, err := d.SlaveLink(schema...)
if err != nil {
return nil, err
}
result, err = d.DoSelect(ctx, link, `SELECT NAME FROM SQLITE_MASTER WHERE TYPE='table' ORDER BY NAME`)
if err != nil {
return
}
for _, m := range result {
for _, v := range m {
tables = append(tables, v.String())
}
}
return
}
// TableFields retrieves and returns the fields' information of specified table of current schema.
//
// Also see DriverMysql.TableFields.
func (d *Driver) TableFields(
ctx context.Context, table string, schema ...string,
) (fields map[string]*gdb.TableField, err error) {
var (
result gdb.Result
link gdb.Link
useSchema = gutil.GetOrDefaultStr(d.GetSchema(), schema...)
)
if link, err = d.SlaveLink(useSchema); err != nil {
return nil, err
}
result, err = d.DoSelect(ctx, link, fmt.Sprintf(`PRAGMA TABLE_INFO(%s)`, table))
if err != nil {
return nil, err
}
fields = make(map[string]*gdb.TableField)
for i, m := range result {
mKey := ""
if m["pk"].Bool() {
mKey = "pri"
}
fields[m["name"].String()] = &gdb.TableField{
Index: i,
Name: m["name"].String(),
Type: m["type"].String(),
Key: mKey,
Default: m["dflt_value"].Val(),
Null: !m["notnull"].Bool(),
}
}
return fields, nil
}
// DoInsert is not supported in sqlite.
func (d *Driver) DoInsert(
ctx context.Context, link gdb.Link, table string, list gdb.List, option gdb.DoInsertOption,
) (result sql.Result, err error) {
switch option.InsertOption {
case gdb.InsertOptionSave:
return nil, gerror.NewCode(gcode.CodeNotSupported, `Save operation is not supported by sqlite driver`)
case gdb.InsertOptionIgnore, gdb.InsertOptionReplace:
var (
keys []string // Field names.
values []string // Value holder string array, like: (?,?,?)
params []interface{} // Values that will be committed to underlying database driver.
onDuplicateStr string // onDuplicateStr is used in "ON DUPLICATE KEY UPDATE" statement.
)
// Handle the field names and placeholders.
for k := range list[0] {
keys = append(keys, k)
}
// Prepare the batch result pointer.
var (
charL, charR = d.GetChars()
batchResult = new(gdb.SqlResult)
keysStr = charL + strings.Join(keys, charR+","+charL) + charR
operation = "INSERT OR IGNORE"
)
if option.InsertOption == gdb.InsertOptionReplace {
operation = "INSERT OR REPLACE"
}
var (
listLength = len(list)
valueHolder = make([]string, 0)
)
for i := 0; i < listLength; i++ {
values = values[:0]
// Note that the map type is unordered,
// so it should use slice+key to retrieve the value.
for _, k := range keys {
if s, ok := list[i][k].(gdb.Raw); ok {
values = append(values, gconv.String(s))
} else {
values = append(values, "?")
params = append(params, list[i][k])
}
}
valueHolder = append(valueHolder, "("+gstr.Join(values, ",")+")")
// Batch package checks: It meets the batch number, or it is the last element.
if len(valueHolder) == option.BatchCount || (i == listLength-1 && len(valueHolder) > 0) {
var (
stdSqlResult sql.Result
affectedRows int64
)
stdSqlResult, err = d.DoExec(ctx, link, fmt.Sprintf(
"%s INTO %s(%s) VALUES%s %s",
operation, d.QuotePrefixTableName(table), keysStr,
gstr.Join(valueHolder, ","),
onDuplicateStr,
), params...)
if err != nil {
return stdSqlResult, err
}
if affectedRows, err = stdSqlResult.RowsAffected(); err != nil {
err = gerror.WrapCode(gcode.CodeDbOperationError, err, `sql.Result.RowsAffected failed`)
return stdSqlResult, err
} else {
batchResult.Result = stdSqlResult
batchResult.Affected += affectedRows
}
params = params[:0]
valueHolder = valueHolder[:0]
}
}
return batchResult, nil
default:
return d.Core.DoInsert(ctx, link, table, list, option)
}
}

View File

@@ -0,0 +1,48 @@
module github.com/cool-team-official/cool-admin-go/contrib/drivers/sqlite
go 1.18
require (
github.com/cool-team-official/cool-admin-go/cool v1.5.9
github.com/glebarez/sqlite v1.10.0
github.com/gogf/gf/v2 v2.6.3
gorm.io/gorm v1.25.7
)
require (
github.com/BurntSushi/toml v1.3.2 // indirect
github.com/clbanning/mxj/v2 v2.7.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/glebarez/go-sqlite v1.22.0 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/websocket v1.5.1 // indirect
github.com/grokify/html-strip-tags-go v0.1.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/rogpeppe/go-internal v1.6.1 // indirect
go.opentelemetry.io/otel v1.24.0 // indirect
go.opentelemetry.io/otel/metric v1.24.0 // indirect
go.opentelemetry.io/otel/sdk v1.24.0 // indirect
go.opentelemetry.io/otel/trace v1.24.0 // indirect
golang.org/x/net v0.21.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/text v0.14.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
modernc.org/libc v1.41.0 // indirect
modernc.org/mathutil v1.6.0 // indirect
modernc.org/memory v1.7.2 // indirect
modernc.org/sqlite v1.29.1 // indirect
)

View File

@@ -0,0 +1,98 @@
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
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/cool-team-official/cool-admin-go/cool v1.5.9 h1:mvZkckumdnhkr8BGRbB+FKmUeP3tbxmyvSxfNyZAlhE=
github.com/cool-team-official/cool-admin-go/cool v1.5.9/go.mod h1:kle9oSJM+yl8ZtQwZFL8PWbz7ByI8Glj1431njGbWPo=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec+ruQ=
github.com/glebarez/go-sqlite v1.22.0/go.mod h1:PlBIdHe0+aUEFn+r2/uthrWq4FxbzugL0L8Li6yQJbc=
github.com/glebarez/sqlite v1.10.0 h1:u4gt8y7OND/cCei/NMHmfbLxF6xP2wgKcT/BJf2pYkc=
github.com/glebarez/sqlite v1.10.0/go.mod h1:IJ+lfSOmiekhQsFTJRx/lHtGYmCdtAiTaf5wI9u5uHA=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
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/gogf/gf/v2 v2.6.3 h1:DoqeuwU98wotpFoDSQEx8RZbmJdK8KdGiJtzJeqpyIo=
github.com/gogf/gf/v2 v2.6.3/go.mod h1:x2XONYcI4hRQ/4gMNbWHmZrNzSEIg20s2NULbzom5k0=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=
github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
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.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/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/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw=
go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg=
go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/gorm v1.25.7 h1:VsD6acwRjz2zFxGO50gPO6AkNs7KKnvfzUjHQhZDz/A=
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
modernc.org/libc v1.41.0 h1:g9YAc6BkKlgORsUWj+JwqoB1wU3o4DE3bM3yvA3k+Gk=
modernc.org/libc v1.41.0/go.mod h1:w0eszPsiXoOnoMJgrXjglgLuDy/bt5RR4y3QzUUeodY=
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E=
modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E=
modernc.org/sqlite v1.29.1 h1:19GY2qvWB4VPw0HppFlZCPAbmxFU41r+qjKZQdQ1ryA=
modernc.org/sqlite v1.29.1/go.mod h1:hG41jCYxOAOoO6BRK66AdRlmOcDzXf7qnwlwjUIOqa0=

View File

@@ -0,0 +1,72 @@
package sqlite
import (
"fmt"
"github.com/cool-team-official/cool-admin-go/cool/cooldb"
"github.com/glebarez/sqlite"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/encoding/gurl"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
"gorm.io/gorm"
)
type DriverSqlite struct {
}
func NewSqlite() cooldb.Driver {
return &DriverSqlite{}
}
func (d *DriverSqlite) GetConn(config *gdb.ConfigNode) (db *gorm.DB, err error) {
var (
source string
)
if config.Link != "" {
source = config.Link
} else {
source = config.Name
}
// It searches the source file to locate its absolute path..
if absolutePath, _ := gfile.Search(source); absolutePath != "" {
source = absolutePath
}
// Multiple PRAGMAs can be specified, e.g.:
// path/to/some.db?_pragma=busy_timeout(5000)&_pragma=journal_mode(WAL)
if config.Extra != "" {
var (
options string
extraMap map[string]interface{}
)
if extraMap, err = gstr.Parse(config.Extra); err != nil {
return nil, err
}
for k, v := range extraMap {
if options != "" {
options += "&"
}
options += fmt.Sprintf(`_pragma=%s(%s)`, k, gurl.Encode(gconv.String(v)))
}
if len(options) > 1 {
source += "?" + options
}
}
println("Will use", source, "to open DB")
return gorm.Open(sqlite.Open(source), &gorm.Config{})
}
func init() {
var (
err error
driverObj = NewSqlite()
driverNames = g.SliceStr{"sqlite"}
)
for _, driverName := range driverNames {
if err = cooldb.Register(driverName, driverObj); err != nil {
panic(err)
}
}
}

17
contrib/files/README.md Normal file
View File

@@ -0,0 +1,17 @@
# 文件上传驱动
## 本地文件上传(local)
配置文件中的配置项示例
```yaml
cool:
file:
mode: "local"
domain: "http://127.0.0.1:8002"
```
驱动引入
```go
import _ "github.com/cool-team-official/cool-admin-go/contrib/files/local"
```

View File

@@ -0,0 +1,39 @@
module github.com/cool-team-official/cool-admin-go/contrib/files/local
go 1.18
require (
github.com/cool-team-official/cool-admin-go/cool v1.5.9
github.com/gogf/gf/v2 v2.6.3
)
require (
github.com/BurntSushi/toml v1.3.2 // indirect
github.com/clbanning/mxj/v2 v2.7.0 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/gorilla/websocket v1.5.1 // indirect
github.com/grokify/html-strip-tags-go v0.1.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/rogpeppe/go-internal v1.6.1 // indirect
go.opentelemetry.io/otel v1.24.0 // indirect
go.opentelemetry.io/otel/metric v1.24.0 // indirect
go.opentelemetry.io/otel/sdk v1.24.0 // indirect
go.opentelemetry.io/otel/trace v1.24.0 // indirect
golang.org/x/net v0.21.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/text v0.14.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gorm.io/gorm v1.25.7 // indirect
)

View File

@@ -0,0 +1,79 @@
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
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/cool-team-official/cool-admin-go/cool v1.5.9 h1:mvZkckumdnhkr8BGRbB+FKmUeP3tbxmyvSxfNyZAlhE=
github.com/cool-team-official/cool-admin-go/cool v1.5.9/go.mod h1:kle9oSJM+yl8ZtQwZFL8PWbz7ByI8Glj1431njGbWPo=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
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/gogf/gf/v2 v2.6.3 h1:DoqeuwU98wotpFoDSQEx8RZbmJdK8KdGiJtzJeqpyIo=
github.com/gogf/gf/v2 v2.6.3/go.mod h1:x2XONYcI4hRQ/4gMNbWHmZrNzSEIg20s2NULbzom5k0=
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=
github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
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.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/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/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw=
go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg=
go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/gorm v1.25.7 h1:VsD6acwRjz2zFxGO50gPO6AkNs7KKnvfzUjHQhZDz/A=
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=

View File

@@ -0,0 +1,71 @@
// Package local 提供本地文件上传支持
package local
import (
"github.com/cool-team-official/cool-admin-go/cool"
"github.com/cool-team-official/cool-admin-go/cool/coolfile"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gtime"
)
type Local struct {
}
func (l *Local) Upload(ctx g.Ctx) (string, error) {
var (
err error
Request = g.RequestFromCtx(ctx)
)
file := Request.GetUploadFile("file")
if file == nil {
return "", gerror.New("上传文件为空")
}
// 以当前年月日为目录
dir := gtime.Now().Format("Ymd")
fileName, err := file.Save("./public/uploads/"+dir, true)
if err != nil {
return "", err
}
return cool.Config.File.Domain + "/public/uploads/" + dir + "/" + fileName, err
}
func (l *Local) GetMode() (data interface{}, err error) {
data = g.MapStrStr{
"mode": cool.Config.File.Mode,
"type": "local",
}
return
}
func (l *Local) New() coolfile.Driver {
return &Local{}
}
func New() coolfile.Driver {
return &Local{}
}
func init() {
var (
err error
driverObj = New()
driverNames = g.SliceStr{"local"}
)
for _, driverName := range driverNames {
if err = coolfile.Register(driverName, driverObj); err != nil {
panic(err)
}
}
s := g.Server()
if !gfile.Exists("./public/uploads") {
err := gfile.Mkdir("./public/uploads")
if err != nil {
panic(err)
}
}
s.AddStaticPath("/public", "./public")
}

View File

@@ -0,0 +1,53 @@
module github.com/cool-team-official/cool-admin-go/contrib/files/minio
go 1.18
require (
github.com/cool-team-official/cool-admin-go/cool v1.5.9
github.com/gogf/gf/v2 v2.6.3
github.com/minio/minio-go/v7 v7.0.67
)
require (
github.com/BurntSushi/toml v1.3.2 // indirect
github.com/clbanning/mxj/v2 v2.7.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/websocket v1.5.1 // indirect
github.com/grokify/html-strip-tags-go v0.1.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.17.7 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/minio/md5-simd v1.1.2 // indirect
github.com/minio/sha256-simd v1.0.1 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/rogpeppe/go-internal v1.6.1 // indirect
github.com/rs/xid v1.5.0 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
go.opentelemetry.io/otel v1.24.0 // indirect
go.opentelemetry.io/otel/metric v1.24.0 // indirect
go.opentelemetry.io/otel/sdk v1.24.0 // indirect
go.opentelemetry.io/otel/trace v1.24.0 // indirect
golang.org/x/crypto v0.19.0 // indirect
golang.org/x/net v0.21.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/text v0.14.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gorm.io/gorm v1.25.7 // indirect
)

119
contrib/files/minio/go.sum Normal file
View File

@@ -0,0 +1,119 @@
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
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/cool-team-official/cool-admin-go/cool v1.5.9 h1:mvZkckumdnhkr8BGRbB+FKmUeP3tbxmyvSxfNyZAlhE=
github.com/cool-team-official/cool-admin-go/cool v1.5.9/go.mod h1:kle9oSJM+yl8ZtQwZFL8PWbz7ByI8Glj1431njGbWPo=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
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/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
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/gogf/gf/v2 v2.6.3 h1:DoqeuwU98wotpFoDSQEx8RZbmJdK8KdGiJtzJeqpyIo=
github.com/gogf/gf/v2 v2.6.3/go.mod h1:x2XONYcI4hRQ/4gMNbWHmZrNzSEIg20s2NULbzom5k0=
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=
github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg=
github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
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.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/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/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
github.com/minio/minio-go/v7 v7.0.67 h1:BeBvZWAS+kRJm1vGTMJYVjKUNoo0FoEt/wUWdUtfmh8=
github.com/minio/minio-go/v7 v7.0.67/go.mod h1:+UXocnUeZ3wHvVh5s95gcrA4YjMIbccT6ubB+1m054A=
github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM=
github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw=
go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg=
go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/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=
gorm.io/gorm v1.25.7 h1:VsD6acwRjz2zFxGO50gPO6AkNs7KKnvfzUjHQhZDz/A=
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=

View File

@@ -0,0 +1,130 @@
package minio
import (
"context"
"fmt"
"github.com/cool-team-official/cool-admin-go/cool"
"github.com/cool-team-official/cool-admin-go/cool/coolfile"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/grand"
"github.com/minio/minio-go/v7"
"github.com/minio/minio-go/v7/pkg/credentials"
)
var (
ctx g.Ctx
minioDriverObj = New()
)
type Minio struct {
Client *minio.Client
BucketName string
}
func (m *Minio) New() coolfile.Driver {
g.Log().Debug(ctx, m, m.BucketName)
return m
}
func (m *Minio) GetMode() (data interface{}, err error) {
data = g.MapStrStr{
"mode": "local",
"type": "minio",
}
return
}
func (m *Minio) Upload(ctx g.Ctx) (string, error) {
g.Log().Debug(ctx, m)
var (
err error
Request = g.RequestFromCtx(ctx)
)
file := Request.GetUploadFile("file")
if file == nil {
return "", gerror.New("上传文件为空")
}
src, err := file.Open()
if err != nil {
g.Log().Error(ctx, "文件打开失败")
}
defer src.Close()
// 以当前年月日为目录
dir := gtime.Now().Format("Ymd")
fileName := Request.Get("key", grand.S(16, false)).String()
fullPath := fmt.Sprintf("uploads/%s/%s", dir, fileName)
g.Log().Debug(ctx, fullPath)
// 创建目录
info, err := m.Client.PutObject(ctx, m.BucketName, fullPath, src, -1, minio.PutObjectOptions{})
g.Log().Debug(ctx, info)
if err != nil {
return "上传失败", err
}
return info.Location, nil
}
func New() coolfile.Driver {
ctx := context.Background()
if cool.Config.File.Mode != "minio" {
return nil
}
endpoint := cool.Config.File.Oss.Endpoint
accessKeyID := cool.Config.File.Oss.AccessKeyID
secretAccessKey := cool.Config.File.Oss.SecretAccessKey
useSSL := cool.Config.File.Oss.UseSSL
bucketName := cool.Config.File.Oss.BucketName
location := cool.Config.File.Oss.Location
// Initialize minio client object.
client, err := minio.New(endpoint, &minio.Options{
Creds: credentials.NewStaticV4(accessKeyID, secretAccessKey, ""),
Secure: useSSL,
})
if err != nil {
g.Log().Error(ctx, "初始化Minio失败")
return nil
}
if client.IsOffline() {
g.Log().Error(ctx, "Minio当前不在线")
return nil
}
err = client.MakeBucket(ctx, bucketName, minio.MakeBucketOptions{Region: location})
if err != nil {
exists, errBucketExists := client.BucketExists(ctx, bucketName)
if errBucketExists == nil && exists {
g.Log().Debug(ctx, fmt.Sprintf("存储桶%s已存在", bucketName))
} else {
g.Log().Fatal(ctx, err)
return nil
}
} else {
g.Log().Info(ctx, fmt.Sprintf("存储桶%s创建成功", bucketName))
}
return &Minio{Client: client, BucketName: bucketName}
}
func init() {
var (
err error
driverNames = g.SliceStr{"minio"}
)
if err != nil {
g.Log().Fatal(ctx, err)
}
for _, driverName := range driverNames {
if err = coolfile.Register(driverName, minioDriverObj); err != nil {
panic(err)
}
}
}

41
contrib/files/oss/go.mod Normal file
View File

@@ -0,0 +1,41 @@
module github.com/cool-team-official/cool-admin-go/contrib/files/oss
go 1.18
require (
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible
github.com/cool-team-official/cool-admin-go/cool v1.5.9
github.com/gogf/gf/v2 v2.6.3
)
require (
github.com/BurntSushi/toml v1.3.2 // indirect
github.com/clbanning/mxj/v2 v2.7.0 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/gorilla/websocket v1.5.1 // indirect
github.com/grokify/html-strip-tags-go v0.1.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/rogpeppe/go-internal v1.6.1 // indirect
go.opentelemetry.io/otel v1.24.0 // indirect
go.opentelemetry.io/otel/metric v1.24.0 // indirect
go.opentelemetry.io/otel/sdk v1.24.0 // indirect
go.opentelemetry.io/otel/trace v1.24.0 // indirect
golang.org/x/net v0.21.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.5.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gorm.io/gorm v1.25.7 // indirect
)

83
contrib/files/oss/go.sum Normal file
View File

@@ -0,0 +1,83 @@
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible h1:8psS8a+wKfiLt1iVDX79F7Y6wUM49Lcha2FMXt4UM8g=
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
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/cool-team-official/cool-admin-go/cool v1.5.9 h1:mvZkckumdnhkr8BGRbB+FKmUeP3tbxmyvSxfNyZAlhE=
github.com/cool-team-official/cool-admin-go/cool v1.5.9/go.mod h1:kle9oSJM+yl8ZtQwZFL8PWbz7ByI8Glj1431njGbWPo=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
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/gogf/gf/v2 v2.6.3 h1:DoqeuwU98wotpFoDSQEx8RZbmJdK8KdGiJtzJeqpyIo=
github.com/gogf/gf/v2 v2.6.3/go.mod h1:x2XONYcI4hRQ/4gMNbWHmZrNzSEIg20s2NULbzom5k0=
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=
github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
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.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/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/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw=
go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg=
go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/gorm v1.25.7 h1:VsD6acwRjz2zFxGO50gPO6AkNs7KKnvfzUjHQhZDz/A=
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=

127
contrib/files/oss/oss.go Normal file
View File

@@ -0,0 +1,127 @@
package oss
import (
"context"
"fmt"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
"github.com/cool-team-official/cool-admin-go/cool"
"github.com/cool-team-official/cool-admin-go/cool/coolfile"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/grand"
)
var (
ctx g.Ctx
ossDriverObj = New()
)
type Oss struct {
Client *oss.Client
Bucket *oss.Bucket
}
func (m *Oss) New() coolfile.Driver {
return m
}
func (m *Oss) GetMode() (data interface{}, err error) {
data = g.MapStrStr{
"mode": "local",
"type": "oss",
}
return
}
func (m *Oss) Upload(ctx g.Ctx) (string, error) {
var (
err error
Request = g.RequestFromCtx(ctx)
)
file := Request.GetUploadFile("file")
if file == nil {
return "", gerror.New("上传文件为空")
}
src, err := file.Open()
if err != nil {
g.Log().Error(ctx, "文件打开失败")
}
defer src.Close()
// 以当前年月日为目录
dir := gtime.Now().Format("Ymd")
fileName := Request.Get("key", grand.S(16, false)).String()
fullPath := fmt.Sprintf("uploads/%s/%s", dir, fileName)
// 创建目录
err = m.Bucket.PutObject(fullPath, src)
if err != nil {
return "上传失败", err
}
url := fmt.Sprintf("https://%s.%s/%s", m.Bucket.BucketName, cool.Config.File.Oss.Endpoint, fullPath)
return url, nil
}
func New() coolfile.Driver {
ctx := context.Background()
if cool.Config.File.Mode != "oss" {
return nil
}
endpoint := cool.Config.File.Oss.Endpoint
accessKeyID := cool.Config.File.Oss.AccessKeyID
secretAccessKey := cool.Config.File.Oss.SecretAccessKey
bucketName := cool.Config.File.Oss.BucketName
// Initialize oss client object.
client, err := oss.New(endpoint, accessKeyID, secretAccessKey)
if err != nil {
g.Log().Fatal(ctx, err)
return nil
}
exist, err := client.IsBucketExist(bucketName)
if err != nil {
g.Log().Fatal(ctx, err)
return nil
}
if exist {
g.Log().Debug(ctx, fmt.Sprintf("存储桶%s已存在", bucketName))
} else {
// 创建存储桶
err = client.CreateBucket(bucketName)
if err != nil {
g.Log().Fatal(ctx, err)
return nil
}
g.Log().Debug(ctx, fmt.Sprintf("存储桶%s创建成功", bucketName))
}
bucket, _ := client.Bucket(bucketName)
return &Oss{Client: client, Bucket: bucket}
}
func init() {
var (
err error
driverNames = g.SliceStr{"oss"}
)
if err != nil {
panic(err)
}
for _, driverName := range driverNames {
if err = coolfile.Register(driverName, ossDriverObj); err != nil {
panic(err)
}
}
}

72
cool-tools/Makefile Normal file
View File

@@ -0,0 +1,72 @@
.PHONY: help
help: ## 查看帮助
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
.PHONY: pack.template-simple
pack.template-simple:
@rm -fr temp
@mkdir temp || exit 0
@cd temp && git clone --depth=1 -b simple https://github.com/cool-team-official/cool-admin-go.git cool-admin-go-simple
@rm -fr temp/cool-admin-go-simple/.git
@cd temp && gf pack cool-admin-go-simple ../internal/packed/cool-admin-go-simple.go -n=packed -y
@rm -fr temp/cool-admin-go-simple
.PHONY: pack.template-simple.ssh
pack.template-simple.ssh:
@rm -fr temp
@mkdir temp || exit 0
@cd temp && git clone --depth=1 -b simple git@github.com:cool-team-official/cool-admin-go.git cool-admin-go-simple
@rm -fr temp/cool-admin-go-simple/.git
@cd temp && gf pack cool-admin-go-simple ../internal/packed/cool-admin-go-simple.go -n=packed -y
@rm -fr temp
.PHONY: pack.docs
pack.docs:
@rm -fr temp
@mkdir temp || exit 0
@cd temp && git clone --depth=1 -b gh-pages https://github.com/cool-team-official/cool-admin-go.git docs/cool-admin-go
@rm -fr temp/docs/cool-admin-go/.git
@cd temp && gf pack docs ../internal/packed/docs.go -n=packed -y
@rm -fr temp/docs
.PHONY: pack.docs.ssh
pack.docs.ssh:
@rm -fr temp
@mkdir temp || exit 0
@cd temp && git clone --depth=1 -b gh-pages git@github.com:cool-team-official/cool-admin-go.git docs/cool-admin-go
@rm -fr temp/docs/cool-admin-go/.git
@cd temp && gf pack docs ../internal/packed/docs.go -n=packed -y
@rm -fr temp/docs
# 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 && \
rm ./gf
# Install/Update to the latest cool-tools.
.PHONY: tools
tools:
@set -e; \
curl -L https://download.fastgit.org/cool-team-official/cool-admin-go/releases/latest/download/cool-tools_$(shell go env GOOS)_$(shell go env GOARCH) -o ./cool-tools && \
chmod +x cool-tools && \
./cool-tools install && \
rm ./cool-tools
# Check and install cool-tools.
.PHONY: tools.install
tools.install:
@set -e; \
echo "Checking cool-tools..."; \
cool-tools -v > /dev/null 2>&1 || if [[ "$?" -ne "0" ]]; then \
echo "cool-tools is not installed, start proceeding auto installation..."; \
make tools; \
fi;\
echo "cool-tools is installed.";

19
cool-tools/README.MD Normal file
View File

@@ -0,0 +1,19 @@
# CoolTools
[![Go Reference](https://pkg.go.dev/badge/github.com/cool-team-official/cool-admin-go/cool-tools.svg)](https://pkg.go.dev/github.com/cool-team-official/cool-admin-go/cool-tools)
cool-tools is a collection of tools for cool people.
## 安装
```bash
go install github.com/cool-team-official/cool-admin-go/cool-tools@latest
```
## 使用
初始化一个新的 cool-admin-go 项目
```bash
cool-tools init <project-name>
```

32
cool-tools/go.mod Normal file
View File

@@ -0,0 +1,32 @@
module github.com/cool-team-official/cool-admin-go/cool-tools
go 1.18
require github.com/gogf/gf/v2 v2.6.3
require (
github.com/BurntSushi/toml v1.3.2 // indirect
github.com/clbanning/mxj/v2 v2.7.0 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/gorilla/websocket v1.5.1 // indirect
github.com/grokify/html-strip-tags-go v0.1.0 // indirect
github.com/kr/pretty v0.3.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
go.opentelemetry.io/otel v1.24.0 // indirect
go.opentelemetry.io/otel/metric v1.24.0 // indirect
go.opentelemetry.io/otel/sdk v1.24.0 // indirect
go.opentelemetry.io/otel/trace v1.24.0 // indirect
golang.org/x/net v0.21.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/text v0.14.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

72
cool-tools/go.sum Normal file
View File

@@ -0,0 +1,72 @@
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
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/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
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/gogf/gf/v2 v2.6.3 h1:DoqeuwU98wotpFoDSQEx8RZbmJdK8KdGiJtzJeqpyIo=
github.com/gogf/gf/v2 v2.6.3/go.mod h1:x2XONYcI4hRQ/4gMNbWHmZrNzSEIg20s2NULbzom5k0=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=
github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
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.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/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/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw=
go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg=
go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -0,0 +1,12 @@
# CLI tool, only in development environment.
# https://goframe.org/pages/viewpage.action?pageId=3673173
gfcli:
build:
name: "cool-tools"
arch: "all"
system: "linux,darwin,windows"

View File

@@ -0,0 +1,14 @@
package cmd
import (
"github.com/gogf/gf/v2/os/gcmd"
)
var (
Main = gcmd.Command{
Name: "cool-tools",
Usage: "cool-tools [command] [args...]",
Brief: "cool-tools is a collection of tools for cool people.",
Description: `cool-tools is a collection of tools for cool people.`,
}
)

View File

@@ -0,0 +1,328 @@
package cmd
import (
"context"
"encoding/json"
"fmt"
"os"
"regexp"
"runtime"
"strings"
"github.com/gogf/gf/v2/encoding/gbase64"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gcmd"
"github.com/gogf/gf/v2/os/genv"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gproc"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/text/gregex"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gtag"
"github.com/cool-team-official/cool-admin-go/cool-tools/internal/utility/mlog"
)
var (
Build = cBuild{
nodeNameInConfigFile: "gfcli.build",
packedGoFileName: "internal/packed/build_pack_data.go",
}
)
type cBuild struct {
g.Meta `name:"build" brief:"{cBuildBrief}" dc:"{cBuildDc}" eg:"{cBuildEg}" ad:"{cBuildAd}"`
nodeNameInConfigFile string // nodeNameInConfigFile is the node name for compiler configurations in configuration file.
packedGoFileName string // packedGoFileName specifies the file name for packing common folders into one single go file.
}
const (
cBuildBrief = `cross-building go project for lots of platforms`
cBuildEg = `
cool-tools build main.go
cool-tools build main.go --pack public,template
cool-tools build main.go --cgo
cool-tools build main.go -m none
cool-tools build main.go -n my-app -a all -s all
cool-tools build main.go -n my-app -a amd64,386 -s linux -p .
cool-tools build main.go -n my-app -v 1.0 -a amd64,386 -s linux,windows,darwin -p ./docker/bin
`
cBuildDc = `
The "build" command is most commonly used command, which is designed as a powerful wrapper for
"go build" command for convenience cross-compiling usage.
It provides much more features for building binary:
1. Cross-Compiling for many platforms and architectures.
2. Configuration file support for compiling.
3. Build-In Variables.
`
cBuildAd = `
PLATFORMS
darwin amd64,arm64
freebsd 386,amd64,arm
linux 386,amd64,arm,arm64,ppc64,ppc64le,mips,mipsle,mips64,mips64le
netbsd 386,amd64,arm
openbsd 386,amd64,arm
windows 386,amd64
`
// https://golang.google.cn/doc/install/source
cBuildPlatforms = `
darwin amd64
darwin arm64
ios amd64
ios arm64
freebsd 386
freebsd amd64
freebsd arm
linux 386
linux amd64
linux arm
linux arm64
linux ppc64
linux ppc64le
linux mips
linux mipsle
linux mips64
linux mips64le
netbsd 386
netbsd amd64
netbsd arm
openbsd 386
openbsd amd64
openbsd arm
windows 386
windows amd64
android arm
dragonfly amd64
plan9 386
plan9 amd64
solaris amd64
`
)
func init() {
gtag.Sets(g.MapStrStr{
`cBuildBrief`: cBuildBrief,
`cBuildDc`: cBuildDc,
`cBuildEg`: cBuildEg,
`cBuildAd`: cBuildAd,
})
Main.AddObject(Build)
}
type cBuildInput struct {
g.Meta `name:"build" config:"gfcli.build"`
File string `name:"FILE" arg:"true" brief:"building file path"`
Name string `short:"n" name:"name" brief:"output binary name"`
Version string `short:"v" name:"version" brief:"output binary version"`
Arch string `short:"a" name:"arch" brief:"output binary architecture, multiple arch separated with ','"`
System string `short:"s" name:"system" brief:"output binary system, multiple os separated with ','"`
Output string `short:"o" name:"output" brief:"output binary path, used when building single binary file"`
Path string `short:"p" name:"path" brief:"output binary directory path, default is './temp'" d:"./temp"`
Extra string `short:"e" name:"extra" brief:"extra custom \"go build\" options"`
Mod string `short:"m" name:"mod" brief:"like \"-mod\" option of \"go build\", use \"-m none\" to disable go module"`
Cgo bool `short:"c" name:"cgo" brief:"enable or disable cgo feature, it's disabled in default" orphan:"true"`
VarMap g.Map `short:"r" name:"varMap" brief:"custom built embedded variable into binary"`
PackSrc string `short:"ps" name:"packSrc" brief:"pack one or more folders into one go file before building"`
PackDst string `short:"pd" name:"packDst" brief:"temporary go file path for pack, this go file will be automatically removed after built" d:"internal/packed/build_pack_data.go"`
ExitWhenError bool `short:"ew" name:"exitWhenError" brief:"exit building when any error occurs, default is false" orphan:"true"`
}
type cBuildOutput struct{}
func (c cBuild) Index(ctx context.Context, in cBuildInput) (out *cBuildOutput, err error) {
mlog.SetHeaderPrint(true)
mlog.Debugf(`build input: %+v`, in)
// Necessary check.
if gproc.SearchBinary("go") == "" {
mlog.Fatalf(`command "go" not found in your environment, please install golang first to proceed this command`)
}
var (
parser = gcmd.ParserFromCtx(ctx)
file = parser.GetArg(2).String()
)
if len(file) < 1 {
// Check and use the main.go file.
if gfile.Exists("main.go") {
file = "main.go"
} else {
mlog.Fatal("build file path cannot be empty")
}
}
if in.Name == "" {
in.Name = gfile.Name(file)
}
if len(in.Name) < 1 || in.Name == "*" {
mlog.Fatal("name cannot be empty")
}
if in.Mod != "" && in.Mod != "none" {
mlog.Debugf(`mod is %s`, in.Mod)
if in.Extra == "" {
in.Extra = fmt.Sprintf(`-mod=%s`, in.Mod)
} else {
in.Extra = fmt.Sprintf(`-mod=%s %s`, in.Mod, in.Extra)
}
}
if in.Extra != "" {
in.Extra += " "
}
var (
customSystems = gstr.SplitAndTrim(in.System, ",")
customArches = gstr.SplitAndTrim(in.Arch, ",")
)
if len(in.Version) > 0 {
in.Path += "/" + in.Version
}
// System and arch checks.
var (
spaceRegex = regexp.MustCompile(`\s+`)
platformMap = make(map[string]map[string]bool)
)
for _, line := range strings.Split(strings.TrimSpace(cBuildPlatforms), "\n") {
line = gstr.Trim(line)
line = spaceRegex.ReplaceAllString(line, " ")
var (
array = strings.Split(line, " ")
system = strings.TrimSpace(array[0])
arch = strings.TrimSpace(array[1])
)
if platformMap[system] == nil {
platformMap[system] = make(map[string]bool)
}
platformMap[system][arch] = true
}
// Auto packing.
if in.PackSrc != "" {
if in.PackDst == "" {
mlog.Fatal(`parameter "packDst" should not be empty when "packSrc" is used`)
}
if gfile.Exists(in.PackDst) && !gfile.IsFile(in.PackDst) {
mlog.Fatalf(`parameter "packDst" path "%s" should be type of file not directory`, in.PackDst)
}
if !gfile.Exists(in.PackDst) {
// Remove the go file that is automatically packed resource.
defer func() {
_ = gfile.Remove(in.PackDst)
mlog.Printf(`remove the automatically generated resource go file: %s`, in.PackDst)
}()
}
// remove black space in separator.
in.PackSrc, _ = gregex.ReplaceString(`,\s+`, `,`, in.PackSrc)
packCmd := fmt.Sprintf(`gf pack %s %s --keepPath=true`, in.PackSrc, in.PackDst)
mlog.Print(packCmd)
gproc.MustShellRun(ctx, packCmd)
}
// Injected information by building flags.
ldFlags := fmt.Sprintf(
`-X 'github.com/gogf/gf/v2/os/gbuild.builtInVarStr=%v'`,
c.getBuildInVarStr(ctx, in),
)
// start building
mlog.Print("start building...")
if in.Cgo {
genv.MustSet("CGO_ENABLED", "1")
} else {
genv.MustSet("CGO_ENABLED", "0")
}
var (
cmd = ""
ext = ""
)
for system, item := range platformMap {
cmd = ""
ext = ""
if len(customSystems) > 0 && customSystems[0] != "all" && !gstr.InArray(customSystems, system) {
continue
}
for arch := range item {
if len(customArches) > 0 && customArches[0] != "all" && !gstr.InArray(customArches, arch) {
continue
}
if len(customSystems) == 0 && len(customArches) == 0 {
if runtime.GOOS == "windows" {
ext = ".exe"
}
// Single binary building, output the binary to current working folder.
output := ""
if len(in.Output) > 0 {
output = "-o " + in.Output + ext
} else {
output = "-o " + in.Name + ext
}
cmd = fmt.Sprintf(`go build %s -ldflags "%s" %s %s`, output, ldFlags, in.Extra, file)
} else {
// Cross-building, output the compiled binary to specified path.
if system == "windows" {
ext = ".exe"
}
genv.MustSet("GOOS", system)
genv.MustSet("GOARCH", arch)
cmd = fmt.Sprintf(
`go build -o %s/%s/%s%s -ldflags "%s" %s%s`,
in.Path, system+"_"+arch, in.Name, ext, ldFlags, in.Extra, file,
)
}
mlog.Debug(cmd)
// It's not necessary printing the complete command string.
cmdShow, _ := gregex.ReplaceString(`\s+(-ldflags ".+?")\s+`, " ", cmd)
mlog.Print(cmdShow)
if result, err := gproc.ShellExec(ctx, cmd); err != nil {
mlog.Printf(
"failed to build, os:%s, arch:%s, error:\n%s\n\n%s\n",
system, arch, gstr.Trim(result),
`you may use command option "--debug" to enable debug info and check the details`,
)
if in.ExitWhenError {
os.Exit(1)
}
} else {
mlog.Debug(gstr.Trim(result))
}
// single binary building.
if len(customSystems) == 0 && len(customArches) == 0 {
goto buildDone
}
}
}
buildDone:
mlog.Print("done!")
return
}
// getBuildInVarMapJson retrieves and returns the custom build-in variables in configuration
// file as json.
func (c cBuild) getBuildInVarStr(ctx context.Context, in cBuildInput) string {
buildInVarMap := in.VarMap
if buildInVarMap == nil {
buildInVarMap = make(g.Map)
}
buildInVarMap["builtGit"] = c.getGitCommit(ctx)
buildInVarMap["builtTime"] = gtime.Now().String()
b, err := json.Marshal(buildInVarMap)
if err != nil {
mlog.Fatal(err)
}
return gbase64.EncodeToString(b)
}
// getGitCommit retrieves and returns the latest git commit hash string if present.
func (c cBuild) getGitCommit(ctx context.Context) string {
if gproc.SearchBinary("git") == "" {
return ""
}
var (
cmd = `git log -1 --format="%cd %H" --date=format:"%Y-%m-%d %H:%M:%S"`
s, _ = gproc.ShellExec(ctx, cmd)
)
mlog.Debug(cmd)
if s != "" {
if !gstr.Contains(s, "fatal") {
return gstr.Trim(s)
}
}
return ""
}

View File

@@ -0,0 +1,99 @@
package cmd
import (
"context"
"strings"
"github.com/cool-team-official/cool-admin-go/cool-tools/internal/utility/allyes"
"github.com/cool-team-official/cool-admin-go/cool-tools/internal/utility/mlog"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gcmd"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gres"
"github.com/gogf/gf/v2/util/gtag"
)
var (
Pack = cPack{}
)
type cPack struct {
g.Meta `name:"pack" usage:"{cPackUsage}" brief:"{cPackBrief}" eg:"{cPackEg}"`
}
const (
cPackUsage = `cool-tools pack SRC DST`
cPackBrief = `packing any file/directory to a resource file, or a go file`
cPackEg = `
cool-tools pack public data.bin
cool-tools pack public,template data.bin
cool-tools pack public,template packed/data.go
cool-tools pack public,template,config packed/data.go
cool-tools pack public,template,config packed/data.go -n=packed -p=/var/www/my-app
cool-tools pack /var/www/public packed/data.go -n=packed
`
cPackSrcBrief = `source path for packing, which can be multiple source paths.`
cPackDstBrief = `
destination file path for packed file. if extension of the filename is ".go" and "-n" option is given,
it enables packing SRC to go file, or else it packs SRC into a binary file.
`
cPackNameBrief = `package name for output go file, it's set as its directory name if no name passed`
cPackPrefixBrief = `prefix for each file packed into the resource file`
cPackKeepPathBrief = `keep the source path from system to resource file, usually for relative path`
)
func init() {
gtag.Sets(g.MapStrStr{
`cPackUsage`: cPackUsage,
`cPackBrief`: cPackBrief,
`cPackEg`: cPackEg,
`cPackSrcBrief`: cPackSrcBrief,
`cPackDstBrief`: cPackDstBrief,
`cPackNameBrief`: cPackNameBrief,
`cPackPrefixBrief`: cPackPrefixBrief,
`cPackKeepPathBrief`: cPackKeepPathBrief,
})
Main.AddObject(Pack)
}
type cPackInput struct {
g.Meta `name:"pack"`
Src string `name:"SRC" arg:"true" v:"required" brief:"{cPackSrcBrief}"`
Dst string `name:"DST" arg:"true" v:"required" brief:"{cPackDstBrief}"`
Name string `name:"name" short:"n" brief:"{cPackNameBrief}"`
Prefix string `name:"prefix" short:"p" brief:"{cPackPrefixBrief}"`
KeepPath bool `name:"keepPath" short:"k" brief:"{cPackKeepPathBrief}" orphan:"true"`
}
type cPackOutput struct{}
func (c cPack) Index(ctx context.Context, in cPackInput) (out *cPackOutput, err error) {
if gfile.Exists(in.Dst) && gfile.IsDir(in.Dst) {
mlog.Fatalf("DST path '%s' cannot be a directory", in.Dst)
}
if !gfile.IsEmpty(in.Dst) && !allyes.Check() {
s := gcmd.Scanf("path '%s' is not empty, files might be overwrote, continue? [y/n]: ", in.Dst)
if strings.EqualFold(s, "n") {
return
}
}
if in.Name == "" && gfile.ExtName(in.Dst) == "go" {
in.Name = gfile.Basename(gfile.Dir(in.Dst))
}
var option = gres.Option{
Prefix: in.Prefix,
KeepPath: in.KeepPath,
}
if in.Name != "" {
if err = gres.PackToGoFileWithOption(in.Src, in.Dst, in.Name, option); err != nil {
mlog.Fatalf("pack failed: %v", err)
}
} else {
if err = gres.PackToFileWithOption(in.Src, in.Dst, option); err != nil {
mlog.Fatalf("pack failed: %v", err)
}
}
mlog.Print("done!")
return
}

View File

@@ -0,0 +1,170 @@
package cmd
// 同步自 gf v2.2.2 https://github.com/gogf/gf/blob/60d828397149ed281111a7530074ce20f997224a/cmd/gf/internal/cmd/cmd_build.go
import (
"context"
"fmt"
"runtime"
"github.com/gogf/gf/v2/container/gtype"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gfsnotify"
"github.com/gogf/gf/v2/os/gproc"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/os/gtimer"
"github.com/gogf/gf/v2/util/gtag"
"github.com/cool-team-official/cool-admin-go/cool-tools/internal/utility/mlog"
)
var (
Run = cRun{}
)
type cRun struct {
g.Meta `name:"run" usage:"{cRunUsage}" brief:"{cRunBrief}" eg:"{cRunEg}" dc:"{cRunDc}"`
}
type cRunApp struct {
File string // Go run file name.
Path string // Directory storing built binary.
Options string // Extra "go run" options.
Args string // Custom arguments.
}
const (
cRunUsage = `cool-tools run FILE [OPTION]`
cRunBrief = `running go codes with hot-compiled-like feature`
cRunEg = `
cool-tools run main.go
cool-tools run main.go --args "server -p 8080"
cool-tools run main.go -mod=vendor
`
cRunDc = `
The "run" command is used for running go codes with hot-compiled-like feature,
which compiles and runs the go codes asynchronously when codes change.
`
cRunFileBrief = `building file path.`
cRunPathBrief = `output directory path for built binary file. it's "manifest/output" in default`
cRunExtraBrief = `the same options as "go run"/"go build" except some options as follows defined`
cRunArgsBrief = `custom arguments for your process`
)
var (
process *gproc.Process
)
func init() {
gtag.Sets(g.MapStrStr{
`cRunUsage`: cRunUsage,
`cRunBrief`: cRunBrief,
`cRunEg`: cRunEg,
`cRunDc`: cRunDc,
`cRunFileBrief`: cRunFileBrief,
`cRunPathBrief`: cRunPathBrief,
`cRunExtraBrief`: cRunExtraBrief,
`cRunArgsBrief`: cRunArgsBrief,
})
// 注册命令
Main.AddObject(Run)
}
type (
cRunInput struct {
g.Meta `name:"run"`
File string `name:"FILE" arg:"true" brief:"{cRunFileBrief}" v:"required"`
Path string `name:"path" short:"p" brief:"{cRunPathBrief}" d:"./"`
Extra string `name:"extra" short:"e" brief:"{cRunExtraBrief}"`
Args string `name:"args" short:"a" brief:"{cRunArgsBrief}"`
}
cRunOutput struct{}
)
func (c cRun) Index(ctx context.Context, in cRunInput) (out *cRunOutput, err error) {
// Necessary check.
if gproc.SearchBinary("go") == "" {
mlog.Fatalf(`command "go" not found in your environment, please install golang first to proceed this command`)
}
app := &cRunApp{
File: in.File,
Path: in.Path,
Options: in.Extra,
Args: in.Args,
}
dirty := gtype.NewBool()
_, err = gfsnotify.Add(gfile.RealPath("."), func(event *gfsnotify.Event) {
if gfile.ExtName(event.Path) != "go" {
return
}
// Variable `dirty` is used for running the changes only one in one second.
if !dirty.Cas(false, true) {
return
}
// With some delay in case of multiple code changes in very short interval.
gtimer.SetTimeout(ctx, 1500*gtime.MS, func(ctx context.Context) {
defer dirty.Set(false)
mlog.Printf(`go file changes: %s`, event.String())
app.Run(ctx)
})
})
if err != nil {
mlog.Fatal(err)
}
go app.Run(ctx)
select {}
}
func (app *cRunApp) Run(ctx context.Context) {
// Rebuild and run the codes.
renamePath := ""
mlog.Printf("build: %s", app.File)
outputPath := gfile.Join(app.Path, gfile.Name(app.File))
if runtime.GOOS == "windows" {
outputPath += ".exe"
if gfile.Exists(outputPath) {
renamePath = outputPath + "~"
if err := gfile.Rename(outputPath, renamePath); err != nil {
mlog.Print(err)
}
}
}
// In case of `pipe: too many open files` error.
// Build the app.
buildCommand := fmt.Sprintf(
`go build -o %s %s %s`,
outputPath,
app.Options,
app.File,
)
mlog.Print(buildCommand)
result, err := gproc.ShellExec(ctx, buildCommand)
if err != nil {
mlog.Printf("build error: \n%s%s", result, err.Error())
return
}
// Kill the old process if build successfully.
if process != nil {
if err := process.Kill(); err != nil {
mlog.Debugf("kill process error: %s", err.Error())
//return
}
}
// Run the binary file.
runCommand := fmt.Sprintf(`%s %s`, outputPath, app.Args)
mlog.Print(runCommand)
if runtime.GOOS == "windows" {
// Special handling for windows platform.
// DO NOT USE "cmd /c" command.
process = gproc.NewProcess(runCommand, nil)
} else {
process = gproc.NewProcessCmd(runCommand, nil)
}
if pid, err := process.Start(ctx); err != nil {
mlog.Printf("build running error: %s", err.Error())
} else {
mlog.Printf("build running pid: %d", pid)
}
}

View File

@@ -0,0 +1,80 @@
package cmd
import (
"context"
"net"
"github.com/cool-team-official/cool-admin-go/cool-tools/internal/utility/mlog"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gcmd"
"github.com/gogf/gf/v2/util/gconv"
)
var (
Docs = gcmd.Command{
Name: "docs",
Usage: "cool-tools docs",
Brief: "查看帮助文档",
Description: "查看帮助文档",
Func: func(ctx context.Context, parser *gcmd.Parser) error {
s := g.Server("docs")
// 获取本机未占用的端口
port, err := getfreeport()
if err != nil {
mlog.Fatal(err)
return err
}
// 获取本机ip
// ip, err := getlocalip()
// if err != nil {
// mlog.Fatal(err)
// return err
// }
s.SetServerRoot("docs")
s.BindHandler("/", func(r *ghttp.Request) {
r.Response.RedirectTo("/cool-admin-go/")
})
// 设置端口
s.SetPort(gconv.Int(port))
mlog.Printf("CoolAdminGo docs server is running at %s", "http://"+"127.0.0.1"+":"+gconv.String(port)+"/cool-admin-go/")
s.Run()
return nil
},
}
)
func init() {
Main.AddCommand(&Docs)
}
// getfreeport 获取本机未占用的端口
func getfreeport() (int, error) {
addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
if err != nil {
return 0, err
}
l, err := net.ListenTCP("tcp", addr)
if err != nil {
return 0, err
}
defer l.Close()
return l.Addr().(*net.TCPAddr).Port, nil
}
// getlocalip 获取本机ip
// func getlocalip() (string, error) {
// addrs, err := net.InterfaceAddrs()
// if err != nil {
// return "", err
// }
// for _, address := range addrs {
// // 检查ip地址判断是否回环地址
// if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
// if ipnet.IP.To4() != nil {
// return ipnet.IP.String(), nil
// }
// }
// }
// return "", nil
// }

View File

@@ -0,0 +1,27 @@
package cmd
import (
"context"
"github.com/gogf/gf/v2/os/gcmd"
"github.com/gogf/gf/v2/os/gres"
)
var (
Dump = &gcmd.Command{
Name: "dump",
Usage: "cool-tools dump",
Brief: "查看打包的资源文件",
Description: "查看打包的资源文件",
Arguments: []gcmd.Argument{},
Func: func(ctx context.Context, parser *gcmd.Parser) (err error) {
gres.Dump()
return nil
},
}
)
// init
func init() {
Main.AddCommand(Dump)
}

View File

@@ -0,0 +1,18 @@
package cmd
import (
"github.com/gogf/gf/v2/frame/g"
)
var (
Gen = cGen{}
)
type cGen struct {
g.Meta `name:"gen" brief:"生成代码" description:"生成代码, 例如: cool-tools gen model"`
cGenModel
}
func init() {
Main.AddObject(Gen)
}

View File

@@ -0,0 +1,46 @@
package cmd
import (
"github.com/cool-team-official/cool-admin-go/cool"
"github.com/gogf/gf/v2/frame/g"
"gorm.io/gen"
)
type cGenModel struct {
g.Meta `name:"model" brief:"生成模型代码" description:"生成模型代码, 例如: cool-tools gen model"`
}
var (
GenModel = cGenModel{}
)
type cGenModelInput struct {
g.Meta `name:"model" brief:"生成模型代码" description:"生成模型代码, 例如: cool-tools gen model"`
Database string `v:"required#请输入数据库名称" arg:"true" name:"database" brief:"数据库名称" description:"数据库名称"`
}
type cGenModelOutput struct{}
func (c *cGenModel) Index(ctx g.Ctx, in cGenModelInput) (out cGenModelOutput, err error) {
g.Log().Print(ctx, in.Database)
// 获取数据库
db, err := cool.InitDB(in.Database)
if err != nil {
panic(err.Error())
}
generator := gen.NewGenerator(gen.Config{
OutPath: "temp/gen/model",
OutFile: "",
ModelPkgPath: "",
WithUnitTest: false,
FieldNullable: true,
FieldCoverable: true,
FieldSignable: true,
FieldWithIndexTag: true,
FieldWithTypeTag: true,
Mode: 0,
})
generator.UseDB(db)
generator.GenerateAllTable()
generator.Execute()
return
}

View File

@@ -0,0 +1,68 @@
package cmd
import (
"context"
"strings"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gcmd"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gres"
)
var (
Init = gcmd.Command{
Name: "init",
Usage: "cool-tools init [dst]",
Brief: "创建一个新的cool-admin-go项目",
Arguments: []gcmd.Argument{
{
Name: "dst",
// Short: "m",
Brief: "the destination path",
IsArg: true,
},
},
Func: func(ctx context.Context, parser *gcmd.Parser) (err error) {
dst := parser.GetArg(2).String()
if dst == "" {
dst = "."
}
// 如果目标路径不存在,则创建目标路径
if gfile.IsEmpty(dst) {
if err = gfile.Mkdir(dst); err != nil {
return
}
} else {
if !gfile.IsDir(dst) {
g.Log().Panicf(ctx, "%s is not a directory", dst)
} else {
s := gcmd.Scanf(`the folder "%s" is not empty, files might be overwrote, continue? [y/n]: `, dst)
if strings.EqualFold(s, "n") {
return
}
}
}
err = gres.Export("cool-admin-go-simple", dst, gres.ExportOption{
RemovePrefix: "cool-admin-go-simple",
})
if err != nil {
return
}
err = gfile.ReplaceDir("cool-admin-go-simple", gfile.Basename(gfile.RealPath(dst)), dst, "*", true)
if err != nil {
return
}
g.Log().Infof(ctx, "init success")
return nil
},
}
)
// init 初始化模块
func init() {
Main.AddCommand(&Init)
}

View File

@@ -0,0 +1,25 @@
package cmd
import (
"context"
"github.com/cool-team-official/cool-admin-go/cool-tools/internal/service"
"github.com/gogf/gf/v2/os/gcmd"
)
var (
Install = gcmd.Command{
Name: "install",
Usage: "cool-tools install",
Brief: "Install cool-tools to the system.",
Func: func(ctx context.Context, parser *gcmd.Parser) (err error) {
err = service.Install.Run(ctx)
return
},
}
)
// init
func init() {
Main.AddCommand(&Install)
}

View File

@@ -0,0 +1,61 @@
package cmd
import (
"context"
"github.com/cool-team-official/cool-admin-go/cool-tools/internal/service"
"github.com/gogf/gf/v2/os/gcmd"
)
var (
Module = &gcmd.Command{
Name: "module",
Usage: "cool-tools module moduleName",
Brief: "在modules目录下创建模块",
Description: "在modules目录下创建模块, 并且创建相应的目录结构,注意: 如果模块已经存在, 则会覆盖原有的模块,本命令需在项目根目录下执行.",
Arguments: []gcmd.Argument{
{
Name: "moduleName",
IsArg: true,
Orphan: false,
},
},
Func: func(ctx context.Context, parser *gcmd.Parser) (err error) {
moduleName := parser.GetArg(2).String()
if moduleName == "" {
println("moduleName is empty")
return nil
}
err = service.CreatModule(ctx, moduleName)
return
},
}
M = &gcmd.Command{
Name: "m",
Usage: "cool-tools module moduleName",
Brief: "在modules目录下创建模块,为module的简写模式",
Description: "在modules目录下创建模块, 并且创建相应的目录结构,注意: 如果模块已经存在, 则会覆盖原有的模块,本命令需在项目根目录下执行.",
Arguments: []gcmd.Argument{
{
Name: "moduleName",
IsArg: true,
Orphan: false,
},
},
Func: func(ctx context.Context, parser *gcmd.Parser) (err error) {
moduleName := parser.GetArg(2).String()
if moduleName == "" {
println("moduleName is empty")
return nil
}
err = service.CreatModule(ctx, moduleName)
return
},
}
)
func init() {
Main.AddCommand(Module)
Main.AddCommand(M)
}

View File

@@ -0,0 +1,61 @@
package cmd
import (
"context"
"github.com/gogf/gf/v2/container/garray"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/os/gcmd"
"github.com/gogf/gf/v2/os/gfile"
)
var (
SnippetsMaker = gcmd.Command{
Name: "snippetsmaker",
Usage: "snippetsmaker",
Brief: "代码片段生成器",
Func: func(ctx context.Context, parser *gcmd.Parser) (err error) {
g.Log().Debug(ctx, "snippetsmaker,生成工具^.^")
files := garray.New(true)
files.Append("modules/demo/model/demo_sample.go")
files.Append("modules/demo/service/demo_sample.go")
files.Append("modules/demo/controller/admin/demo_sample.go")
// 遍历files
for _, file := range files.Slice() {
sArray := garray.NewStrArray()
gfile.ReadLines(file.(string), func(line string) error {
// g.Log().Debug(ctx, line)
// println(line)
// search := `Sample`
// replace := `${TM_FILENAME_BASE/(.*)/${1:/capitalize}/}`
// replaceArray := []string{"Sample", "${TM_FILENAME_BASE/(.*)/${1:/pascalcase}/}", "sample", "${TM_FILENAME_BASE/(.*)/${1:/downcase}/}", "demo", "${2:模块名称}", "app", "${TM_DIRECTORY/^.+[\\/\\\\]+(.*)$/$1/}"}
replaceArray := []string{"DemoSample", "${TM_FILENAME_BASE/(.*)/${1:/pascalcase}/}", "demo_sample", "${TM_FILENAME_BASE/(.*)/${1:/downcase}/}"}
result := gstr.ReplaceByArray(line, replaceArray)
sArray.Append(gstr.AddSlashes(result))
return nil
})
// g.Dump(sArray)
println(file.(string))
println("--------------------------------------code start------------------------------------------")
println(`"body":[`)
sArray.Iterator(
func(index int, value string) bool {
println("\"" + value + "\",")
return true
},
)
println("]")
println("--------------------------------------code end------------------------------------------")
}
return nil
},
}
)
func init() {
Main.AddCommand(&SnippetsMaker)
}

View File

@@ -0,0 +1,53 @@
package cmd
import (
"context"
"github.com/gogf/gf/v2/os/gbuild"
"github.com/gogf/gf/v2/os/gcmd"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/util/gutil"
)
type sVersion struct {
Name string //程序名称
Homepage string //程序主页
Version string //程序版本
GoFrame string //goframe version
Golang string //golang version
Git string //git commit id
Time string //build datetime
InstallPath string //安装路径
}
var (
Version = gcmd.Command{
Name: "version",
Usage: "cool-tools version",
Brief: "查看版本信息",
Func: func(ctx context.Context, parser *gcmd.Parser) (err error) {
info := gbuild.Info()
binVersion := "v1.5.10"
// 生成sVersion结构体
res := sVersion{
Name: "cool-tools",
Homepage: "https://cool-js.com",
Version: binVersion,
GoFrame: info.GoFrame,
Golang: info.Golang,
Git: info.Git,
Time: info.Time,
InstallPath: gfile.SelfDir(),
}
// mlog.Printf(`CLI Installed At: %s`, gfile.SelfPath())
gutil.Dump(res)
return nil
},
}
)
// init 初始化模块
func init() {
Main.AddCommand(&Version)
}

View File

@@ -0,0 +1 @@
package consts

View File

View File

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
package packed

View File

View File

@@ -0,0 +1,235 @@
package service
import (
"context"
"runtime"
"strings"
"github.com/cool-team-official/cool-admin-go/cool-tools/internal/utility/allyes"
"github.com/cool-team-official/cool-admin-go/cool-tools/internal/utility/mlog"
"github.com/gogf/gf/v2/container/garray"
"github.com/gogf/gf/v2/container/gset"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gcmd"
"github.com/gogf/gf/v2/os/genv"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
)
var (
Install = serviceInstall{}
)
type serviceInstall struct{}
type serviceInstallAvailablePath struct {
dirPath string
filePath string
writable bool
installed bool
}
func (s serviceInstall) Run(ctx context.Context) (err error) {
// Ask where to install.
paths := s.getAvailablePaths()
if len(paths) <= 0 {
mlog.Printf("no path detected, you can manually install cool-tools by copying the binary to path folder.")
return
}
mlog.Printf("I found some installable paths for you(from $PATH): ")
mlog.Printf(" %2s | %8s | %9s | %s", "Id", "Writable", "Installed", "Path")
// Print all paths status and determine the default selectedID value.
var (
selectedID = -1
newPaths []serviceInstallAvailablePath
pathSet = gset.NewStrSet() // Used for repeated items filtering.
)
for _, path := range paths {
if !pathSet.AddIfNotExist(path.dirPath) {
continue
}
newPaths = append(newPaths, path)
}
paths = newPaths
for id, path := range paths {
mlog.Printf(" %2d | %8t | %9t | %s", id, path.writable, path.installed, path.dirPath)
if selectedID == -1 {
// Use the previously installed path as the most priority choice.
if path.installed {
selectedID = id
}
}
}
// If there's no previously installed path, use the first writable path.
if selectedID == -1 {
// Order by choosing priority.
commonPaths := garray.NewStrArrayFrom(g.SliceStr{
s.getGoPathBin(),
`/usr/local/bin`,
`/usr/bin`,
`/usr/sbin`,
`C:\Windows`,
`C:\Windows\system32`,
`C:\Go\bin`,
`C:\Program Files`,
`C:\Program Files (x86)`,
})
// Check the common installation directories.
commonPaths.Iterator(func(k int, v string) bool {
for id, aPath := range paths {
if strings.EqualFold(aPath.dirPath, v) {
selectedID = id
return false
}
}
return true
})
if selectedID == -1 {
selectedID = 0
}
}
if allyes.Check() {
// Use the default selectedID.
mlog.Printf("please choose one installation destination [default %d]: %d", selectedID, selectedID)
} else {
for {
// Get input and update selectedID.
var (
inputID int
input = gcmd.Scanf("please choose one installation destination [default %d]: ", selectedID)
)
if input != "" {
inputID = gconv.Int(input)
}
// Check if out of range.
if inputID >= len(paths) || inputID < 0 {
mlog.Printf("invalid install destination Id: %d", inputID)
continue
}
selectedID = inputID
break
}
}
// Get selected destination path.
dstPath := paths[selectedID]
// Install the new binary.
err = gfile.CopyFile(gfile.SelfPath(), dstPath.filePath)
if err != nil {
mlog.Printf("install cool-tools binary to '%s' failed: %v", dstPath.dirPath, err)
mlog.Printf("you can manually install cool-tools by copying the binary to folder: %s", dstPath.dirPath)
} else {
mlog.Printf("cool-tools binary is successfully installed to: %s", dstPath.dirPath)
}
// Uninstall the old binary.
for _, path := range paths {
// Do not delete myself.
if path.filePath != "" && path.filePath != dstPath.filePath && gfile.SelfPath() != path.filePath {
_ = gfile.Remove(path.filePath)
}
}
return
}
// IsInstalled checks and returns whether the binary is installed.
func (s serviceInstall) IsInstalled() bool {
paths := s.getAvailablePaths()
for _, aPath := range paths {
if aPath.installed {
return true
}
}
return false
}
// getGoPathBinFilePath retrieves ad returns the GOPATH/bin path for binary.
func (s serviceInstall) getGoPathBin() string {
if goPath := genv.Get(`GOPATH`).String(); goPath != "" {
return gfile.Join(goPath, "bin")
}
return ""
}
// getAvailablePaths returns the installation paths data for the binary.
func (s serviceInstall) getAvailablePaths() []serviceInstallAvailablePath {
var (
folderPaths []serviceInstallAvailablePath
binaryFileName = "cool-tools" + gfile.Ext(gfile.SelfPath())
)
// $GOPATH/bin
if goPathBin := s.getGoPathBin(); goPathBin != "" {
folderPaths = s.checkAndAppendToAvailablePath(
folderPaths, goPathBin, binaryFileName,
)
}
switch runtime.GOOS {
case "darwin":
darwinInstallationCheckPaths := []string{"/usr/local/bin"}
for _, v := range darwinInstallationCheckPaths {
folderPaths = s.checkAndAppendToAvailablePath(
folderPaths, v, binaryFileName,
)
}
fallthrough
default:
// Search and find the writable directory path.
envPath := genv.Get("PATH", genv.Get("Path").String()).String()
if gstr.Contains(envPath, ";") {
// windows.
for _, v := range gstr.SplitAndTrim(envPath, ";") {
if v == "." {
continue
}
folderPaths = s.checkAndAppendToAvailablePath(
folderPaths, v, binaryFileName,
)
}
} else if gstr.Contains(envPath, ":") {
// *nix.
for _, v := range gstr.SplitAndTrim(envPath, ":") {
if v == "." {
continue
}
folderPaths = s.checkAndAppendToAvailablePath(
folderPaths, v, binaryFileName,
)
}
} else if envPath != "" {
folderPaths = s.checkAndAppendToAvailablePath(
folderPaths, envPath, binaryFileName,
)
} else {
folderPaths = s.checkAndAppendToAvailablePath(
folderPaths, "/usr/local/bin", binaryFileName,
)
}
}
return folderPaths
}
// checkAndAppendToAvailablePath checks if `path` is writable and already installed.
// It adds the `path` to `folderPaths` if it is writable or already installed, or else it ignores the `path`.
func (s serviceInstall) checkAndAppendToAvailablePath(folderPaths []serviceInstallAvailablePath, dirPath string, binaryFileName string) []serviceInstallAvailablePath {
var (
filePath = gfile.Join(dirPath, binaryFileName)
writable = gfile.IsWritable(dirPath)
installed = gfile.Exists(filePath)
)
if !writable && !installed {
return folderPaths
}
return append(
folderPaths,
serviceInstallAvailablePath{
dirPath: dirPath,
writable: writable,
filePath: filePath,
installed: installed,
})
}

View File

@@ -0,0 +1,67 @@
package service
import (
"context"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gres"
"github.com/gogf/gf/v2/text/gstr"
)
func CreatModule(ctx context.Context, moduleName string) (err error) {
// 检测当前目录是否存在go.mod文件
if !gfile.Exists("go.mod") {
err = gerror.New("当前目录不存在go.mod文件,请在项目根目录下执行")
return
}
module := ""
// 读取go.mod文件第一行文本
gfile.ReadLines("go.mod", func(text string) error {
if gstr.Contains(text, "module") && module == "" {
// println("module:", text)
module = gstr.StrEx(text, "module")
// println("module:", module)
module = gstr.TrimAll(module)
// println("module:", module)
return nil
}
return nil
})
if module == "" {
err = gerror.New("go.mod文件中不存在module行")
return
}
// println(module)
// 创建模块目录
moduleDir := gfile.Join(gfile.Pwd(), "modules", moduleName)
if gfile.Exists(moduleDir) {
err = gerror.New("模块已经存在,请先删除原有模块")
return
}
err = gfile.Mkdir(moduleDir)
if err != nil {
return
}
// 创建模块目录结构
err = gres.Export("cool-admin-go-simple/modules/demo", moduleDir, gres.ExportOption{
RemovePrefix: "cool-admin-go-simple/modules/demo",
})
if err != nil {
return
}
// 替换import路径
err = gfile.ReplaceDir("cool-admin-go-simple/modules/demo", module+"/modules/"+moduleName, moduleDir, "*", true)
if err != nil {
return
}
// 重命名demo.go 为 moduleName.go
err = gfile.Rename(gfile.Join(moduleDir, "demo.go"), gfile.Join(moduleDir, moduleName+".go"))
if err != nil {
return
}
println("创建模块成功:", moduleDir)
return nil
}

View File

@@ -0,0 +1,22 @@
package allyes
import (
"github.com/gogf/gf/v2/os/gcmd"
"github.com/gogf/gf/v2/os/genv"
)
const (
EnvName = "GF_CLI_ALL_YES"
)
// Init initializes the package manually.
func Init() {
if gcmd.GetOpt("y") != nil {
genv.MustSet(EnvName, "1")
}
}
// Check checks whether option allow all yes for command.
func Check() bool {
return genv.Get(EnvName).String() == "1"
}

View File

@@ -0,0 +1,66 @@
package mlog
import (
"context"
"github.com/gogf/gf/v2/os/gcmd"
"github.com/gogf/gf/v2/os/genv"
"github.com/gogf/gf/v2/os/glog"
)
const (
headerPrintEnvName = "GF_CLI_MLOG_HEADER"
)
var (
ctx = context.TODO()
logger = glog.New()
)
func init() {
logger.SetStack(false)
if genv.Get(headerPrintEnvName).String() == "1" {
logger.SetHeaderPrint(true)
} else {
logger.SetHeaderPrint(false)
}
if gcmd.GetOpt("debug") != nil || gcmd.GetOpt("gf.debug") != nil {
logger.SetDebug(true)
} else {
logger.SetDebug(false)
}
}
// SetHeaderPrint enables/disables header printing to stdout.
func SetHeaderPrint(enabled bool) {
logger.SetHeaderPrint(enabled)
if enabled {
_ = genv.Set(headerPrintEnvName, "1")
} else {
_ = genv.Set(headerPrintEnvName, "0")
}
}
func Print(v ...interface{}) {
logger.Print(ctx, v...)
}
func Printf(format string, v ...interface{}) {
logger.Printf(ctx, format, v...)
}
func Fatal(v ...interface{}) {
logger.Fatal(ctx, v...)
}
func Fatalf(format string, v ...interface{}) {
logger.Fatalf(ctx, format, v...)
}
func Debug(v ...interface{}) {
logger.Debug(ctx, v...)
}
func Debugf(format string, v ...interface{}) {
logger.Debugf(ctx, format, v...)
}

35
cool-tools/main.go Normal file
View File

@@ -0,0 +1,35 @@
package main
import (
"github.com/cool-team-official/cool-admin-go/cool-tools/internal/cmd"
_ "github.com/cool-team-official/cool-admin-go/cool-tools/internal/packed"
"github.com/cool-team-official/cool-admin-go/cool-tools/internal/utility/allyes"
"github.com/cool-team-official/cool-admin-go/cool-tools/internal/utility/mlog"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gcfg"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/os/gfile"
)
const (
cliFolderName = `hack`
)
func main() {
// gres.Dump()
// CLI configuration.
if path, _ := gfile.Search(cliFolderName); path != "" {
if adapter, ok := g.Cfg().GetAdapter().(*gcfg.AdapterFile); ok {
if err := adapter.SetPath(path); err != nil {
mlog.Fatal(err)
}
}
}
// -y option checks.
allyes.Init()
err := cmd.Main.RunWithError(gctx.New())
if err != nil {
println(err.Error())
}
}

View File

@@ -0,0 +1,38 @@
server:
address: ":8000"
openapiPath: "/api.json"
swaggerPath: "/swagger"
logger:
level : "all"
stdout: true
database:
default:
- type: "mysql"
link: "root:123456@tcp(127.0.0.1:3306)/cooltest?charset=utf8mb4&parseTime=True&loc=Local"
role: "master"
debug: true
createdAt: "createTime"
updatedAt: "updateTime"
- type: "mysql"
link: "root:123456@tcp(127.0.0.1:3306)/cooltest?charset=utf8mb4&parseTime=True&loc=Local"
role: "slave"
debug: true
createdAt: "createTime"
updatedAt: "updateTime"
test:
type: "sqlite"
link: "./temp/db.sqlite"
logLevel: "all"
createdAt: "createTime"
updatedAt: "updateTime"
bill:
type: "mssql"
# link: "sqlserver://sa:fjTGgpaFlp3LLi3tsB@localhost:1433?database=bill"
link: "server=localhost;user id=sa;password=fjTGgpaFlp3LLi3tsB;port=1433;database=bill;"
logLevel: "all"
createdAt: "createTime"
updatedAt: "updateTime"

View File

@@ -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

View File

@@ -0,0 +1,8 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml

View File

@@ -0,0 +1,12 @@
apiVersion: v1
kind: Service
metadata:
name: template-single
spec:
ports:
- port: 80
protocol: TCP
targetPort: 8000
selector:
app: template-single

View File

@@ -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

View File

@@ -0,0 +1,10 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: template-single
spec:
template:
spec:
containers:
- name : main
image: template-single:develop

View File

@@ -0,0 +1,14 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
- configmap.yaml
patchesStrategicMerge:
- deployment.yaml
namespace: default

View File

@@ -0,0 +1,16 @@
FROM loads/alpine:3.8
###############################################################################
# INSTALLATION
###############################################################################
ENV WORKDIR /app
ADD resource $WORKDIR/
ADD ./temp/linux_amd64/main $WORKDIR/main
RUN chmod +x $WORKDIR/main
###############################################################################
# START
###############################################################################
WORKDIR $WORKDIR
CMD ./main

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# This shell is executed before docker build.

8
cool/config.go Normal file
View File

@@ -0,0 +1,8 @@
package cool
import "github.com/cool-team-official/cool-admin-go/cool/coolconfig"
var (
Config = coolconfig.Config // 配置中的cool节相关配置
GetCfgWithDefault = coolconfig.GetCfgWithDefault // GetCfgWithDefault 获取配置,如果配置不存在,则使用默认值
)

8
cool/const.go Normal file
View File

@@ -0,0 +1,8 @@
package cool
// Join 类型
const (
LeftJoin JoinType = "LeftJoin"
RightJoin JoinType = "RightJoin"
InnerJoin JoinType = "InnerJoin"
)

27
cool/controller-simple.go Normal file
View File

@@ -0,0 +1,27 @@
package cool
import (
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/util/gconv"
)
type IControllerSimple interface {
}
type ControllerSimple struct {
Prefix string
}
// 注册不带crud的路由
func RegisterControllerSimple(c IControllerSimple) {
var sController = &ControllerSimple{}
// var sService = &Service{}
gconv.Struct(c, &sController)
g.Server().Group(
sController.Prefix, func(group *ghttp.RouterGroup) {
group.Middleware(MiddlewareHandlerResponse)
group.Bind(
c,
)
})
}

216
cool/controller.go Normal file
View File

@@ -0,0 +1,216 @@
package cool
import (
"context"
"strings"
"github.com/cool-team-official/cool-admin-go/cool/coolconfig"
"github.com/gogf/gf/v2/container/garray"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
)
type IController interface {
Add(ctx context.Context, req *AddReq) (res *BaseRes, err error)
Delete(ctx context.Context, req *DeleteReq) (res *BaseRes, err error)
Update(ctx context.Context, req *UpdateReq) (res *BaseRes, err error)
Info(ctx context.Context, req *InfoReq) (res *BaseRes, err error)
List(ctx context.Context, req *ListReq) (res *BaseRes, err error)
Page(ctx context.Context, req *PageReq) (res *BaseRes, err error)
}
type Controller struct {
Prefix string `json:"prefix"`
Api g.ArrayStr `json:"api"`
Service IService `json:"service"`
}
type AddReq struct {
g.Meta `path:"/add" method:"POST"`
}
type DeleteReq struct {
g.Meta `path:"/delete" method:"POST"`
Ids []int `json:"ids" v:"required#请选择要删除的数据"`
}
type UpdateReq struct {
g.Meta `path:"/update" method:"POST"`
}
type InfoReq struct {
g.Meta `path:"/info" method:"GET"`
Id int `json:"id" v:"integer|required#请选择要查询的数据"`
}
// type InfoRes struct {
// *BaseRes
// Data interface{} `json:"data"`
// }
type ListReq struct {
g.Meta `path:"/list" method:"POST"`
Order string `json:"order"`
Sort string `json:"sort"`
}
type PageReq struct {
g.Meta `path:"/page" method:"POST"`
Page int `d:"1" json:"page"` // 页码
Size int `d:"15" json:"size"` //每页条数
Order string `json:"order"` // 排序字段
Sort string `json:"sort"` // 排序方式 asc desc
IsExport bool `json:"isExport"` // 是否导出
MaxExportLimit int `json:"maxExportLimit"` // 最大导出条数,不传或者小于等于0则不限制
}
func (c *Controller) Add(ctx context.Context, req *AddReq) (res *BaseRes, err error) {
if garray.NewStrArrayFrom(c.Api).Contains("Add") {
err := c.Service.ModifyBefore(ctx, "Add", g.RequestFromCtx(ctx).GetMap())
if err != nil {
return nil, err
}
data, err := c.Service.ServiceAdd(ctx, req)
if err != nil {
return Fail(err.Error()), err
}
err = c.Service.ModifyAfter(ctx, "Add", g.RequestFromCtx(ctx).GetMap())
if err != nil {
return Fail(err.Error()), err
}
return Ok(data), err
}
g.RequestFromCtx(ctx).Response.Status = 404
return nil, nil
}
func (c *Controller) Delete(ctx context.Context, req *DeleteReq) (res *BaseRes, err error) {
if garray.NewStrArrayFrom(c.Api).Contains("Delete") {
err := c.Service.ModifyBefore(ctx, "Delete", g.RequestFromCtx(ctx).GetMap())
if err != nil {
return nil, err
}
data, err := c.Service.ServiceDelete(ctx, req)
if err != nil {
return Fail(err.Error()), err
}
c.Service.ModifyAfter(ctx, "Delete", g.RequestFromCtx(ctx).GetMap())
return Ok(data), err
}
g.RequestFromCtx(ctx).Response.Status = 404
return nil, nil
}
func (c *Controller) Update(ctx context.Context, req *UpdateReq) (res *BaseRes, err error) {
if garray.NewStrArrayFrom(c.Api).Contains("Update") {
err := c.Service.ModifyBefore(ctx, "Update", g.RequestFromCtx(ctx).GetMap())
if err != nil {
return nil, err
}
data, err := c.Service.ServiceUpdate(ctx, req)
if err != nil {
return Fail(err.Error()), err
}
c.Service.ModifyAfter(ctx, "Update", g.RequestFromCtx(ctx).GetMap())
return Ok(data), err
}
g.RequestFromCtx(ctx).Response.Status = 404
return nil, nil
}
func (c *Controller) Info(ctx context.Context, req *InfoReq) (res *BaseRes, err error) {
if garray.NewStrArrayFrom(c.Api).Contains("Info") {
data, err := c.Service.ServiceInfo(ctx, req)
return Ok(data), err
}
g.RequestFromCtx(ctx).Response.Status = 404
return nil, nil
}
func (c *Controller) List(ctx context.Context, req *ListReq) (res *BaseRes, err error) {
if garray.NewStrArrayFrom(c.Api).Contains("List") {
data, err := c.Service.ServiceList(ctx, req)
return Ok(data), err
}
g.RequestFromCtx(ctx).Response.Status = 404
return nil, nil
}
func (c *Controller) Page(ctx context.Context, req *PageReq) (res *BaseRes, err error) {
if garray.NewStrArrayFrom(c.Api).Contains("Page") {
data, err := c.Service.ServicePage(ctx, req)
return Ok(data), err
}
g.RequestFromCtx(ctx).Response.Status = 404
return nil, nil
}
// 注册控制器到路由
func RegisterController(c IController) {
var ctx = context.Background()
var sController = &Controller{}
gconv.Struct(c, &sController)
if coolconfig.Config.Eps {
model := sController.Service.GetModel()
columns := getModelInfo(ctx, sController.Prefix, model)
ModelInfo[sController.Prefix] = columns
}
g.Server().Group(
sController.Prefix, func(group *ghttp.RouterGroup) {
group.Middleware(MiddlewareHandlerResponse)
group.Bind(
c,
)
})
}
// ColumnInfo 表字段信息
type ColumnInfo struct {
Comment string `json:"comment"`
Length string `json:"length"`
Nullable bool `json:"nullable"`
PropertyName string `json:"propertyName"`
Type string `json:"type"`
}
// ModelInfo 路由prefix 对应的model信息
var ModelInfo = make(map[string][]*ColumnInfo)
// getModelInfo 获取模型信息
func getModelInfo(ctx g.Ctx, prefix string, model IModel) (columns []*ColumnInfo) {
fields, err := g.DB(model.GroupName()).TableFields(ctx, model.TableName())
if err != nil {
panic(err)
}
// g.Log().Info(ctx, "fields", fields)
sortedFields := garray.NewArraySize(len(fields), len(fields))
for _, field := range fields {
sortedFields.Set(field.Index, field)
}
for _, field := range sortedFields.Slice() {
if field.(*gdb.TableField).Name == "deleted_at" {
continue
}
var comment string
if field.(*gdb.TableField).Comment != "" {
comment = field.(*gdb.TableField).Comment
} else {
comment = field.(*gdb.TableField).Name
}
// 去除 type中的长度
var length string
if strings.Contains(field.(*gdb.TableField).Type, "(") {
length = field.(*gdb.TableField).Type[strings.Index(field.(*gdb.TableField).Type, "(")+1 : strings.Index(field.(*gdb.TableField).Type, ")")]
}
columnType := gstr.Replace(field.(*gdb.TableField).Type, "("+length+")", "")
column := &ColumnInfo{
Comment: comment,
Length: "",
Nullable: field.(*gdb.TableField).Null,
PropertyName: field.(*gdb.TableField).Name,
Type: columnType,
}
columns = append(columns, column)
}
return
}

91
cool/cool.go Normal file
View File

@@ -0,0 +1,91 @@
package cool
import (
"context"
"github.com/gogf/gf/v2/database/gredis"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/i18n/gi18n"
"github.com/gogf/gf/v2/os/gbuild"
"github.com/gogf/gf/v2/os/gcache"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/util/guid"
"gorm.io/gorm"
)
var (
GormDBS = make(map[string]*gorm.DB) // 定义全局gorm.DB对象集合 仅供内部使用
CacheEPS = gcache.New() // 定义全局缓存对象 供EPS使用
CacheManager = gcache.New() // 定义全局缓存对象 供其他业务使用
ProcessFlag = guid.S() // 定义全局进程标识
RunMode = "dev" // 定义全局运行模式
IsRedisMode = false // 定义全局是否为redis模式
I18n = gi18n.New() // 定义全局国际化对象
)
func init() {
var (
ctx = gctx.GetInitCtx()
redisConfig = &gredis.Config{}
)
g.Log().Debug(ctx, "module cool init start ...")
buildData := gbuild.Data()
if _, ok := buildData["mode"]; ok {
RunMode = buildData["mode"].(string)
}
if RunMode == "cool-tools" {
return
}
redisVar, err := g.Cfg().Get(ctx, "redis.cool")
if err != nil {
g.Log().Error(ctx, "初始化缓存失败,请检查配置文件")
panic(err)
}
if !redisVar.IsEmpty() {
redisVar.Struct(redisConfig)
redis, err := gredis.New(redisConfig)
if err != nil {
panic(err)
}
CacheManager.SetAdapter(gcache.NewAdapterRedis(redis))
IsRedisMode = true
}
g.Log().Debug(ctx, "当前运行模式", RunMode)
g.Log().Debug(ctx, "当前实例ID:", ProcessFlag)
g.Log().Debug(ctx, "是否缓存模式:", IsRedisMode)
g.Log().Debug(ctx, "module cool init finished ...")
}
// cool.OK 正常返回
type BaseRes struct {
Code int `json:"code"`
Message string `json:"message"`
Data interface{} `json:"data,omitempty"`
}
// 返回正常结果
func Ok(data interface{}) *BaseRes {
return &BaseRes{
Code: 1000,
Message: I18n.Translate(context.TODO(), "BaseResMessage"),
Data: data,
}
}
// 失败返回结果
func Fail(message string) *BaseRes {
return &BaseRes{
Code: 1001,
Message: message,
}
}
// 分布式函数
// func DistributedFunc(ctx g.Ctx, f func(ctx g.Ctx) (interface{}, error)) (interface{}, error) {
// if ProcessFlag == ctx.Request.Header.Get("processFlag") {
// return f(ctx)
// }
// return nil, nil
// }

64
cool/coolconfig/config.go Normal file
View File

@@ -0,0 +1,64 @@
package coolconfig
import "github.com/gogf/gf/v2/frame/g"
// cool config
type sConfig struct {
AutoMigrate bool `json:"auto_migrate,omitempty"` // 是否自动创建表
Eps bool `json:"eps,omitempty"` // 是否开启eps
File *file `json:"file,omitempty"` // 文件上传配置
}
// OSS相关配置
type oss struct {
Endpoint string `json:"endpoint"`
AccessKeyID string `json:"accessKeyID"`
SecretAccessKey string `json:"secretAccessKey"`
UseSSL bool `json:"useSSL"`
BucketName string `json:"bucketName"`
Location string `json:"location"`
}
// 文件上传配置
type file struct {
Mode string `json:"mode"` // 模式 local oss
Domain string `json:"domain"` // 域名 http://
Oss *oss `json:"oss,omitempty"`
}
// NewConfig new config
func newConfig() *sConfig {
var ctx g.Ctx
config := &sConfig{
AutoMigrate: GetCfgWithDefault(ctx, "cool.autoMigrate", g.NewVar(false)).Bool(),
Eps: GetCfgWithDefault(ctx, "cool.eps", g.NewVar(false)).Bool(),
File: &file{
Mode: GetCfgWithDefault(ctx, "cool.file.mode", g.NewVar("none")).String(),
Domain: GetCfgWithDefault(ctx, "cool.file.domain", g.NewVar("http://127.0.0.1:8300")).String(),
Oss: &oss{
Endpoint: GetCfgWithDefault(ctx, "cool.file.oss.endpoint", g.NewVar("127.0.0.1:9000")).String(),
AccessKeyID: GetCfgWithDefault(ctx, "cool.file.oss.accessKeyID", g.NewVar("")).String(),
SecretAccessKey: GetCfgWithDefault(ctx, "cool.file.oss.secretAccessKey", g.NewVar("")).String(),
UseSSL: GetCfgWithDefault(ctx, "cool.file.oss.useSSL", g.NewVar(false)).Bool(),
BucketName: GetCfgWithDefault(ctx, "cool.file.oss.bucketName", g.NewVar("cool-admin-go")).String(),
Location: GetCfgWithDefault(ctx, "cool.file.oss.location", g.NewVar("us-east-1")).String(),
},
},
}
return config
}
// Config config
var Config = newConfig()
// GetCfgWithDefault get config with default value
func GetCfgWithDefault(ctx g.Ctx, key string, defaultValue *g.Var) *g.Var {
value, err := g.Cfg().GetWithEnv(ctx, key)
if err != nil {
return defaultValue
}
if value.IsEmpty() || value.IsNil() {
return defaultValue
}
return value
}

40
cool/cooldb/cooldb.go Normal file
View File

@@ -0,0 +1,40 @@
package cooldb
import (
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/errors/gerror"
"gorm.io/gorm"
)
// Driver 数据库驱动通用接口
type Driver interface {
GetConn(node *gdb.ConfigNode) (db *gorm.DB, err error) // 获取数据库连接
}
var (
driverMap = map[string]Driver{} // driverMap is the map for registered database drivers.
)
// GetConn returns the connection object of specified database driver.
func GetConn(node *gdb.ConfigNode) (db *gorm.DB, err error) {
if driver, ok := driverMap[node.Type]; ok {
return driver.GetConn(node)
}
errorMsg := "\n"
errorMsg += `cannot find database driver for specified database type "%s"`
errorMsg += `, did you misspell type name "%s" or forget importing the database driver? `
errorMsg += `possible reference: https://github.com/cool-team-official/cool-admin-go/tree/master/contrib/drivers`
// 换行
errorMsg += "\n"
errorMsg += `无法找到指定数据库类型的数据库驱动 "%s"`
errorMsg += `,您是否拼写错误了类型名称 "%s" 或者忘记导入数据库驱动?`
errorMsg += `参考:https://github.com/cool-team-official/cool-admin-go/contrib/drivers`
err = gerror.Newf(errorMsg, node.Type, node.Type, node.Type, node.Type)
return
}
// Register registers custom database driver to gdb.
func Register(name string, driver Driver) error {
driverMap[name] = driver
return nil
}

48
cool/coolfile/coolfile.go Normal file
View File

@@ -0,0 +1,48 @@
package coolfile
import (
"github.com/cool-team-official/cool-admin-go/cool/coolconfig"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
)
type Driver interface {
New() Driver
GetMode() (data interface{}, err error)
Upload(ctx g.Ctx) (string, error)
}
var (
// FileMap is the map for registered file drivers.
FileMap = map[string]Driver{}
)
func NewFile() (d Driver) {
if driver, ok := FileMap[coolconfig.Config.File.Mode]; ok {
return driver.New()
}
errorMsg := "\n"
errorMsg += `无法找到指定文件上传类型 "%s"`
errorMsg += `,您是否拼写错误了类型名称 "%s" 或者忘记导入上传支持包?`
errorMsg += `参考:https://github.com/cool-team-official/cool-admin-go/tree/master/contrib/files`
err := gerror.Newf(errorMsg, coolconfig.Config.File.Mode, coolconfig.Config.File.Mode)
panic(err)
}
// Register registers custom file driver to cool.
func Register(name string, driver Driver) error {
FileMap[name] = driver
return nil
}
// func init() {
// // Register("local", &Local{})
// // Register("oss", &Oss{})
// file, err := NewFile()
// if err != nil {
// panic(err)
// }
// File = file
// }

37
cool/ctx.go Normal file
View File

@@ -0,0 +1,37 @@
package cool
import (
"context"
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/frame/g"
"github.com/golang-jwt/jwt/v4"
)
type Claims struct {
IsRefresh bool `json:"isRefresh"`
RoleIds []string `json:"roleIds"`
Username string `json:"username"`
UserId uint `json:"userId"`
PasswordVersion *int32 `json:"passwordVersion"`
jwt.RegisteredClaims
}
type Admin struct {
IsRefresh bool `json:"isRefresh"`
RoleIds []string `json:"roleIds"`
Username string `json:"username"`
UserId uint `json:"userId"`
PasswordVersion *int32 `json:"passwordVersion"`
}
// 获取传入ctx 中的 admin 对象
func GetAdmin(ctx context.Context) *Admin {
r := g.RequestFromCtx(ctx)
admin := &Admin{}
err := gjson.New(r.GetCtxVar("admin").String()).Scan(admin)
if err != nil {
g.Log().Error(ctx, err)
}
return admin
}

16
cool/db.go Normal file
View File

@@ -0,0 +1,16 @@
package cool
import (
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
)
// Deprecated 请使用 cool.DBM 替代
func GDBM(m IModel) *gdb.Model {
return g.DB(m.GroupName()).Model(m.TableName())
}
// DBM 根据model获取 *gdb.Model
func DBM(m IModel) *gdb.Model {
return g.DB(m.GroupName()).Model(m.TableName())
}

7
cool/file.go Normal file
View File

@@ -0,0 +1,7 @@
package cool
import "github.com/cool-team-official/cool-admin-go/cool/coolfile"
var (
File = coolfile.NewFile // File 文件上传操作
)

103
cool/func.go Normal file
View File

@@ -0,0 +1,103 @@
package cool
import (
"time"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/text/gstr"
)
type CoolFunc interface {
// Func handler
Func(ctx g.Ctx, param string) (err error)
// IsSingleton 是否单例,当为true时只能有一个任务在执行,在注意函数为计划任务时使用
IsSingleton() bool
// IsAllWorker 是否所有worker都执行
IsAllWorker() bool
}
// FuncMap 函数列表
var FuncMap = make(map[string]CoolFunc)
// RegisterFunc 注册函数
func RegisterFunc(name string, f CoolFunc) {
FuncMap[name] = f
}
// GetFunc 获取函数
func GetFunc(name string) CoolFunc {
return FuncMap[name]
}
// RunFunc 运行函数
func RunFunc(ctx g.Ctx, funcstring string) (err error) {
funcName := gstr.SubStr(funcstring, 0, gstr.Pos(funcstring, "("))
funcParam := gstr.SubStr(funcstring, gstr.Pos(funcstring, "(")+1, gstr.Pos(funcstring, ")")-gstr.Pos(funcstring, "(")-1)
if _, ok := FuncMap[funcName]; !ok {
err = gerror.New("函数不存在:" + funcName)
return
}
if !FuncMap[funcName].IsAllWorker() {
// 检查当前是否为主进程, 如果不是主进程, 则不执行
if ProcessFlag != CacheManager.MustGetOrSet(ctx, "cool:masterflag", ProcessFlag, 60*time.Second).String() {
g.Log().Debug(ctx, "当前进程不是主进程, 不执行单例函数", funcName)
return
}
}
err = FuncMap[funcName].Func(ctx, funcParam)
return
}
// ClusterRunFunc 集群运行函数,如果是单机模式, 则直接运行函数
func ClusterRunFunc(ctx g.Ctx, funcstring string) (err error) {
if IsRedisMode {
conn, err := g.Redis("cool").Conn(ctx)
if err != nil {
return err
}
defer conn.Close(ctx)
_, err = conn.Do(ctx, "publish", "cool:func", funcstring)
return err
} else {
return RunFunc(ctx, funcstring)
}
}
// ListenFunc 监听函数
func ListenFunc(ctx g.Ctx) {
if IsRedisMode {
conn, err := g.Redis("cool").Conn(ctx)
if err != nil {
panic(err)
}
defer conn.Close(ctx)
_, err = conn.Do(ctx, "subscribe", "cool:func")
if err != nil {
panic(err)
}
for {
data, err := conn.Receive(ctx)
if err != nil {
g.Log().Error(ctx, err)
time.Sleep(10 * time.Second)
continue
}
if data != nil {
dataMap := data.MapStrStr()
if dataMap["Kind"] == "subscribe" {
continue
}
if dataMap["Channel"] == "cool:func" {
g.Log().Debug(ctx, "执行函数", dataMap["Payload"])
err := RunFunc(ctx, dataMap["Payload"])
if err != nil {
g.Log().Error(ctx, "执行函数失败", err)
}
}
}
}
} else {
panic(gerror.New("集群模式下, 请使用Redis作为缓存"))
}
}

39
cool/go.mod Normal file
View File

@@ -0,0 +1,39 @@
module github.com/cool-team-official/cool-admin-go/cool
go 1.18
require (
github.com/gogf/gf/v2 v2.6.3
github.com/golang-jwt/jwt/v4 v4.5.0
gorm.io/gorm v1.25.7
)
require go.opentelemetry.io/otel/metric v1.24.0 // indirect
require (
github.com/BurntSushi/toml v1.3.2 // indirect
github.com/clbanning/mxj/v2 v2.7.0 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/gorilla/websocket v1.5.1 // indirect
github.com/grokify/html-strip-tags-go v0.1.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/kr/pretty v0.3.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
go.opentelemetry.io/otel v1.24.0 // indirect
go.opentelemetry.io/otel/sdk v1.24.0 // indirect
go.opentelemetry.io/otel/trace v1.24.0 // indirect
golang.org/x/net v0.21.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/text v0.14.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

80
cool/go.sum Normal file
View File

@@ -0,0 +1,80 @@
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
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/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
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/gogf/gf/v2 v2.6.3 h1:DoqeuwU98wotpFoDSQEx8RZbmJdK8KdGiJtzJeqpyIo=
github.com/gogf/gf/v2 v2.6.3/go.mod h1:x2XONYcI4hRQ/4gMNbWHmZrNzSEIg20s2NULbzom5k0=
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=
github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
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.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/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/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw=
go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg=
go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/gorm v1.25.7 h1:VsD6acwRjz2zFxGO50gPO6AkNs7KKnvfzUjHQhZDz/A=
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=

92
cool/initdb.go Normal file
View File

@@ -0,0 +1,92 @@
package cool
import (
"github.com/cool-team-official/cool-admin-go/cool/cooldb"
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gres"
"gorm.io/gorm"
)
// 初始化数据库连接供gorm使用
func InitDB(group string) (*gorm.DB, error) {
// var ctx context.Context
var db *gorm.DB
// 如果group为空则使用默认的group否则使用group参数
if group == "" {
group = "default"
}
defer func() {
if err := recover(); err != nil {
panic("failed to connect database")
}
}()
config := g.DB(group).GetConfig()
db, err := cooldb.GetConn(config)
if err != nil {
panic(err.Error())
}
GormDBS[group] = db
return db, nil
}
// 根据entity结构体获取 *gorm.DB
func getDBbyModel(model IModel) *gorm.DB {
group := model.GroupName()
// 判断是否存在 GormDBS[group] 字段如果存在则使用该字段的值作为DB否则初始化DB
if _, ok := GormDBS[group]; ok {
return GormDBS[group]
} else {
db, err := InitDB(group)
if err != nil {
panic("failed to connect database")
}
// 把重新初始化的GormDBS存入全局变量中
GormDBS[group] = db
return db
}
}
// 根据entity结构体创建表
func CreateTable(model IModel) error {
if Config.AutoMigrate {
db := getDBbyModel(model)
return db.AutoMigrate(model)
}
return nil
}
// FillInitData 数据库填充初始数据
func FillInitData(ctx g.Ctx, moduleName string, model IModel) error {
mInit := g.DB("default").Model("base_sys_init")
n, err := mInit.Clone().Where("group", model.GroupName()).Where("table", model.TableName()).Count()
if err != nil {
g.Log().Error(ctx, "读取表 base_sys_init 失败 ", err.Error())
return err
}
if n > 0 {
g.Log().Debug(ctx, "分组", model.GroupName(), "中的表", model.TableName(), "已经初始化过,跳过本次初始化.")
return nil
}
m := g.DB(model.GroupName()).Model(model.TableName())
jsonData, _ := gjson.LoadContent(gres.GetContent("modules/" + moduleName + "/resource/initjson/" + model.TableName() + ".json"))
if jsonData.Var().Clone().IsEmpty() {
g.Log().Debug(ctx, "分组", model.GroupName(), "中的表", model.TableName(), "无可用的初始化数据,跳过本次初始化.")
return nil
}
_, err = m.Data(jsonData).Insert()
if err != nil {
g.Log().Error(ctx, err.Error())
return err
}
_, err = mInit.Insert(g.Map{"group": model.GroupName(), "table": model.TableName()})
if err != nil {
g.Log().Error(ctx, err.Error())
return err
}
g.Log().Info(ctx, "分组", model.GroupName(), "中的表", model.TableName(), "初始化完成.")
return nil
}

1
cool/middleware.go Normal file
View File

@@ -0,0 +1 @@
package cool

View File

@@ -0,0 +1,79 @@
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package cool
import (
"net/http"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/net/ghttp"
)
// DefaultHandlerResponse is the default implementation of HandlerResponse.
type DefaultHandlerResponse struct {
Code int `json:"code" dc:"Error code"`
Message string `json:"message" dc:"Error message"`
Data interface{} `json:"data,omitempty" dc:"Result data for certain request according API definition"`
}
// MiddlewareHandlerResponse is the default middleware handling handler response object and its error.
func MiddlewareHandlerResponse(r *ghttp.Request) {
r.Middleware.Next()
// There's custom buffer content, it then exits current handler.
if r.Response.BufferLength() > 0 {
return
}
var (
// ctx g.Ctx
msg string
err = r.GetError()
res = r.GetHandlerResponse()
code = gerror.Code(err).Code()
)
// g.Log().Debug(ctx, code, msg, res)
msg = "success"
if err != nil {
if code == -1 {
code = 1001
}
msg = err.Error()
} else if r.Response.Status > 0 && r.Response.Status != http.StatusOK {
msg = http.StatusText(r.Response.Status)
switch r.Response.Status {
case http.StatusNotFound:
code = 404
case http.StatusForbidden:
code = 403
default:
code = 500
}
} else {
// code = gcode.CodeOK
code = 1000
}
// 做一些code转换适配cooladmin的错误码
switch code {
case 51: // 参数错误
code = 51
case 50: // 内部错误
code = 1003
default:
}
// g.Log().Debug(ctx, code, msg, res)
// 如果是正常返回直接返回res
if code == 1000 && r.Response.Status == 200 {
r.Response.WriteJsonExit(res)
}
r.Response.WriteJson(DefaultHandlerResponse{
Code: code,
Message: msg,
})
}

35
cool/model.go Normal file
View File

@@ -0,0 +1,35 @@
package cool
import (
"time"
)
type IModel interface {
TableName() string
GroupName() string
}
type Model struct {
ID uint `gorm:"primaryKey" json:"id"`
CreateTime time.Time `gorm:"column:createTime;not null;index,priority:1;autoCreateTime:nano;comment:创建时间" json:"createTime"` // 创建时间
UpdateTime time.Time `gorm:"column:updateTime;not null;index,priority:1;autoUpdateTime:nano;comment:更新时间" json:"updateTime"` // 更新时间
DeletedAt time.Time `gorm:"index" json:"deletedAt"`
}
// 返回表名
func (m *Model) TableName() string {
return "this_table_should_not_exist"
}
// 返回分组名
func (m *Model) GroupName() string {
return "default"
}
func NewModel() *Model {
return &Model{
ID: 0,
CreateTime: time.Time{},
UpdateTime: time.Time{},
DeletedAt: time.Time{},
}
}

429
cool/service.go Normal file
View File

@@ -0,0 +1,429 @@
package cool
import (
"context"
"github.com/gogf/gf/v2/container/garray"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/util/gconv"
)
type IService interface {
ServiceAdd(ctx context.Context, req *AddReq) (data interface{}, err error) // 新增
ServiceDelete(ctx context.Context, req *DeleteReq) (data interface{}, err error) // 删除
ServiceUpdate(ctx context.Context, req *UpdateReq) (data interface{}, err error) // 修改
ServiceInfo(ctx context.Context, req *InfoReq) (data interface{}, err error) // 详情
ServiceList(ctx context.Context, req *ListReq) (data interface{}, err error) // 列表
ServicePage(ctx context.Context, req *PageReq) (data interface{}, err error) // 分页
ModifyBefore(ctx context.Context, method string, param g.MapStrAny) (err error) // 新增|删除|修改前的操作
ModifyAfter(ctx context.Context, method string, param g.MapStrAny) (err error) // 新增|删除|修改后的操作
GetModel() IModel // 获取model
}
type Service struct {
Model IModel
ListQueryOp *QueryOp
PageQueryOp *QueryOp
InsertParam func(ctx context.Context) g.MapStrAny // Add时插入参数
Before func(ctx context.Context) (err error) // CRUD前的操作
InfoIgnoreProperty string // Info时忽略的字段,多个字段用逗号隔开
UniqueKey g.MapStrStr // 唯一键 key:字段名 value:错误信息
NotNullKey g.MapStrStr // 非空键 key:字段名 value:错误信息
}
// List/Add接口条件配置
type QueryOp struct {
FieldEQ []string // 字段等于
KeyWordField []string // 模糊搜索匹配的数据库字段
AddOrderby g.MapStrStr // 添加排序
Where func(ctx context.Context) []g.Array // 自定义条件
Select string // 查询字段,多个字段用逗号隔开 如: id,name 或 a.id,a.name,b.name AS bname
Join []*JoinOp // 关联查询
Extend func(ctx g.Ctx, m *gdb.Model) *gdb.Model // 追加其他条件
ModifyResult func(ctx g.Ctx, data interface{}) interface{} // 修改结果
}
// JoinOp 关联查询
type JoinOp struct {
Model IModel // 关联的model
Alias string // 别名
Condition string // 关联条件
Type JoinType // 关联类型 LeftJoin RightJoin InnerJoin
}
// JoinType 关联类型
type JoinType string
// ServiceAdd 新增
func (s *Service) ServiceAdd(ctx context.Context, req *AddReq) (data interface{}, err error) {
r := g.RequestFromCtx(ctx)
rmap := r.GetMap()
// 非空键
if s.NotNullKey != nil {
for k, v := range s.NotNullKey {
if rmap[k] == nil {
return nil, gerror.New(v)
}
}
}
// 唯一键
if s.UniqueKey != nil {
for k, v := range s.UniqueKey {
if rmap[k] != nil {
m := DBM(s.Model)
count, err := m.Where(k, rmap[k]).Count()
if err != nil {
return nil, err
}
if count > 0 {
err = gerror.New(v)
return nil, err
}
}
}
}
if s.InsertParam != nil {
insertParams := s.InsertParam(ctx)
if len(insertParams) > 0 {
for k, v := range insertParams {
rmap[k] = v
}
}
}
m := DBM(s.Model)
lastInsertId, err := m.Data(rmap).InsertAndGetId()
if err != nil {
return
}
data = g.Map{"id": lastInsertId}
return
}
// ServiceDelete 删除
func (s *Service) ServiceDelete(ctx context.Context, req *DeleteReq) (data interface{}, err error) {
ids := g.RequestFromCtx(ctx).Get("ids").Slice()
m := g.DB(s.Model.GroupName()).Model(s.Model.TableName())
data, err = m.WhereIn("id", ids).Delete()
return
}
// ServiceUpdate 修改
func (s *Service) ServiceUpdate(ctx context.Context, req *UpdateReq) (data interface{}, err error) {
r := g.RequestFromCtx(ctx)
rmap := r.GetMap()
if rmap["id"] == nil {
err = gerror.New("id不能为空")
return
}
if s.UniqueKey != nil {
for k, v := range s.UniqueKey {
if rmap[k] != nil {
count, err := DBM(s.Model).Where(k, rmap[k]).WhereNot("id", rmap["id"]).Count()
if err != nil {
return nil, err
}
if count > 0 {
err = gerror.New(v)
return nil, err
}
}
}
}
m := DBM(s.Model)
_, err = m.Data(rmap).Where("id", rmap["id"]).Update()
return
}
func (s *Service) ServiceInfo(ctx context.Context, req *InfoReq) (data interface{}, err error) {
if s.Before != nil {
err = s.Before(ctx)
if err != nil {
return
}
}
m := g.DB(s.Model.GroupName()).Model(s.Model.TableName())
// 如果InfoIgnoreProperty不为空 则忽略相关字段
if len(s.InfoIgnoreProperty) > 0 {
m = m.FieldsEx(s.InfoIgnoreProperty)
}
data, err = m.Clone().Where("id", req.Id).One()
return
}
func (s *Service) ServiceList(ctx context.Context, req *ListReq) (data interface{}, err error) {
if s.Before != nil {
err = s.Before(ctx)
if err != nil {
return
}
}
r := g.RequestFromCtx(ctx)
m := g.DB(s.Model.GroupName()).Model(s.Model.TableName())
// 如果 req.Order 和 req.Sort 均不为空 则添加排序
if !r.Get("order").IsEmpty() && !r.Get("sort").IsEmpty() {
m.Order(r.Get("order").String() + " " + r.Get("sort").String())
// m.OrderDesc("orderNum")
}
// 如果 ListQueryOp 不为空 则使用 ListQueryOp 进行查询
if s.ListQueryOp != nil {
if Select := s.ListQueryOp.Select; Select != "" {
m.Fields(Select)
}
// 如果Join不为空 则添加Join
if len(s.ListQueryOp.Join) > 0 {
for _, join := range s.ListQueryOp.Join {
switch join.Type {
case LeftJoin:
m.LeftJoin(join.Model.TableName(), join.Condition).As(join.Alias)
case RightJoin:
m.RightJoin(join.Model.TableName(), join.Condition).As(join.Alias)
case InnerJoin:
m.InnerJoin(join.Model.TableName(), join.Condition).As(join.Alias)
}
}
}
// 如果fileldEQ不为空 则添加查询条件
if len(s.ListQueryOp.FieldEQ) > 0 {
for _, field := range s.ListQueryOp.FieldEQ {
if !r.Get(field).IsEmpty() {
m.Where(field, r.Get(field))
}
}
}
// 如果KeyWordField不为空 则添加查询条件
if !r.Get("keyWord").IsEmpty() {
if len(s.ListQueryOp.KeyWordField) > 0 {
builder := m.Builder()
for _, field := range s.ListQueryOp.KeyWordField {
// g.DumpWithType(field)
// builder.WhereLike(field, "%"+r.Get("keyWord").String()+"%")
builder = builder.WhereOrLike(field, "%"+r.Get("keyWord").String()+"%")
}
m.Where(builder)
}
}
if s.ListQueryOp.Where != nil {
where := s.ListQueryOp.Where(ctx)
if len(where) > 0 {
for _, v := range where {
if len(v) == 3 {
if gconv.Bool(v[2]) {
m.Where(v[0], v[1])
}
}
if len(v) == 2 {
m.Where(v[0], v[1])
}
}
}
}
// 如果ListQueryOp的Extend不为空 则执行Extend
if s.ListQueryOp.Extend != nil {
m = s.ListQueryOp.Extend(ctx, m)
}
// 如果 addOrderby 不为空 则添加排序
if len(s.ListQueryOp.AddOrderby) > 0 && r.Get("order").IsEmpty() && r.Get("sort").IsEmpty() {
for field, order := range s.ListQueryOp.AddOrderby {
m.Order(field, order)
}
}
}
// 增加默认数据限制,防止查询所有数据
m.Limit(10000)
result, err := m.All()
if err != nil {
g.Log().Error(ctx, "ServiceList error:", err)
}
if result == nil {
data = garray.New()
} else {
data = result
}
if s.ListQueryOp != nil {
if s.ListQueryOp.ModifyResult != nil {
data = s.ListQueryOp.ModifyResult(ctx, data)
}
}
return
}
func (s *Service) ServicePage(ctx context.Context, req *PageReq) (data interface{}, err error) {
var (
r = g.RequestFromCtx(ctx)
total = 0
)
type pagination struct {
Page int `json:"page"`
Size int `json:"size"`
Total int `json:"total"`
}
if req.Size <= 0 {
req.Size = 10
}
if req.Page <= 0 {
req.Page = 1
}
m := g.DB(s.Model.GroupName()).Model(s.Model.TableName())
// 如果pageQueryOp不为空 则使用pageQueryOp进行查询
if s.PageQueryOp != nil {
// 如果Join不为空 则添加Join
if len(s.PageQueryOp.Join) > 0 {
for _, join := range s.PageQueryOp.Join {
switch join.Type {
case LeftJoin:
m.LeftJoin(join.Model.TableName(), join.Condition).As(join.Alias)
case RightJoin:
m.RightJoin(join.Model.TableName(), join.Condition).As(join.Alias)
case InnerJoin:
m.InnerJoin(join.Model.TableName(), join.Condition).As(join.Alias)
}
}
}
// 如果fileldEQ不为空 则添加查询条件
if len(s.PageQueryOp.FieldEQ) > 0 {
for _, field := range s.PageQueryOp.FieldEQ {
if !r.Get(field).IsEmpty() {
m.Where(field, r.Get(field))
}
}
}
// 如果KeyWordField不为空 则添加查询条件
if !r.Get("keyWord").IsEmpty() {
if len(s.PageQueryOp.KeyWordField) > 0 {
builder := m.Builder()
for _, field := range s.PageQueryOp.KeyWordField {
// g.DumpWithType(field)
// builder.WhereLike(field, "%"+r.Get("keyWord").String()+"%")
builder = builder.WhereOrLike(field, "%"+r.Get("keyWord").String()+"%")
}
m.Where(builder)
}
}
// 加入where条件
if s.PageQueryOp.Where != nil {
where := s.PageQueryOp.Where(ctx)
if len(where) > 0 {
for _, v := range where {
if len(v) == 3 {
if gconv.Bool(v[2]) {
m.Where(v[0], v[1])
}
}
if len(v) == 2 {
m.Where(v[0], v[1])
}
}
}
}
// 如果PageQueryOp的Extend不为空 则执行Extend
if s.PageQueryOp.Extend != nil {
m = s.PageQueryOp.Extend(ctx, m)
}
// 如果 addOrderby 不为空 则添加排序
if len(s.PageQueryOp.AddOrderby) > 0 && r.Get("order").IsEmpty() && r.Get("sort").IsEmpty() {
for field, order := range s.PageQueryOp.AddOrderby {
m.Order(field, order)
}
}
}
// 统计总数
total, err = m.Clone().Count()
if err != nil {
return nil, err
}
if s.PageQueryOp != nil {
if Select := s.PageQueryOp.Select; Select != "" {
m.Fields(Select)
}
}
// 如果 req.Order 和 req.Sort 均不为空 则添加排序
if !r.Get("order").IsEmpty() && !r.Get("sort").IsEmpty() {
m.Order(r.Get("order").String() + " " + r.Get("sort").String())
}
// 如果req.IsExport为true 则导出数据
if req.IsExport {
// 如果req.MaxExportSize大于0 则限制导出数据的最大条数
if req.MaxExportLimit > 0 {
m.Limit(req.MaxExportLimit)
}
result, err := m.All()
if err != nil {
return nil, err
}
data = g.Map{
"list": result,
"total": total,
}
return data, nil
}
result, err := m.Offset((req.Page - 1) * req.Size).Limit(req.Size).All()
if err != nil {
return nil, err
}
if result != nil {
data = g.Map{
"list": result,
"pagination": pagination{
Page: req.Page,
Size: req.Size,
Total: total,
},
}
} else {
data = g.Map{
"list": garray.New(),
"pagination": pagination{
Page: req.Page,
Size: req.Size,
Total: total,
},
}
}
if s.PageQueryOp != nil {
if s.PageQueryOp.ModifyResult != nil {
data = s.PageQueryOp.ModifyResult(ctx, data)
}
}
return
}
// ModifyBefore 新增|删除|修改前的操作
func (s *Service) ModifyBefore(ctx context.Context, method string, param g.MapStrAny) (err error) {
// g.Log().Debugf(ctx, "ModifyBefore: %s", method)
return
}
// ModifyAfter 新增|删除|修改后的操作
func (s *Service) ModifyAfter(ctx context.Context, method string, param g.MapStrAny) (err error) {
return
}
// GetModel 获取model
func (s *Service) GetModel() IModel {
return s.Model
}
// NewService 新建一个service
func NewService(model IModel) *Service {
return &Service{
Model: model,
}
}

BIN
default.etcd/member/snap/db Normal file

Binary file not shown.

63
docker-compose.yml Normal file
View File

@@ -0,0 +1,63 @@
version: "3"
services:
# mysql8 数据库
mysql:
image: mysql:8
container_name: mysql8
command: --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
# restart: always
environment:
TZ: Asia/Shanghai # 指定时区
MYSQL_ROOT_PASSWORD: "123456" # 配置root用户密码
MYSQL_DATABASE: "cooltest" # 业务库名
MYSQL_USER: "cooltest" # 业务库用户名
MTSQL_PASSWORD: "123123" # 业务库密码
ports:
- 3306:3306
volumes:
- ./data/mysql/:/var/lib/mysql/
# redis 数据库
redis:
image: redis
# command: --requirepass "12345678" # redis库密码,不需要密码注释本行
# restart: always
environment:
TZ: Asia/Shanghai # 指定时区
volumes:
- ./data/redis/:/data/
ports:
- 6379:6379
# PostgreSQL 数据库
pgsql:
image: postgres
# restart: always
environment:
TZ: Asia/Shanghai # 指定时区
POSTGRES_PASSWORD: "123456" # 配置root用户密码
POSTGRES_DB: "cooltest" # 业务库名
POSTGRES_USER: "cooltest" # 业务库用户名
volumes:
- ./data/pgsql/:/var/lib/postgresql/data/
ports:
- 5432:5432
etcd1:
image: bitnami/etcd:latest
restart: always
container_name: etcd1
environment:
- ETCD_NAME=etcd1
- ETCD_LISTEN_PEER_URLS=http://etcd1:12380
- ETCD_LISTEN_CLIENT_URLS=http://etcd1:12379
- ETCD_ADVERTISE_CLIENT_URLS=http://etcd1:12379
- ETCD_INITIAL_ADVERTISE_PEER_URLS=http://etcd1:12380
- ETCD_INITIAL_CLUSTER_TOKEN=etcd-cluster
- ETCD_INITIAL_CLUSTER=etcd1=http://etcd1:12380,etcd2=http://etcd2:22380,etcd3=http://etcd3:32380
- ETCD_INITIAL_CLUSTER_TIMEOUT=5000
- ETCD_INITIAL_CLUSTER_STATE=new
- ALLOW_NONE_AUTHENTICATION=yes
volumes:
- ./data/etcd1/:/bitnami/etcd
ports:
- 12379:12379

37
docs/.vuepress/config.js Normal file
View File

@@ -0,0 +1,37 @@
module.exports = {
title: 'CoolAdminGo文档',
description: 'CoolAdminGo文档',
base: '/cool-admin-go/',
locales: {
'/': {
lang: 'zh-CN',
title: 'CoolAdminGo文档',
description: 'CoolAdminGo文档',
},
},
themeConfig: {
logo: '/logo-admin-new.png',
repo: 'https://github.com/cool-team-official/cool-admin-go',
docsDir: 'docs',
editLinks: true,
editLinkText: ' GitHub 上编辑此页',
nav: [
{ text: '首页', link: '/' },
{ text: 'CoolAdmin官网', link: 'https://cool-js.com' },
{ text: 'GoFrame官网', link: 'https://goframe.org' },
],
lastUpdated: '上次更新',
sidebar: [
"/",
"/introduction",
"/feedback",
"/development",
"/cli",
"/quick_start",
"/config",
"/changelog",
"/known_issues",
],
},
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

View File

@@ -0,0 +1,89 @@
#!/bin/bash
###############################################################################
# Install Golang 安装Golang,仅限linux系统. #
# Author: LiDong #
# Email: cnlidong@live.cn #
# Date: 2022-08-15 #
###############################################################################
# 出错退出
set -e
# 进入脚本所在目录
# 获取第一个参数设为版本号
VERSION=$1
# 判断版本号参数是否为空
if [ -z "$VERSION" ]; then
echo "Usage: $0 VERSION [mirror]"
echo "Example: $0 1.19.2 https://mirrors.aliyun.com/golang"
echo "You can visit https://go.dev/dl/ to find version"
exit 1
fi
echo "version: $VERSION"
# 获取第二个参数为镜像地址前缀
PREFIX=$2
# 判断镜像地址前缀参数是否为空
if [ -z "$PREFIX" ]; then
PREFIX="https://go.dev/dl"
fi
echo "prefix: $PREFIX"
# 判断当前用户是否为root不是则退出
if [ "$(id -u)" != "0" ]; then
echo "Error: This script must be run as root."
echo "You can use 'sudo su' command switch to root "
exit 1
fi
# 安装Golang
echo "Install Golang..."
# 获取当前操作系统
OS=$(uname)
# 判断是否是Linux系统,如果不是则退出
if [ $OS != "Linux" ]; then
echo "Not Linux system, exit..."
exit
else
OS="linux"
fi
# 获取CPU类型
ARCH=$(uname -m)
# 转换CPU类型为go env arch格式
if [ $ARCH = "x86_64" ]; then
ARCH="amd64"
elif [ $ARCH = "i686" ]; then
ARCH="386"
elif [ $ARCH = "armv6l" ]; then
ARCH="armv6l"
elif [ $ARCH = "aarch64" ]; then
ARCH="arm64"
else
echo "Not support CPU, exit..."
exit
fi
# 安装Golang
echo "Download Golang..."
echo $PREFIX/go${VERSION}.$OS-$ARCH.tar.gz
curl -L $PREFIX/go${VERSION}.$OS-$ARCH.tar.gz -o /tmp/go${VERSION}.$OS-$ARCH.tar.gz
tar -C /usr/local -xzf /tmp/go${VERSION}.$OS-$ARCH.tar.gz
# 删除临时文件
rm -f /tmp/go${VERSION}.$OS-$ARCH.tar.gz
# 配置环境变量
echo 'export PATH=$PATH:/usr/local/node/bin' >>/etc/profile
echo 'export PATH=$PATH:/usr/local/go/bin' >>/etc/profile
source /etc/profile
echo 'export PATH=$PATH:$(go env GOPATH)/bin' >>/etc/profile
go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.cn,direct
source /etc/profile
# 安装成功
echo "Install Golang success!"
# 查看Golang版本
go version
# 提示重启终端
echo "Please restart the terminal to take effect!"
echo "安装成功,请重启终端使其生效!"
echo "You can use 'source /etc/profile' command to make the PATH changes effective immediately."
echo "你可以使用 'source /etc/profile' 命令使其立即生效."

View File

@@ -0,0 +1,75 @@
#!/bin/bash
# Install Node.js on linux x86_64
# 出错时停止
set -e
# 判断当前操作系统是否为Linux,如果不是则退出
if [ "$(uname)" != "Linux" ]; then
echo "Error: This script only supports Linux."
exit 1
fi
# 获取当前CPU架构
ARCH=$(uname -m)
# 判断当前CPU架构是否为x86_64,如果不是则退出
if [ "$ARCH" != "x86_64" ]; then
echo "Error: This script only supports x86_64."
exit 1
fi
# 判断当前是否为root,如果不是则退出
if [ "$(id -u)" != "0" ]; then
echo "Error: This script must be run as root."
echo "You can use 'sudo su' command switch to root "
exit 1
fi
# 获取第一个参数为版本号
VERSION=$1
# 校验版本号
if [ -z "$VERSION" ]; then
echo "Usage: $0 VERSION"
echo "Example: $0 18.12.0"
echo "You can visit https://nodejs.org/en/download/ to find version"
exit 1
fi
# 校验版本号格式
if ! echo "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then
echo "Invalid version: $VERSION, should be like 1.2.3"
exit 1
fi
# 下载安装包
wget https://nodejs.org/dist/v$VERSION/node-v$VERSION-linux-x64.tar.xz
# 解压
tar -xvf node-v$VERSION-linux-x64.tar.xz
# 移动到 /usr/local
mv node-v$VERSION-linux-x64 /usr/local/node
# 添加到环境变量
echo 'export PATH=$PATH:/usr/local/node/bin' >>/etc/profile
# 使环境变量生效
source /etc/profile
# 删除安装包
rm node-v$VERSION-linux-x64.tar.xz
# 查看版本
node -v
npm -v
# 激活yarn
corepack enable
# 配置淘宝镜像
npm config set registry https://registry.npmmirror.com
# 查看配置
npm config list
# 提示安装成功
echo "Node.js $VERSION installed successfully."
# 提示用户重启终端
echo "Please restart your terminal to make the PATH changes effective."
echo "You can use 'source /etc/profile' command to make the PATH changes effective immediately."

25
docs/README.md Normal file
View File

@@ -0,0 +1,25 @@
# CoolAdminGo 文档
本文档使用`vuepress`编写可使用`cool-tools docs`进行本地预览版本随`CoolAdminGo`版本更新
## 文档目录
- [介绍](introduction.md)
- [问题反馈](feedback.md)
- [开发环境](development.md)
- [开发工具](cli.md)
- [快速开始](quick_start.md)
- [配置](config.md)
- [CRUD](crud.md)
- [数据库](database.md)
- [文件上传](file_upload.md)
- [表单验证](form_validate.md)
- [系统模块](system_module.md)
- [分布式函数](distributed_function.md)
- [定时任务](cron.md)
- [部署](deploy.md)
- [日志](log.md)
- [常见问题](faq.md)
- [更新日志](changelog.md)
- [已知问题](known_issues.md)
- [贡献代码](contributing.md)

92
docs/changelog.md Normal file
View File

@@ -0,0 +1,92 @@
# 更新日志
## 1.5.0
- 更新 gf v2.4.0
## 1.0.19
- 修复base/parma模块的bug 感谢 @vera-byte
## 1.0.18
- 增加app接口下的EPS以匹配cool-uni
- 更新依赖
## 1.0.17
- list page 接口增加 ModifyAfter 钩子,用于对数据进行修改
- 更新 gf v2.3.2
## 1.0.16
- 更新依赖
- cool-tools创建的项目增加容器开发环境
## 1.0.15
- 更新 gf v2.3.1
## 1.0.14
- 更新 gf v2.3.0
- 调整 base 模块中的事务对象为接口定义以匹配 gf 的变更
- 引入 redis (gf v2.3.0 版本 redis 拆分为单独的库)
- 增加用户时对密码进行 md5 加密
## 1.0.13
- 增加 pgsql 支持
- 调整部分表字段类型以兼容 pgsql
## 1.0.12
- 更新 gf 版本至 v2.2.6(sql 统计中 total int64 修改为 int)
## 1.0.11
- 修复 dict 模块的 bug
## 1.0.10
- 修复 base/menu/add 不支持数组菜单的问题
## 1.0.9
- GetCfgWithDefault 函数支持环境变量,优先级 配置文件>环境变量>默认值
- 更新 gf 版本至 v2.2.5 修复软删除 bug
## 1.0.8
- 更新依赖包版本
- 调整 cool-tools version 命令输出格式
- 修复 go install 模式安装的 cool-tools docs 命令无法使用的问题
## 1.0.7
- 更新 gf 依赖至 v2.2.4
- cool-tools 增加 -y 支持
- 集成 gf pack
## 1.0.6
- docs 独立为单独 mod,减小主库体积
- 清理部分无用文件,减小主库体积
- 更新依赖
- 主库移除内置的前端
- 增加 make frontend 命令,用于构建前端
- 权限中间件移除部分 Debug 日志
- 清理 cool-tools 模块部分无用文件
- 引入 gf run 命令至 cool-tools 模块
- 引入 gf build 命令至 cool-tools 模块
- 调整 cool-tools 使用 hack 目录下的配置文件
## 1.0.5
- 本次更新主要针对主库开发环境
- Added changelog.md
- 更新主框架开发用前端打包脚本 使用 make public 更新
- 更新主框架支持 remote container 开发, 基于`cool-admin-codespace`镜像
- 调整优化文档发布更新了一些依赖

88
docs/cli.md Normal file
View File

@@ -0,0 +1,88 @@
# 开发工具
[返回目录](README.md)
::: warning 注意
以下部分命令需您已经安装了 Go 语言环境如果没有安装请自行安装如果已经安装请自行配置环境变量
:::
## cool-tools
cool-tools 是一个用于快速生成`CoolAdminGo`项目的脚手架工具可用于快速生成项目模块页面接口等
### `cool-tools`安装
Linux, Mac 可使用以下命令安装
github 下载
```bash
wget -O cool-tools \
https://github.com/cool-team-official/cool-admin-go/releases/latest/download/cool-tools_$(go env GOOS)_$(go env GOARCH) \
&& chmod +x cool-tools \
&& ./cool-tools install \
&& rm ./cool-tools
```
从镜像下载
```bash
wget -O cool-tools \
https://gh.hjmcloud.cn/github.com/cool-team-official/cool-admin-go/releases/latest/download/cool-tools_$(go env GOOS)_$(go env GOARCH) \
&& chmod +x cool-tools \
&& ./cool-tools install \
&& rm ./cool-tools
```
验证
```bash
cool-tools version
```
Windows 可以直接下载编译后的可执行文件下载地址[releases](https://github.com/cool-team-official/cool-admin-go/releases),选择对应的版本下载。下载后复制到`PATH`环境变量中的目录下即可。
::: tip 提示
在正确地将 GOPATH/bin 目录添加到 PATH 环境变量中后可以直接使用`go install`命令安装,因为该安装方式为本地编译安装,可享受`goproxy`的加速服务,安装速度更快,适用于所有平台
:::
```bash
go install github.com/cool-team-official/cool-admin-go/cool-tools@latest
```
## gf
`GoFrame`框架提供了功能强大的`gf`命令行开发辅助工具是框架发展的一个重要组成部分
### `gf`安装
Linux, Mac 可使用以下命令安装
github 下载
```bash
wget -O gf \
https://github.com/gogf/gf/releases/latest/download/gf_$(go env GOOS)_$(go env GOARCH) \
&& chmod +x gf \
&& ./gf install \
&& rm ./gf
```
使用镜像下载
```
wget -O gf \
https://gh.hjmcloud.cn/github.com/gogf/gf/releases/latest/download/gf_$(go env GOOS)_$(go env GOARCH) \
&& chmod +x gf \
&& ./gf install \
&& rm ./gf
```
验证
```bash
gf version
```
更多`gf`工具的安装使用说明,可以访问 [https://goframe.org/pages/viewpage.action?pageId=1114260](https://goframe.org/pages/viewpage.action?pageId=1114260)

154
docs/config.md Normal file
View File

@@ -0,0 +1,154 @@
# 配置
[返回目录](README.md)
## 配置文件
`CoolAdminGo`配置文件默认位于`mainfest/config/config.yaml`.继承自`GoFrame`的配置文件支持多种格式包括`yaml``toml``json``ini``xml`可访问[GoFrame 配置文件](https://goframe.org/pages/viewpage.action?pageId=1114668)查看更多配置文件格式。
## 数据库配置
`CoolAdminGo`支持多种数据库可通过引入不同的依赖包进行切换同时您也可以开发自己的数据库驱动
### SQLite 配置
使用`sqllite`数据库时需在`main.go`中引入`_ "github.com/cool-team-official/cool-admin-go/contrib/drivers/sqlite"`然后在`config.yaml`中配置`sqlite`数据库
::: warning 注意
`sqlite`引入应早于使用数据库的包 为防止编辑器自动排序可在数据包引入下方加一个空行
:::
```go
// main.go
import (
// 引入sqlite驱动
_ "github.com/cool-team-official/cool-admin-go/contrib/drivers/sqlite"
// 引入其他包
"github.com/cool-team-official/cool-admin-go/pkg/dao"
)
```
配置文件中相关配置如下
```yaml
database:
default: # 数据源名称,当不指定数据源时 default 为默认数据源
type: "sqlite" # 数据库类型
link: "cool.sqlite" # 数据库文件名称,可以带路径,如:/tmp/cool.sqlite
extra: busy_timeout=5000 # 数据库连接扩展参数
createdAt: "createTime" # 创建时间字段
updatedAt: "updateTime" # 更新时间字段
debug: true # 是否开启调试模式开启后会打印SQL日志
```
### MySQL 配置
使用`mysql`数据库时需在`main.go`中引入`_ "github.com/cool-team-official/cool-admin-go/contrib/drivers/mysql"`然后在`config.yaml`中配置`mysql`数据库
::: warning 注意
`mysql`引入应早于使用数据库的包 为防止编辑器自动排序可在数据包引入下方加一个空行
:::
```go
// main.go
import (
// 引入mysql驱动
_ "github.com/cool-team-official/cool-admin-go/contrib/drivers/mysql"
// 引入其他包
"github.com/cool-team-official/cool-admin-go/pkg/dao"
)
```
配置文件中相关配置如下
```yaml
database:
default: # 数据源名称,当不指定数据源时 default 为默认数据源
type: "mysql" # 数据库类型
host: "127.0.0.1" # 数据库地址
port: "3306" # 数据库端口
user: "root" # 数据库用户名
pass: "123456" # 数据库密码
name: "cooltest" # 数据库名称
charset: "utf8mb4" # 数据库编码
timezone: "Asia/Shanghai" # 数据库时区
debug: true # 是否开启调试模式开启后会打印SQL日志
createdAt: "createTime" # 创建时间字段
updatedAt: "updateTime" # 更新时间字段
```
可以使用`docker-compose`快速启动一个`mysql`数据库配置如下
```yaml
# docker-compose.yaml
version: "3"
services:
# mysql8 数据库
mysql8:
image: mysql:8
container_name: mysql8
command: --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
# restart: always # 重启策略
environment:
TZ: Asia/Shanghai # 指定时区
MYSQL_ROOT_PASSWORD: "123456" # 配置root用户密码
MYSQL_DATABASE: "cooltest" # 业务库名
MYSQL_USER: "cooltest" # 业务库用户名
MTSQL_PASSWORD: "123123" # 业务库密码
ports:
- 3306:3306
volumes:
- ./data/mysql/:/var/lib/mysql/
```
启动`mysql`数据库
```bash
docker compose -f "docker-compose.yml" up -d --build mysql8
```
关闭`mysql`数据库
```bash
docker compose -f "docker-compose.yml" down mysql8
```
### PostgreSQL 配置
使用`postgresql`数据库时需在`main.go`中引入`_ "github.com/cool-team-official/cool-admin-go/contrib/drivers/pgsql"`然后在`config.yaml`中配置`postgresql`数据库
::: warning 注意
`postgresql`引入应早于使用数据库的包 为防止编辑器自动排序可在数据包引入下方加一个空行
:::
```go
// main.go
import (
// 引入postgresql驱动
_ "github.com/cool-team-official/cool-admin-go/contrib/drivers/pgsql"
// 引入其他包
"github.com/cool-team-official/cool-admin-go/pkg/dao"
)
```
配置文件中相关配置如下
```yaml
database:
default:
type: "pgsql" # 数据库类型
host: "127.0.0.1" # 数据库地址
port: "5432" # 数据库端口
user: "cooltest" # 数据库用户名
pass: "123456" # 数据库密码
name: "cooltest" # 数据库名称
debug: true # 是否开启调试模式开启后会打印SQL日志
createdAt: "createTime" # 创建时间字段
updatedAt: "updateTime" # 更新时间字段
```

118
docs/development.md Normal file
View File

@@ -0,0 +1,118 @@
# 开发环境
[返回目录](README.md)
::: warning 注意
推荐使用 Linux MacOS 进行开发Windows 下可使用 WSL2
Linux WSL2 下推荐使用 root 用户进行开发.
:::
## Node.js 环境
官网下载地址[https://nodejs.org/en/download/](https://nodejs.org/en/download/)
一般选择 LTS 版本即可
MacOS 下可使用 Homebrew 进行安装 nvm
```bash
brew install nvm
```
nvm node 版本管理工具可以通过`nvm install <version>` 安装指定版本使用 `nvm use <version>` 切换版本
或者直接下载 pkg 安装包进行安装
Linux 下可使用以下脚本进行安装
```bash
wget -O nodejs-install.sh https://cool-team-official.github.io/cool-admin-go/scripts/nodejs-install.sh \
&& chmod +x nodejs-install.sh \
&& ./nodejs-install.sh 18.12.0
```
脚本文件内容如下:
<<< @/docs/.vuepress/public/scripts/nodejs-install.sh
::: tip
安装完成后可使用`node -v`查看版本号使用`npm -v`查看 npm 版本号
为提高依赖包下载速度可使用`npm config set registry https://registry.npmmirror.com`切换到淘宝镜像
新版本的 node 已经集成了 yarn,需激活`corepack`,可使用 `corepack enable`命令激活激活后可使用`yarn -v`查看版本号
Linux 安装脚本已完成镜像切换及 corepack 激活
:::
## Go 环境
官网下载地址[https://go.dev/dl/](https://go.dev/dl/)
一般选择最新版本即可
MacOS 下可使用 Homebrew 进行安装
```bash
brew install go
```
或者直接下载 pkg 安装包进行安装
Linux 下可使用以下脚本进行安装
```bash
wget -O golang-install.sh https://cool-team-official.github.io/cool-admin-go/scripts/golang-install.sh \
&& chmod +x golang-install.sh \
&& ./golang-install.sh 1.19.3
```
脚本文件内容如下:
<<< @/docs/.vuepress/public/scripts/golang-install.sh
::: tip
安装完成后可使用`go version`查看版本号
为提高依赖下载速度推荐配置`goproxy`可使用`go env -w GOPROXY=https://goproxy.cn,direct`切换到 goproxy.cn 镜像
:::
## VSCode
官网下载地址[https://code.visualstudio.com/](https://code.visualstudio.com/)
一般选择最新版本即可
推荐安装以下插件
- [Go](https://marketplace.visualstudio.com/items?itemName=golang.go)
- [Vetur](https://marketplace.visualstudio.com/items?itemName=octref.vetur)
- [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint)
- [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode)
- [EditorConfig](https://marketplace.visualstudio.com/items?itemName=EditorConfig.EditorConfig)
- [GitLens](https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens)
## Docker
云原生时代Docker 已经成为开发者必备的工具之一
开发过程中我们将使用 Docker 进行数据库管理以及打包测试
官网下载地址[https://www.docker.com/products/docker-desktop](https://www.docker.com/products/docker-desktop)
一般选择最新版本即可
配置 Docker 镜像加速器
```bash
# Linux
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://registry.docker-cn.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
```
MacOS Windows 下可在 Docker Desktop 的设置中配置

48
docs/docs-deploy.sh Normal file
View File

@@ -0,0 +1,48 @@
#!/usr/bin/env sh
# This script deploys the documentation to the gh-pages branch.
# 发布文档到 https://cooladmingo.github.io
# 确保脚本抛出遇到的错误
set -e
# 检测是否存在 package.json,如果不存在说明运行目录不对
if [ ! -f "package.json" ]; then
echo "package.json not found, please run this script in the root directory of the project"
exit 1
fi
# 生成静态文件
npm run docs:build
# 进入生成的文件夹
cd docs/.vuepress/dist
# 如果是发布到自定义域名
# echo 'www.example.com' > CNAME
# 获取当前时间
now=$(date "+%Y.%m.%d-%H.%M.%S")
echo "${now}" > version.txt
git init
git add -A
git commit -m 'deploy'
# 如果当前运行在 github codespace , 则使用 https 方式提交.否则使用 ssh 方式提交
if [ -n "$CODESPACES" ]; then
echo "github codespace detected, using https to push"
git push -f https://github.com/cool-team-official/cool-admin-go.git main:gh-pages
else
echo "github codespace not detected, use ssh"
git push -f git@github.com:cool-team-official/cool-admin-go.git master:gh-pages
fi
# 如果发布到 https://<USERNAME>.github.io
# git push -f git@github.com:cooladmingo/cooladmingo.github.io.git master:gh-pages
# git push -f https://github.com/cool-team-official/cool-admin-go.git master:gh-pages
# 如果发布到 https://<USERNAME>.github.io/<REPO>
# git push -f git@github.com:<USERNAME>/<REPO>.git master:gh-pages
cd -

1
docs/docs.go Normal file
View File

@@ -0,0 +1 @@
package docs

Some files were not shown because too many files have changed in this diff Show More