├── temp
└── logs
│ └── job
│ └── 15.pid
├── _config.yml
├── tools
├── int.go
├── int64.go
├── float64.go
├── app
│ ├── msg
│ │ └── message.go
│ ├── model.go
│ └── return.go
├── config
│ ├── log.go
│ ├── jwt.go
│ ├── application.go
│ ├── database.go
│ └── config.go
├── env.go
├── url.go
├── command
│ ├── task_test.go
│ ├── command_test.go
│ ├── task.go
│ └── command.go
├── ip.go
├── captcha
│ └── captcha.go
├── gois
│ └── is.go
├── string.go
├── logger.go
├── user.go
├── gofile
│ └── file.go
├── utils.go
├── ws
│ └── webSocket.go
└── gostring
│ └── string.go
├── database
├── sqlite3.go
├── drill.go
└── mysql.go
├── global
└── orm
│ └── db.go
├── .gitignore
├── handler
├── ping.go
└── nofound.go
├── README.md
├── apis
├── tpl
│ └── tpl.go
├── system
│ ├── captcha.go
│ ├── index.go
│ ├── rolemenu.go
│ ├── info.go
│ ├── config.go
│ ├── dict
│ │ ├── dictType.go
│ │ └── dictData.go
│ ├── menu.go
│ └── post.go
├── deploy
│ ├── websocketUpgrader.go
│ ├── server.go
│ └── deploytask.go
├── common
│ ├── inspace.go
│ ├── queryForm.go
│ ├── hook.go
│ └── common.go
├── tools
│ ├── dbcolumns.go
│ ├── dbtables.go
│ └── gen.go
├── monitor
│ └── server.go
├── article
│ └── article.go
├── process
│ └── classify.go
└── log
│ └── operlog.go
├── pkg
├── task
│ ├── send.go
│ ├── server.go
│ └── worker
│ │ ├── worker.go
│ │ └── tasks.go
├── file
│ ├── file.go
│ └── getdir.go
├── convert
│ └── convert.go
├── cronjob
│ └── testjob.go
├── cache
│ └── freecache.go
├── hash
│ ├── string.go
│ ├── byte.go
│ ├── string_test.go
│ ├── byte_test.go
│ ├── file_test.go
│ └── file.go
├── ldap
│ ├── login.go
│ ├── connection.go
│ ├── ldapFieldsMap.go
│ ├── updatePwd.go
│ └── search.go
├── service
│ ├── task.go
│ ├── getState.go
│ └── getVariableValue.go
├── pagination
│ ├── params.go
│ └── pagination.go
├── jsonTime
│ └── JSONTime.go
├── casbin
│ └── mycasbin.go
└── notify
│ ├── email
│ └── email.go
│ └── send.go
├── static
└── go.txt
├── Makefile
├── config
├── rbac_model.conf
├── settings.yml
└── settings-prod.yml
├── middleware
├── init.go
├── requestid.go
├── auth.go
├── permission.go
├── customerror.go
├── header.go
└── logger.go
├── models
├── process
│ ├── classify.go
│ ├── tplData.go
│ ├── task.go
│ ├── tpl.go
│ ├── history.go
│ ├── circulationHistory.go
│ ├── process.go
│ └── workOrder.go
├── base
│ └── base.go
├── casbinrule.go
├── login.go
├── gorm
│ └── gorm.go
├── server_group.go
├── roledept.go
├── initdb.go
├── deploytask.go
├── server.go
├── datascope.go
├── tools
│ ├── dbtables.go
│ ├── dbcolumns.go
│ └── syscolumns.go
├── loginlog.go
└── article.go
├── router
├── process
│ ├── classify.go
│ ├── task.go
│ ├── tpl.go
│ ├── process.go
│ └── workOrder.go
├── init_router.go
├── article_router.go
├── article_router.go-copy
├── deploy_router.go
├── router.go
└── releasecicd_router.go
├── sonar-project.properties
├── cmd
├── cobra.go
├── migrate
│ └── server.go
└── api
│ └── server.go
├── template
├── js.go.template
├── router.go.template
└── api.go.template
├── test
├── gen_test.go
├── model.go.template
└── api.go.template
├── render
└── render.go
├── go.mod
├── main.go
└── module
└── deploy
├── build.go
├── apply.go
└── cmdexe.go
/temp/logs/job/15.pid:
--------------------------------------------------------------------------------
1 | 䆈
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-cayman
--------------------------------------------------------------------------------
/tools/int.go:
--------------------------------------------------------------------------------
1 | package tools
2 |
3 | import "strconv"
4 |
5 | func IntToString(e int) string {
6 | return strconv.Itoa(e)
7 | }
--------------------------------------------------------------------------------
/database/sqlite3.go:
--------------------------------------------------------------------------------
1 | // +build sqlite3
2 |
3 | package database
4 |
5 | import (
6 | _ "github.com/jinzhu/gorm/dialects/sqlite"
7 | )
8 |
--------------------------------------------------------------------------------
/tools/int64.go:
--------------------------------------------------------------------------------
1 | package tools
2 |
3 | import "strconv"
4 |
5 | func Int64ToString(e int64) string {
6 | return strconv.FormatInt(e, 10)
7 | }
--------------------------------------------------------------------------------
/global/orm/db.go:
--------------------------------------------------------------------------------
1 | package orm
2 |
3 | import (
4 | "github.com/jinzhu/gorm"
5 | )
6 |
7 | var Eloquent *gorm.DB
8 | var MysqlConn string
9 |
10 |
--------------------------------------------------------------------------------
/tools/float64.go:
--------------------------------------------------------------------------------
1 | package tools
2 |
3 | import "strconv"
4 |
5 | func Float64ToString(e float64) string {
6 | return strconv.FormatFloat(e, 'E', -1, 64)
7 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | static/uploadfile
3 | *.exe
4 | main
5 | temp/
6 | !temp
7 | vendor
8 | config/settings.dev.yml
9 | pashash
10 | devnotes.txt
11 | *.log
--------------------------------------------------------------------------------
/handler/ping.go:
--------------------------------------------------------------------------------
1 | package handler
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | )
6 |
7 | func Ping(c *gin.Context) {
8 | c.JSON(200, gin.H{
9 | "message": "ok",
10 | })
11 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ### vAdmin[后端] -- CICD过程指标度量、自动化收集、可视化呈现
2 |
3 | #### 配置
4 | ...
5 |
6 | #### 编译
7 | `go build main.go`
8 |
9 | #### 迁移
10 | `main migrate -c config/settings.yml`
11 |
12 | #### 启动
13 | `main server -c config/settings.yml`
14 |
--------------------------------------------------------------------------------
/tools/app/msg/message.go:
--------------------------------------------------------------------------------
1 | package msg
2 |
3 | var (
4 | CreatedSuccess = "创建成功!"
5 | UpdatedSuccess = "更新成功!"
6 | DeletedSuccess = "删除成功!"
7 | DeletedFail = "删除失败!"
8 | GetSuccess = "查询成功!"
9 | NotFound = "未找到相关内容或者数据为空!"
10 | )
11 |
--------------------------------------------------------------------------------
/apis/tpl/tpl.go:
--------------------------------------------------------------------------------
1 | package tpl
2 |
3 | import (
4 | "net/http"
5 |
6 | "github.com/gin-gonic/gin"
7 | )
8 |
9 | /*
10 | @Author : Rongxin Linghu
11 | */
12 |
13 | func Tpl(c *gin.Context) {
14 | c.HTML(http.StatusOK, "index.html", gin.H{})
15 | }
16 |
--------------------------------------------------------------------------------
/tools/config/log.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import "github.com/spf13/viper"
4 |
5 | type Log struct {
6 | Dir string
7 | }
8 |
9 | func InitLog(cfg *viper.Viper) *Log {
10 | return &Log{
11 | Dir: cfg.GetString("dir"),
12 | }
13 | }
14 |
15 | var LogConfig = new(Log)
16 |
--------------------------------------------------------------------------------
/tools/env.go:
--------------------------------------------------------------------------------
1 | package tools
2 |
3 | type (
4 | Mode string
5 | )
6 |
7 | const (
8 | ModeDev Mode = "dev" //开发模式
9 | ModeTest Mode = "test" //测试模式
10 | ModeProd Mode = "prod" //生产模式
11 | Mysql = "mysql" //mysql数据库标识
12 | Sqlite = "sqlite" //sqlite
13 | )
14 |
--------------------------------------------------------------------------------
/pkg/task/send.go:
--------------------------------------------------------------------------------
1 | package task
2 |
3 | /*
4 | @Author : Rongxin Linghu
5 | */
6 |
7 | import (
8 | "context"
9 | "vAdmin/pkg/task/worker"
10 | )
11 |
12 | func Send(classify string, scriptPath string, params string) {
13 | worker.SendTask(context.Background(), classify, scriptPath, params)
14 | }
15 |
--------------------------------------------------------------------------------
/static/go.txt:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ,---.
5 | ,----._,. ' ,'\
6 | / / ' / / / |
7 | | : |. ; ,. :
8 | | | .\ .' | |: :
9 | . ; '; |' | .; :
10 | ' . . || : |
11 | `---`-'| | \ \ /
12 | .'__/\_: | `----'
13 | | : :
14 | \ \ /
15 | `--`-'
16 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | PROJECT:=vAdmin
2 |
3 | .PHONY: build
4 | build:
5 | CGO_ENABLED=0 go build -o vAdmin main.go
6 | build-sqlite:
7 | go build -tags sqlite3 -o vAdmin main.go
8 | #.PHONY: test
9 | #test:
10 | # go test -v ./... -cover
11 |
12 | #.PHONY: docker
13 | #docker:
14 | # docker build . -t vAdmin:latest
15 |
--------------------------------------------------------------------------------
/config/rbac_model.conf:
--------------------------------------------------------------------------------
1 | [request_definition]
2 | r = sub, obj, act
3 |
4 | [policy_definition]
5 | p = sub, obj, act
6 |
7 | [policy_effect]
8 | e = some(where (p.eft == allow))
9 |
10 | [matchers]
11 | m = r.sub == p.sub && (keyMatch2(r.obj, p.obj) || keyMatch(r.obj, p.obj)) && (r.act == p.act || p.act == "*")
--------------------------------------------------------------------------------
/tools/config/jwt.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import (
4 | "github.com/spf13/viper"
5 | )
6 |
7 | type Jwt struct {
8 | Secret string
9 | Timeout int64
10 | }
11 |
12 | func InitJwt(cfg *viper.Viper) *Jwt {
13 | return &Jwt{
14 | Secret: cfg.GetString("secret"),
15 | Timeout: cfg.GetInt64("timeout"),
16 | }
17 | }
18 |
19 | var JwtConfig = new(Jwt)
20 |
--------------------------------------------------------------------------------
/pkg/file/file.go:
--------------------------------------------------------------------------------
1 | package file
2 |
3 | import(
4 | "io/ioutil"
5 | )
6 |
7 | // 获取文件夹内各文件的文件名
8 | func GetFolderSubFileName(path string) (fileNames []string,err error) {
9 | dirList, err := ioutil.ReadDir(path)
10 | if err != nil {
11 | return
12 | }
13 | for _, v := range dirList {
14 | fileNames=append(fileNames,v.Name())
15 | }
16 | return
17 | }
18 |
--------------------------------------------------------------------------------
/pkg/convert/convert.go:
--------------------------------------------------------------------------------
1 | package convert
2 |
3 | import(
4 | "encoding/binary"
5 | )
6 |
7 | // int64 转 byte
8 | func Int64ToBytes(i int64) []byte {
9 | var buf = make([]byte, 8)
10 | binary.BigEndian.PutUint64(buf, uint64(i))
11 | return buf
12 | }
13 |
14 | // byte 转 int64
15 | func BytesToInt64(buf []byte) int64 {
16 | return int64(binary.BigEndian.Uint64(buf))
17 | }
--------------------------------------------------------------------------------
/handler/nofound.go:
--------------------------------------------------------------------------------
1 | package handler
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | jwt "vAdmin/pkg/jwtauth"
6 | "log"
7 | "net/http"
8 | )
9 |
10 | func NoFound(c *gin.Context) {
11 | claims := jwt.ExtractClaims(c)
12 | log.Printf("NoRoute claims: %#v\n", claims)
13 | c.JSON(http.StatusOK, gin.H{
14 | "code": "404",
15 | "message": "not found",
16 | })
17 | }
18 |
--------------------------------------------------------------------------------
/pkg/cronjob/testjob.go:
--------------------------------------------------------------------------------
1 | package cronjob
2 |
3 | import (
4 | "github.com/robfig/cron/v3"
5 | "log"
6 | )
7 |
8 | func TestJob(c *cron.Cron) {
9 | id, err := c.AddFunc("1 * * * *", func() {
10 |
11 | log.Println("Every hour on the one hour")
12 | })
13 | if err != nil {
14 | log.Println(err)
15 | log.Println("start error")
16 | } else {
17 | log.Println("Start Success; ID: %v", id)
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/pkg/cache/freecache.go:
--------------------------------------------------------------------------------
1 | package cache
2 |
3 | import (
4 | "github.com/coocood/freecache"
5 | )
6 |
7 | var cache = freecache.NewCache(100 * 1024 * 1024)
8 |
9 | func Set(key, value []byte, expireSeconds int) error {
10 | return cache.Set(key, value, expireSeconds)
11 | }
12 |
13 | func Get(key []byte) ([]byte, error) {
14 | return cache.Get(key)
15 | }
16 |
17 | func Del(key []byte) bool {
18 | return cache.Del(key)
19 | }
20 |
--------------------------------------------------------------------------------
/pkg/task/server.go:
--------------------------------------------------------------------------------
1 | package task
2 |
3 | /*
4 | @Author : Rongxin Linghu
5 | */
6 |
7 | import (
8 | "vAdmin/pkg/logger"
9 | "vAdmin/pkg/task/worker"
10 | )
11 |
12 | func Start() {
13 | // 1. 启动服务,连接redis
14 | worker.StartServer()
15 |
16 | // 2. 启动异步调度
17 | taskWorker := worker.NewAsyncTaskWorker(10)
18 | err := taskWorker.Launch()
19 | if err != nil {
20 | logger.Errorf("启动machinery失败,%v", err.Error())
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/middleware/init.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 |
6 | )
7 |
8 |
9 | func InitMiddleware(r *gin.Engine) {
10 | // 日志处理
11 | r.Use(LoggerToFile())
12 | // 自定义错误处理
13 | r.Use(CustomError)
14 | // NoCache is a middleware function that appends headers
15 | r.Use(NoCache)
16 | // 跨域处理
17 | r.Use(Options)
18 | // Secure is a middleware function that appends security
19 | r.Use(Secure)
20 | // Set X-Request-Id header
21 | r.Use(RequestId())
22 | }
--------------------------------------------------------------------------------
/models/process/classify.go:
--------------------------------------------------------------------------------
1 | package process
2 |
3 | import (
4 | "vAdmin/models/base"
5 | )
6 |
7 | /*
8 | @Author : Rongxin Linghu
9 | */
10 |
11 | // 流程分类
12 | type Classify struct {
13 | base.Model
14 | Name string `gorm:"column:name; type: varchar(128)" json:"name" form:"name"` // 分类名称
15 | Creator int `gorm:"column:creator; type: int(11)" json:"creator" form:"creator"` // 创建者
16 | }
17 |
18 | func (Classify) TableName() string {
19 | return "p_process_classify"
20 | }
21 |
--------------------------------------------------------------------------------
/tools/url.go:
--------------------------------------------------------------------------------
1 | package tools
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "strings"
6 | )
7 |
8 | //获取URL中批量id并解析
9 | func IdsStrToIdsIntGroup(key string, c *gin.Context) []int {
10 | return idsStrToIdsIntGroup(c.Param(key))
11 | }
12 |
13 |
14 | func idsStrToIdsIntGroup(keys string) []int {
15 | IDS := make([]int, 0)
16 | ids := strings.Split(keys, ",")
17 | for i := 0; i < len(ids); i++ {
18 | ID, _ := StringToInt(ids[i])
19 | IDS = append(IDS, ID)
20 | }
21 | return IDS
22 | }
--------------------------------------------------------------------------------
/apis/system/captcha.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "vAdmin/tools"
6 | _ "vAdmin/tools"
7 | "vAdmin/tools/app"
8 | "vAdmin/tools/captcha"
9 | )
10 |
11 | func GenerateCaptchaHandler(c *gin.Context) {
12 | id, b64s, err := captcha.DriverDigitFunc()
13 | tools.HasError(err, "验证码获取失败", 500)
14 | //id, b64s, _ := captcha.DriverDigitFunc()
15 | app.Custum(c, gin.H{
16 | "code": 200,
17 | "data": b64s,
18 | "id": id,
19 | "msg": "success",
20 | })
21 | }
22 |
--------------------------------------------------------------------------------
/pkg/hash/string.go:
--------------------------------------------------------------------------------
1 | package hash
2 |
3 | /* 对字符串取hash值 */
4 |
5 | // Md5String 获取字符串md5值
6 | func Md5String(s string) string {
7 | return Md5Byte([]byte(s))
8 | }
9 |
10 | // Sha1String 获取字符串sha1值
11 | func Sha1String(s string) string {
12 | return Sha1Byte([]byte(s))
13 | }
14 |
15 | // Sha256String 获取字符串sha256值
16 | func Sha256String(s string) string {
17 | return Sha256Byte([]byte(s))
18 | }
19 |
20 | // Sha512String 获取字符串sha512值
21 | func Sha512String(s string) string {
22 | return Sha512Byte([]byte(s))
23 | }
24 |
--------------------------------------------------------------------------------
/models/base/base.go:
--------------------------------------------------------------------------------
1 | /*
2 | @Author : Rongxin Linghu
3 | */
4 |
5 | package base
6 |
7 | import (
8 | "vAdmin/pkg/jsonTime"
9 | )
10 |
11 | type Model struct {
12 | Id int `gorm:"primary_key;AUTO_INCREMENT;column:id" json:"id" form:"id"`
13 | CreatedAt jsonTime.JSONTime `gorm:"column:create_time" json:"create_time" form:"create_time"`
14 | UpdatedAt jsonTime.JSONTime `gorm:"column:update_time" json:"update_time" form:"update_time"`
15 | DeletedAt *jsonTime.JSONTime `gorm:"column:delete_time" sql:"index" json:"-"`
16 | }
17 |
--------------------------------------------------------------------------------
/apis/deploy/websocketUpgrader.go:
--------------------------------------------------------------------------------
1 | package deploy
2 |
3 | import (
4 | "github.com/gorilla/websocket"
5 | //"github.com/gin-gonic/gin"
6 | "net/http"
7 | )
8 |
9 | var (
10 | upGrader websocket.Upgrader
11 | wsUpdateInterval int64
12 | )
13 |
14 | func InitWs() {
15 |
16 | /*
17 | router := gin.Default()
18 | router.GET("/api/v1/deployws", DeployStart)
19 | router.Run(":3000")
20 | */
21 | upGrader = websocket.Upgrader{
22 | // 允许跨域
23 | CheckOrigin: func(r *http.Request) bool {
24 | return true
25 | },
26 | }
27 | wsUpdateInterval = 10
28 | }
29 |
--------------------------------------------------------------------------------
/models/casbinrule.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | //casbin_rule
4 | type CasbinRule struct {
5 | PType string `json:"p_type" gorm:"type:varchar(100);"`
6 | V0 string `json:"v0" gorm:"type:varchar(100);"`
7 | V1 string `json:"v1" gorm:"type:varchar(100);"`
8 | V2 string `json:"v2" gorm:"type:varchar(100);"`
9 | V3 string `json:"v3" gorm:"type:varchar(100);"`
10 | V4 string `json:"v4" gorm:"type:varchar(100);"`
11 | V5 string `json:"v5" gorm:"type:varchar(100);"`
12 | }
13 |
14 | func (CasbinRule) TableName() string {
15 | return "casbin_rule"
16 | }
17 |
--------------------------------------------------------------------------------
/tools/command/task_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2018 syncd Author. All Rights Reserved.
2 | // Use of this source code is governed by a MIT-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package command
6 |
7 | import (
8 | "testing"
9 | )
10 |
11 | func TestTaskRun(t *testing.T) {
12 | cmds := []string{
13 | "echo 'syncd'",
14 | "whoami",
15 | "date",
16 | }
17 | task := TaskNew(cmds, 10)
18 | task.Run()
19 | if err := task.GetError(); err != nil {
20 | t.Errorf("cmd task running error: %s", err.Error())
21 | }
22 | }
--------------------------------------------------------------------------------
/pkg/ldap/login.go:
--------------------------------------------------------------------------------
1 | package ldap
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/go-ldap/ldap/v3"
7 | )
8 |
9 | /*
10 | @Author : Rongxin Linghu
11 | */
12 |
13 | func LdapLogin(username string, password string) (userInfo *ldap.Entry, err error) {
14 | err = ldapConnection()
15 | if err != nil {
16 | return
17 | }
18 | defer conn.Close()
19 |
20 | userInfo, err = searchRequest(username)
21 | if err != nil {
22 | return
23 | }
24 |
25 | err = conn.Bind(userInfo.DN, password)
26 | if err != nil {
27 | return nil, fmt.Errorf("用户或密码不正确。")
28 | }
29 |
30 | return
31 | }
32 |
--------------------------------------------------------------------------------
/pkg/service/task.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "vAdmin/pkg/task"
5 | "fmt"
6 | "strings"
7 |
8 | "github.com/spf13/viper"
9 | )
10 |
11 | /*
12 | @Author : Rongxin Linghu
13 | */
14 |
15 | func ExecTask(taskList []string, params string) {
16 | for _, taskName := range taskList {
17 | filePath := fmt.Sprintf("%v/%v", viper.GetString("script.path"), taskName)
18 | if strings.HasSuffix(filePath, ".py") {
19 | task.Send("python", filePath, params)
20 | } else if strings.HasSuffix(filePath, ".sh") {
21 | task.Send("shell", filePath, params)
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/router/process/classify.go:
--------------------------------------------------------------------------------
1 | package process
2 |
3 | /*
4 | @Author : Rongxin Linghu
5 | */
6 |
7 | import (
8 | "vAdmin/apis/process"
9 | "vAdmin/middleware"
10 | jwt "vAdmin/pkg/jwtauth"
11 |
12 | "github.com/gin-gonic/gin"
13 | )
14 |
15 | func RegisterClassifyRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
16 | classify := v1.Group("/classify").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
17 | {
18 | classify.GET("", process.ClassifyList)
19 | classify.POST("", process.CreateClassify)
20 | classify.PUT("", process.UpdateClassify)
21 | classify.DELETE("", process.DeleteClassify)
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/sonar-project.properties:
--------------------------------------------------------------------------------
1 | sonar.host.url=http://xxx.xx.xx
2 | sonar.sourceEncoding=UTF-8
3 | sonar.login=admin
4 | sonar.password=xxxxxxxxxx
5 | sonar.projectKey=vAdmin
6 | sonar.projectName=vAdmin
7 | sonar.projectVersion=1.0
8 | sonar.golint.reportPath=report.xml
9 | sonar.coverage.reportPath=coverage.xml
10 | sonar.coverage.dtdVerification=false
11 | sonar.test.reportPath=test.xml
12 | sonar.sources=./
13 | sonar.sources.inclusions=**/**.go
14 | sonar.sources.exclusions=**/**_test.go,**/vendor/*.com/**,**/vendor/*.org/**,**/vendor/**
15 | sonar.tests=./
16 | sonar.test.inclusions=**/**_test.go
17 | sonar.test.exclusions=**/vendor/*.com/**,**/vendor/*.org/**,**/vendor/**
--------------------------------------------------------------------------------
/middleware/requestid.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/satori/go.uuid"
6 | )
7 |
8 | func RequestId() gin.HandlerFunc {
9 | return func(c *gin.Context) {
10 | // Check for incoming header, use it if exists
11 | requestId := c.Request.Header.Get("X-Request-Id")
12 |
13 | // Create request id with UUID4
14 | if requestId == "" {
15 | u4 := uuid.NewV4()
16 | requestId = u4.String()
17 | }
18 |
19 | // Expose it for use in the application
20 | c.Set("X-Request-Id", requestId)
21 |
22 | // Set X-Request-Id header
23 | c.Writer.Header().Set("X-Request-Id", requestId)
24 | c.Next()
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/router/init_router.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "vAdmin/middleware"
6 | _ "vAdmin/pkg/jwtauth"
7 | "vAdmin/tools"
8 | )
9 |
10 | func InitRouter() *gin.Engine {
11 |
12 | r := gin.New()
13 | middleware.InitMiddleware(r)
14 | // the jwt middleware
15 | authMiddleware, err := middleware.AuthInit()
16 | tools.HasError(err, "JWT Init Error", 500)
17 |
18 | // 注册系统路由
19 | InitSysRouter(r, authMiddleware)
20 |
21 | // 注册业务路由
22 | // TODO: 这里可存放业务路由,里边并无实际路由是有演示代码
23 | InitAppsRouter(r, authMiddleware)
24 |
25 | //InitarticleCheckRoleRouter(r, authMiddleware)
26 | //InitreleasecicdCheckRoleRouter(r, authMiddleware)
27 | return r
28 | }
29 |
--------------------------------------------------------------------------------
/router/process/task.go:
--------------------------------------------------------------------------------
1 | package process
2 |
3 | import (
4 | "vAdmin/apis/process"
5 | "vAdmin/middleware"
6 | jwt "vAdmin/pkg/jwtauth"
7 |
8 | "github.com/gin-gonic/gin"
9 | )
10 |
11 | /*
12 | @Author : Rongxin Linghu
13 | */
14 |
15 | func RegisterTaskRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
16 | taskRouter := v1.Group("/task").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
17 | {
18 | taskRouter.GET("", process.TaskList)
19 | taskRouter.GET("/details", process.TaskDetails)
20 | taskRouter.POST("", process.CreateTask)
21 | taskRouter.PUT("", process.UpdateTask)
22 | taskRouter.DELETE("", process.DeleteTask)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/pkg/pagination/params.go:
--------------------------------------------------------------------------------
1 | package pagination
2 |
3 | import (
4 | "vAdmin/pkg/logger"
5 |
6 | "github.com/gin-gonic/gin"
7 | )
8 |
9 | /*
10 | @Author : Rongxin Linghu
11 | */
12 |
13 | func RequestParams(c *gin.Context) map[string]interface{} {
14 | params := make(map[string]interface{}, 10)
15 |
16 | if c.Request.Form == nil {
17 | if err := c.Request.ParseMultipartForm(32 << 20); err != nil {
18 | logger.Error(err)
19 | }
20 | }
21 |
22 | if len(c.Request.Form) > 0 {
23 | for key, value := range c.Request.Form {
24 | if key == "page" || key == "per_page" || key == "sort" {
25 | continue
26 | }
27 | params[key] = value[0]
28 | }
29 | }
30 |
31 | return params
32 | }
33 |
--------------------------------------------------------------------------------
/models/process/tplData.go:
--------------------------------------------------------------------------------
1 | package process
2 |
3 | import (
4 | "encoding/json"
5 | "vAdmin/models/base"
6 | )
7 |
8 | /*
9 | @Author : Rongxin Linghu
10 | */
11 |
12 | // 工单绑定模版数据
13 | type TplData struct {
14 | base.Model
15 | WorkOrder int `gorm:"column:work_order; type: int(11)" json:"work_order" form:"work_order"` // 工单ID
16 | FormStructure json.RawMessage `gorm:"column:form_structure; type: json" json:"form_structure" form:"form_structure"` // 表单结构
17 | FormData json.RawMessage `gorm:"column:form_data; type: json" json:"form_data" form:"form_data"` // 表单数据
18 | }
19 |
20 | func (TplData) TableName() string {
21 | return "p_work_order_tpl_data"
22 | }
23 |
--------------------------------------------------------------------------------
/apis/common/inspace.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 syncd Author. All Rights Reserved.
2 | // Use of this source code is governed by a MIT-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package common
6 |
7 | import (
8 | "github.com/gin-gonic/gin"
9 | "github.com/dreamans/syncd/render"
10 | "github.com/dreamans/syncd/module/project"
11 | )
12 |
13 | func InSpaceCheck(c *gin.Context, spaceId int) bool {
14 | member := &project.Member{
15 | UserId: c.GetInt("user_id"),
16 | SpaceId: spaceId,
17 | }
18 | if in := member.MemberInSpace(); !in {
19 | render.CustomerError(c, render.CODE_ERR_NO_PRIV, "user is not in the project space")
20 | return false
21 | }
22 | return true
23 | }
--------------------------------------------------------------------------------
/tools/ip.go:
--------------------------------------------------------------------------------
1 | package tools
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "io/ioutil"
7 | "net/http"
8 | )
9 |
10 | func GetLocation(ip string) string {
11 | if ip == "127.0.0.1" || ip == "localhost" {
12 | return "内部IP"
13 | }
14 | resp, err := http.Get("https://restapi.amap.com/v3/ip?ip=" + ip + "&key=3fabc36c20379fbb9300c79b19d5d05e")
15 | if err != nil {
16 | panic(err)
17 |
18 | }
19 | defer resp.Body.Close()
20 | s, err := ioutil.ReadAll(resp.Body)
21 | fmt.Printf(string(s))
22 |
23 | m := make(map[string]string)
24 |
25 | err = json.Unmarshal(s, &m)
26 | if err != nil {
27 | fmt.Println("Umarshal failed:", err)
28 | }
29 | if m["province"] == "" {
30 | return "未知位置"
31 | }
32 | return m["province"] + "-" + m["city"]
33 | }
--------------------------------------------------------------------------------
/router/process/tpl.go:
--------------------------------------------------------------------------------
1 | /*
2 | @Author : Rongxin Linghu
3 | */
4 |
5 | package process
6 |
7 | import (
8 | "vAdmin/apis/process"
9 | "vAdmin/middleware"
10 |
11 | //"vAdmin/apis/process"
12 | //"vAdmin/middleware"
13 | jwt "vAdmin/pkg/jwtauth"
14 |
15 | "github.com/gin-gonic/gin"
16 | )
17 |
18 | func RegisterTplRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
19 | tplRouter := v1.Group("/tpl").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
20 | {
21 | tplRouter.GET("", process.TemplateList)
22 | tplRouter.POST("", process.CreateTemplate)
23 | tplRouter.PUT("", process.UpdateTemplate)
24 | tplRouter.DELETE("", process.DeleteTemplate)
25 | tplRouter.GET("/details", process.TemplateDetails)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/router/article_router.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | //InitarticleCheckRoleRouter(r, authMiddleware)
4 | import (
5 | "github.com/gin-gonic/gin"
6 | "vAdmin/middleware"
7 | "vAdmin/pkg/jwtauth"
8 | "vAdmin/apis/article"
9 | )
10 |
11 | //业务 需要认证的路由
12 | func InitarticleCheckRoleRouter(v1 *gin.Engine, authMiddleware *jwtauth.GinJWTMiddleware) {
13 |
14 | v1auth := v1.Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
15 | {
16 | v1auth.GET("/api/v1/articleList", article.GetArticleList)
17 | v1auth.GET("/api/v1/article/:articleId", article.GetArticle)
18 | v1auth.POST("/api/v1/article", article.InsertArticle)
19 | v1auth.PUT("/api/v1/article", article.UpdateArticle)
20 | v1auth.DELETE("/api/v1/article/:articleId", article.DeleteArticle)
21 | }
22 |
23 | }
--------------------------------------------------------------------------------
/router/process/process.go:
--------------------------------------------------------------------------------
1 | package process
2 |
3 | /*
4 | @Author : Rongxin Linghu
5 | */
6 |
7 | import (
8 | "vAdmin/apis/process"
9 | "vAdmin/middleware"
10 | jwt "vAdmin/pkg/jwtauth"
11 |
12 | "github.com/gin-gonic/gin"
13 | )
14 |
15 | func RegisterProcessRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
16 | processRouter := v1.Group("/process").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
17 | {
18 | processRouter.GET("/classify", process.ClassifyProcessList)
19 | processRouter.GET("", process.ProcessList)
20 | processRouter.POST("", process.CreateProcess)
21 | processRouter.PUT("", process.UpdateProcess)
22 | processRouter.DELETE("", process.DeleteProcess)
23 | processRouter.GET("/details", process.ProcessDetails)
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/middleware/auth.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "vAdmin/handler"
5 | jwt "vAdmin/pkg/jwtauth"
6 | "vAdmin/tools/config"
7 | "time"
8 | )
9 |
10 | func AuthInit() (*jwt.GinJWTMiddleware, error) {
11 | return jwt.New(&jwt.GinJWTMiddleware{
12 | Realm: "test zone",
13 | Key: []byte(config.ApplicationConfig.JwtSecret),
14 | Timeout: time.Hour,
15 | MaxRefresh: time.Hour,
16 | PayloadFunc: handler.PayloadFunc,
17 | IdentityHandler: handler.IdentityHandler,
18 | Authenticator: handler.Authenticator,
19 | Authorizator: handler.Authorizator,
20 | Unauthorized: handler.Unauthorized,
21 | TokenLookup: "header: Authorization, query: token, cookie: jwt",
22 | TokenHeadName: "Bearer",
23 | TimeFunc: time.Now,
24 | })
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/router/article_router.go-copy:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | //InitarticleCheckRoleRouter(r, authMiddleware)
4 | import (
5 | "github.com/gin-gonic/gin"
6 | //_ "vAdmin/pkg/jwtauth"
7 | "vAdmin/middleware"
8 | "vAdmin/pkg/jwtauth"
9 | "vAdmin/apis/article"
10 | )
11 |
12 | //业务 需要认证的路由
13 | func InitarticleCheckRoleRouter(v1 *gin.Engine, authMiddleware *jwtauth.GinJWTMiddleware) {
14 |
15 | v1auth := v1.Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
16 | {
17 | v1auth.GET("/api/v1/articleList", article.GetArticleList)
18 | v1auth.GET("/api/v1/article/:articleId", article.GetArticle)
19 | v1auth.POST("/api/v1/article", article.InsertArticle)
20 | v1auth.PUT("/api/v1/article", article.UpdateArticle)
21 | v1auth.DELETE("/api/v1/article/:articleId", article.DeleteArticle)
22 | }
23 |
24 | }
--------------------------------------------------------------------------------
/models/process/task.go:
--------------------------------------------------------------------------------
1 | package process
2 |
3 | import (
4 | "vAdmin/models/base"
5 | )
6 |
7 | /*
8 | @Author : Rongxin Linghu
9 | */
10 |
11 | // 任务
12 | type TaskInfo struct {
13 | base.Model
14 | Name string `gorm:"column:name; type: varchar(256)" json:"name" form:"name"` // 任务名称
15 | TaskType string `gorm:"column:task_type; type: varchar(45)" json:"task_type" form:"task_type"` // 任务类型
16 | Content string `gorm:"column:content; type: longtext" json:"content" form:"content"` // 任务内容
17 | Creator int `gorm:"column:creator; type: int(11)" json:"creator" form:"creator"` // 创建者
18 | Remarks string `gorm:"column:remarks; type: longtext" json:"remarks" form:"remarks"` // 备注
19 | }
20 |
21 | func (TaskInfo) TableName() string {
22 | return "p_task_info"
23 | }
24 |
--------------------------------------------------------------------------------
/pkg/file/getdir.go:
--------------------------------------------------------------------------------
1 | package file
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | "os/exec"
7 | "path/filepath"
8 | "strings"
9 | )
10 |
11 | func GetCurrentDirectory() string {
12 | dir, _ := filepath.Abs(filepath.Dir(os.Args[0]))
13 | return strings.Replace(dir, "\\", "/", -1)
14 | }
15 |
16 | func GetRootDir() string {
17 | file, err := filepath.Abs(filepath.Dir(os.Args[0]))
18 | if err != nil {
19 | file = fmt.Sprintf(".%s", string(os.PathSeparator))
20 | } else {
21 | file = fmt.Sprintf("%s%s", file, string(os.PathSeparator))
22 | }
23 | return file
24 | }
25 |
26 | func GetExecFilePath() string {
27 | file, err := exec.LookPath(os.Args[0])
28 | if err != nil {
29 | file = fmt.Sprintf(".%s", string(os.PathSeparator))
30 | } else {
31 | file, _ = filepath.Abs(file)
32 | }
33 | return file
34 | }
35 |
--------------------------------------------------------------------------------
/pkg/hash/byte.go:
--------------------------------------------------------------------------------
1 | package hash
2 |
3 | import (
4 | "crypto/md5"
5 | "crypto/sha1"
6 | "crypto/sha256"
7 | "crypto/sha512"
8 | "encoding/hex"
9 | )
10 |
11 | /* 对字节数组取hash值 */
12 |
13 | // Md5Byte 获取字节数组md5值
14 | func Md5Byte(s []byte) string {
15 | h := md5.New()
16 | h.Write(s)
17 | return hex.EncodeToString(h.Sum(nil))
18 | }
19 |
20 | // Sha1Byte 获取节数组sha1值
21 | func Sha1Byte(s []byte) string {
22 | h := sha1.New()
23 | h.Write(s)
24 | return hex.EncodeToString(h.Sum(nil))
25 | }
26 |
27 | // Sha256Byte 获取节数组sha256值
28 | func Sha256Byte(s []byte) string {
29 | h := sha256.New()
30 | h.Write(s)
31 | return hex.EncodeToString(h.Sum(nil))
32 | }
33 |
34 | // Sha512Byte 获取节数组sha512值
35 | func Sha512Byte(s []byte) string {
36 | h := sha512.New()
37 | h.Write(s)
38 | return hex.EncodeToString(h.Sum(nil))
39 | }
40 |
--------------------------------------------------------------------------------
/pkg/jsonTime/JSONTime.go:
--------------------------------------------------------------------------------
1 | /*
2 | @Author : Rongxin Linghu
3 | */
4 |
5 | package jsonTime
6 |
7 | import (
8 | "database/sql/driver"
9 | "fmt"
10 | "time"
11 | )
12 |
13 | // 重写MarshalJSON实现models json返回的时间格式
14 | type JSONTime struct {
15 | time.Time
16 | }
17 |
18 | func (t JSONTime) MarshalJSON() ([]byte, error) {
19 | formatted := fmt.Sprintf("\"%s\"", t.Format("2006-01-02 15:04:05"))
20 | return []byte(formatted), nil
21 | }
22 |
23 | func (t JSONTime) Value() (driver.Value, error) {
24 | var zeroTime time.Time
25 | if t.Time.UnixNano() == zeroTime.UnixNano() {
26 | return nil, nil
27 | }
28 | return t.Time, nil
29 | }
30 |
31 | func (t *JSONTime) Scan(v interface{}) error {
32 | value, ok := v.(time.Time)
33 | if ok {
34 | *t = JSONTime{Time: value}
35 | return nil
36 | }
37 | return fmt.Errorf("无法转换 %v 的时间格式", v)
38 | }
39 |
--------------------------------------------------------------------------------
/tools/config/application.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import "github.com/spf13/viper"
4 |
5 | type Application struct {
6 | ReadTimeout int
7 | WriterTimeout int
8 | Host string
9 | Port string
10 | Name string
11 | JwtSecret string
12 | Mode string
13 | DemoMsg string
14 | }
15 |
16 | func InitApplication(cfg *viper.Viper) *Application {
17 | return &Application{
18 | ReadTimeout: cfg.GetInt("readTimeout"),
19 | WriterTimeout: cfg.GetInt("writerTimeout"),
20 | Host: cfg.GetString("host"),
21 | Port: cfg.GetString("port"),
22 | Name: cfg.GetString("name"),
23 | JwtSecret: cfg.GetString("jwtSecret"),
24 | Mode: cfg.GetString("mode"),
25 | DemoMsg: cfg.GetString("demoMsg"),
26 | }
27 | }
28 |
29 | var ApplicationConfig = new(Application)
30 |
--------------------------------------------------------------------------------
/models/login.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import (
4 | orm "vAdmin/database"
5 | "vAdmin/tools"
6 | )
7 |
8 | type Login struct {
9 | Username string `form:"UserName" json:"username" binding:"required"`
10 | Password string `form:"Password" json:"password" binding:"required"`
11 | Code string `form:"Code" json:"code" binding:""`
12 | UUID string `form:"UUID" json:"uuid" binding:"required"`
13 | }
14 |
15 | func (u *Login) GetUser() (user SysUser, role SysRole, e error) {
16 |
17 | e = orm.Eloquent.Table("sys_user").Where("username = ? ", u.Username).Find(&user).Error
18 | if e != nil {
19 | return
20 | }
21 | _, e = tools.CompareHashAndPassword(user.Password, u.Password)
22 | if e != nil {
23 | return
24 | }
25 | e = orm.Eloquent.Table("sys_role").Where("role_id = ? ", user.RoleId).First(&role).Error
26 | if e != nil {
27 | return
28 | }
29 | return
30 | }
31 |
--------------------------------------------------------------------------------
/models/process/tpl.go:
--------------------------------------------------------------------------------
1 | package process
2 |
3 | import (
4 | "encoding/json"
5 | "vAdmin/models/base"
6 | )
7 |
8 | /*
9 | @Author : Rongxin Linghu
10 | */
11 |
12 | // 模板
13 | type TplInfo struct {
14 | base.Model
15 | Name string `gorm:"column:name; type: varchar(128)" json:"name" form:"name" binding:"required"` // 模板名称
16 | FormStructure json.RawMessage `gorm:"column:form_structure; type: json" json:"form_structure" form:"form_structure" binding:"required"` // 表单结构
17 | Creator int `gorm:"column:creator; type: int(11)" json:"creator" form:"creator"` // 创建者
18 | Remarks string `gorm:"column:remarks; type: longtext" json:"remarks" form:"remarks"` // 备注
19 | }
20 |
21 | func (TplInfo) TableName() string {
22 | return "p_tpl_info"
23 | }
24 |
--------------------------------------------------------------------------------
/router/deploy_router.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "vAdmin/apis/deploy"
6 | "vAdmin/middleware"
7 | jwt "vAdmin/pkg/jwtauth"
8 | )
9 |
10 | //业务 需要认证的路由
11 |
12 | func registerDeployAppRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
13 |
14 | r := v1.Group("/deploy").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
15 | {
16 | r.GET("/:id", deploy.GetDeployApp)
17 | r.POST("", deploy.InsertDeployApp)
18 | r.PUT("", deploy.UpdateDeployApp)
19 | }
20 |
21 | l := v1.Group("").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
22 | {
23 | l.GET("/applyList", deploy.GetDeployAppList)
24 | l.GET("/rollList", deploy.GetRollbackAppList)
25 | l.GET("/deploystatus", deploy.DeployStatus)
26 | l.GET("/deploystart", deploy.DeployStart)
27 | //l.GET("/killtask", deploy.KillTask)
28 | }
29 |
30 | }
--------------------------------------------------------------------------------
/tools/app/model.go:
--------------------------------------------------------------------------------
1 | package app
2 |
3 | type Response struct {
4 | // 代码
5 | Code int `json:"code" example:"200"`
6 | // 数据集
7 | Data interface{} `json:"data"`
8 | // 消息
9 | Msg string `json:"msg"`
10 | }
11 |
12 | type Page struct {
13 | List interface{} `json:"list"`
14 | Count int `json:"count"`
15 | PageIndex int `json:"pageIndex"`
16 | PageSize int `json:"pageSize"`
17 | }
18 |
19 | type PageResponse struct {
20 | // 代码
21 | Code int `json:"code" example:"200"`
22 | // 数据集
23 | Data Page `json:"data"`
24 | // 消息
25 | Msg string `json:"msg"`
26 | }
27 |
28 |
29 | func (res *Response) ReturnOK() *Response {
30 | res.Code = 200
31 | return res
32 | }
33 |
34 | func (res *Response) ReturnError(code int) *Response {
35 | res.Code = code
36 | return res
37 | }
38 |
39 |
40 | func (res *PageResponse) ReturnOK() *PageResponse {
41 | res.Code = 200
42 | return res
43 | }
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/middleware/permission.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | mycasbin "vAdmin/pkg/casbin"
6 | "vAdmin/pkg/jwtauth"
7 | _ "vAdmin/pkg/jwtauth"
8 | "vAdmin/tools"
9 | "log"
10 | "net/http"
11 | )
12 |
13 | //权限检查中间件
14 | func AuthCheckRole() gin.HandlerFunc {
15 | return func(c *gin.Context) {
16 | data, _ := c.Get("JWT_PAYLOAD")
17 | v := data.(jwtauth.MapClaims)
18 | e, err := mycasbin.Casbin()
19 | tools.HasError(err, "", 500)
20 | //检查权限
21 | res, err := e.Enforce(v["rolekey"], c.Request.URL.Path, c.Request.Method)
22 | log.Println("----------------", v["rolekey"], c.Request.URL.Path, c.Request.Method)
23 |
24 | tools.HasError(err, "", 500)
25 |
26 | if res {
27 | c.Next()
28 | } else {
29 | c.JSON(http.StatusOK, gin.H{
30 | "code": 403,
31 | "msg": "对不起,您没有该接口访问权限,请联系管理员",
32 | })
33 | c.Abort()
34 | return
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/apis/system/index.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import(
4 | "github.com/gin-gonic/gin"
5 | )
6 |
7 | const INDEX = `
8 |
9 |
10 |
11 |
12 | vAdmin欢迎您
13 |
20 |
21 |
29 |
30 |
31 |
32 |
33 |
34 | `
35 |
36 |
37 | func HelloWorld(c *gin.Context){
38 | c.Header("Content-Type", "text/html; charset=utf-8")
39 | c.String(200, INDEX)
40 | }
41 |
--------------------------------------------------------------------------------
/pkg/ldap/connection.go:
--------------------------------------------------------------------------------
1 | package ldap
2 |
3 | import (
4 | "crypto/tls"
5 | "errors"
6 | "vAdmin/pkg/logger"
7 | "fmt"
8 | "time"
9 |
10 | "github.com/spf13/viper"
11 |
12 | "github.com/go-ldap/ldap/v3"
13 | )
14 |
15 | /*
16 | @Author : Rongxin Linghu
17 | */
18 |
19 | var conn *ldap.Conn
20 |
21 | // ldap连接
22 | func ldapConnection() (err error) {
23 | var ldapConn = fmt.Sprintf("%v:%v", viper.GetString("settings.ldap.host"), viper.GetString("settings.ldap.port"))
24 |
25 | if viper.GetBool("settings.ldap.tls") {
26 | tlsConf := &tls.Config{
27 | InsecureSkipVerify: true,
28 | }
29 | conn, err = ldap.DialTLS("tcp", ldapConn, tlsConf)
30 | } else {
31 | conn, err = ldap.Dial("tcp", ldapConn)
32 | }
33 | if err != nil {
34 | err = errors.New(fmt.Sprintf("无法连接到ldap服务器,%v", err))
35 | logger.Error(err)
36 | return
37 | }
38 |
39 | //设置超时时间
40 | conn.SetTimeout(5 * time.Second)
41 |
42 | return
43 | }
44 |
--------------------------------------------------------------------------------
/models/process/history.go:
--------------------------------------------------------------------------------
1 | package process
2 |
3 | import (
4 | "vAdmin/models/base"
5 | )
6 |
7 | /*
8 | @Author : Rongxin Linghu
9 | */
10 |
11 | // 任务
12 | type History struct {
13 | base.Model
14 | Task int `gorm:"column:task; type: int(11)" json:"task" form:"task"` // 任务ID
15 | Name string `gorm:"column:name; type: varchar(256)" json:"name" form:"name"` // 任务名称
16 | TaskType int `gorm:"column:task_type; type: int(11)" json:"task_type" form:"task_type"` // 任务类型, python, shell
17 | ExecutionTime string `gorm:"column:execution_time; type: varchar(128)" json:"execution_time" form:"execution_time"` // 执行时间
18 | Result string `gorm:"column:result; type: longtext" json:"result" form:"result"` // 任务返回
19 | }
20 |
21 | func (History) TableName() string {
22 | return "p_task_history"
23 | }
24 |
--------------------------------------------------------------------------------
/pkg/casbin/mycasbin.go:
--------------------------------------------------------------------------------
1 | package mycasbin
2 |
3 | import (
4 | "fmt"
5 | "github.com/casbin/casbin/v2"
6 | gormadapter "github.com/casbin/gorm-adapter/v2"
7 | "github.com/go-kit/kit/endpoint"
8 | _ "github.com/go-sql-driver/mysql"
9 | "vAdmin/database"
10 | "vAdmin/tools/config"
11 | )
12 |
13 | var Em endpoint.Middleware
14 |
15 | func Casbin() (*casbin.Enforcer, error) {
16 | conn := database.GetMysqlConnect()
17 | if config.MysqlConfig.Dbtype == "sqlite3" {
18 | conn = config.MysqlConfig.Host
19 | }
20 | Apter, err := gormadapter.NewAdapter(config.MysqlConfig.Dbtype, conn, true)
21 | if err != nil {
22 | return nil, err
23 | }
24 | e, err := casbin.NewEnforcer("config/rbac_model.conf", Apter)
25 | if err != nil {
26 | return nil, err
27 | }
28 | if err := e.LoadPolicy(); err == nil {
29 | return e, err
30 | } else {
31 | fmt.Print("casbin rbac_model or policy init error, message: %v", err)
32 | return nil, err
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/models/gorm/gorm.go:
--------------------------------------------------------------------------------
1 | package gorm
2 |
3 | import (
4 | "github.com/jinzhu/gorm"
5 | "vAdmin/models"
6 | "vAdmin/models/process"
7 | "vAdmin/models/tools"
8 | )
9 |
10 | func AutoMigrate(db *gorm.DB) error {
11 | db.SingularTable(true)
12 | return db.AutoMigrate(
13 |
14 | // 系统管理
15 | new(models.CasbinRule),
16 | new(tools.SysTables),
17 | new(tools.SysColumns),
18 | new(models.Dept),
19 | new(models.Menu),
20 | new(models.LoginLog),
21 | new(models.SysOperLog),
22 | new(models.RoleMenu),
23 | new(models.SysRoleDept),
24 | new(models.SysUser),
25 | new(models.SysRole),
26 | new(models.Post),
27 | new(models.DictData),
28 | new(models.SysConfig),
29 | new(models.DictType),
30 |
31 | // 流程中心
32 | new(process.Classify),
33 | new(process.TplInfo),
34 | new(process.TplData),
35 | new(process.WorkOrderInfo),
36 | new(process.TaskInfo),
37 | new(process.Info),
38 | new(process.History),
39 | new(process.CirculationHistory),
40 | ).Error
41 | }
42 |
--------------------------------------------------------------------------------
/pkg/hash/string_test.go:
--------------------------------------------------------------------------------
1 | package hash
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | // 测试字符串hash
8 |
9 | func Test_Md5String(t *testing.T) {
10 | val := Md5String("111111")
11 | if val != "96e79218965eb72c92a549dd5a330112" {
12 | t.Errorf("string md5值计算错误:%s", val)
13 | }
14 | }
15 |
16 | func Test_Sha1String(t *testing.T) {
17 | val := Sha1String("111111")
18 | if val != "3d4f2bf07dc1be38b20cd6e46949a1071f9d0e3d" {
19 | t.Errorf("string sha1值计算错误:%s", val)
20 | }
21 | }
22 |
23 | func Test_Sha256String(t *testing.T) {
24 | val := Sha256String("111111")
25 | if val != "bcb15f821479b4d5772bd0ca866c00ad5f926e3580720659cc80d39c9d09802a" {
26 | t.Errorf("string sha256值计算错误:%s", val)
27 | }
28 | }
29 |
30 | func Test_Sha512String(t *testing.T) {
31 | val := Sha512String("111111")
32 | if val != "b0412597dcea813655574dc54a5b74967cf85317f0332a2591be7953a016f8de56200eb37d5ba593b1e4aa27cea5ca27100f94dccd5b04bae5cadd4454dba67d" {
33 | t.Errorf("string sha512值计算错误:%s", val)
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/pkg/hash/byte_test.go:
--------------------------------------------------------------------------------
1 | package hash
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | // 测试字节数组hash
8 |
9 | func Test_Md5Byte(t *testing.T) {
10 | val := Md5Byte([]byte("111111"))
11 | if val != "96e79218965eb72c92a549dd5a330112" {
12 | t.Errorf("byte md5值计算错误:%s", val)
13 | }
14 | }
15 |
16 | func Test_Sha1Byte(t *testing.T) {
17 | val := Sha1Byte([]byte("111111"))
18 | if val != "3d4f2bf07dc1be38b20cd6e46949a1071f9d0e3d" {
19 | t.Errorf("byte sha1值计算错误:%s", val)
20 | }
21 | }
22 |
23 | func Test_Sha256Byte(t *testing.T) {
24 | val := Sha256Byte([]byte("111111"))
25 | if val != "bcb15f821479b4d5772bd0ca866c00ad5f926e3580720659cc80d39c9d09802a" {
26 | t.Errorf("byte sha256值计算错误:%s", val)
27 | }
28 | }
29 |
30 | func Test_Sha512Byte(t *testing.T) {
31 | val := Sha512Byte([]byte("111111"))
32 | if val != "b0412597dcea813655574dc54a5b74967cf85317f0332a2591be7953a016f8de56200eb37d5ba593b1e4aa27cea5ca27100f94dccd5b04bae5cadd4454dba67d" {
33 | t.Errorf("byte sha512值计算错误:%s", val)
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/tools/config/database.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import "github.com/spf13/viper"
4 |
5 | type Database struct {
6 | Dbtype string
7 | Host string
8 | Port int
9 | Name string
10 | Username string
11 | Password string
12 | MaxIdleConns int
13 | MaxOpenConns int
14 | }
15 |
16 | func InitMysql(cfg *viper.Viper) *Database {
17 | return &Database{
18 | Port: cfg.GetInt("port"),
19 | Dbtype: cfg.GetString("dbType"),
20 | Host: cfg.GetString("host"),
21 | Name: cfg.GetString("name"),
22 | Username: cfg.GetString("username"),
23 | Password: cfg.GetString("password"),
24 | MaxIdleConns: cfg.GetInt("MaxIdleConns"),
25 | MaxOpenConns: cfg.GetInt("MaxOpenConns"),
26 | }
27 | }
28 |
29 | func InitDrill(cfg *viper.Viper) *Database {
30 | return &Database{
31 | Port: cfg.GetInt("port"),
32 | Dbtype: cfg.GetString("dbType"),
33 | Host: cfg.GetString("host"),
34 | }
35 | }
36 |
37 | var MysqlConfig = new(Database)
38 |
39 | var DrillConfig = new(Database)
40 |
41 |
--------------------------------------------------------------------------------
/cmd/cobra.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "errors"
5 | "github.com/spf13/cobra"
6 | "vAdmin/cmd/api"
7 | "vAdmin/cmd/migrate"
8 | "log"
9 | "os"
10 | )
11 |
12 | var rootCmd = &cobra.Command{
13 | Use: "main",
14 | Short: "-v",
15 | SilenceUsage: true,
16 | DisableAutoGenTag: true,
17 | Long: `main`,
18 | Args: func(cmd *cobra.Command, args []string) error {
19 | if len(args) < 1 {
20 | return errors.New("requires at least one arg")
21 | }
22 | return nil
23 | },
24 | PersistentPreRunE: func(*cobra.Command, []string) error { return nil },
25 | Run: func(cmd *cobra.Command, args []string) {
26 | usageStr := `rnotes web 1.0.0 欢迎使用,可以是用 -h 查看命令`
27 | log.Printf("%s\n", usageStr)
28 | },
29 | }
30 |
31 | func init() {
32 | rootCmd.AddCommand(api.StartCmd)
33 | rootCmd.AddCommand(migrate.StartCmd)
34 | }
35 |
36 | //Execute : apply commands
37 | func Execute() {
38 | if err := rootCmd.Execute(); err != nil {
39 | os.Exit(-1)
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/template/js.go.template:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request'
2 |
3 | // 查询{{.ClassName}}列表
4 | export function list{{.ClassName}}(query) {
5 | return request({
6 | url: '/api/v1/{{.ModuleName}}List',
7 | method: 'get',
8 | params: query
9 | })
10 | }
11 |
12 | // 查询{{.ClassName}}详细
13 | export function get{{.ClassName}} ({{.PkJsonField}}) {
14 | return request({
15 | url: '/api/v1/{{.ModuleName}}/' + {{.PkJsonField}},
16 | method: 'get'
17 | })
18 | }
19 |
20 |
21 | // 新增{{.ClassName}}
22 | export function add{{.ClassName}}(data) {
23 | return request({
24 | url: '/api/v1/{{.ModuleName}}',
25 | method: 'post',
26 | data: data
27 | })
28 | }
29 |
30 | // 修改{{.ClassName}}
31 | export function update{{.ClassName}}(data) {
32 | return request({
33 | url: '/api/v1/{{.ModuleName}}',
34 | method: 'put',
35 | data: data
36 | })
37 | }
38 |
39 | // 删除{{.ClassName}}
40 | export function del{{.ClassName}}({{.PkJsonField}}) {
41 | return request({
42 | url: '/api/v1/{{.ModuleName}}/' + {{.PkJsonField}},
43 | method: 'delete'
44 | })
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/tools/app/return.go:
--------------------------------------------------------------------------------
1 | package app
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "net/http"
6 | )
7 |
8 | // 失败数据处理
9 | func Error(c *gin.Context, code int, err error, msg string) {
10 | var res Response
11 | res.Msg = err.Error()
12 | if msg != "" {
13 | res.Msg = msg
14 | }
15 | c.JSON(http.StatusOK, res.ReturnError(code))
16 | }
17 |
18 | // 通常成功数据处理
19 | func OK(c *gin.Context, data interface{}, msg string) {
20 | var res Response
21 | res.Data = data
22 | if msg != "" {
23 | res.Msg = msg
24 | }
25 | c.JSON(http.StatusOK, res.ReturnOK())
26 | }
27 |
28 | // 分页数据处理
29 | func PageOK(c *gin.Context, result interface{},count int,pageIndex int,pageSize int, msg string) {
30 | var res PageResponse
31 | res.Data.List = result
32 | res.Data.Count = count
33 | res.Data.PageIndex = pageIndex
34 | res.Data.PageSize = pageSize
35 | if msg != "" {
36 | res.Msg = msg
37 | }
38 | c.JSON(http.StatusOK, res.ReturnOK())
39 | }
40 |
41 | // 兼容函数
42 | func Custum(c *gin.Context, data gin.H) {
43 | c.JSON(http.StatusOK,data)
44 | }
45 |
--------------------------------------------------------------------------------
/router/process/workOrder.go:
--------------------------------------------------------------------------------
1 | /*
2 | @Author : Rongxin Linghu
3 | */
4 |
5 | package process
6 |
7 | import (
8 | "vAdmin/apis/process"
9 | "vAdmin/middleware"
10 | jwt "vAdmin/pkg/jwtauth"
11 |
12 | "github.com/gin-gonic/gin"
13 | )
14 |
15 | func RegisterWorkOrderRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
16 | workOrderRouter := v1.Group("/work-order").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
17 | {
18 | workOrderRouter.GET("/process-structure", process.ProcessStructure)
19 | workOrderRouter.POST("/create", process.CreateWorkOrder)
20 | workOrderRouter.GET("/list", process.WorkOrderList)
21 | workOrderRouter.POST("/handle", process.ProcessWorkOrder)
22 | workOrderRouter.GET("/unity", process.UnityWorkOrder)
23 | workOrderRouter.POST("/inversion", process.InversionWorkOrder)
24 | workOrderRouter.GET("/urge", process.UrgeWorkOrder)
25 | workOrderRouter.PUT("/active-order/:id", process.ActiveOrder)
26 | workOrderRouter.DELETE("/delete/:id", process.DeleteWorkOrder)
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/test/gen_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "vAdmin/models/tools"
5 | "os"
6 | "testing"
7 | "text/template"
8 | )
9 |
10 | func TestGoModelTemplate(t *testing.T) {
11 | t1, err := template.ParseFiles("model.go.template")
12 | if err != nil {
13 | t.Error(err)
14 | }
15 | table := tools.SysTables{}
16 | table.TableName = "sys_tables"
17 | tab, err := table.Get()
18 | if err != nil {
19 | t.Error(err)
20 | }
21 | file, err := os.Create("models/"+table.PackageName+".go")
22 | if err != nil {
23 | t.Error(err)
24 | }
25 | defer file.Close()
26 |
27 | _ = t1.Execute(file, tab)
28 | t.Log("")
29 | }
30 |
31 | func TestGoApiTemplate(t *testing.T) {
32 | t1, err := template.ParseFiles("api.go.template")
33 | if err != nil {
34 | t.Error(err)
35 | }
36 | table := tools.SysTables{}
37 | table.TableName = "sys_tables"
38 | tab, _ := table.Get()
39 | file, err := os.Create("apis/"+table.PackageName+".go")
40 | if err != nil {
41 | t.Error(err)
42 | }
43 | defer file.Close()
44 |
45 | _ = t1.Execute(file, tab)
46 | t.Log("")
47 | }
48 |
--------------------------------------------------------------------------------
/apis/tools/dbcolumns.go:
--------------------------------------------------------------------------------
1 | package tools
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "vAdmin/models/tools"
6 | tools2 "vAdmin/tools"
7 | "vAdmin/tools/app"
8 | "net/http"
9 | )
10 |
11 | func GetDBColumnList(c *gin.Context) {
12 | var data tools.DBColumns
13 | var err error
14 | var pageSize = 10
15 | var pageIndex = 1
16 |
17 | if size := c.Request.FormValue("pageSize"); size != "" {
18 | pageSize = tools2.StrToInt(err, size)
19 | }
20 |
21 | if index := c.Request.FormValue("pageIndex"); index != "" {
22 | pageIndex = tools2.StrToInt(err, index)
23 | }
24 |
25 | data.TableName = c.Request.FormValue("tableName")
26 | tools2.Assert(data.TableName=="","table name cannot be empty!",500)
27 | result, count, err := data.GetPage(pageSize, pageIndex)
28 | tools2.HasError(err, "", -1)
29 |
30 | var mp = make(map[string]interface{}, 3)
31 | mp["list"] = result
32 | mp["count"] = count
33 | mp["pageIndex"] = pageIndex
34 | mp["pageSize"] = pageSize
35 |
36 | var res app.Response
37 | res.Data = mp
38 |
39 | c.JSON(http.StatusOK, res.ReturnOK())
40 | }
41 |
--------------------------------------------------------------------------------
/middleware/customerror.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "fmt"
5 | "github.com/gin-gonic/gin"
6 | "net/http"
7 | "strconv"
8 | "strings"
9 | "time"
10 | )
11 |
12 | func CustomError(c *gin.Context) {
13 | defer func() {
14 | if err := recover(); err != nil {
15 |
16 | if c.IsAborted() {
17 | c.Status(200)
18 | }
19 | switch errStr := err.(type) {
20 | case string:
21 | p := strings.Split(errStr, "#")
22 | if len(p) == 3 && p[0] == "CustomError" {
23 | statusCode, e := strconv.Atoi(p[1])
24 | if e != nil {
25 | break
26 | }
27 | c.Status(statusCode)
28 | fmt.Println(
29 | time.Now().Format("\n 2006-01-02 15:04:05.9999"),
30 | "[ERROR]",
31 | c.Request.Method,
32 | c.Request.URL,
33 | statusCode,
34 | c.Request.RequestURI,
35 | c.ClientIP(),
36 | p[2],
37 | )
38 | c.JSON(http.StatusOK, gin.H{
39 | "code": statusCode,
40 | "msg": p[2],
41 | })
42 | }
43 | default:
44 | panic(err)
45 | }
46 | }
47 | }()
48 | c.Next()
49 | }
50 |
--------------------------------------------------------------------------------
/models/server_group.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | type ServerGroup struct {
4 | ID int `gorm:"primary_key"`
5 | Name string `gorm:"type:varchar(100);not null;default:''"`
6 | CreateBy string `json:"create_by" gorm:"type:varchar(128);"` // 创建人
7 | UpdateBy string `json:"update_by" gorm:"type:varchar(128);"` // 更新者
8 | }
9 |
10 | func (m *ServerGroup) TableName() string {
11 | return "dep_server_group"
12 | }
13 |
14 | func (m *ServerGroup) Create() bool {
15 | //m.Ctime = int(time.Now().Unix())
16 | return Create(m)
17 | }
18 |
19 | func (m *ServerGroup) Update() bool {
20 | return UpdateByPk(m)
21 | }
22 |
23 | func (m *ServerGroup) List(query QueryParam) ([]ServerGroup, bool) {
24 | var data []ServerGroup
25 | ok := GetMulti(&data, query)
26 | return data, ok
27 | }
28 |
29 | func (m *ServerGroup) Count(query QueryParam) (int, bool) {
30 | var count int
31 | ok := Count(m, &count, query)
32 | return count, ok
33 | }
34 |
35 | func (m *ServerGroup) Delete() bool {
36 | return DeleteByPk(m)
37 | }
38 |
39 | func (m *ServerGroup) Get(id int) bool {
40 | return GetByPk(m, id)
41 | }
42 |
--------------------------------------------------------------------------------
/pkg/ldap/ldapFieldsMap.go:
--------------------------------------------------------------------------------
1 | package ldap
2 |
3 | import (
4 | "vAdmin/models/system"
5 |
6 | "github.com/go-ldap/ldap/v3"
7 | )
8 |
9 | /*
10 | @Author : Rongxin Linghu
11 | */
12 |
13 | func LdapFieldsMap(ldapUserInfo *ldap.Entry) (userInfo system.SysUser, err error) {
14 | var (
15 | ldapFields []map[string]string
16 | )
17 |
18 | ldapFields, err = getLdapFields()
19 | if err != nil {
20 | return
21 | }
22 |
23 | for _, v := range ldapFields {
24 | switch v["local_field_name"] {
25 | case "nick_name":
26 | userInfo.NickName = ldapUserInfo.GetAttributeValue(v["ldap_field_name"])
27 | case "phone":
28 | userInfo.Phone = ldapUserInfo.GetAttributeValue(v["ldap_field_name"])
29 | case "avatar":
30 | userInfo.Avatar = ldapUserInfo.GetAttributeValue(v["ldap_field_name"])
31 | case "sex":
32 | userInfo.Sex = ldapUserInfo.GetAttributeValue(v["ldap_field_name"])
33 | case "email":
34 | userInfo.Email = ldapUserInfo.GetAttributeValue(v["ldap_field_name"])
35 | case "remark":
36 | userInfo.Remark = ldapUserInfo.GetAttributeValue(v["ldap_field_name"])
37 | }
38 | }
39 |
40 | return
41 | }
42 |
--------------------------------------------------------------------------------
/pkg/ldap/updatePwd.go:
--------------------------------------------------------------------------------
1 | package ldap
2 |
3 | import (
4 | "vAdmin/pkg/logger"
5 | "fmt"
6 |
7 | "github.com/go-ldap/ldap/v3"
8 | "golang.org/x/text/encoding/unicode"
9 |
10 | "github.com/spf13/viper"
11 | )
12 |
13 | /*
14 | @Author : Rongxin Linghu
15 | */
16 |
17 | func LdapUpdatePwd(username string, oldPassword string, newPassword string) (err error) {
18 | err = ldapConnection()
19 | if err != nil {
20 | return
21 | }
22 | defer conn.Close()
23 |
24 | var userDn = fmt.Sprintf("cn=%v,%v", username, viper.GetString("settings.ldap.baseDn"))
25 |
26 | err = conn.Bind(userDn, oldPassword)
27 | if err != nil {
28 | logger.Error("用户或密码错误。", err)
29 | return
30 | }
31 |
32 | sql2 := ldap.NewModifyRequest(userDn, nil)
33 |
34 | utf16 := unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM)
35 | pwdEncoded, _ := utf16.NewEncoder().String(newPassword)
36 |
37 | sql2.Replace("unicodePwd", []string{pwdEncoded})
38 | sql2.Replace("userAccountControl", []string{"512"})
39 |
40 | if err = conn.Modify(sql2); err != nil {
41 | logger.Error("密码修改失败,%v", err.Error())
42 | return
43 | }
44 |
45 | return
46 | }
47 |
--------------------------------------------------------------------------------
/template/router.go.template:
--------------------------------------------------------------------------------
1 |
2 | // 需认证的路由代码
3 | func register{{.ClassName}}Router(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
4 |
5 | r := v1.Group("/{{.ModuleName}}").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
6 | {
7 | r.GET("/:{{.PkJsonField}}", {{.ModuleName}}.Get{{.ClassName}})
8 | r.POST("", {{.ModuleName}}.Insert{{.ClassName}})
9 | r.PUT("", {{.ModuleName}}.Update{{.ClassName}})
10 | r.DELETE("/:{{.PkJsonField}}", {{.ModuleName}}.Delete{{.ClassName}})
11 | }
12 |
13 | l := v1.Group("").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
14 | {
15 | l.GET("/{{.ModuleName}}List",{{.ModuleName}}.Get{{.ClassName}}List)
16 | }
17 |
18 | }
19 |
20 | // 无需认证的路由代码
21 | func register{{.ClassName}}Router(v1 *gin.RouterGroup) {
22 |
23 | v1.GET("/{{.ModuleName}}List",{{.ModuleName}}.Get{{.ClassName}}List)
24 |
25 | r := v1.Group("/{{.ModuleName}}")
26 | {
27 | r.GET("/:{{.PkJsonField}}", {{.ModuleName}}.Get{{.ClassName}})
28 | r.POST("", {{.ModuleName}}.Insert{{.ClassName}})
29 | r.PUT("", {{.ModuleName}}.Update{{.ClassName}})
30 | r.DELETE("/:{{.PkJsonField}}", {{.ModuleName}}.Delete{{.ClassName}})
31 | }
32 | }
33 |
34 |
--------------------------------------------------------------------------------
/apis/tools/dbtables.go:
--------------------------------------------------------------------------------
1 | package tools
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "vAdmin/models/tools"
6 | tools2 "vAdmin/tools"
7 | "vAdmin/tools/app"
8 | config2 "vAdmin/tools/config"
9 | "net/http"
10 | )
11 |
12 | func GetDBTableList(c *gin.Context) {
13 | var res app.Response
14 | var data tools.DBTables
15 | var err error
16 | var pageSize = 10
17 | var pageIndex = 1
18 | if config2.MysqlConfig.Dbtype=="sqlite3"{
19 | res.Msg="对不起,sqlite3 暂不支持代码生成!"
20 | c.JSON(http.StatusOK, res.ReturnError(500))
21 | return
22 | }
23 |
24 | if size := c.Request.FormValue("pageSize"); size != "" {
25 | pageSize = tools2.StrToInt(err, size)
26 | }
27 |
28 | if index := c.Request.FormValue("pageIndex"); index != "" {
29 | pageIndex = tools2.StrToInt(err, index)
30 | }
31 |
32 | data.TableName = c.Request.FormValue("tableName")
33 | result, count, err := data.GetPage(pageSize, pageIndex)
34 | tools2.HasError(err, "", -1)
35 |
36 | var mp = make(map[string]interface{}, 3)
37 | mp["list"] = result
38 | mp["count"] = count
39 | mp["pageIndex"] = pageIndex
40 | mp["pageSize"] = pageSize
41 |
42 |
43 | res.Data = mp
44 |
45 | c.JSON(http.StatusOK, res.ReturnOK())
46 | }
47 |
--------------------------------------------------------------------------------
/pkg/hash/file_test.go:
--------------------------------------------------------------------------------
1 | package hash
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | // 测试文件hash
8 |
9 | func Test_Md5File(t *testing.T) {
10 | val, err := Md5File("./test.txt")
11 | if err != nil {
12 | t.Error(err)
13 | }
14 | if val != "098f6bcd4621d373cade4e832627b4f6" {
15 | t.Errorf("file md5值计算错误:%s", val)
16 | }
17 | }
18 |
19 | func Test_Sha1File(t *testing.T) {
20 | val, err := Sha1File("./test.txt")
21 | if err != nil {
22 | t.Error(err)
23 | }
24 | if val != "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3" {
25 | t.Errorf("file sha1值计算错误:%s", val)
26 | }
27 | }
28 |
29 | func Test_Sha256File(t *testing.T) {
30 | val, err := Sha256File("./test.txt")
31 | if err != nil {
32 | t.Error(err)
33 | }
34 | if val != "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08" {
35 | t.Errorf("file sha256值计算错误:%s", val)
36 | }
37 | }
38 |
39 | func Test_Sha512File(t *testing.T) {
40 | val, err := Sha512File("./test.txt")
41 | if err != nil {
42 | t.Error(err)
43 | }
44 | if val != "ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff" {
45 | t.Errorf("file sha512值计算错误:%s", val)
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/models/roledept.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import (
4 | "fmt"
5 | orm "vAdmin/database"
6 | )
7 |
8 | //sys_role_dept
9 | type SysRoleDept struct {
10 | RoleId int `gorm:"type:int(11)"`
11 | DeptId int `gorm:"type:int(11)"`
12 | }
13 |
14 | func (SysRoleDept) TableName() string {
15 | return "sys_role_dept"
16 | }
17 |
18 | func (rm *SysRoleDept) Insert(roleId int, deptIds []int) (bool, error) {
19 | //ORM不支持批量插入所以需要拼接 sql 串
20 | sql := "INSERT INTO `sys_role_dept` (`role_id`,`dept_id`) VALUES "
21 |
22 | for i := 0; i < len(deptIds); i++ {
23 | if len(deptIds)-1 == i {
24 | //最后一条数据 以分号结尾
25 | sql += fmt.Sprintf("(%d,%d);", roleId, deptIds[i])
26 | } else {
27 | sql += fmt.Sprintf("(%d,%d),", roleId, deptIds[i])
28 | }
29 | }
30 | orm.Eloquent.Exec(sql)
31 |
32 | return true, nil
33 | }
34 |
35 | func (rm *SysRoleDept) DeleteRoleDept(roleId int) (bool, error) {
36 | if err := orm.Eloquent.Table("sys_role_dept").Where("role_id = ?", roleId).Delete(&rm).Error; err != nil {
37 | return false, err
38 | }
39 | var role SysRole
40 | if err := orm.Eloquent.Table("sys_role").Where("role_id = ?", roleId).First(&role).Error; err != nil {
41 | return false, err
42 | }
43 |
44 | return true, nil
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/apis/system/rolemenu.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | "fmt"
5 | "github.com/gin-gonic/gin"
6 | "vAdmin/models"
7 | "vAdmin/tools/app"
8 | "net/http"
9 | )
10 |
11 | func GetRoleMenu(c *gin.Context) {
12 | var Rm models.RoleMenu
13 | err := c.ShouldBind(&Rm)
14 | result, err := Rm.Get()
15 | var res app.Response
16 | if err != nil {
17 | res.Msg = "抱歉未找到相关信息"
18 | c.JSON(http.StatusOK, res.ReturnError(200))
19 | return
20 | }
21 | res.Data = result
22 | c.JSON(http.StatusOK, res.ReturnOK())
23 | }
24 |
25 | type RoleMenuPost struct {
26 | RoleId string
27 | RoleMenu []models.RoleMenu
28 | }
29 |
30 | func InsertRoleMenu(c *gin.Context) {
31 |
32 | var res app.Response
33 | res.Msg = "添加成功"
34 | c.JSON(http.StatusOK, res.ReturnOK())
35 | return
36 |
37 | }
38 |
39 | func DeleteRoleMenu(c *gin.Context) {
40 | var t models.RoleMenu
41 | id := c.Param("id")
42 | menuId := c.Request.FormValue("menu_id")
43 | fmt.Println(menuId)
44 | _, err := t.Delete(id, menuId)
45 | if err != nil {
46 | var res app.Response
47 | res.Msg = "删除失败"
48 | c.JSON(http.StatusOK, res.ReturnError(200))
49 | return
50 | }
51 | var res app.Response
52 | res.Msg = "删除成功"
53 | c.JSON(http.StatusOK, res.ReturnOK())
54 | return
55 | }
56 |
--------------------------------------------------------------------------------
/config/settings.yml:
--------------------------------------------------------------------------------
1 | script:
2 | path: ./static/scripts
3 | settings:
4 | application:
5 | host: 0.0.0.0
6 | mode: dev
7 | name: vAdmin
8 | port: "8000"
9 | readtimeout: 1
10 | writertimeout: 2
11 | domain:
12 | gethost: 1
13 | url: localhost:9527
14 | drill:
15 | dbtype: drill
16 | host: 192.168.0.18
17 | port: 30700
18 | email:
19 | alias: vAdmin
20 | host: smtp.163.com
21 | pass: xxx
22 | port: 465
23 | user: pygo_k8s@163.com
24 | gorm:
25 | logmode: 0
26 | maxidleconn: 0
27 | maxopenconn: 20000
28 | jwt:
29 | secret: vAdminx
30 | timeout: 7200
31 | log:
32 | compress: 1
33 | consolestdout: 1
34 | dir: temp/logs
35 | filestdout: 0
36 | level: debug
37 | localtime: 1
38 | maxage: 30
39 | maxbackups: 300
40 | maxsize: 10240
41 | path: ./logs/vAdmin.log
42 | mysql:
43 | dbtype: mysql
44 | host: xx.xx.xx.xx
45 | maxidleconns: 0
46 | maxopenconns: 100
47 | name: cicdadmin
48 | password: ********8
49 | port: 3306
50 | username: cicd_user
51 | public:
52 | islocation: 0
53 | redis:
54 | url: redis://xx.xx.xx.xx:6379
55 | ssl:
56 | key: keystring
57 | pem: temp/pem.pem
58 |
--------------------------------------------------------------------------------
/models/initdb.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import (
4 | "fmt"
5 | orm "vAdmin/database"
6 | config2 "vAdmin/tools/config"
7 | "io/ioutil"
8 | "strings"
9 | )
10 |
11 | func InitDb() error {
12 | filePath := "config/db.sql"
13 | if config2.MysqlConfig.Dbtype == "sqlite3" {
14 | fmt.Println("sqlite3数据库无需初始化!")
15 | return nil
16 | }
17 | sql, err := Ioutil(filePath)
18 | if err != nil {
19 | fmt.Println("数据库基础数据初始化脚本读取失败!原因:", err.Error())
20 | return err
21 | }
22 | sqlList := strings.Split(sql, ";")
23 | for i := 0; i < len(sqlList) - 1; i++ {
24 | if strings.Contains(sqlList[i], "--") {
25 | fmt.Println(sqlList[i])
26 | continue
27 | }
28 | sql := strings.Replace(sqlList[i]+";", "\n", "", 0)
29 | if err = orm.Eloquent.Exec(sql).Error; err != nil {
30 | if !strings.Contains(err.Error(), "Query was empty") {
31 | return err
32 | }
33 | }
34 | }
35 | return nil
36 | }
37 |
38 | func Ioutil(name string) (string, error) {
39 | if contents, err := ioutil.ReadFile(name); err == nil {
40 | //因为contents是[]byte类型,直接转换成string类型后会多一行空格,需要使用strings.Replace替换换行符
41 | result := strings.Replace(string(contents), "\n", "", 1)
42 | fmt.Println("Use ioutil.ReadFile to read a file:", result)
43 | return result, nil
44 | } else {
45 | return "", err
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/tools/captcha/captcha.go:
--------------------------------------------------------------------------------
1 | package captcha
2 |
3 | import (
4 | "github.com/google/uuid"
5 | "github.com/mojocn/base64Captcha"
6 | "image/color"
7 | )
8 |
9 | var store = base64Captcha.DefaultMemStore
10 |
11 | //configJsonBody json request body.
12 | type configJsonBody struct {
13 | Id string
14 | CaptchaType string
15 | VerifyValue string
16 | DriverAudio *base64Captcha.DriverAudio
17 | DriverString *base64Captcha.DriverString
18 | DriverChinese *base64Captcha.DriverChinese
19 | DriverMath *base64Captcha.DriverMath
20 | DriverDigit *base64Captcha.DriverDigit
21 | }
22 |
23 |
24 | func DriverStringFunc() (id, b64s string, err error) {
25 | e :=configJsonBody{}
26 | e.Id = uuid.New().String()
27 | e.DriverString = base64Captcha.NewDriverString(46, 140, 2, 2, 4, "234567890abcdefghjkmnpqrstuvwxyz", &color.RGBA{240, 240, 246, 246}, []string{"wqy-microhei.ttc"})
28 | driver := e.DriverString.ConvertFonts()
29 | cap := base64Captcha.NewCaptcha(driver, store)
30 | return cap.Generate()
31 | }
32 |
33 |
34 | func DriverDigitFunc() (id, b64s string, err error) {
35 | e := configJsonBody{}
36 | e.Id = uuid.New().String()
37 | e.DriverDigit = base64Captcha.DefaultDriverDigit
38 | driver := e.DriverDigit
39 | cap := base64Captcha.NewCaptcha(driver, store)
40 | return cap.Generate()
41 | }
--------------------------------------------------------------------------------
/tools/gois/is.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 syncd Author. All Rights Reserved.
2 | // Use of this source code is governed by a MIT-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package gois
6 |
7 | import (
8 | "strings"
9 | "net"
10 | "regexp"
11 | )
12 |
13 | func IsInteger(val interface{}) bool {
14 | switch val.(type) {
15 | case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
16 | case string:
17 | str := val.(string)
18 | if str == "" {
19 | return false
20 | }
21 | str = strings.TrimSpace(str)
22 | if str[0] == '-' || str[0] == '+' {
23 | if len(str) == 1 {
24 | return false
25 | }
26 | str = str[1:]
27 | }
28 | for _, v := range str {
29 | if v < '0' || v > '9' {
30 | return false
31 | }
32 | }
33 | }
34 | return true
35 | }
36 |
37 | func IsIp(s string) bool {
38 | ip := net.ParseIP(s)
39 | if ip == nil {
40 | return false
41 | }
42 | return true
43 | }
44 |
45 | func IsEmail(s string) bool {
46 | pattern := `^[0-9A-Za-z][\.\-_0-9A-Za-z]*\@[0-9A-Za-z\-]+(\.[0-9A-Za-z]+)+$`
47 | reg := regexp.MustCompile(pattern)
48 | return reg.MatchString(s)
49 | }
50 |
--------------------------------------------------------------------------------
/pkg/service/getState.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "strconv"
5 | )
6 |
7 | /*
8 | @Author : Rongxin Linghu
9 | @Desc : 获取节点数据
10 | */
11 |
12 | type ProcessState struct {
13 | Structure map[string][]map[string]interface{}
14 | }
15 |
16 | // 获取节点信息
17 | func (p *ProcessState) GetNode(stateId string) (nodeValue map[string]interface{}, err error) {
18 | for _, node := range p.Structure["nodes"] {
19 | if node["id"] == stateId {
20 | nodeValue = node
21 | }
22 | }
23 | return
24 | }
25 |
26 | // 获取流转信息
27 | func (p *ProcessState) GetEdge(stateId string, classify string) (edgeValue []map[string]interface{}, err error) {
28 | var (
29 | leftSort int
30 | rightSort int
31 | )
32 |
33 | for _, edge := range p.Structure["edges"] {
34 | if edge[classify] == stateId {
35 | edgeValue = append(edgeValue, edge)
36 | }
37 | }
38 |
39 | // 排序
40 | if len(edgeValue) > 1 {
41 | for i := 0; i < len(edgeValue)-1; i++ {
42 | for j := i + 1; j < len(edgeValue); j++ {
43 | if t, ok := edgeValue[i]["sort"]; ok {
44 | leftSort, _ = strconv.Atoi(t.(string))
45 | }
46 | if t, ok := edgeValue[j]["sort"]; ok {
47 | rightSort, _ = strconv.Atoi(t.(string))
48 | }
49 | if leftSort > rightSort {
50 | edgeValue[j], edgeValue[i] = edgeValue[i], edgeValue[j]
51 | }
52 | }
53 | }
54 | }
55 |
56 | return
57 | }
58 |
--------------------------------------------------------------------------------
/apis/system/info.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "vAdmin/models"
6 | "vAdmin/tools"
7 | "vAdmin/tools/app"
8 | )
9 |
10 | func GetInfo(c *gin.Context) {
11 |
12 | var roles = make([]string, 1)
13 | roles[0] = tools.GetRoleName(c)
14 |
15 | var permissions = make([]string, 1)
16 | permissions[0] = "*:*:*"
17 |
18 | var buttons = make([]string, 1)
19 | buttons[0] = "*:*:*"
20 |
21 | RoleMenu := models.RoleMenu{}
22 | RoleMenu.RoleId = tools.GetRoleId(c)
23 |
24 | var mp = make(map[string]interface{})
25 | mp["roles"] = roles
26 | if tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员" {
27 | mp["permissions"] = permissions
28 | mp["buttons"] = buttons
29 | } else {
30 | list, _ := RoleMenu.GetPermis()
31 | mp["permissions"] = list
32 | mp["buttons"] = list
33 | }
34 |
35 | sysuser := models.SysUser{}
36 | sysuser.UserId = tools.GetUserId(c)
37 | user, err := sysuser.Get()
38 | tools.HasError(err, "", 500)
39 |
40 | mp["introduction"] = " am a super administrator"
41 |
42 | mp["avatar"] = "https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif"
43 | if user.Avatar != "" {
44 | mp["avatar"] = user.Avatar
45 | }
46 | mp["userName"] = user.NickName
47 | mp["userId"] = user.UserId
48 | mp["deptId"] = user.DeptId
49 | mp["name"] = user.NickName
50 |
51 | app.OK(c, mp, "")
52 | }
53 |
--------------------------------------------------------------------------------
/models/deploytask.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | type DeployTask struct {
4 | ID int `gorm:"primary_key"`
5 | ApplyId int `gorm:"type:int(11);not null;default:0"`
6 | GroupId int `gorm:"type:int(11);not null;default:0"`
7 | Status int `json:"status" gorm:"type:varchar(50);"`
8 | Content string `gorm:"type:text;not null"`
9 | CreateBy string `json:"create_by" gorm:"type:varchar(128);"` // 创建人
10 | UpdateBy string `json:"update_by" gorm:"type:varchar(128);"` // 更新者
11 | }
12 |
13 | func (m *DeployTask) TableName() string {
14 | return "dep_task"
15 | }
16 |
17 | func (m *DeployTask) List(query QueryParam) ([]DeployTask, bool) {
18 | var data []DeployTask
19 | ok := GetMulti(&data, query)
20 | return data, ok
21 | }
22 |
23 | func (m *DeployTask) GetByApplyId(id int) bool {
24 | return GetOne(m, QueryParam{
25 | Where: []WhereParam{
26 | WhereParam{
27 | Field: "apply_id",
28 | Prepare: id,
29 | },
30 | },
31 | })
32 | }
33 |
34 | func (m *DeployTask) UpdateByFields(data map[string]interface{}, query QueryParam) bool {
35 | return Update(m, data, query)
36 | }
37 |
38 | func (m *DeployTask) Create() bool {
39 | //m.Ctime = int(time.Now().Unix())
40 | return Create(m)
41 | }
42 |
43 | func (m *DeployTask) Delete(query QueryParam) bool {
44 | return Delete(m, query)
45 | }
46 |
--------------------------------------------------------------------------------
/pkg/service/getVariableValue.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | orm "vAdmin/database"
5 | system "vAdmin/models"
6 | )
7 |
8 | /*
9 | @Author : Rongxin Linghu
10 | */
11 |
12 | func GetVariableValue(stateList []interface{}, creator int) (err error) {
13 | var (
14 | userInfo system.SysUser
15 | deptInfo system.Dept
16 | )
17 |
18 | // 变量转为实际的数据
19 | for _, stateItem := range stateList {
20 | if stateItem.(map[string]interface{})["process_method"] == "variable" {
21 | for processorIndex, processor := range stateItem.(map[string]interface{})["processor"].([]interface{}) {
22 | if int(processor.(float64)) == 1 {
23 | // 创建者
24 | stateItem.(map[string]interface{})["processor"].([]interface{})[processorIndex] = creator
25 | } else if int(processor.(float64)) == 2 {
26 | // 1. 查询用户信息
27 | err = orm.Eloquent.Model(&userInfo).Where("user_id = ?", creator).Find(&userInfo).Error
28 | if err != nil {
29 | return
30 | }
31 | // 2. 查询部门信息
32 | err = orm.Eloquent.Model(&deptInfo).Where("dept_id = ?", userInfo.DeptId).Find(&deptInfo).Error
33 | if err != nil {
34 | return
35 | }
36 |
37 | // 3. 替换处理人信息
38 | stateItem.(map[string]interface{})["processor"].([]interface{})[processorIndex] = deptInfo.Leader
39 | }
40 | }
41 | stateItem.(map[string]interface{})["process_method"] = "person"
42 | }
43 | }
44 |
45 | return
46 | }
47 |
--------------------------------------------------------------------------------
/cmd/migrate/server.go:
--------------------------------------------------------------------------------
1 | package migrate
2 |
3 | import (
4 | "fmt"
5 | "vAdmin/database"
6 | orm "vAdmin/database"
7 | "vAdmin/models"
8 | "vAdmin/models/gorm"
9 | "vAdmin/tools"
10 | config2 "vAdmin/tools/config"
11 | "log"
12 |
13 | "github.com/spf13/cobra"
14 | )
15 |
16 | var (
17 | config string
18 | mode string
19 | StartCmd = &cobra.Command{
20 | Use: "init",
21 | Short: "initialize the database",
22 | Run: func(cmd *cobra.Command, args []string) {
23 | run()
24 | },
25 | }
26 | )
27 |
28 | func init() {
29 | StartCmd.PersistentFlags().StringVarP(&config, "config", "c", "config/settings.yml", "Start server with provided configuration file")
30 | StartCmd.PersistentFlags().StringVarP(&mode, "mode", "m", "dev", "server mode ; eg:dev,test,prod")
31 | }
32 |
33 | func run() {
34 | usage := `start init`
35 | fmt.Println(usage)
36 | //1. 读取配置
37 | config2.ConfigSetup(config)
38 | //2. 设置日志
39 | tools.InitLogger()
40 | //3. 初始化数据库链接
41 | database.SetupMysql()
42 | //4. 数据库迁移
43 | _ = migrateModel()
44 | log.Println("数据库结构初始化成功!")
45 | //5. 数据初始化完成
46 | if err := models.InitDb(); err != nil {
47 | log.Fatal("数据库基础数据初始化失败!")
48 | }
49 |
50 | usage = `数据库基础数据初始化成功`
51 | fmt.Println(usage)
52 | }
53 |
54 | func migrateModel() error {
55 | if config2.MysqlConfig.Dbtype == "mysql" {
56 | orm.Eloquent = orm.Eloquent.Set("gorm:table_options", "ENGINE=InnoDB CHARSET=utf8mb4")
57 | }
58 | return gorm.AutoMigrate(orm.Eloquent)
59 | }
60 |
--------------------------------------------------------------------------------
/config/settings-prod.yml:
--------------------------------------------------------------------------------
1 | script:
2 | path: ./static/scripts
3 | settings:
4 | application:
5 | host: 0.0.0.0
6 | mode: dev
7 | name: vAdmin
8 | port: "8000"
9 | readtimeout: 1
10 | writertimeout: 2
11 | domain:
12 | gethost: 1
13 | url: localhost:9527
14 | drill:
15 | dbtype: drill
16 | host: 192.168.0.18
17 | port: 30700
18 | email:
19 | alias: vAdmin
20 | host: smtp.163.com
21 | pass: your password
22 | port: 465
23 | user: fdevops@163.com
24 | gorm:
25 | logmode: 0
26 | maxidleconn: 0
27 | maxopenconn: 20000
28 | jwt:
29 | secret: vAdminx
30 | timeout: 7200
31 | ldap:
32 | anonymousquery: 0
33 | basedn: dc=vdevops,dc=com
34 | bindpwd: 123456
35 | binduserdn: cn=admin,dc=fdevops,dc=com
36 | host: localhost
37 | port: 389
38 | tls: 0
39 | userfield: uid
40 | log:
41 | compress: 1
42 | consolestdout: 1
43 | dir: temp/logs
44 | filestdout: 0
45 | level: debug
46 | localtime: 1
47 | maxage: 30
48 | maxbackups: 300
49 | maxsize: 10240
50 | path: ./logs/vAdmin.log
51 | mysql:
52 | dbtype: mysql
53 | host: xx.xx.xx.xx
54 | maxidleconns: 20
55 | maxopenconns: 100
56 | name: vadmin
57 | password: ********
58 | port: 3306
59 | username: root
60 | public:
61 | islocation: 0
62 | redis:
63 | url: redis://vAdmin123456@xx.xx.xx.xx:6379
64 | ssl:
65 | key: keystring
66 | pem: temp/pem.pem
67 |
--------------------------------------------------------------------------------
/models/server.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 syncd Author. All Rights Reserved.
2 | // Use of this source code is governed by a MIT-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package models
6 |
7 | type Server struct {
8 | ID int `gorm:"primary_key"`
9 | GroupId int `gorm:"type:int(11);not null;default:0"`
10 | Name string `gorm:"type:varchar(100);not null;default:''"`
11 | Ip string `gorm:"type:varchar(100);not null;default:''"`
12 | SSHPort int `gorm:"type:int(11);not null;default:0"`
13 | CreateBy string `json:"create_by" gorm:"type:varchar(128);"` // 创建人
14 | UpdateBy string `json:"update_by" gorm:"type:varchar(128);"` // 更新者
15 | }
16 |
17 | func (m *Server) TableName() string {
18 | return "dep_server"
19 | }
20 |
21 | func (m *Server) Create() bool {
22 | //m.Ctime = int(time.Now().Unix())
23 | return Create(m)
24 | }
25 |
26 | func (m *Server) Update() bool {
27 | return UpdateByPk(m)
28 | }
29 |
30 | func (m *Server) List(query QueryParam) ([]Server, bool) {
31 | var data []Server
32 | ok := GetMulti(&data, query)
33 | return data, ok
34 | }
35 |
36 | func (m *Server) Count(query QueryParam) (int, bool) {
37 | var count int
38 | ok := Count(m, &count, query)
39 | return count, ok
40 | }
41 |
42 | func (m *Server) Delete() bool {
43 | return DeleteByPk(m)
44 | }
45 |
46 | func (m *Server) Get(id int) bool {
47 | return GetByPk(m, id)
48 | }
49 |
--------------------------------------------------------------------------------
/models/datascope.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import (
4 | "errors"
5 | "github.com/jinzhu/gorm"
6 | "vAdmin/tools"
7 | )
8 |
9 | type DataPermission struct {
10 | DataScope string
11 | UserId int
12 | DeptId int
13 | RoleId int
14 | }
15 |
16 | func (e *DataPermission) GetDataScope(tbname string, table *gorm.DB) (*gorm.DB, error) {
17 | SysUser := new(SysUser)
18 | SysRole := new(SysRole)
19 | SysUser.UserId = e.UserId
20 | user, err := SysUser.Get()
21 | if err != nil {
22 | return nil, errors.New("获取用户数据出错 msg:" + err.Error())
23 | }
24 | SysRole.RoleId = user.RoleId
25 | role, err := SysRole.Get()
26 | if err != nil {
27 | return nil, errors.New("获取用户数据出错 msg:" + err.Error())
28 | }
29 | if role.DataScope == "2" {
30 | table = table.Where(tbname+".create_by in (select sys_user.user_id from sys_role_dept left join sys_user on sys_user.dept_id=sys_role_dept.dept_id where sys_role_dept.role_id = ?)", user.RoleId)
31 | }
32 | if role.DataScope == "3" {
33 | table = table.Where(tbname+".create_by in (SELECT user_id from sys_user where dept_id = ? )", user.DeptId)
34 | }
35 | if role.DataScope == "4" {
36 | table = table.Where(tbname+".create_by in (SELECT user_id from sys_user where sys_user.dept_id in(select dept_id from sys_dept where dept_path like ? ))", "%"+tools.IntToString(user.DeptId)+"%")
37 | }
38 | if role.DataScope == "5" || role.DataScope == "" {
39 | table = table.Where(tbname+".create_by = ?", e.UserId)
40 | }
41 |
42 | return table, nil
43 | }
44 |
--------------------------------------------------------------------------------
/pkg/task/worker/worker.go:
--------------------------------------------------------------------------------
1 | package worker
2 |
3 | import (
4 | "vAdmin/pkg/logger"
5 |
6 | "github.com/spf13/viper"
7 |
8 | "github.com/RichardKnop/machinery/v1"
9 | taskConfig "github.com/RichardKnop/machinery/v1/config"
10 | "github.com/RichardKnop/machinery/v1/tasks"
11 | )
12 |
13 | var AsyncTaskCenter *machinery.Server
14 |
15 | func StartServer() {
16 | tc, err := NewTaskCenter()
17 | if err != nil {
18 | panic(err)
19 | }
20 | AsyncTaskCenter = tc
21 | }
22 |
23 | func NewTaskCenter() (*machinery.Server, error) {
24 | cnf := &taskConfig.Config{
25 | Broker: viper.GetString("settings.redis.url"),
26 | DefaultQueue: "ServerTasksQueue",
27 | ResultBackend: "eager",
28 | }
29 | server, err := machinery.NewServer(cnf)
30 | if err != nil {
31 | return nil, err
32 | }
33 | initAsyncTaskMap()
34 | return server, server.RegisterTasks(asyncTaskMap)
35 | }
36 |
37 | func NewAsyncTaskWorker(concurrency int) *machinery.Worker {
38 | consumerTag := "TaskWorker"
39 | worker := AsyncTaskCenter.NewWorker(consumerTag, concurrency)
40 | errorHandler := func(err error) {
41 | logger.Error("执行失败: ", err)
42 | }
43 | preTaskHandler := func(signature *tasks.Signature) {
44 | logger.Info("开始执行: ", signature.Name)
45 | }
46 | postTaskHandler := func(signature *tasks.Signature) {
47 | logger.Info("执行结束: ", signature.Name)
48 | }
49 | worker.SetPostTaskHandler(postTaskHandler)
50 | worker.SetErrorHandler(errorHandler)
51 | worker.SetPreTaskHandler(preTaskHandler)
52 | return worker
53 | }
54 |
--------------------------------------------------------------------------------
/pkg/notify/email/email.go:
--------------------------------------------------------------------------------
1 | package email
2 |
3 | /*
4 | @Author : Rongxin Linghu
5 | @Desc : 发送邮件
6 | */
7 |
8 | import (
9 | "vAdmin/pkg/logger"
10 | "strconv"
11 |
12 | "github.com/spf13/viper"
13 |
14 | "gopkg.in/gomail.v2"
15 | )
16 |
17 | func server(mailTo []string, subject, body string, args ...string) error {
18 | //定义邮箱服务器连接信息,如果是网易邮箱 pass填密码,qq邮箱填授权码
19 | mailConn := map[string]string{
20 | "user": viper.GetString("settings.email.user"),
21 | "pass": viper.GetString("settings.email.pass"),
22 | "host": viper.GetString("settings.email.host"),
23 | "port": viper.GetString("settings.email.port"),
24 | }
25 |
26 | port, _ := strconv.Atoi(mailConn["port"]) //转换端口类型为int
27 |
28 | m := gomail.NewMessage()
29 |
30 | m.SetHeader("From", m.FormatAddress(mailConn["user"], viper.GetString("settings.email.alias"))) //这种方式可以添加别名,即“XX官方”
31 | m.SetHeader("To", mailTo...) //发送给多个用户
32 | m.SetHeader("Subject", subject) //设置邮件主题
33 | m.SetBody("text/html", body) //设置邮件正文
34 |
35 | d := gomail.NewDialer(mailConn["host"], port, mailConn["user"], mailConn["pass"])
36 | err := d.DialAndSend(m)
37 | return err
38 |
39 | }
40 |
41 | func SendMail(mailTo []string, subject, body string) {
42 | err := server(mailTo, subject, body)
43 | if err != nil {
44 | logger.Info(err)
45 | return
46 | }
47 | logger.Info("send successfully")
48 | }
49 |
--------------------------------------------------------------------------------
/pkg/hash/file.go:
--------------------------------------------------------------------------------
1 | package hash
2 |
3 | import (
4 | "crypto/md5"
5 | "crypto/sha1"
6 | "crypto/sha256"
7 | "crypto/sha512"
8 | "encoding/hex"
9 | "io"
10 | "os"
11 | )
12 |
13 | /* 对文件取hash值 */
14 |
15 | // Md5File 文件md5值
16 | func Md5File(path string) (string, error) {
17 | f, err := os.Open(path)
18 | if err != nil {
19 | return "", err
20 | }
21 | defer f.Close()
22 |
23 | h := md5.New()
24 | if _, err := io.Copy(h, f); err != nil {
25 | return "", err
26 | }
27 | return hex.EncodeToString(h.Sum(nil)), nil
28 | }
29 |
30 | // Sha1File 文件sha1值
31 | func Sha1File(path string) (string, error) {
32 | f, err := os.Open(path)
33 | if err != nil {
34 | return "", err
35 | }
36 | defer f.Close()
37 |
38 | h := sha1.New()
39 | if _, err := io.Copy(h, f); err != nil {
40 | return "", err
41 | }
42 | return hex.EncodeToString(h.Sum(nil)), nil
43 | }
44 |
45 | // Sha256File 文件sha256值
46 | func Sha256File(path string) (string, error) {
47 | f, err := os.Open(path)
48 | if err != nil {
49 | return "", err
50 | }
51 | defer f.Close()
52 |
53 | h := sha256.New()
54 | if _, err := io.Copy(h, f); err != nil {
55 | return "", err
56 | }
57 | return hex.EncodeToString(h.Sum(nil)), nil
58 | }
59 |
60 | // Sha512File 文件sha512值
61 | func Sha512File(path string) (string, error) {
62 | f, err := os.Open(path)
63 | if err != nil {
64 | return "", err
65 | }
66 | defer f.Close()
67 |
68 | h := sha512.New()
69 | if _, err := io.Copy(h, f); err != nil {
70 | return "", err
71 | }
72 | return hex.EncodeToString(h.Sum(nil)), nil
73 | }
74 |
--------------------------------------------------------------------------------
/apis/monitor/server.go:
--------------------------------------------------------------------------------
1 | package monitor
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/shirou/gopsutil/cpu"
6 | "github.com/shirou/gopsutil/disk"
7 | "github.com/shirou/gopsutil/mem"
8 | "vAdmin/tools/app"
9 | "runtime"
10 | )
11 |
12 | const (
13 | B = 1
14 | KB = 1024 * B
15 | MB = 1024 * KB
16 | GB = 1024 * MB
17 | )
18 |
19 | func ServerInfo(c *gin.Context) {
20 |
21 | osDic := make(map[string]interface{}, 0)
22 | osDic["goOs"] = runtime.GOOS
23 | osDic["arch"] = runtime.GOARCH
24 | osDic["mem"] = runtime.MemProfileRate
25 | osDic["compiler"] = runtime.Compiler
26 | osDic["version"] = runtime.Version()
27 | osDic["numGoroutine"] = runtime.NumGoroutine()
28 |
29 | dis, _ := disk.Usage("/")
30 | diskTotalGB := int(dis.Total) / GB
31 | diskFreeGB := int(dis.Free) / GB
32 | diskDic := make(map[string]interface{}, 0)
33 | diskDic["total"] = diskTotalGB
34 | diskDic["free"] = diskFreeGB
35 |
36 | mem, _ := mem.VirtualMemory()
37 | memUsedMB := int(mem.Used) / GB
38 | memTotalMB := int(mem.Total) / GB
39 | memFreeMB := int(mem.Free) / GB
40 | memUsedPercent := int(mem.UsedPercent)
41 | memDic := make(map[string]interface{}, 0)
42 | memDic["total"] = memTotalMB
43 | memDic["used"] = memUsedMB
44 | memDic["free"] = memFreeMB
45 | memDic["usage"] = memUsedPercent
46 |
47 | cpuDic := make(map[string]interface{}, 0)
48 | cpuDic["cpuNum"], _ = cpu.Counts(false)
49 |
50 |
51 | app.Custum(c, gin.H{
52 | "code": 200,
53 | "os": osDic,
54 | "mem": memDic,
55 | "cpu": cpuDic,
56 | "disk": diskDic,
57 | })
58 | }
59 |
--------------------------------------------------------------------------------
/models/process/circulationHistory.go:
--------------------------------------------------------------------------------
1 | package process
2 |
3 | import (
4 | "vAdmin/models/base"
5 | )
6 |
7 | /*
8 | @Author : Rongxin Linghu
9 | */
10 |
11 | // 工单流转历史
12 | type CirculationHistory struct {
13 | base.Model
14 | Title string `gorm:"column:title; type: varchar(128)" json:"title" form:"title"` // 工单标题
15 | WorkOrder int `gorm:"column:work_order; type: int(11)" json:"work_order" form:"work_order"` // 工单ID
16 | State string `gorm:"column:state; type: varchar(128)" json:"state" form:"state"` // 工单状态
17 | Source string `gorm:"column:source; type: varchar(128)" json:"source" form:"source"` // 源节点ID
18 | Target string `gorm:"column:target; type: varchar(128)" json:"target" form:"target"` // 目标节点ID
19 | Circulation string `gorm:"column:circulation; type: varchar(128)" json:"circulation" form:"circulation"` // 流转ID
20 | Processor string `gorm:"column:processor; type: varchar(45)" json:"processor" form:"processor"` // 处理人
21 | ProcessorId int `gorm:"column:processor_id; type: int(11)" json:"processor_id" form:"processor_id"` // 处理人ID
22 | CostDuration string `gorm:"column:cost_duration; type: varchar(128)" json:"cost_duration" form:"cost_duration"` // 处理时长
23 | Remarks string `gorm:"column:remarks; type: longtext" json:"remarks" form:"remarks"` // 备注
24 | }
25 |
26 | func (CirculationHistory) TableName() string {
27 | return "p_work_order_circulation_history"
28 | }
29 |
--------------------------------------------------------------------------------
/tools/string.go:
--------------------------------------------------------------------------------
1 | package tools
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "github.com/gin-gonic/gin"
7 | "io/ioutil"
8 | "strconv"
9 | "time"
10 | )
11 |
12 | func StringToInt64(e string) (int64, error) {
13 | return strconv.ParseInt(e, 10, 64)
14 | }
15 |
16 | func StringToInt(e string) (int, error) {
17 | return strconv.Atoi(e)
18 | }
19 |
20 |
21 | func GetCurrntTimeStr() string {
22 | return time.Now().Format("2006/01/02 15:04:05")
23 | }
24 |
25 | func GetCurrntTime() time.Time {
26 | return time.Now()
27 | }
28 |
29 |
30 | func StructToJsonStr(e interface{}) (string, error) {
31 | if b, err := json.Marshal(e); err == nil {
32 | return string(b), err
33 | } else {
34 | return "", err
35 | }
36 | }
37 |
38 | func GetBodyString(c *gin.Context) (string, error) {
39 | body, err := ioutil.ReadAll(c.Request.Body)
40 | if err != nil {
41 | fmt.Printf("read body err, %v\n", err)
42 | return string(body), nil
43 | } else {
44 | return "", err
45 | }
46 | }
47 |
48 | func JsonStrToMap(e string) (map[string]interface{}, error) {
49 | var dict map[string]interface{}
50 | if err := json.Unmarshal([]byte(e), &dict); err == nil {
51 | return dict, err
52 | } else {
53 | return nil, err
54 | }
55 | }
56 |
57 | func StructToMap(data interface{}) (map[string]interface{}, error) {
58 | dataBytes, err := json.Marshal(data)
59 | if err != nil {
60 | return nil, err
61 | }
62 | mapData := make(map[string]interface{})
63 | err = json.Unmarshal(dataBytes, &mapData)
64 | if err != nil {
65 | return nil, err
66 | }
67 | return mapData, nil
68 | }
69 |
--------------------------------------------------------------------------------
/tools/logger.go:
--------------------------------------------------------------------------------
1 | package tools
2 |
3 | import (
4 | "errors"
5 | log "github.com/sirupsen/logrus"
6 | "github.com/spf13/viper"
7 | "os"
8 | "time"
9 | )
10 |
11 | func InitLogger() {
12 | switch Mode(viper.GetString("settings.application.mode")) {
13 | case ModeDev, ModeTest:
14 | log.SetOutput(os.Stdout)
15 | log.SetLevel(log.TraceLevel)
16 | case ModeProd:
17 | file, err := os.OpenFile(viper.GetString("logger.dir")+"/api-"+time.Now().Format("2006-01-02")+".log", os.O_WRONLY|os.O_APPEND|os.O_CREATE|os.O_SYNC, 0600)
18 | if err != nil {
19 | log.Fatalln("log init failed")
20 | }
21 |
22 | var info os.FileInfo
23 | info, err = file.Stat()
24 | if err != nil {
25 | log.Fatal(err)
26 | }
27 | fileWriter := logFileWriter{file, info.Size()}
28 | log.SetOutput(&fileWriter)
29 | log.SetLevel(log.ErrorLevel)
30 | }
31 |
32 | log.SetReportCaller(true)
33 | }
34 |
35 | type logFileWriter struct {
36 | file *os.File
37 | size int64
38 | }
39 |
40 | func (p *logFileWriter) Write(data []byte) (n int, err error) {
41 | if p == nil {
42 | return 0, errors.New("logFileWriter is nil")
43 | }
44 | if p.file == nil {
45 | return 0, errors.New("file not opened")
46 | }
47 | n, e := p.file.Write(data)
48 | p.size += int64(n)
49 | //每天一个文件
50 | if p.file.Name() != viper.GetString("logger.dir")+"/api-"+time.Now().Format("2006-01-02")+".log" {
51 | p.file.Close()
52 | p.file, _ = os.OpenFile(viper.GetString("logger.dir")+"/api-"+time.Now().Format("2006-01-02")+".log", os.O_WRONLY|os.O_APPEND|os.O_CREATE|os.O_SYNC, 0600)
53 | p.size = 0
54 | }
55 | return n, e
56 | }
57 |
--------------------------------------------------------------------------------
/apis/tools/gen.go:
--------------------------------------------------------------------------------
1 | package tools
2 |
3 | import (
4 | "bytes"
5 | "github.com/gin-gonic/gin"
6 | "vAdmin/models/tools"
7 | tools2 "vAdmin/tools"
8 | "vAdmin/tools/app"
9 | "net/http"
10 | "text/template"
11 | )
12 |
13 | func Preview(c *gin.Context) {
14 | table := tools.SysTables{}
15 | id, err := tools2.StringToInt(c.Param("tableId"))
16 | tools2.HasError(err, "", -1)
17 | table.TableId = id
18 | t1, err := template.ParseFiles("template/model.go.template")
19 | tools2.HasError(err, "", -1)
20 | t2, err := template.ParseFiles("template/api.go.template")
21 | tools2.HasError(err, "", -1)
22 | t3, err := template.ParseFiles("template/js.go.template")
23 | tools2.HasError(err, "", -1)
24 | t4, err := template.ParseFiles("template/vue.go.template")
25 | tools2.HasError(err, "", -1)
26 | t5, err := template.ParseFiles("template/router.go.template")
27 | tools2.HasError(err, "", -1)
28 | tab, _ := table.Get()
29 | var b1 bytes.Buffer
30 | err = t1.Execute(&b1, tab)
31 | var b2 bytes.Buffer
32 | err = t2.Execute(&b2, tab)
33 | var b3 bytes.Buffer
34 | err = t3.Execute(&b3, tab)
35 | var b4 bytes.Buffer
36 | err = t4.Execute(&b4, tab)
37 | var b5 bytes.Buffer
38 | err = t5.Execute(&b5, tab)
39 |
40 | mp := make(map[string]interface{})
41 | mp["template/model.go.template"] = b1.String()
42 | mp["template/api.go.template"] = b2.String()
43 | mp["template/js.go.template"] = b3.String()
44 | mp["template/vue.go.template"] = b4.String()
45 | mp["template/router.go.template"] = b5.String()
46 | var res app.Response
47 | res.Data = mp
48 |
49 | c.JSON(http.StatusOK, res.ReturnOK())
50 | }
51 |
--------------------------------------------------------------------------------
/database/drill.go:
--------------------------------------------------------------------------------
1 | package database
2 |
3 | import (
4 | "bytes"
5 | _ "github.com/pinpt/go-drill"//加载drill
6 | "database/sql"
7 | "vAdmin/tools/config"
8 | "log"
9 | "strconv"
10 | )
11 |
12 | var Eloq *sql.DB
13 |
14 | type Databasex interface {
15 | Open(dbType string, conn string) (db *sql.DB, err error)
16 | }
17 |
18 | type Drill struct {
19 | }
20 |
21 | func SetupDrill() {
22 |
23 | DbType = config.DrillConfig.Dbtype
24 | Host = config.DrillConfig.Host
25 | Port = config.DrillConfig.Port
26 |
27 | if DbType != "drill" {
28 | log.Println("db type unknow")
29 | }
30 | var err error
31 |
32 | conn := GetDrillConnect()
33 |
34 | log.Println(conn)
35 |
36 | var db Databasex
37 | if DbType == "drill" {
38 | db = new(Drill)
39 | Eloq, err = db.Open(DbType, conn)
40 |
41 | } else {
42 | panic("db type unknow")
43 | }
44 | if err != nil {
45 | log.Fatalf("%s connect error %v", DbType, err)
46 | } else {
47 | log.Printf("%s connect success!", DbType)
48 | }
49 |
50 |
51 | if Eloquent.Error != nil {
52 | log.Fatalf("database error %v", Eloquent.Error)
53 | }
54 |
55 | Eloquent.LogMode(true)
56 | }
57 |
58 | func GetDrillConnect() string {
59 | var conn bytes.Buffer
60 | conn.WriteString("http://")
61 | conn.WriteString(Host)
62 | conn.WriteString(":")
63 | conn.WriteString(strconv.Itoa(Port))
64 | return conn.String()
65 | }
66 |
67 | func (*Drill) Open(dbType string, conn string) (db *sql.DB, err error) {
68 | // sql.Open("drill", "http://192.168.0.18:30700")
69 | eloq, err := sql.Open(dbType, conn)
70 | eloq.SetMaxIdleConns(5)
71 | return eloq, err
72 | }
73 |
74 |
75 |
--------------------------------------------------------------------------------
/models/process/process.go:
--------------------------------------------------------------------------------
1 | package process
2 |
3 | import (
4 | "encoding/json"
5 | "vAdmin/models/base"
6 | )
7 |
8 | /*
9 | @Author : Rongxin Linghu
10 | */
11 |
12 | // 流程
13 | type Info struct {
14 | base.Model
15 | Name string `gorm:"column:name; type:varchar(128)" json:"name" form:"name"` // 流程名称
16 | Icon string `gorm:"column:icon; type:varchar(128)" json:"icon" form:"icon"` // 流程标签
17 | Structure json.RawMessage `gorm:"column:structure; type:json" json:"structure" form:"structure"` // 流程结构
18 | Classify int `gorm:"column:classify; type:int(11)" json:"classify" form:"classify"` // 分类ID
19 | Tpls json.RawMessage `gorm:"column:tpls; type:json" json:"tpls" form:"tpls"` // 模版
20 | Task json.RawMessage `gorm:"column:task; type:json" json:"task" form:"task"` // 任务ID, array, 可执行多个任务,可以当成通知任务,每个节点都会去执行
21 | SubmitCount int `gorm:"column:submit_count; type:int(11); default:0" json:"submit_count" form:"submit_count"` // 提交统计
22 | Creator int `gorm:"column:creator; type:int(11)" json:"creator" form:"creator"` // 创建者
23 | Notice json.RawMessage `gorm:"column:notice; type:json" json:"notice" form:"notice"` // 绑定通知
24 | Remarks string `gorm:"column:remarks; type:varchar(1024)" json:"remarks" form:"remarks"` // 流程备注
25 | }
26 |
27 | func (Info) TableName() string {
28 | return "p_process_info"
29 | }
30 |
--------------------------------------------------------------------------------
/middleware/header.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "net/http"
6 | "time"
7 | )
8 |
9 | // NoCache is a middleware function that appends headers
10 | // to prevent the client from caching the HTTP response.
11 | func NoCache(c *gin.Context) {
12 | c.Header("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate, value")
13 | c.Header("Expires", "Thu, 01 Jan 1970 00:00:00 GMT")
14 | c.Header("Last-Modified", time.Now().UTC().Format(http.TimeFormat))
15 | c.Next()
16 | }
17 |
18 | // Options is a middleware function that appends headers
19 | // for options requests and aborts then exits the middleware
20 | // chain and ends the request.
21 | func Options(c *gin.Context) {
22 | if c.Request.Method != "OPTIONS" {
23 | c.Next()
24 | } else {
25 | c.Header("Access-Control-Allow-Origin", "*")
26 | c.Header("Access-Control-Allow-Methods", "GET,POST,PUT,PATCH,DELETE,OPTIONS")
27 | c.Header("Access-Control-Allow-Headers", "authorization, origin, content-type, accept")
28 | c.Header("Allow", "HEAD,GET,POST,PUT,PATCH,DELETE,OPTIONS")
29 | c.Header("Content-Type", "application/json")
30 | c.AbortWithStatus(200)
31 | }
32 | }
33 |
34 | // Secure is a middleware function that appends security
35 | // and resource access headers.
36 | func Secure(c *gin.Context) {
37 | c.Header("Access-Control-Allow-Origin", "*")
38 | //c.Header("X-Frame-Options", "DENY")
39 | c.Header("X-Content-Type-Options", "nosniff")
40 | c.Header("X-XSS-Protection", "1; mode=block")
41 | if c.Request.TLS != nil {
42 | c.Header("Strict-Transport-Security", "max-age=31536000")
43 | }
44 |
45 | // Also consider adding Content-Security-Policy headers
46 | // c.Header("Content-Security-Policy", "script-src 'self' https://cdnjs.cloudflare.com")
47 | }
48 |
--------------------------------------------------------------------------------
/apis/common/queryForm.go:
--------------------------------------------------------------------------------
1 | package common
2 |
3 | import (
4 | "errors"
5 |
6 | "vAdmin/pkg/convert"
7 |
8 | "github.com/gin-gonic/gin"
9 | )
10 |
11 | // GetQueryToStrE
12 | func GetQueryToStrE(c *gin.Context,key string) (string,error) {
13 | str,ok:=c.GetQuery(key)
14 | if !ok {
15 | return "",errors.New("没有这个值传入")
16 | }
17 | return str,nil
18 | }
19 |
20 | // GetQueryToStr
21 | func GetQueryToStr(c *gin.Context,key string,defaultValues ...string) string {
22 | var defaultValue string
23 | if len(defaultValues)>0{
24 | defaultValue=defaultValues[0]
25 | }
26 | str,err:=GetQueryToStrE(c,key)
27 | if str=="" || err!=nil{
28 | return defaultValue
29 | }
30 | return str
31 | }
32 |
33 | // QueryToUintE
34 | func GetQueryToUintE(c *gin.Context,key string) (uint,error) {
35 | str,err:=GetQueryToStrE(c,key)
36 | if err !=nil {
37 | return 0,err
38 | }
39 | return convert.ToUintE(str)
40 | }
41 |
42 | // QueryToUint
43 | func GetQueryToUint(c *gin.Context,key string,defaultValues ...uint) uint {
44 | var defaultValue uint
45 | if len(defaultValues)>0{
46 | defaultValue=defaultValues[0]
47 | }
48 | val,err:=GetQueryToUintE(c,key)
49 | if err!=nil {
50 | return defaultValue
51 | }
52 | return val
53 | }
54 |
55 | // QueryToUintE
56 | func GetQueryToUint64E(c *gin.Context,key string) (uint64,error) {
57 | str,err:=GetQueryToStrE(c,key)
58 | if err !=nil {
59 | return 0,err
60 | }
61 | return convert.ToUint64E(str)
62 | }
63 |
64 | // QueryToUint
65 | func GetQueryToUint64(c *gin.Context,key string,defaultValues ...uint64) uint64 {
66 | var defaultValue uint64
67 | if len(defaultValues)>0{
68 | defaultValue=defaultValues[0]
69 | }
70 | val,err:=GetQueryToUint64E(c,key)
71 | if err!=nil {
72 | return defaultValue
73 | }
74 | return val
75 | }
76 |
--------------------------------------------------------------------------------
/tools/config/config.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import (
4 | "fmt"
5 | "github.com/spf13/viper"
6 | "io/ioutil"
7 | "log"
8 | "os"
9 | "strings"
10 | )
11 |
12 | var cfgMysql *viper.Viper
13 | var cfgDrill *viper.Viper
14 | var cfgApplication *viper.Viper
15 | var cfgJwt *viper.Viper
16 | var cfgLog *viper.Viper
17 |
18 |
19 | //载入配置文件
20 | func ConfigSetup(path string) {
21 | viper.SetConfigFile(path)
22 | content, err := ioutil.ReadFile(path)
23 | if err != nil {
24 | log.Fatal(fmt.Sprintf("Read config file fail: %s", err.Error()))
25 | }
26 |
27 | //Replace environment variables
28 | err = viper.ReadConfig(strings.NewReader(os.ExpandEnv(string(content))))
29 | if err != nil {
30 | log.Fatal(fmt.Sprintf("Parse config file fail: %s", err.Error()))
31 | }
32 |
33 | cfgMysql = viper.Sub("settings.mysql")
34 | if cfgMysql == nil {
35 | panic("config not found settings.mysql")
36 | }
37 | MysqlConfig = InitMysql(cfgMysql)
38 |
39 | cfgDrill = viper.Sub("settings.drill")
40 | if cfgDrill == nil {
41 | panic("config not found settings.drill")
42 | }
43 | DrillConfig = InitDrill(cfgDrill)
44 |
45 | cfgApplication = viper.Sub("settings.application")
46 | if cfgApplication == nil {
47 | panic("config not found settings.application")
48 | }
49 | ApplicationConfig = InitApplication(cfgApplication)
50 |
51 | cfgJwt = viper.Sub("settings.jwt")
52 | if cfgJwt == nil {
53 | panic("config not found settings.jwt")
54 | }
55 | JwtConfig = InitJwt(cfgJwt)
56 |
57 | cfgLog = viper.Sub("settings.log")
58 | if cfgLog == nil {
59 | panic("config not found settings.log")
60 | }
61 | LogConfig = InitLog(cfgLog)
62 | }
63 |
64 |
65 | func SetConfig(configPath string, key string, value interface{}) {
66 | viper.AddConfigPath(configPath)
67 | viper.Set(key, value)
68 | viper.WriteConfig()
69 | }
70 |
--------------------------------------------------------------------------------
/models/tools/dbtables.go:
--------------------------------------------------------------------------------
1 | package tools
2 |
3 | import (
4 | "errors"
5 | orm "vAdmin/database"
6 | config2 "vAdmin/tools/config"
7 | )
8 |
9 | type DBTables struct {
10 | TableName string `gorm:"column:TABLE_NAME" json:"tableName"`
11 | Engine string `gorm:"column:ENGINE" json:"engine"`
12 | TableRows string `gorm:"column:TABLE_ROWS" json:"tableRows"`
13 | TableCollation string `gorm:"column:TABLE_COLLATION" json:"tableCollation"`
14 | CreateTime string `gorm:"column:CREATE_TIME" json:"createTime"`
15 | UpdateTime string `gorm:"column:UPDATE_TIME" json:"updateTime"`
16 | TableComment string `gorm:"column:TABLE_COMMENT" json:"tableComment"`
17 | }
18 |
19 | func (e *DBTables) GetPage(pageSize int, pageIndex int) ([]DBTables, int, error) {
20 | var doc []DBTables
21 |
22 | table := orm.Eloquent.Select("*").Table("information_schema.tables")
23 | table = table.Where("TABLE_NAME not in (select table_name from "+config2.MysqlConfig.Name+".sys_tables) ")
24 | table = table.Where("table_schema= ? ", config2.MysqlConfig.Name)
25 |
26 | if e.TableName != "" {
27 | table = table.Where("TABLE_NAME = ?", e.TableName)
28 | }
29 |
30 | var count int
31 |
32 | if err := table.Offset((pageIndex - 1) * pageSize).Limit(pageSize).Find(&doc).Error; err != nil {
33 | return nil, 0, err
34 | }
35 | table.Count(&count)
36 | return doc, count, nil
37 | }
38 |
39 | func (e *DBTables) Get() (DBTables, error) {
40 | var doc DBTables
41 |
42 | table := orm.Eloquent.Select("*").Table("information_schema.tables")
43 | table = table.Where("table_schema= ? ", config2.MysqlConfig.Name)
44 | if e.TableName == "" {
45 | return doc, errors.New("table name cannot be empty!")
46 | }
47 | table = table.Where("TABLE_NAME = ?", e.TableName)
48 |
49 | if err := table.First(&doc).Error; err != nil {
50 | return doc, err
51 | }
52 | return doc, nil
53 | }
54 |
--------------------------------------------------------------------------------
/tools/user.go:
--------------------------------------------------------------------------------
1 | package tools
2 |
3 | import (
4 | "fmt"
5 | "github.com/gin-gonic/gin"
6 | jwt "vAdmin/pkg/jwtauth"
7 | "log"
8 | )
9 |
10 | func ExtractClaims(c *gin.Context) jwt.MapClaims {
11 | claims, exists := c.Get("JWT_PAYLOAD")
12 | if !exists {
13 | return make(jwt.MapClaims)
14 | }
15 |
16 | return claims.(jwt.MapClaims)
17 | }
18 |
19 | func GetUserId(c *gin.Context) int {
20 | data := ExtractClaims(c)
21 | if data["identity"] != nil {
22 | return int((data["identity"]).(float64))
23 | }
24 | log.Println("****************************** 路径:" + c.Request.URL.Path + " 请求方法:" + c.Request.Method + " 说明:缺少identity")
25 | return 0
26 | }
27 |
28 | func GetUserIdStr(c *gin.Context) string {
29 | data := ExtractClaims(c)
30 | if data["identity"] != nil {
31 | return Int64ToString(int64((data["identity"]).(float64)))
32 | }
33 | log.Println("****************************** 路径:" + c.Request.URL.Path + " 请求方法:" + c.Request.Method + " 缺少identity")
34 | return ""
35 | }
36 |
37 | func GetUserName(c *gin.Context) string {
38 | data := ExtractClaims(c)
39 | if data["nice"] != nil {
40 | return (data["nice"]).(string)
41 | }
42 | fmt.Println("****************************** 路径:" + c.Request.URL.Path + " 请求方法:" + c.Request.Method + " 缺少nice")
43 | return ""
44 | }
45 |
46 | func GetRoleName(c *gin.Context) string {
47 | data := ExtractClaims(c)
48 | if data["rolekey"] != nil {
49 | return (data["rolekey"]).(string)
50 | }
51 | fmt.Println("****************************** 路径:" + c.Request.URL.Path + " 请求方法:" + c.Request.Method + " 缺少rolekey")
52 | return ""
53 | }
54 |
55 | func GetRoleId(c *gin.Context) int {
56 | data := ExtractClaims(c)
57 | if data["roleid"] != nil {
58 | i := int((data["roleid"]).(float64))
59 | return i
60 | }
61 | fmt.Println("****************************** 路径:" + c.Request.URL.Path + " 请求方法:" + c.Request.Method + " 缺少roleid")
62 | return 0
63 | }
64 |
--------------------------------------------------------------------------------
/models/process/workOrder.go:
--------------------------------------------------------------------------------
1 | package process
2 |
3 | import (
4 | "encoding/json"
5 | "vAdmin/models/base"
6 | )
7 |
8 | /*
9 | @Author : Rongxin Linghu
10 | */
11 |
12 | // 工单
13 | type WorkOrderInfo struct {
14 | base.Model
15 | Title string `gorm:"column:title; type:varchar(128)" json:"title" form:"title"` // 工单标题
16 | Priority int `gorm:"column:priority; type:int(11)" json:"priority" form:"priority"` // 工单优先级 1,正常 2,紧急 3,非常紧急
17 | Process int `gorm:"column:process; type:int(11)" json:"process" form:"process"` // 流程ID
18 | Classify int `gorm:"column:classify; type:int(11)" json:"classify" form:"classify"` // 分类ID
19 | IsEnd int `gorm:"column:is_end; type:int(11); default:0" json:"is_end" form:"is_end"` // 是否结束, 0 未结束,1 已结束
20 | IsDenied int `gorm:"column:is_denied; type:int(11); default:0" json:"is_denied" form:"is_denied"` // 是否被拒绝, 0 没有,1 有
21 | State json.RawMessage `gorm:"column:state; type:json" json:"state" form:"state"` // 状态信息
22 | RelatedPerson json.RawMessage `gorm:"column:related_person; type:json" json:"related_person" form:"related_person"` // 工单所有处理人
23 | Creator int `gorm:"column:creator; type:int(11)" json:"creator" form:"creator"` // 创建人
24 | UrgeCount int `gorm:"column:urge_count; type:int(11); default:0" json:"urge_count" form:"urge_count"` // 催办次数
25 | UrgeLastTime int `gorm:"column:urge_last_time; type:int(11); default:0" json:"urge_last_time" form:"urge_last_time"` // 上一次催促时间
26 | }
27 |
28 | func (WorkOrderInfo) TableName() string {
29 | return "p_work_order_info"
30 | }
31 |
--------------------------------------------------------------------------------
/apis/deploy/server.go:
--------------------------------------------------------------------------------
1 | package deploy
2 |
3 | import (
4 | "fmt"
5 | "vAdmin/tools/command"
6 | )
7 |
8 | const (
9 | COMMAND_TIMEOUT = 3600
10 | )
11 |
12 | type Server struct {
13 | ID int
14 | Addr string
15 | User string
16 | Port int
17 | Cmd string
18 | Key string
19 | task *command.Task
20 | result *ServerResult
21 | }
22 |
23 | type ServerResult struct {
24 | ID int
25 | TaskResult []*command.TaskResult
26 | Status int
27 | Error error
28 | }
29 |
30 | func NewServer(srv *Server) {
31 | srv.result = &ServerResult{
32 | ID: srv.ID,
33 | Status: STATUS_INIT,
34 | }
35 | srv.task = command.NewTask(
36 | srv.deployCmd(),
37 | COMMAND_TIMEOUT,
38 | )
39 | }
40 |
41 | func (srv *Server) Deploy() {
42 | srv.result.Status = STATUS_ING
43 | srv.task.Run()
44 | if err := srv.task.GetError(); err != nil {
45 | srv.result.Error = err
46 | srv.result.Status = STATUS_FAILED
47 | } else {
48 | srv.result.Status = STATUS_DONE
49 | }
50 | }
51 |
52 | func (srv *Server) Terminate() {
53 | if srv.result.Status == STATUS_ING {
54 | srv.task.Terminate()
55 | }
56 | }
57 |
58 | func (srv *Server) Result() *ServerResult {
59 | srv.result.TaskResult = srv.task.Result()
60 | return srv.result
61 | }
62 |
63 | func (srv *Server) deployCmd() []string {
64 | var (
65 | useCustomKey, useSshPort string
66 | )
67 | if srv.Key != "" {
68 | useCustomKey = fmt.Sprintf("-i %s", srv.Key)
69 | }
70 | if srv.Port != 0 {
71 | useSshPort = fmt.Sprintf("-p %d", srv.Port)
72 | }
73 | var cmds []string
74 |
75 | if srv.Cmd != "" {
76 | cmds = append(
77 | cmds,
78 | fmt.Sprintf("/usr/bin/env ssh -o StrictHostKeyChecking=no %s %s %s@%s '%s'",
79 | useCustomKey,
80 | useSshPort,
81 | srv.User,
82 | srv.Addr,
83 | srv.Cmd,
84 | ),
85 | )
86 | }
87 | return cmds
88 | }
--------------------------------------------------------------------------------
/render/render.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 syncd Author. All Rights Reserved.
2 | // Use of this source code is governed by a MIT-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package render
6 |
7 | import (
8 | "net/http"
9 |
10 | "github.com/gin-gonic/gin"
11 | )
12 |
13 | const (
14 | CODE_OK = 0
15 | CODE_ERR_SYSTEM = 1000
16 | CODE_ERR_APP = 1001
17 | CODE_ERR_PARAM = 1002
18 | CODE_ERR_DATA_REPEAT = 1003
19 | CODE_ERR_LOGIN_FAILED = 1004
20 | CODE_ERR_NO_LOGIN = 1005
21 | CODE_ERR_NO_PRIV = 1006
22 | CODE_ERR_TASK_ERROR = 1007
23 | CODE_ERR_USER_OR_PASS_WRONG = 1008
24 | CODE_ERR_NO_DATA = 1009
25 | )
26 |
27 | func JSON(c *gin.Context, data interface{}) {
28 | c.JSON(http.StatusOK, gin.H{
29 | "code": CODE_OK,
30 | "message": "success",
31 | "data": data,
32 | })
33 | }
34 |
35 | func CustomerError(c *gin.Context, code int, message string) {
36 | c.JSON(http.StatusOK, gin.H{
37 | "code": code,
38 | "message": message,
39 | })
40 | }
41 |
42 | func RepeatError(c *gin.Context, message string) {
43 | c.JSON(http.StatusOK, gin.H{
44 | "code": CODE_ERR_DATA_REPEAT,
45 | "message": message,
46 | })
47 | }
48 |
49 | func NoDataError(c *gin.Context, message string) {
50 | c.JSON(http.StatusOK, gin.H{
51 | "code": CODE_ERR_NO_DATA,
52 | "message": message,
53 | })
54 | }
55 |
56 | func ParamError(c *gin.Context, message string) {
57 | c.JSON(http.StatusOK, gin.H{
58 | "code": CODE_ERR_PARAM,
59 | "message": message,
60 | })
61 | }
62 |
63 | func AppError(c *gin.Context, message string) {
64 | c.JSON(http.StatusOK, gin.H{
65 | "code": CODE_ERR_APP,
66 | "message": message,
67 | })
68 | }
69 |
70 | func Success(c *gin.Context) {
71 | c.JSON(http.StatusOK, gin.H{
72 | "code": CODE_OK,
73 | "message": "success",
74 | })
75 | }
76 |
--------------------------------------------------------------------------------
/tools/command/command_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2018 syncd Author. All Rights Reserved.
2 | // Use of this source code is governed by a MIT-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package command
6 |
7 | import (
8 | "testing"
9 | "time"
10 | "strings"
11 | )
12 |
13 | func TestCmdRun(t *testing.T) {
14 | c := &Command{
15 | Cmd: "echo 'syncd'",
16 | Timeout: time.Second * 60,
17 | }
18 | var err error
19 | if c, err = NewCmd(c); err != nil {
20 | t.Error(err)
21 | }
22 | if err = c.Run(); err != nil {
23 | t.Error(err)
24 | }
25 | output := c.Stdout()
26 | if output != "syncd" {
27 | t.Errorf("cmd `echo syncd` output '%s' not eq 'syncd'", output)
28 | }
29 | }
30 |
31 | func TestCmdTimeout(t *testing.T) {
32 | c := &Command{
33 | Cmd: "sleep 2",
34 | Timeout: time.Second * 1,
35 | }
36 | var err error
37 | if c, err = NewCmd(c); err != nil {
38 | t.Error(err)
39 | }
40 | err = c.Run()
41 | if err == nil {
42 | t.Error("cmd should run timeout and output errmsg, but err is nil")
43 | }
44 | if strings.Index(err.Error(), "cmd run timeout") == -1 {
45 | t.Errorf("cmd run timeout output '%s' prefix not eq 'cmd run timeout'", err.Error())
46 | }
47 | }
48 |
49 | func TestCmdTerminate(t *testing.T) {
50 | tChan := make(chan int)
51 | c := &Command{
52 | Cmd: "sleep 5",
53 | TerminateChan: tChan,
54 | }
55 | var err error
56 | if c, err = NewCmd(c); err != nil {
57 | t.Error(err)
58 | }
59 | go func() {
60 | err = c.Run()
61 | if err == nil {
62 | t.Error("cmd should be terminated and output errmsg, but err is nil")
63 | }
64 | if strings.Index(err.Error(), "cmd is terminated") == -1 {
65 | t.Errorf("cmd is terminated output '%s' prefix not eq 'cmd is terminated'", err.Error())
66 | }
67 | }()
68 |
69 | tChan<- 1
70 | }
71 |
72 |
--------------------------------------------------------------------------------
/pkg/notify/send.go:
--------------------------------------------------------------------------------
1 | package notify
2 |
3 | import (
4 | "bytes"
5 | system "vAdmin/models"
6 | "vAdmin/pkg/logger"
7 | "vAdmin/pkg/notify/email"
8 | "text/template"
9 |
10 | "github.com/spf13/viper"
11 | )
12 |
13 | /*
14 | @Author : Rongxin Linghu
15 | @同时发送多种通知方式
16 | */
17 |
18 | type BodyData struct {
19 | SendTo interface{} // 接受人
20 | Subject string // 标题
21 | Classify []int // 通知类型
22 | Id int // 工单ID
23 | Title string // 工单标题
24 | Creator string // 工单创建人
25 | Priority int // 工单优先级
26 | PriorityValue string // 工单优先级
27 | CreatedAt string // 工单创建时间
28 | Content string // 通知的内容
29 | Description string // 表格上面的描述信息
30 | ProcessId int // 流程ID
31 | Domain string // 域名地址
32 | }
33 |
34 | func (b *BodyData) ParsingTemplate() (err error) {
35 | // 读取模版数据
36 | var (
37 | buf bytes.Buffer
38 | )
39 |
40 | tmpl, err := template.ParseFiles("./static/template/email.html")
41 | if err != nil {
42 | return
43 | }
44 |
45 | b.Domain = viper.GetString("settings.domain.url")
46 | err = tmpl.Execute(&buf, b)
47 | if err != nil {
48 | return
49 | }
50 |
51 | b.Content = buf.String()
52 |
53 | return
54 | }
55 |
56 | func (b *BodyData) SendNotify() (err error) {
57 | var (
58 | emailList []string
59 | )
60 |
61 | switch b.Priority {
62 | case 1:
63 | b.PriorityValue = "正常"
64 | case 2:
65 | b.PriorityValue = "紧急"
66 | case 3:
67 | b.PriorityValue = "非常紧急"
68 | }
69 |
70 | for _, c := range b.Classify {
71 | switch c {
72 | case 1: // 邮件
73 | users := b.SendTo.(map[string]interface{})["userList"].([]system.SysUser)
74 | if len(users) > 0 {
75 | for _, user := range users {
76 | emailList = append(emailList, user.Email)
77 | }
78 | err = b.ParsingTemplate()
79 | if err != nil {
80 | logger.Errorf("模版内容解析失败,%v", err.Error())
81 | return
82 | }
83 | go email.SendMail(emailList, b.Subject, b.Content)
84 | }
85 | }
86 | }
87 | return
88 | }
89 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module vAdmin
2 |
3 | go 1.12
4 |
5 | require (
6 | github.com/RichardKnop/machinery v1.10.0
7 | github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect
8 | github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751
9 | github.com/casbin/casbin/v2 v2.2.1
10 | github.com/casbin/gorm-adapter/v2 v2.0.3
11 | github.com/coocood/freecache v1.1.0
12 | github.com/dgrijalva/jwt-go v3.2.0+incompatible
13 | github.com/dreamans/syncd v0.0.0-20200328071902-9eed461abb73
14 | github.com/francoispqt/gojay v1.2.13 // indirect
15 | github.com/gin-gonic/gin v1.4.0
16 | github.com/go-kit/kit v0.8.0
17 | github.com/go-ldap/ldap/v3 v3.4.1
18 | github.com/go-ole/go-ole v1.2.4 // indirect
19 | github.com/go-openapi/spec v0.19.8 // indirect
20 | github.com/go-openapi/swag v0.19.9 // indirect
21 | github.com/go-sql-driver/mysql v1.5.0
22 | github.com/google/uuid v1.1.2
23 | github.com/gorilla/websocket v1.4.0
24 | github.com/jinzhu/gorm v1.9.10
25 | github.com/jinzhu/now v1.1.2 // indirect
26 | github.com/json-iterator/go v1.1.9 // indirect
27 | github.com/mailru/easyjson v0.7.1 // indirect
28 | github.com/mattn/go-isatty v0.0.10 // indirect
29 | github.com/mojocn/base64Captcha v1.3.1
30 | github.com/mssola/user_agent v0.5.1
31 | github.com/pinpt/go-drill v0.0.0-20190117152140-1a586edddf3d
32 | github.com/pkg/errors v0.9.1
33 | github.com/robfig/cron/v3 v3.0.1
34 | github.com/satori/go.uuid v1.2.0
35 | github.com/shirou/gopsutil v2.20.3+incompatible
36 | github.com/sirupsen/logrus v1.4.2
37 | github.com/spf13/afero v1.2.2 // indirect
38 | github.com/spf13/cobra v1.0.0
39 | github.com/spf13/pflag v1.0.5 // indirect
40 | github.com/spf13/viper v1.6.2
41 | github.com/stretchr/testify v1.6.1
42 | github.com/swaggo/gin-swagger v1.2.0
43 | github.com/swaggo/swag v1.6.7
44 | github.com/ugorji/go v1.1.7 // indirect
45 | go.uber.org/zap v1.10.0
46 | golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392
47 | golang.org/x/text v0.3.4
48 | gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
49 | gopkg.in/natefinch/lumberjack.v2 v2.0.0
50 | )
51 |
--------------------------------------------------------------------------------
/router/router.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | //"vAdmin/apis/tpl"
6 | "vAdmin/apis/releasecicd"
7 | "vAdmin/router/process"
8 | jwt "vAdmin/pkg/jwtauth"
9 | )
10 |
11 |
12 |
13 | // 路由示例
14 | func InitAppsRouter(r *gin.Engine, authMiddleware *jwt.GinJWTMiddleware) *gin.Engine {
15 |
16 | // 无需认证的路由
17 | examplesNoCheckRoleRouter(r)
18 | // 需要认证的路由
19 | ReleasecicdCheckRoleRouter(r, authMiddleware)
20 |
21 | DeployAppCheckRoleRouter(r, authMiddleware)
22 |
23 | ProcessCheckRoleRouter(r, authMiddleware)
24 |
25 | return r
26 | }
27 |
28 | // 无需认证的路由示例
29 | func examplesNoCheckRoleRouter(r *gin.Engine) {
30 |
31 | v1 := r.Group("/api/v1")
32 | //v1.GET("/examples/list", examples.apis)
33 | v1.GET("/releasechart/deploybyday",releasecicd.GetDeployByDay)
34 | v1.GET("/releasechart/deploybyhour",releasecicd.GetDeployByHour)
35 | }
36 |
37 | // 需要认证的路由示例
38 | func ReleasecicdCheckRoleRouter(r *gin.Engine, authMiddleware *jwt.GinJWTMiddleware) {
39 | v1:= r.Group("/api/v1")
40 | registerReleasecicdRouter(v1,authMiddleware)
41 | registerReleaseridRouter(v1,authMiddleware)
42 | registerReleasetodoRouter(v1,authMiddleware)
43 | //registerReleaseChartRouter(v0,authMiddleware)
44 | registerReleaseStgRouter(v1,authMiddleware)
45 | //v1auth := v1.Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
46 | //{
47 | // v1auth.GET("/examples/list", examples.apis)
48 | //}
49 | }
50 |
51 | func ProcessCheckRoleRouter(r *gin.Engine, authMiddleware *jwt.GinJWTMiddleware) {
52 |
53 | v1 := r.Group("/api/v1")
54 |
55 | // 兼容前后端不分离的情
56 | // r.GET("/", tpl.Tpl)
57 |
58 | // 流程中心
59 | process.RegisterClassifyRouter(v1, authMiddleware)
60 | process.RegisterProcessRouter(v1, authMiddleware)
61 | process.RegisterTaskRouter(v1, authMiddleware)
62 | process.RegisterTplRouter(v1, authMiddleware)
63 | process.RegisterWorkOrderRouter(v1, authMiddleware)
64 |
65 | }
66 |
67 | // 需要认证的路由示例
68 | func DeployAppCheckRoleRouter(r *gin.Engine, authMiddleware *jwt.GinJWTMiddleware) {
69 | v1:= r.Group("/api/v1")
70 | registerDeployAppRouter(v1,authMiddleware)
71 | }
--------------------------------------------------------------------------------
/pkg/task/worker/tasks.go:
--------------------------------------------------------------------------------
1 | package worker
2 |
3 | import (
4 | "context"
5 | "errors"
6 | "vAdmin/pkg/logger"
7 | "os/exec"
8 | "syscall"
9 |
10 | "github.com/RichardKnop/machinery/v1/tasks"
11 | )
12 |
13 | var asyncTaskMap map[string]interface{}
14 |
15 | func executeTaskBase(scriptPath string, params string) (err error) {
16 | command := exec.Command(scriptPath, params) //初始化Cmd
17 | out, err := command.CombinedOutput()
18 | if err != nil {
19 | logger.Errorf("task exec failed,%v", err.Error())
20 | return
21 | }
22 | logger.Info("Output: ", string(out))
23 | logger.Info("ProcessState PID: ", command.ProcessState.Pid())
24 | logger.Info("Exit Code ", command.ProcessState.Sys().(syscall.WaitStatus).ExitStatus())
25 | return
26 | }
27 |
28 | // ExecCommand 异步任务
29 | func ExecCommand(classify string, scriptPath string, params string) (err error) {
30 | if classify == "shell" {
31 | logger.Info("start exec shell - ", scriptPath)
32 | err = executeTaskBase(scriptPath, params)
33 | if err != nil {
34 | return
35 | }
36 | } else if classify == "python" {
37 | logger.Info("start exec python - ", scriptPath)
38 | err = executeTaskBase(scriptPath, params)
39 | if err != nil {
40 | return
41 | }
42 | } else {
43 | err = errors.New("目前仅支持Python与Shell脚本的执行,请知悉。")
44 | return
45 | }
46 | return
47 | }
48 |
49 | func SendTask(ctx context.Context, classify string, scriptPath string, params string) {
50 | args := make([]tasks.Arg, 0)
51 | args = append(args, tasks.Arg{
52 | Name: "classify",
53 | Type: "string",
54 | Value: classify,
55 | })
56 | args = append(args, tasks.Arg{
57 | Name: "scriptPath",
58 | Type: "string",
59 | Value: scriptPath,
60 | })
61 | args = append(args, tasks.Arg{
62 | Name: "params",
63 | Type: "string",
64 | Value: params,
65 | })
66 | task, _ := tasks.NewSignature("ExecCommandTask", args)
67 | task.RetryCount = 5
68 | _, err := AsyncTaskCenter.SendTaskWithContext(ctx, task)
69 | if err != nil {
70 | logger.Error(err.Error())
71 | }
72 | }
73 |
74 | func initAsyncTaskMap() {
75 | asyncTaskMap = make(map[string]interface{})
76 | asyncTaskMap["ExecCommandTask"] = ExecCommand
77 | }
78 |
--------------------------------------------------------------------------------
/tools/command/task.go:
--------------------------------------------------------------------------------
1 | // Copyright 2018 syncd Author. All Rights Reserved.
2 | // Use of this source code is governed by a MIT-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package command
6 |
7 | import (
8 | "errors"
9 | "time"
10 | )
11 |
12 | type Task struct {
13 | Commands []string
14 | done bool
15 | timeout int
16 | termChan chan int
17 | err error
18 | result []*TaskResult
19 | }
20 |
21 | type TaskResult struct {
22 | Cmd string `json:"cmd"`
23 | Stdout string `json:"stdout"`
24 | Stderr string `json:"stderr"`
25 | Success bool `json:"success"`
26 | }
27 |
28 | func NewTask(cmds []string, timeout int) *Task {
29 | return &Task{
30 | Commands: cmds,
31 | termChan: make(chan int),
32 | timeout: timeout,
33 | }
34 | }
35 |
36 | func (t *Task) Run() {
37 | for _, cmd := range t.Commands {
38 | result, err := t.next(cmd)
39 | t.result = append(t.result, result)
40 | if err != nil {
41 | t.err = errors.New("task run failed, " + err.Error())
42 | break
43 | }
44 | }
45 | t.done = true
46 | }
47 |
48 | func (t *Task) GetError() error {
49 | return t.err
50 | }
51 |
52 | func (t *Task) Result() []*TaskResult {
53 | return t.result
54 | }
55 |
56 | func (t *Task) next(cmd string) (*TaskResult, error) {
57 | result := &TaskResult{
58 | Cmd: cmd,
59 | }
60 | command := &Command{
61 | Cmd: cmd,
62 | Timeout: time.Second * time.Duration(t.timeout),
63 | TerminateChan: t.termChan,
64 | }
65 | var err error
66 | command, err = NewCmd(command)
67 | if err != nil {
68 | return result, err
69 | }
70 | if err := command.Run(); err != nil {
71 | result.Stderr = command.Stderr()
72 | return result, err
73 | }
74 | result.Stdout = command.Stdout()
75 | println("result.Stdout:%s", result.Stdout)
76 | result.Success = true
77 | return result, nil
78 | }
79 |
80 | func (t *Task) Terminate() {
81 | if !t.done {
82 | t.termChan <- 1
83 | }
84 | }
--------------------------------------------------------------------------------
/template/api.go.template:
--------------------------------------------------------------------------------
1 | package apis
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/gin-gonic/gin/binding"
6 | "vAdmin/models"
7 | "vAdmin/tools"
8 | "vAdmin/tools/app"
9 | "vAdmin/tools/app/msg"
10 | )
11 |
12 | func Get{{.ClassName}}List(c *gin.Context) {
13 | var data models.{{.ClassName}}
14 | var err error
15 | var pageSize = 10
16 | var pageIndex = 1
17 |
18 | if size := c.Request.FormValue("pageSize"); size != "" {
19 | pageSize = tools.StrToInt(err, size)
20 | }
21 | if index := c.Request.FormValue("pageIndex"); index != "" {
22 | pageIndex = tools.StrToInt(err, index)
23 | }
24 |
25 | {{ range .Columns -}}
26 | {{$z := .IsQuery}}
27 | {{- if ($z) -}}data.{{.GoField}} = c.Request.FormValue("{{.JsonField}}")
28 | {{ end -}}
29 | {{end}}
30 |
31 | data.DataScope = tools.GetUserIdStr(c)
32 | result, count, err := data.GetPage(pageSize, pageIndex)
33 | tools.HasError(err, "", -1)
34 |
35 | app.PageOK(c, result, count, pageIndex, pageSize, "")
36 | }
37 |
38 | func Get{{.ClassName}}(c *gin.Context) {
39 | var data models.{{.ClassName}}
40 | data.{{.PkGoField}}, _ = tools.StringToInt(c.Param("{{.PkJsonField}}"))
41 | result, err := data.Get()
42 | tools.HasError(err, "抱歉未找到相关信息", -1)
43 |
44 | app.OK(c, result, "")
45 | }
46 |
47 | func Insert{{.ClassName}}(c *gin.Context) {
48 | var data models.{{.ClassName}}
49 | err := c.ShouldBindJSON(&data)
50 | data.CreateBy = tools.GetUserIdStr(c)
51 | tools.HasError(err, "", 500)
52 | result, err := data.Create()
53 | tools.HasError(err, "", -1)
54 | app.OK(c, result, "")
55 | }
56 |
57 | func Update{{.ClassName}}(c *gin.Context) {
58 | var data models.{{.ClassName}}
59 | err := c.BindWith(&data, binding.JSON)
60 | tools.HasError(err, "数据解析失败", -1)
61 | data.UpdateBy = tools.GetUserIdStr(c)
62 | result, err := data.Update(data.{{.PkGoField}})
63 | tools.HasError(err, "", -1)
64 |
65 | app.OK(c, result, "")
66 | }
67 |
68 | func Delete{{.ClassName}}(c *gin.Context) {
69 | var data models.{{.ClassName}}
70 | data.UpdateBy = tools.GetUserIdStr(c)
71 |
72 | IDS := tools.IdsStrToIdsIntGroup("{{.PkJsonField}}", c)
73 | _, err := data.BatchDelete(IDS)
74 | tools.HasError(err, msg.DeletedFail, 500)
75 | app.OK(c, nil, msg.DeletedSuccess)
76 | }
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "vAdmin/cmd"
5 | )
6 |
7 | // @title DevOps API
8 | // @version 0.0.1
9 | // @description Rnotes系统
10 | // @SecurityDefinitions.apikey Bearer
11 | // @in header
12 | // @name Authorization
13 | // @BasePath /
14 |
15 | //func main() {
16 | // configName := "settings"
17 | //
18 | //
19 | // config.InitConfig(configName)
20 | //
21 | // gin.SetMode(gin.DebugMode)
22 | // log.Println(config.MysqlConfig.Port)
23 | //
24 | // err := gorm.AutoMigrate(orm.Eloquent)
25 | // if err != nil {
26 | // log.Fatalln("数据库初始化失败 err: %v", err)
27 | // }
28 | //
29 | // if config.ApplicationConfig.IsInit {
30 | // if err := models.InitDb(); err != nil {
31 | // log.Fatal("数据库基础数据初始化失败!")
32 | // } else {
33 | // config.SetApplicationIsInit()
34 | // }
35 | // }
36 | //
37 | // r := router.InitRouter()
38 | //
39 | // defer orm.Eloquent.Close()
40 | //
41 | // srv := &http.Server{
42 | // Addr: config.ApplicationConfig.Host + ":" + config.ApplicationConfig.Port,
43 | // Handler: r,
44 | // }
45 | //
46 | // go func() {
47 | // // 服务连接
48 | // if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
49 | // log.Fatalf("listen: %s\n", err)
50 | // }
51 | // }()
52 | // log.Println("Server Run ", config.ApplicationConfig.Host+":"+config.ApplicationConfig.Port)
53 | // log.Println("Enter Control + C Shutdown Server")
54 | // // 等待中断信号以优雅地关闭服务器(设置 5 秒的超时时间)
55 | // quit := make(chan os.Signal)
56 | // signal.Notify(quit, os.Interrupt)
57 | // <-quit
58 | // log.Println("Shutdown Server ...")
59 | //
60 | // ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
61 | // defer cancel()
62 | // if err := srv.Shutdown(ctx); err != nil {
63 | // log.Fatal("Server Shutdown:", err)
64 | // }
65 | // log.Println("Server exiting")
66 | //}
67 |
68 | func main() {
69 |
70 | /*
71 | log.Println("Starting...")
72 |
73 | c := cron.New()
74 | c.AddFunc("0 0 0 *", func() {
75 | log.Println("Run models.PullRelease...")
76 | models.PullRelease()
77 | })
78 |
79 | c.Start()
80 |
81 | t1 := time.NewTimer(time.Second * 10)
82 | for {
83 | select {
84 | case <-t1.C:
85 | t1.Reset(time.Second * 10)
86 | }
87 | }
88 | */
89 | cmd.Execute()
90 | }
91 |
--------------------------------------------------------------------------------
/tools/gofile/file.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 syncd Author. All Rights Reserved.
2 | // Use of this source code is governed by a MIT-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package gofile
6 |
7 | import (
8 | "bufio"
9 | "io"
10 | "io/ioutil"
11 | "os"
12 | "strings"
13 | )
14 |
15 | func CreateFile(filePath string, data []byte, perm os.FileMode) error {
16 | return ioutil.WriteFile(filePath, data, perm)
17 | }
18 |
19 | func ReadlineAddHead(filePath string, headstr string) error {
20 | var result string
21 | f, err := os.Open(filePath)
22 | if err != nil {
23 | return err
24 | }
25 | defer f.Close()
26 | rd := bufio.NewReader(f)
27 | for {
28 | line, err := rd.ReadString('\n')
29 | line = strings.Replace(line,"\r","",-1)
30 | line = strings.Replace(line,"\n","",-1)
31 | //fmt.Println(line)
32 | result += headstr + " " + string(line) + "\n"
33 | if err != nil || io.EOF == err {
34 | break
35 | }
36 | }
37 |
38 | fw, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)//os.O_TRUNC清空文件重新写入,否则原文件内容可能残留
39 | w := bufio.NewWriter(fw)
40 | w.WriteString(result)
41 | if err != nil {
42 | return err
43 | }
44 | w.Flush()
45 | return err
46 | }
47 |
48 | func ReadlineAddafter(filePath string, afterstr string) error {
49 | var result string
50 | f, err := os.Open(filePath)
51 | if err != nil {
52 | return err
53 | }
54 | defer f.Close()
55 | rd := bufio.NewReader(f)
56 | for {
57 | line, err := rd.ReadString('\n')
58 | line = strings.Replace(line,"\r","",-1)
59 | line = strings.Replace(line,"\n","",-1)
60 | //fmt.Println(line)
61 | result += string(line) + " " + afterstr + "\n"
62 | if err != nil || io.EOF == err {
63 | break
64 | }
65 | }
66 |
67 | fw, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)//os.O_TRUNC清空文件重新写入,否则原文件内容可能残留
68 | w := bufio.NewWriter(fw)
69 | w.WriteString(result)
70 | if err != nil {
71 | return err
72 | }
73 | w.Flush()
74 | return err
75 | }
--------------------------------------------------------------------------------
/router/releasecicd_router.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "vAdmin/apis/releasecicd"
6 | "vAdmin/middleware"
7 | jwt "vAdmin/pkg/jwtauth"
8 | )
9 |
10 | //业务 需要认证的路由
11 | func registerReleasecicdRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
12 |
13 | r := v1.Group("/releasecicd").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
14 | {
15 | r.GET("/:id", releasecicd.GetReleasecicd)
16 | r.POST("", releasecicd.InsertReleasecicd)
17 | r.PUT("", releasecicd.UpdateReleasecicd)
18 | r.DELETE("/:id", releasecicd.DeleteReleasecicd)
19 | }
20 |
21 | l := v1.Group("").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
22 | {
23 | l.GET("/releasecicdList",releasecicd.GetReleasecicdList)
24 | l.GET("/pageList",releasecicd.GetPageList)
25 | }
26 |
27 | }
28 |
29 | func registerReleaseridRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
30 |
31 | l := v1.Group("").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
32 | {
33 | l.GET("/releaseridList",releasecicd.GetRidList)
34 | }
35 |
36 | }
37 |
38 | func registerReleasetodoRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
39 |
40 | r := v1.Group("/releasetodo").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
41 | {
42 | r.PUT("", releasecicd.UpdateReleasetodo)
43 | }
44 |
45 | l := v1.Group("").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
46 | {
47 | l.GET("/releasetodoList",releasecicd.GetReleasetodolist)
48 | }
49 |
50 | }
51 |
52 | func registerReleaseStgRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
53 |
54 | l := v1.Group("").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
55 | {
56 | l.GET("/releasestgList",releasecicd.GetReleaseStglist)
57 | }
58 |
59 | }
60 |
61 | /*
62 | func registerReleaseChartRouter(v1 *gin.RouterGroup,authMiddleware *jwt.GinJWTMiddleware) {
63 | c := v1.Group("releasechart").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
64 |
65 | {
66 | c.GET("/deploybyday",releasecicd.GetDeployByDay)
67 | c.GET("/deploybyhour",releasecicd.GetDeployByHour)
68 | }
69 | }
70 | */
--------------------------------------------------------------------------------
/pkg/ldap/search.go:
--------------------------------------------------------------------------------
1 | package ldap
2 |
3 | import (
4 | "encoding/json"
5 | "errors"
6 | orm "vAdmin/database"
7 | "vAdmin/models/system"
8 | "vAdmin/pkg/logger"
9 | "fmt"
10 |
11 | "github.com/go-ldap/ldap/v3"
12 | "github.com/spf13/viper"
13 | )
14 |
15 | /*
16 | @Author : Rongxin Linghu
17 | */
18 |
19 | func getLdapFields() (ldapFields []map[string]string, err error) {
20 | var (
21 | settingsValue system.Settings
22 | contentList []map[string]string
23 | )
24 |
25 | err = orm.Eloquent.Model(&settingsValue).Where("classify = 2").Find(&settingsValue).Error
26 | if err != nil {
27 | return
28 | }
29 |
30 | err = json.Unmarshal(settingsValue.Content, &contentList)
31 | if err != nil {
32 | return
33 | }
34 |
35 | for _, v := range contentList {
36 | if v["ldap_field_name"] != "" {
37 | ldapFields = append(ldapFields, v)
38 | }
39 | }
40 | return
41 | }
42 |
43 | func searchRequest(username string) (userInfo *ldap.Entry, err error) {
44 | var (
45 | ldapFields []map[string]string
46 | cur *ldap.SearchResult
47 | ldapFieldsFilter = []string{
48 | "dn",
49 | }
50 | )
51 | ldapFields, err = getLdapFields()
52 | for _, v := range ldapFields {
53 | ldapFieldsFilter = append(ldapFieldsFilter, v["ldap_field_name"])
54 | }
55 | // 用来获取查询权限的用户。如果 ldap 禁止了匿名查询,那我们就需要先用这个帐户 bind 以下才能开始查询
56 | if !viper.GetBool("settings.ldap.anonymousQuery") {
57 | err = conn.Bind(
58 | viper.GetString("settings.ldap.bindUserDn"),
59 | viper.GetString("settings.ldap.bindPwd"))
60 | if err != nil {
61 | logger.Error("用户或密码错误。", err)
62 | return
63 | }
64 | }
65 |
66 | sql := ldap.NewSearchRequest(
67 | viper.GetString("settings.ldap.baseDn"),
68 | ldap.ScopeWholeSubtree,
69 | ldap.DerefAlways,
70 | 0,
71 | 0,
72 | false,
73 | fmt.Sprintf("(%v=%v)", viper.GetString("settings.ldap.userField"), username),
74 | ldapFieldsFilter,
75 | nil)
76 |
77 | if cur, err = conn.Search(sql); err != nil {
78 | err = errors.New(fmt.Sprintf("在Ldap搜索用户失败, %v", err))
79 | logger.Error(err)
80 | return
81 | }
82 |
83 | if len(cur.Entries) == 0 {
84 | err = errors.New("未查询到对应的用户信息。")
85 | logger.Error(err)
86 | return
87 | }
88 |
89 | userInfo = cur.Entries[0]
90 |
91 | return
92 | }
93 |
--------------------------------------------------------------------------------
/apis/article/article.go:
--------------------------------------------------------------------------------
1 | package article
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/gin-gonic/gin/binding"
6 | "vAdmin/models"
7 | "vAdmin/tools"
8 | "vAdmin/tools/app"
9 | "vAdmin/tools/app/msg"
10 | "strconv"
11 | )
12 |
13 | func GetArticleList(c *gin.Context) {
14 | var data models.Article
15 | var err error
16 | var pageSize = 10
17 | var pageIndex = 1
18 |
19 | if size := c.Request.FormValue("pageSize"); size != "" {
20 | pageSize = tools.StrToInt(err, size)
21 | }
22 | if index := c.Request.FormValue("pageIndex"); index != "" {
23 | pageIndex = tools.StrToInt(err, index)
24 | }
25 |
26 | s, err := strconv.Atoi(c.Request.FormValue("articleId"))
27 | data.ArticleId = s
28 | //data.ArticleId = tools.StrToInt(err, c.Request.FormValue("articleId"))
29 | data.Title = c.Request.FormValue("title")
30 | data.Author = c.Request.FormValue("author")
31 |
32 |
33 | data.DataScope = tools.GetUserIdStr(c)
34 | result, count, err := data.GetPage(pageSize, pageIndex)
35 | tools.HasError(err, "", -1)
36 |
37 | app.PageOK(c, result, count, pageIndex, pageSize, "")
38 | }
39 |
40 | func GetArticle(c *gin.Context) {
41 | var data models.Article
42 | data.ArticleId, _ = tools.StringToInt(c.Param("articleId"))
43 | result, err := data.Get()
44 | tools.HasError(err, "抱歉未找到相关信息", -1)
45 |
46 | app.OK(c, result, "")
47 | }
48 |
49 | func InsertArticle(c *gin.Context) {
50 | var data models.Article
51 | err := c.ShouldBindJSON(&data)
52 | data.CreateBy = tools.GetUserIdStr(c)
53 | tools.HasError(err, "", 500)
54 | result, err := data.Create()
55 | tools.HasError(err, "", -1)
56 | app.OK(c, result, "")
57 | }
58 |
59 | func UpdateArticle(c *gin.Context) {
60 | var data models.Article
61 | err := c.BindWith(&data, binding.JSON)
62 | tools.HasError(err, "数据解析失败", -1)
63 | data.UpdateBy = tools.GetUserIdStr(c)
64 | result, err := data.Update(data.ArticleId)
65 | tools.HasError(err, "", -1)
66 |
67 | app.OK(c, result, "")
68 | }
69 |
70 | func DeleteArticle(c *gin.Context) {
71 | var data models.Article
72 | data.UpdateBy = tools.GetUserIdStr(c)
73 |
74 | IDS := tools.IdsStrToIdsIntGroup("articleId", c)
75 | _, err := data.BatchDelete(IDS)
76 | tools.HasError(err, msg.DeletedFail, 500)
77 | app.OK(c, nil, msg.DeletedSuccess)
78 | }
--------------------------------------------------------------------------------
/models/tools/dbcolumns.go:
--------------------------------------------------------------------------------
1 | package tools
2 |
3 | import (
4 | "errors"
5 | orm "vAdmin/database"
6 | config2 "vAdmin/tools/config"
7 | )
8 |
9 | type DBColumns struct {
10 | TableSchema string `gorm:"column:TABLE_SCHEMA" json:"tableSchema"`
11 | TableName string `gorm:"column:TABLE_NAME" json:"tableName"`
12 | ColumnName string `gorm:"column:COLUMN_NAME" json:"columnName"`
13 | ColumnDefault string `gorm:"column:COLUMN_DEFAULT" json:"columnDefault"`
14 | IsNullable string `gorm:"column:IS_NULLABLE" json:"isNullable"`
15 | DataType string `gorm:"column:DATA_TYPE" json:"dataType"`
16 | CharacterMaximumLength string `gorm:"column:CHARACTER_MAXIMUM_LENGTH" json:"characterMaximumLength"`
17 | CharacterSetName string `gorm:"column:CHARACTER_SET_NAME" json:"characterSetName"`
18 | ColumnType string `gorm:"column:COLUMN_TYPE" json:"columnType"`
19 | ColumnKey string `gorm:"column:COLUMN_KEY" json:"columnKey"`
20 | Extra string `gorm:"column:EXTRA" json:"extra"`
21 | ColumnComment string `gorm:"column:COLUMN_COMMENT" json:"columnComment"`
22 | }
23 |
24 | func (e *DBColumns) GetPage(pageSize int, pageIndex int) ([]DBColumns, int, error) {
25 | var doc []DBColumns
26 |
27 | table := orm.Eloquent.Select("*").Table("information_schema.`COLUMNS`")
28 | table = table.Where("table_schema= ? ", config2.MysqlConfig.Name)
29 |
30 | if e.TableName != "" {
31 | return nil, 0, errors.New("table name cannot be empty!")
32 | }
33 |
34 | table = table.Where("TABLE_NAME = ?", e.TableName)
35 |
36 | var count int
37 |
38 | if err := table.Offset((pageIndex - 1) * pageSize).Limit(pageSize).Find(&doc).Error; err != nil {
39 | return nil, 0, err
40 | }
41 | table.Count(&count)
42 | return doc, count, nil
43 | }
44 |
45 | func (e *DBColumns) GetList() ([]DBColumns, error) {
46 | var doc []DBColumns
47 |
48 | table := orm.Eloquent.Select("*").Table("information_schema.columns")
49 | table = table.Where("table_schema= ? ", config2.MysqlConfig.Name)
50 |
51 | if e.TableName == "" {
52 | return nil, errors.New("table name cannot be empty!")
53 | }
54 |
55 | table = table.Where("TABLE_NAME = ?", e.TableName)
56 |
57 | if err := table.Find(&doc).Error; err != nil {
58 | return doc, err
59 | }
60 | return doc, nil
61 | }
62 |
--------------------------------------------------------------------------------
/apis/common/hook.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 syncd Author. All Rights Reserved.
2 | // Use of this source code is governed by a MIT-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package common
6 |
7 | import (
8 | "fmt"
9 | "io/ioutil"
10 | "vAdmin/module/deploy"
11 | "vAdmin/tools/command"
12 | "vAdmin/tools/gofile"
13 | "vAdmin/tools/gostring"
14 | )
15 |
16 | func HookDeploy(applyId int) {
17 | apply := &deploy.Apply{
18 | ID: applyId,
19 | }
20 | if err := apply.Detail(); err != nil {
21 | return
22 | }
23 | if apply.CommitVersion == "" {
24 | return
25 | }
26 |
27 | tmpFile := gostring.JoinStrings("/tmp", "/", gostring.StrRandom(24), ".log")
28 | if err := gofile.CreateFile(tmpFile, []byte(apply.CommitVersion), 0744); err != nil {
29 | fmt.Println("apply.CommitVersion tmp file create failed, err[%s], apply_id[%d]", err.Error(), applyId)
30 | return
31 | }
32 | if err := gofile.ReadlineAddHead(tmpFile,"ls"); err != nil {
33 | fmt.Println("read file change failed, err[%s], apply_id[%d]", err.Error(), applyId)
34 | return
35 | }
36 |
37 | var deployCmd string
38 | data, err := ioutil.ReadFile(tmpFile)
39 | if err != nil {
40 | fmt.Println(err)
41 | } else {
42 | //fmt.Println(string(data))
43 | deployCmd = string(data)
44 | }
45 |
46 | var deployStatus int
47 | if apply.Status == deploy.APPLY_STATUS_SUCCESS {
48 | deployStatus = 1
49 | }
50 |
51 | s := gostring.JoinStrings(
52 | "#!/bin/bash\n\n",
53 | "#--------- deploy hook scripts env ---------\n",
54 | fmt.Sprintf("env_apply_id=%d\n", apply.ID),
55 | fmt.Sprintf("env_apply_name=%s\n", apply.DemandId),
56 | fmt.Sprintf("env_deploy_status=%d\n", deployStatus),
57 | deployCmd,
58 | )
59 | hookCommandTaskRun(s, applyId)
60 | }
61 |
62 | func hookCommandTaskRun(s string, applyId int) {
63 | scriptFile := gostring.JoinStrings("/tmp", "/", gostring.StrRandom(24), ".sh")
64 | if err := gofile.CreateFile(scriptFile, []byte(s), 0744); err != nil {
65 | fmt.Println("hook script file create failed, err[%s], apply_id[%d]", err.Error(), applyId)
66 | return
67 | }
68 | cmds := []string{
69 | fmt.Sprintf("/bin/bash -c %s", scriptFile),
70 | //fmt.Sprintf("rm -f %s", scriptFile),
71 | }
72 | task := command.NewTask(cmds, 86400)
73 | task.Run()
74 | if err := task.GetError(); err != nil {
75 | fmt.Println("hook script run failed, err[%s], output[%s], apply_id[%d]", err.Error(), gostring.JsonEncode(task.Result()), applyId)
76 | }
77 | }
--------------------------------------------------------------------------------
/database/mysql.go:
--------------------------------------------------------------------------------
1 | package database
2 |
3 | import (
4 | "bytes"
5 | _ "github.com/go-sql-driver/mysql" //加载mysql
6 | "github.com/jinzhu/gorm"
7 | "vAdmin/tools/config"
8 | "log"
9 | "strconv"
10 | )
11 |
12 | var Eloquent *gorm.DB
13 |
14 | var (
15 | DbType string
16 | Host string
17 | Port int
18 | Name string
19 | Username string
20 | Password string
21 | MaxIdleConns int
22 | MaxOpenConns int
23 |
24 | )
25 |
26 | func SetupMysql() {
27 |
28 | DbType = config.MysqlConfig.Dbtype
29 | Host = config.MysqlConfig.Host
30 | Port = config.MysqlConfig.Port
31 | Name = config.MysqlConfig.Name
32 | Username = config.MysqlConfig.Username
33 | Password = config.MysqlConfig.Password
34 | MaxIdleConns = config.MysqlConfig.MaxIdleConns
35 | MaxOpenConns = config.MysqlConfig.MaxOpenConns
36 |
37 | if DbType != "mysql" {
38 | log.Println("db type unknow")
39 | }
40 | var err error
41 |
42 | conn := GetMysqlConnect()
43 |
44 | log.Println(conn)
45 |
46 | var db Database
47 | if DbType == "mysql" {
48 | db = new(Mysql)
49 | Eloquent, err = db.Open(DbType, conn)
50 |
51 | } else {
52 | panic("db type unknow")
53 | }
54 | if err != nil {
55 | log.Fatalf("%s connect error %v", DbType, err)
56 | } else {
57 | log.Printf("%s connect success!", DbType)
58 | }
59 |
60 |
61 | if Eloquent.Error != nil {
62 | log.Fatalf("database error %v", Eloquent.Error)
63 | }
64 |
65 | Eloquent.LogMode(true)
66 | }
67 |
68 | func GetMysqlConnect() string {
69 | var conn bytes.Buffer
70 | conn.WriteString(Username)
71 | conn.WriteString(":")
72 | conn.WriteString(Password)
73 | conn.WriteString("@tcp(")
74 | conn.WriteString(Host)
75 | conn.WriteString(":")
76 | conn.WriteString(strconv.Itoa(Port))
77 | conn.WriteString(")")
78 | conn.WriteString("/")
79 | conn.WriteString(Name)
80 | conn.WriteString("?charset=utf8&parseTime=True&loc=Local&timeout=1000ms")
81 | return conn.String()
82 | }
83 |
84 | type Database interface {
85 | Open(dbType string, conn string) (db *gorm.DB, err error)
86 | }
87 |
88 | type Mysql struct {
89 | }
90 |
91 | func (*Mysql) Open(dbType string, conn string) (db *gorm.DB, err error) {
92 | eloquent, err := gorm.Open(dbType, conn)
93 | return eloquent, err
94 | }
95 |
96 | type SqlLite struct {
97 | }
98 |
99 | func (*SqlLite) Open(dbType string, conn string) (db *gorm.DB, err error) {
100 | eloquent, err := gorm.Open(dbType, conn)
101 | return eloquent, err
102 | }
103 |
--------------------------------------------------------------------------------
/tools/command/command.go:
--------------------------------------------------------------------------------
1 | // Copyright 2018 syncd Author. All Rights Reserved.
2 | // Use of this source code is governed by a MIT-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package command
6 |
7 | import (
8 | "bytes"
9 | "errors"
10 | "fmt"
11 | "os/exec"
12 | "strings"
13 | "time"
14 | )
15 |
16 | const (
17 | DEFAULT_RUM_TIMEOUT = 3600
18 | )
19 |
20 | type Command struct {
21 | Cmd string
22 | Timeout time.Duration
23 | TerminateChan chan int
24 | Setpgid bool
25 | command *exec.Cmd
26 | stdout bytes.Buffer
27 | stderr bytes.Buffer
28 | }
29 |
30 | func NewCmd(c *Command) (*Command, error) {
31 | if c.Timeout == 0 * time.Second {
32 | c.Timeout = DEFAULT_RUM_TIMEOUT * time.Second
33 | }
34 | if c.TerminateChan == nil {
35 | c.TerminateChan = make(chan int)
36 | }
37 | cmd := exec.Command("/bin/bash", "-c", c.Cmd)
38 | /*
39 | if c.Setpgid {
40 | cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
41 | }
42 | */
43 | cmd.Stderr = &c.stderr
44 | cmd.Stdout = &c.stdout
45 | c.command = cmd
46 |
47 | return c, nil
48 | }
49 |
50 | func (c *Command) Run() error {
51 | if err := c.command.Start(); err != nil {
52 | return err
53 | }
54 |
55 | errChan := make(chan error)
56 | go func(){
57 | errChan <- c.command.Wait()
58 | defer close(errChan)
59 | }()
60 |
61 | var err error
62 | select {
63 | case err = <-errChan:
64 | case <-time.After(c.Timeout):
65 | err = c.terminate()
66 | if err == nil {
67 | err = errors.New(fmt.Sprintf("cmd run timeout, cmd [%s], time[%v]", c.Cmd, c.Timeout))
68 | }
69 | case <-c.TerminateChan:
70 | err = c.terminate()
71 | if err == nil {
72 | err = errors.New(fmt.Sprintf("cmd is terminated, cmd [%s]", c.Cmd))
73 | }
74 | }
75 | return err
76 | }
77 |
78 | func (c *Command) Stderr() string {
79 | return strings.TrimSpace(string(c.stderr.Bytes()))
80 | }
81 |
82 | func (c *Command) Stdout() string {
83 | return strings.TrimSpace(string(c.stdout.Bytes()))
84 | }
85 |
86 | func (c *Command) terminate() error {
87 | /*
88 | if c.Setpgid {
89 | return syscall.Kill(-c.command.Process.Pid, syscall.SIGKILL)
90 | } else {
91 | return syscall.Kill(c.command.Process.Pid, syscall.SIGKILL)
92 | }
93 | */
94 | return nil
95 | }
--------------------------------------------------------------------------------
/tools/utils.go:
--------------------------------------------------------------------------------
1 | package tools
2 |
3 | import (
4 | "golang.org/x/crypto/bcrypt"
5 | "log"
6 | "strconv"
7 | )
8 |
9 | func StrToInt(err error, index string) int {
10 | result, err := strconv.Atoi(index)
11 | if err != nil {
12 | HasError(err, "string to int error"+err.Error(), -1)
13 | }
14 | return result
15 | }
16 |
17 | /*
18 | bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password))
19 | Must be the already hashed PW ^ ^ Plain Text Password to compare
20 | */
21 | func CompareHashAndPassword(e string, p string) (bool, error) {
22 |
23 | byteHash := []byte(e) // e: hashedPassword
24 | plainPwd := []byte(p)
25 | log.Println("vvvvvvvvvvvvvvvvvvvvvvv--->hashedPassword", e)
26 | log.Println("vvvvvvvvvvvvvvvvvvvvvvv--->PlainPassword", p)
27 | err := bcrypt.CompareHashAndPassword(byteHash, plainPwd)
28 | if err != nil {
29 | log.Println(err.Error())
30 | return false, err
31 | }
32 | return true, nil
33 | }
34 |
35 | func CompareHashAndPassword2(e string, p string) (bool, error) {
36 |
37 | hash, err := bcrypt.GenerateFromPassword([]byte(e), bcrypt.DefaultCost) //加密处理
38 | if err != nil {
39 | log.Println(err)
40 | }
41 | encodePWD := string(hash) // 保存在数据库的密码,虽然每次生成都不同,只需保存一份即可
42 |
43 | byteHash := []byte(encodePWD) // e: hashedPassword
44 | plainPwd := []byte(p)
45 | log.Println("vvvvvvvvvvvvvvvvvvvvvvv--->hashedPassword", encodePWD)
46 | log.Println("vvvvvvvvvvvvvvvvvvvvvvv--->PlainPassword", p)
47 | err = bcrypt.CompareHashAndPassword(byteHash, plainPwd)
48 | if err != nil {
49 | log.Println(err.Error())
50 | return false, err
51 | }
52 | return true, nil
53 | }
54 |
55 | /*
56 | func CompareHashAndPassword(e string, p []byte) (bool, error) {
57 |
58 | byteHash := []byte(e)
59 | err := bcrypt.CompareHashAndPassword(byteHash, p)
60 | if err != nil {
61 | log.Print(err.Error())
62 | return false, err
63 | }
64 | return true, nil
65 | }
66 | */
67 |
68 | // Assert 条件断言
69 | // 当断言条件为 假 时触发 panic
70 | // 对于当前请求不会再执行接下来的代码,并且返回指定格式的错误信息和错误码
71 | func Assert(condition bool, msg string, code ...int) {
72 | if !condition {
73 | statusCode := 200
74 | if len(code) > 0 {
75 | statusCode = code[0]
76 | }
77 | panic("CustomError#" + strconv.Itoa(statusCode) + "#" + msg)
78 | }
79 | }
80 |
81 | // HasError 错误断言
82 | // 当 error 不为 nil 时触发 panic
83 | // 对于当前请求不会再执行接下来的代码,并且返回指定格式的错误信息和错误码
84 | // 若 msg 为空,则默认为 error 中的内容
85 | func HasError(err error, msg string, code ...int) {
86 | if err != nil {
87 | statusCode := 200
88 | if len(code) > 0 {
89 | statusCode = code[0]
90 | }
91 | if msg == "" {
92 | msg = err.Error()
93 | }
94 | log.Println(err)
95 | panic("CustomError#" + strconv.Itoa(statusCode) + "#" + msg)
96 | }
97 | }
--------------------------------------------------------------------------------
/apis/system/config.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/gin-gonic/gin/binding"
6 | "vAdmin/models"
7 | "vAdmin/tools"
8 | "vAdmin/tools/app"
9 | "vAdmin/tools/app/msg"
10 | "net/http"
11 | )
12 |
13 | func GetConfigList(c *gin.Context) {
14 | var data models.SysConfig
15 | var err error
16 | var pageSize = 10
17 | var pageIndex = 1
18 |
19 | if size := c.Request.FormValue("pageSize"); size != "" {
20 | pageSize = tools.StrToInt(err, size)
21 | }
22 |
23 | if index := c.Request.FormValue("pageIndex"); index != "" {
24 | pageIndex = tools.StrToInt(err, index)
25 | }
26 |
27 | data.ConfigKey = c.Request.FormValue("configKey")
28 | data.ConfigName = c.Request.FormValue("configName")
29 | data.ConfigType = c.Request.FormValue("configType")
30 | data.DataScope = tools.GetUserIdStr(c)
31 | result, count, err := data.GetPage(pageSize, pageIndex)
32 | tools.HasError(err, "", -1)
33 |
34 | var mp = make(map[string]interface{}, 3)
35 | mp["list"] = result
36 | mp["count"] = count
37 | mp["pageIndex"] = pageIndex
38 | mp["pageSize"] = pageSize
39 |
40 | var res app.Response
41 | res.Data = mp
42 |
43 | c.JSON(http.StatusOK, res.ReturnOK())
44 | }
45 |
46 | func GetConfig(c *gin.Context) {
47 | var Config models.SysConfig
48 | Config.ConfigId, _ = tools.StringToInt(c.Param("configId"))
49 | result, err := Config.Get()
50 | tools.HasError(err, "抱歉未找到相关信息", -1)
51 |
52 | var res app.Response
53 | res.Data = result
54 |
55 | c.JSON(http.StatusOK, res.ReturnOK())
56 | }
57 |
58 |
59 | func GetConfigByConfigKey(c *gin.Context) {
60 | var Config models.SysConfig
61 | Config.ConfigKey = c.Param("configKey")
62 | result, err := Config.Get()
63 | tools.HasError(err, "抱歉未找到相关信息", -1)
64 |
65 | app.OK(c, result,result.ConfigValue)
66 | }
67 |
68 | func InsertConfig(c *gin.Context) {
69 | var data models.SysConfig
70 | err := c.BindWith(&data, binding.JSON)
71 | data.CreateBy = tools.GetUserIdStr(c)
72 | tools.HasError(err, "", 500)
73 | result, err := data.Create()
74 | tools.HasError(err, "", -1)
75 |
76 | app.OK(c, result,"")
77 | }
78 |
79 | func UpdateConfig(c *gin.Context) {
80 | var data models.SysConfig
81 | err := c.BindWith(&data, binding.JSON)
82 | tools.HasError(err, "数据解析失败", -1)
83 | data.UpdateBy = tools.GetUserIdStr(c)
84 | result, err := data.Update(data.ConfigId)
85 | tools.HasError(err, "", -1)
86 | app.OK(c, result,"")
87 | }
88 |
89 | func DeleteConfig(c *gin.Context) {
90 | var data models.SysConfig
91 | data.UpdateBy = tools.GetUserIdStr(c)
92 | IDS := tools.IdsStrToIdsIntGroup("configId", c)
93 | result, err := data.BatchDelete(IDS)
94 | tools.HasError(err, "修改失败", 500)
95 | app.OK(c, result, msg.DeletedSuccess)
96 | }
97 |
98 |
99 |
--------------------------------------------------------------------------------
/apis/deploy/deploytask.go:
--------------------------------------------------------------------------------
1 | package deploy
2 |
3 | import (
4 | "sync"
5 | "errors"
6 | "fmt"
7 | )
8 |
9 | type deployTask struct {
10 | deploys map[int][]*Deploy
11 | mu sync.Mutex
12 | }
13 |
14 | type CallbackFn func(int, int, int, []*ServerResult)
15 |
16 | type TaskCallbackFn func(int, int)
17 |
18 | var task = &deployTask{
19 | deploys: map[int][]*Deploy{},
20 | }
21 |
22 | func NewTask(id int, mode string, deploys []*Deploy, startFn, finishFn CallbackFn, taskFn TaskCallbackFn) error {
23 | if exists := task.exists(id); exists {
24 | return errors.New(fmt.Sprintf("deploy task [id: %d] have exists", id))
25 | }
26 | task.append(id, deploys)
27 | go func() {
28 | taskStatus := STATUS_DONE
29 | for _, deploy := range deploys {
30 | if startFn != nil {
31 | rest, status := deploy.Result()
32 | startFn(id, deploy.ID, status, rest)
33 | }
34 | switch mode {
35 | case DEPLOY_PARALLEL:
36 | deploy.Parallel()
37 | default:
38 | deploy.Serial()
39 | }
40 | resultList, status := deploy.Result()
41 | if finishFn != nil {
42 | finishFn(id, deploy.ID, status, resultList)
43 | }
44 | if status == STATUS_FAILED {
45 | taskStatus = STATUS_FAILED
46 | }
47 | }
48 | task.remove(id)
49 | if taskFn != nil {
50 | taskFn(id, taskStatus)
51 | }
52 | }()
53 | return nil
54 | }
55 |
56 | func StopTask(id int) {
57 | task.stop(id)
58 | }
59 |
60 | func ExistsTask(id int) bool {
61 | return task.exists(id)
62 | }
63 |
64 | func StatusTask(id int) []*DeployResult {
65 | deploys, exists := task.get(id)
66 | if !exists {
67 | return nil
68 | }
69 | rests := []*DeployResult{}
70 | for _, deploy := range deploys {
71 | rest, s := deploy.Result()
72 | rests = append(rests, &DeployResult{
73 | ID: deploy.ID,
74 | Status: s,
75 | ServerRest: rest,
76 | })
77 | }
78 | return rests
79 | }
80 |
81 | func (t *deployTask) exists(id int) bool {
82 | t.mu.Lock()
83 | defer t.mu.Unlock()
84 | _, exists := t.deploys[id]
85 | return exists
86 | }
87 |
88 | func (t *deployTask) append(id int, deploys []*Deploy) {
89 | t.mu.Lock()
90 | defer t.mu.Unlock()
91 | t.deploys[id] = deploys
92 | }
93 |
94 | func (t *deployTask) remove(id int) {
95 | t.mu.Lock()
96 | defer t.mu.Unlock()
97 | delete(t.deploys, id)
98 | }
99 |
100 | func (t *deployTask) get(id int) ([]*Deploy, bool) {
101 | t.mu.Lock()
102 | defer t.mu.Unlock()
103 | deploys, exists := t.deploys[id]
104 | return deploys, exists
105 | }
106 |
107 | func (t *deployTask) stop(id int) {
108 | t.mu.Lock()
109 | defer t.mu.Unlock()
110 | deploys, exists := t.deploys[id]
111 | if exists {
112 | for _, deploy := range deploys {
113 | deploy.Terminate()
114 | }
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/tools/ws/webSocket.go:
--------------------------------------------------------------------------------
1 | package ws
2 | import (
3 | "errors"
4 | "fmt"
5 | "github.com/gorilla/websocket"
6 | "vAdmin/pkg/logger"
7 | "sync"
8 | )
9 |
10 | var once sync.Once
11 |
12 | type Connection struct {
13 | WsConn *websocket.Conn
14 | InChan chan []byte
15 | OutChan chan []byte
16 | CloseReadLoopChan chan struct{}
17 | CloseWriteLoopChan chan struct{}
18 | }
19 |
20 | func InitConnection(wsConn *websocket.Conn) *Connection {
21 | conn := &Connection{
22 | WsConn: wsConn,
23 | InChan: make(chan []byte, 1000),
24 | OutChan: make(chan []byte, 1000),
25 | CloseReadLoopChan: make(chan struct{}, 1),
26 | CloseWriteLoopChan: make(chan struct{}, 1),
27 | }
28 |
29 | go conn.readLoop()
30 | go conn.writeLoop()
31 |
32 | return conn
33 | }
34 |
35 | // API
36 | func (c *Connection) ReadMessage() (data []byte, err error) {
37 | select {
38 | case data = <-c.InChan:
39 | case <-c.CloseReadLoopChan:
40 | c.Close()
41 | c.StopWriteLoop()
42 | err = errors.New("connection is closed, stop read msg")
43 | }
44 | return
45 | }
46 |
47 | func (c *Connection) WriteMessage(data []byte) (err error) {
48 | select {
49 | case c.OutChan <- data:
50 | case <-c.CloseWriteLoopChan:
51 | c.Close()
52 | c.StopReadLoop()
53 | err = errors.New("connection is closed, stop write msg")
54 | }
55 | return
56 | }
57 |
58 | func (c *Connection) Close() {
59 | // websocket 的 Close() 方法是线程安全的,是可重入的。是一个特例,websocket其他的方法不是线程安全的。
60 | once.Do(func() {
61 | c.WsConn.Close()
62 | logger.Error("websocket connect closed")
63 | })
64 | }
65 |
66 | func (c *Connection) StopReadLoop() {
67 | c.CloseReadLoopChan <- struct{}{}
68 | }
69 |
70 | func (c *Connection) StopWriteLoop() {
71 | c.CloseWriteLoopChan <- struct{}{}
72 | }
73 |
74 | // 内部实现
75 | func (c *Connection) readLoop() {
76 | for {
77 | _, data, err := c.WsConn.ReadMessage()
78 | if err != nil {
79 | c.Close()
80 | logger.Error(fmt.Sprintf("read message from websocket error, err: %s", err))
81 | c.StopWriteLoop()
82 | return
83 | }
84 | select {
85 | case c.InChan <- data:
86 | case <-c.CloseReadLoopChan:
87 | logger.Info("end websocket read loop")
88 | return
89 | }
90 | }
91 | }
92 |
93 | func (c *Connection) writeLoop() {
94 | for {
95 | select {
96 | case data := <-c.OutChan:
97 | err := c.WsConn.WriteMessage(websocket.TextMessage, data)
98 | if err != nil {
99 | logger.Error(fmt.Sprintf("write message to websocket error, err: %s", err))
100 | c.Close()
101 | c.StopReadLoop()
102 | return
103 | }
104 | case <-c.CloseWriteLoopChan:
105 | logger.Info("end websocket write loop")
106 | return
107 | }
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/middleware/logger.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/sirupsen/logrus"
6 | "vAdmin/models"
7 | "vAdmin/tools"
8 | "strings"
9 | "time"
10 | )
11 |
12 | //实例化
13 | var logger = logrus.New()
14 |
15 | // 日志记录到文件
16 | func LoggerToFile() gin.HandlerFunc {
17 |
18 | return func(c *gin.Context) {
19 | // 开始时间
20 | startTime := time.Now()
21 |
22 | // 处理请求
23 | c.Next()
24 |
25 | // 结束时间
26 | endTime := time.Now()
27 |
28 | // 执行时间
29 | latencyTime := endTime.Sub(startTime)
30 |
31 | // 请求方式
32 | reqMethod := c.Request.Method
33 |
34 | // 请求路由
35 | reqUri := c.Request.RequestURI
36 |
37 | // 状态码
38 | statusCode := c.Writer.Status()
39 |
40 | // 请求IP
41 | clientIP := c.ClientIP()
42 |
43 | // 日志格式
44 | logger.Infof("%s [%s] %3d %13v %15s %s %s \r\n",
45 | startTime.Format("2006-01-02 15:04:05.9999"),
46 | strings.ToUpper(logger.Level.String()),
47 | statusCode,
48 | latencyTime,
49 | clientIP,
50 | reqMethod,
51 | reqUri,
52 | )
53 |
54 | if c.Request.Method != "GET" && c.Request.Method != "OPTIONS" {
55 | menu := models.Menu{}
56 | menu.Path = reqUri
57 | menu.Action = reqMethod
58 | menuList, _ := menu.Get()
59 | sysOperLog := models.SysOperLog{}
60 | sysOperLog.OperIp = clientIP
61 | sysOperLog.OperLocation = tools.GetLocation(clientIP)
62 | sysOperLog.Status = tools.IntToString(statusCode)
63 | sysOperLog.OperName = tools.GetUserName(c)
64 | sysOperLog.RequestMethod = c.Request.Method
65 | sysOperLog.OperUrl = reqUri
66 | if reqUri == "/login" {
67 | sysOperLog.BusinessType = "10"
68 | sysOperLog.Title = "用户登录"
69 | sysOperLog.OperName = "-"
70 | } else if strings.Contains(reqUri, "/api/v1/logout") {
71 | sysOperLog.BusinessType = "11"
72 | } else if strings.Contains(reqUri, "/api/v1/getCaptcha") {
73 | sysOperLog.BusinessType = "12"
74 | sysOperLog.Title = "验证码"
75 | } else {
76 | if reqMethod == "POST" {
77 | sysOperLog.BusinessType = "1"
78 | } else if reqMethod == "PUT" {
79 | sysOperLog.BusinessType = "2"
80 | } else if reqMethod == "DELETE" {
81 | sysOperLog.BusinessType = "3"
82 | }
83 | }
84 | sysOperLog.Method = reqMethod
85 | if len(menuList) > 0 {
86 | sysOperLog.Title = menuList[0].Title
87 | }
88 | b, _ := c.Get("body")
89 | sysOperLog.OperParam, _ = tools.StructToJsonStr(b)
90 | sysOperLog.CreateBy = tools.GetUserName(c)
91 | sysOperLog.OperTime = tools.GetCurrntTime()
92 | sysOperLog.LatencyTime = (latencyTime).String()
93 | sysOperLog.UserAgent = c.Request.UserAgent()
94 | if c.Err() == nil {
95 | sysOperLog.Status = "0"
96 | } else {
97 | sysOperLog.Status = "1"
98 | }
99 | _, _ = sysOperLog.Create()
100 | }
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/pkg/pagination/pagination.go:
--------------------------------------------------------------------------------
1 | package pagination
2 |
3 | /*
4 | @Author : Rongxin Linghu
5 | */
6 |
7 | import (
8 | "vAdmin/pkg/logger"
9 | "fmt"
10 | "math"
11 |
12 | "github.com/gin-gonic/gin"
13 | "github.com/jinzhu/gorm"
14 | )
15 |
16 | type Param struct {
17 | C *gin.Context
18 | DB *gorm.DB
19 | ShowSQL bool
20 | }
21 |
22 | type Paginator struct {
23 | TotalCount int `json:"total_count"`
24 | TotalPage int `json:"total_page"`
25 | Data interface{} `json:"data"`
26 | PerPage int `json:"per_page"`
27 | Page int `json:"page"`
28 | }
29 |
30 | type ListRequest struct {
31 | Page int `json:"page" form:"page"`
32 | PerPage int `json:"per_page" form:"per_page"`
33 | Sort int `json:"sort" form:"sort"`
34 | }
35 |
36 | // Paging 分页
37 | func Paging(p *Param, result interface{}, args ...interface{}) (*Paginator, error) {
38 | var (
39 | param ListRequest
40 | paginator Paginator
41 | count int
42 | offset int
43 | tableName string
44 | )
45 |
46 | if err := p.C.Bind(¶m); err != nil {
47 | logger.Errorf("参数绑定失败,错误:%v", err)
48 | return nil, err
49 | }
50 |
51 | db := p.DB
52 |
53 | if p.ShowSQL {
54 | db = db.Debug()
55 | }
56 |
57 | if param.Page < 1 {
58 | param.Page = 1
59 | }
60 |
61 | if param.PerPage == 0 {
62 | param.PerPage = 10
63 | }
64 |
65 | if param.Sort == 0 || param.Sort == -1 {
66 | db = db.Order("id desc")
67 | }
68 |
69 | if len(args) > 1 {
70 | tableName = fmt.Sprintf("`%s`.", args[1].(string))
71 | }
72 |
73 | if len(args) > 0 {
74 | for paramType, paramsValue := range args[0].(map[string]map[string]interface{}) {
75 | if paramType == "like" {
76 | for key, value := range paramsValue {
77 | db = db.Where(fmt.Sprintf("%v%v like ?", tableName, key), fmt.Sprintf("%%%v%%", value))
78 | }
79 | } else if paramType == "equal" {
80 | for key, value := range paramsValue {
81 | db = db.Where(fmt.Sprintf("%v%v = ?", tableName, key), value)
82 | }
83 | }
84 | }
85 | }
86 |
87 | done := make(chan bool, 1)
88 |
89 | go countRecords(db, result, done, &count)
90 |
91 | if param.Page == 1 {
92 | offset = 0
93 | } else {
94 | offset = (param.Page - 1) * param.PerPage
95 | }
96 | err := db.Limit(param.PerPage).Offset(offset).Scan(result).Error
97 | if err != nil {
98 | logger.Errorf("数据查询失败,错误:%v", err)
99 | return nil, err
100 | }
101 | <-done
102 |
103 | paginator.TotalCount = count
104 | paginator.Data = result
105 | paginator.Page = param.Page
106 | paginator.PerPage = param.PerPage
107 | paginator.TotalPage = int(math.Ceil(float64(count) / float64(param.PerPage)))
108 |
109 | return &paginator, nil
110 | }
111 |
112 | func countRecords(db *gorm.DB, anyType interface{}, done chan bool, count *int) {
113 | db.Model(anyType).Count(count)
114 | done <- true
115 | }
116 |
--------------------------------------------------------------------------------
/apis/system/dict/dictType.go:
--------------------------------------------------------------------------------
1 | package dict
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/gin-gonic/gin/binding"
6 | "vAdmin/models"
7 | "vAdmin/tools"
8 | "vAdmin/tools/app"
9 | "net/http"
10 | )
11 |
12 | func GetDictTypeList(c *gin.Context) {
13 | var data models.DictType
14 | var err error
15 | var pageSize = 10
16 | var pageIndex = 1
17 |
18 | if size := c.Request.FormValue("pageSize"); size != "" {
19 | pageSize = tools.StrToInt(err, size)
20 | }
21 |
22 | if index := c.Request.FormValue("pageIndex"); index != "" {
23 | pageIndex = tools.StrToInt(err, index)
24 | }
25 |
26 | data.DictName = c.Request.FormValue("dictName")
27 | id := c.Request.FormValue("dictId")
28 | data.DictId, _ = tools.StringToInt(id)
29 | data.DictType = c.Request.FormValue("dictType")
30 | data.DataScope = tools.GetUserIdStr(c)
31 | result, count, err := data.GetPage(pageSize, pageIndex)
32 | tools.HasError(err, "", -1)
33 |
34 | var mp = make(map[string]interface{}, 3)
35 | mp["list"] = result
36 | mp["count"] = count
37 | mp["pageIndex"] = pageIndex
38 | mp["pageSize"] = pageSize
39 |
40 | var res app.Response
41 | res.Data = mp
42 | c.JSON(http.StatusOK, res.ReturnOK())
43 | }
44 |
45 | func GetDictType(c *gin.Context) {
46 | var DictType models.DictType
47 | DictType.DictName = c.Request.FormValue("dictName")
48 | DictType.DictId, _ = tools.StringToInt(c.Param("dictId"))
49 | result, err := DictType.Get()
50 | tools.HasError(err, "抱歉未找到相关信息", -1)
51 | var res app.Response
52 | res.Data = result
53 | c.JSON(http.StatusOK, res.ReturnOK())
54 | }
55 |
56 | func GetDictTypeOptionSelect(c *gin.Context) {
57 | var DictType models.DictType
58 | DictType.DictName = c.Request.FormValue("dictName")
59 | DictType.DictId, _ = tools.StringToInt(c.Param("dictId"))
60 | result, err := DictType.GetList()
61 | tools.HasError(err, "抱歉未找到相关信息", -1)
62 | var res app.Response
63 | res.Data = result
64 | c.JSON(http.StatusOK, res.ReturnOK())
65 | }
66 |
67 | func InsertDictType(c *gin.Context) {
68 | var data models.DictType
69 | err := c.BindWith(&data, binding.JSON)
70 | data.CreateBy = tools.GetUserIdStr(c)
71 | tools.HasError(err, "", 500)
72 | result, err := data.Create()
73 | tools.HasError(err, "", -1)
74 | var res app.Response
75 | res.Data = result
76 | c.JSON(http.StatusOK, res.ReturnOK())
77 | }
78 |
79 | func UpdateDictType(c *gin.Context) {
80 | var data models.DictType
81 | err := c.BindWith(&data, binding.JSON)
82 | data.UpdateBy = tools.GetUserIdStr(c)
83 | tools.HasError(err, "", -1)
84 | result, err := data.Update(data.DictId)
85 | tools.HasError(err, "", -1)
86 | var res app.Response
87 | res.Data = result
88 | c.JSON(http.StatusOK, res.ReturnOK())
89 | }
90 |
91 | func DeleteDictType(c *gin.Context) {
92 | var data models.DictType
93 | data.UpdateBy = tools.GetUserIdStr(c)
94 | IDS := tools.IdsStrToIdsIntGroup("dictId", c)
95 | result, err := data.BatchDelete(IDS)
96 | tools.HasError(err, "修改失败", 500)
97 | app.OK(c, result, "删除成功")
98 | }
99 |
--------------------------------------------------------------------------------
/apis/system/menu.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/gin-gonic/gin/binding"
6 | "vAdmin/models"
7 | "vAdmin/tools"
8 | "vAdmin/tools/app"
9 | )
10 |
11 | func GetMenuList(c *gin.Context) {
12 | var Menu models.Menu
13 | Menu.MenuName = c.Request.FormValue("menuName")
14 | Menu.Visible = c.Request.FormValue("visible")
15 | Menu.Title = c.Request.FormValue("title")
16 | Menu.DataScope = tools.GetUserIdStr(c)
17 | result, err := Menu.SetMenu()
18 | tools.HasError(err, "抱歉未找到相关信息", -1)
19 |
20 | app.OK(c, result, "")
21 | }
22 |
23 | func GetMenu(c *gin.Context) {
24 | var data models.Menu
25 | id, err := tools.StringToInt(c.Param("id"))
26 | data.MenuId = id
27 | result, err := data.GetByMenuId()
28 | tools.HasError(err, "抱歉未找到相关信息", -1)
29 | app.OK(c, result, "")
30 | }
31 |
32 | func GetMenuTreeRoleselect(c *gin.Context) {
33 | var Menu models.Menu
34 | var SysRole models.SysRole
35 | id, err := tools.StringToInt(c.Param("roleId"))
36 | SysRole.RoleId = id
37 | result, err := Menu.SetMenuLable()
38 | tools.HasError(err, "抱歉未找到相关信息", -1)
39 | menuIds := make([]int, 0)
40 | if id != 0 {
41 | menuIds, err = SysRole.GetRoleMeunId()
42 | tools.HasError(err, "抱歉未找到相关信息", -1)
43 | }
44 | app.Custum(c, gin.H{
45 | "code": 200,
46 | "menus": result,
47 | "checkedKeys": menuIds,
48 | })
49 | }
50 |
51 | func GetMenuTreeelect(c *gin.Context) {
52 | var data models.Menu
53 | result, err := data.SetMenuLable()
54 | tools.HasError(err, "抱歉未找到相关信息", -1)
55 | app.OK(c, result, "")
56 | }
57 |
58 | func InsertMenu(c *gin.Context) {
59 | var data models.Menu
60 | err := c.BindWith(&data, binding.JSON)
61 | tools.HasError(err, "抱歉未找到相关信息", -1)
62 | data.CreateBy = tools.GetUserIdStr(c)
63 | result, err := data.Create()
64 | tools.HasError(err, "抱歉未找到相关信息", -1)
65 | app.OK(c, result, "")
66 | }
67 |
68 | func UpdateMenu(c *gin.Context) {
69 | var data models.Menu
70 | err2 := c.BindWith(&data, binding.JSON)
71 | data.UpdateBy = tools.GetUserIdStr(c)
72 | tools.HasError(err2, "修改失败", -1)
73 | _, err := data.Update(data.MenuId)
74 | tools.HasError(err, "", 501)
75 | app.OK(c, "", "修改成功")
76 |
77 | }
78 |
79 |
80 | func DeleteMenu(c *gin.Context) {
81 | var data models.Menu
82 | id, err := tools.StringToInt(c.Param("id"))
83 | data.UpdateBy = tools.GetUserIdStr(c)
84 | _, err = data.Delete(id)
85 | tools.HasError(err, "删除失败", 500)
86 | app.OK(c, "", "删除成功")
87 | }
88 |
89 | func GetMenuRole(c *gin.Context) {
90 | var Menu models.Menu
91 | result, err := Menu.SetMenuRole(tools.GetRoleName(c))
92 | tools.HasError(err, "获取失败", 500)
93 | app.OK(c, result, "")
94 | }
95 |
96 | func GetMenuIDS(c *gin.Context) {
97 | var data models.RoleMenu
98 | data.RoleName = c.GetString("role")
99 | data.UpdateBy = tools.GetUserIdStr(c)
100 | result, err := data.GetIDS()
101 | tools.HasError(err, "获取失败", 500)
102 | app.OK(c, result, "")
103 | }
104 |
--------------------------------------------------------------------------------
/apis/system/dict/dictData.go:
--------------------------------------------------------------------------------
1 | package dict
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/gin-gonic/gin/binding"
6 | "vAdmin/models"
7 | "vAdmin/tools"
8 | "vAdmin/tools/app"
9 | "net/http"
10 | )
11 |
12 | func GetDictDataList(c *gin.Context) {
13 | var data models.DictData
14 | var err error
15 | var pageSize = 10
16 | var pageIndex = 1
17 |
18 | if size := c.Request.FormValue("pageSize"); size != "" {
19 | pageSize = tools.StrToInt(err, size)
20 | }
21 |
22 | if index := c.Request.FormValue("pageIndex"); index != "" {
23 | pageIndex = tools.StrToInt(err, index)
24 | }
25 |
26 | data.DictLabel = c.Request.FormValue("dictLabel")
27 | data.Status = c.Request.FormValue("status")
28 | data.DictType = c.Request.FormValue("dictType")
29 | id := c.Request.FormValue("dictCode")
30 | data.DictCode, _ = tools.StringToInt(id)
31 | data.DataScope = tools.GetUserIdStr(c)
32 | result, count, err := data.GetPage(pageSize, pageIndex)
33 | tools.HasError(err, "", -1)
34 |
35 | var mp = make(map[string]interface{}, 3)
36 | mp["list"] = result
37 | mp["count"] = count
38 | mp["pageIndex"] = pageIndex
39 | mp["pageSize"] = pageSize
40 |
41 | var res app.Response
42 | res.Data = mp
43 |
44 | c.JSON(http.StatusOK, res.ReturnOK())
45 | }
46 |
47 | func GetDictData(c *gin.Context) {
48 | var DictData models.DictData
49 | DictData.DictLabel = c.Request.FormValue("dictLabel")
50 | DictData.DictCode, _ = tools.StringToInt(c.Param("dictCode"))
51 | result, err := DictData.GetByCode()
52 | tools.HasError(err, "抱歉未找到相关信息", -1)
53 | var res app.Response
54 | res.Data = result
55 | c.JSON(http.StatusOK, res.ReturnOK())
56 | }
57 |
58 | func GetDictDataByDictType(c *gin.Context) {
59 | var DictData models.DictData
60 | DictData.DictType = c.Param("dictType")
61 | result, err := DictData.Get()
62 | tools.HasError(err, "抱歉未找到相关信息", -1)
63 |
64 | var res app.Response
65 | res.Data = result
66 | c.JSON(http.StatusOK, res.ReturnOK())
67 | }
68 |
69 | func InsertDictData(c *gin.Context) {
70 | var data models.DictData
71 | err := c.BindWith(&data, binding.JSON)
72 | data.CreateBy = tools.GetUserIdStr(c)
73 | tools.HasError(err, "", 500)
74 | result, err := data.Create()
75 | tools.HasError(err, "", -1)
76 | var res app.Response
77 | res.Data = result
78 | c.JSON(http.StatusOK, res.ReturnOK())
79 | }
80 |
81 | func UpdateDictData(c *gin.Context) {
82 | var data models.DictData
83 | err := c.BindWith(&data, binding.JSON)
84 | data.UpdateBy = tools.GetUserIdStr(c)
85 | tools.HasError(err, "", -1)
86 | result, err := data.Update(data.DictCode)
87 | tools.HasError(err, "", -1)
88 | var res app.Response
89 | res.Data = result
90 | c.JSON(http.StatusOK, res.ReturnOK())
91 | }
92 |
93 | func DeleteDictData(c *gin.Context) {
94 | var data models.DictData
95 | data.UpdateBy = tools.GetUserIdStr(c)
96 | IDS := tools.IdsStrToIdsIntGroup("dictCode", c)
97 | result, err := data.BatchDelete(IDS)
98 | tools.HasError(err, "修改失败", 500)
99 | app.OK(c,result,"删除成功")
100 | }
101 |
--------------------------------------------------------------------------------
/apis/common/common.go:
--------------------------------------------------------------------------------
1 | package common
2 |
3 | import (
4 | "net/http"
5 |
6 | "github.com/gin-gonic/gin"
7 | )
8 |
9 | const (
10 | SUCCESS_CODE = 20000 //成功的状态码
11 | FAIL_CODE = 30000 //失败的状态码
12 | MD5_PREFIX = "jkfldfsf" //MD5加密前缀字符串
13 | TOKEN_KEY = "X-Token" //页面token键名
14 | USER_ID_Key = "X-USERID" //页面用户ID键名
15 | USER_UUID_Key = "X-UUID" //页面UUID键名
16 | SUPER_ADMIN_ID uint64 = 956986 // 超级管理员账号ID
17 | )
18 |
19 | type ResponseModel struct {
20 | Code int `json:"code"`
21 | Message string `json:"message"`
22 | Data interface{} `json:"data"`
23 | }
24 |
25 | type ResponseModelBase struct {
26 | Code int `json:"code"`
27 | Message string `json:"message"`
28 | }
29 |
30 | // 响应成功
31 | func ResSuccess(c *gin.Context, v interface{}) {
32 | ret := ResponseModel{Code: SUCCESS_CODE, Message: "ok", Data: v}
33 | ResJSON(c, http.StatusOK, &ret)
34 | }
35 |
36 | // 响应成功
37 | func ResSuccessMsg(c *gin.Context) {
38 | ret := ResponseModelBase{Code: SUCCESS_CODE, Message: "ok"}
39 | ResJSON(c, http.StatusOK, &ret)
40 | }
41 |
42 | // 响应失败
43 | func ResFail(c *gin.Context, msg string) {
44 | ret := ResponseModelBase{Code: FAIL_CODE, Message: msg}
45 | ResJSON(c, http.StatusOK, &ret)
46 | }
47 |
48 | // 响应失败
49 | func ResFailCode(c *gin.Context, msg string, code int) {
50 | ret := ResponseModelBase{Code: code, Message: msg}
51 | ResJSON(c, http.StatusOK, &ret)
52 | }
53 |
54 | // 响应JSON数据
55 | func ResJSON(c *gin.Context, status int, v interface{}) {
56 | c.JSON(status, v)
57 | c.Abort()
58 | }
59 |
60 | // 响应错误-服务端故障
61 | func ResErrSrv(c *gin.Context, err error) {
62 | ret := ResponseModelBase{Code: FAIL_CODE, Message: "服务端故障"}
63 | ResJSON(c, http.StatusOK, &ret)
64 | }
65 |
66 | // 响应错误-用户端故障
67 | func ResErrCli(c *gin.Context, err error) {
68 | ret := ResponseModelBase{Code: FAIL_CODE, Message: "err"}
69 | ResJSON(c, http.StatusOK, &ret)
70 | }
71 |
72 | type ResponsePageData struct {
73 | Total uint64 `json:"total"`
74 | Items interface{} `json:"items"`
75 | }
76 |
77 | type ResponsePage struct {
78 | Code int `json:"code"`
79 | Message string `json:"message"`
80 | Data ResponsePageData `json:"data"`
81 | }
82 |
83 | // 响应成功-分页数据
84 | func ResSuccessPage(c *gin.Context, total uint64, list interface{}) {
85 | ret := ResponsePage{Code: SUCCESS_CODE, Message: "ok", Data: ResponsePageData{Total: total, Items: list}}
86 | ResJSON(c, http.StatusOK, &ret)
87 | }
88 |
89 | // 获取页码
90 | func GetPageIndex(c *gin.Context) uint64 {
91 | return GetQueryToUint64(c, "page", 1)
92 | }
93 |
94 | // 获取每页记录数
95 | func GetPageLimit(c *gin.Context) uint64 {
96 | limit := GetQueryToUint64(c, "limit", 20)
97 | if limit > 500 {
98 | limit = 20
99 | }
100 | return limit
101 | }
102 |
103 | // 获取排序信息
104 | func GetPageSort(c *gin.Context) string {
105 | return GetQueryToStr(c, "sort")
106 | }
107 |
108 | // 获取搜索关键词信息
109 | func GetPageKey(c *gin.Context) string {
110 | return GetQueryToStr(c, "key")
111 | }
112 |
--------------------------------------------------------------------------------
/test/model.go.template:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import (
4 | orm "vAdmin/database"
5 | "vAdmin/utils"
6 | "time"
7 | )
8 |
9 | type {{.ClassName}} struct {
10 |
11 | {{ range .Columns -}}
12 | {{$x := .Pk}}
13 | // {{.ColumnComment}}
14 | {{if ($x)}}{{.GoField}} {{.GoType}} `json:"{{.JsonField}}" gorm:"column:{{.ColumnName}};primary_key"`{{else}}{{.GoField}} {{.GoType}} `json:"{{.JsonField}}" gorm:"column:{{.ColumnName}};"`{{end}}
15 | {{ end -}}
16 | }
17 |
18 | // 创建{{.ClassName}}
19 | func (e *{{.ClassName}}) Create() ({{.ClassName}}, error) {
20 | var doc {{.ClassName}}
21 | doc.IsDel = "0"
22 | e.CreateTime = time.Now().String()
23 | result := orm.Eloquent.Table("{{.TableName}}").Create(&e)
24 | if result.Error != nil {
25 | err := result.Error
26 | return doc, err
27 | }
28 | doc = *e
29 | return doc, nil
30 | }
31 |
32 | // 获取{{.ClassName}}
33 | func (e *{{.ClassName}}) Get() ({{.ClassName}}, error) {
34 | var doc {{.ClassName}}
35 |
36 | table := orm.Eloquent.Table("{{.TableName}}")
37 | {{ range .Columns -}}
38 | {{$z := .IsQuery}}
39 | {{- if ($z) -}}if e.{{.GoField}} != "" {
40 | table = table.Where("{{.ColumnName}} = ?", e.{{.GoField}})
41 | }
42 | {{ end }}
43 | {{- end -}}
44 |
45 | if err := table.First(&doc).Error; err != nil {
46 | return doc, err
47 | }
48 | return doc, nil
49 | }
50 |
51 | // 获取{{.ClassName}}带分页
52 | func (e *{{.ClassName}}) GetPage(pageSize int, pageIndex int) ([]{{.ClassName}}, int32, error) {
53 | var doc []{{.ClassName}}
54 |
55 | table := orm.Eloquent.Select("*").Table("{{.TableName}}")
56 | {{ range .Columns -}}
57 | {{$z := .IsQuery}}
58 | {{- if ($z) -}}if e.{{.GoField}} != "" {
59 | table = table.Where("{{.ColumnName}} = ?", e.{{.GoField}})
60 | }
61 | {{ end }}
62 | {{- end -}}
63 |
64 | // 数据权限控制
65 | dataPermission := new(DataPermission)
66 | dataPermission.UserId, _ = utils.StringToInt(e.DataScope)
67 | table,err := dataPermission.GetDataScope("{{.TableName}}", table)
68 | if err != nil {
69 | return nil, 0, err
70 | }
71 | var count int32
72 | table = table.Offset((pageIndex - 1) * pageSize).Limit(pageSize)
73 | if err := table.Find(&doc).Error; err != nil {
74 | return nil, 0, err
75 | }
76 | table.Count(&count)
77 | return doc, count, nil
78 | }
79 |
80 | // 更新{{.ClassName}}
81 | func (e *{{.ClassName}}) Update(id int) (update {{.ClassName}}, err error) {
82 | if err = orm.Eloquent.Table("{{.TableName}}").Where("{{.PkColumn}} = ?", id).First(&update).Error; err != nil {
83 | return
84 | }
85 |
86 | //参数1:是要修改的数据
87 | //参数2:是修改的数据
88 | if err = orm.Eloquent.Table("{{.TableName}}").Model(&update).Updates(&e).Error; err != nil {
89 | return
90 | }
91 | return
92 | }
93 |
94 | // 删除{{.ClassName}}
95 | func (e *{{.ClassName}}) Delete(id int) (success bool, err error) {
96 |
97 | if err = orm.Eloquent.Table("{{.TableName}}").Where("{{.PkColumn}} = ?", id).Delete(&{{.ClassName}}{}).Error; err != nil {
98 | success = false
99 | return
100 | }
101 | success = true
102 | return
103 | }
104 |
105 |
--------------------------------------------------------------------------------
/cmd/api/server.go:
--------------------------------------------------------------------------------
1 | package api
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "github.com/gin-gonic/gin"
7 | "github.com/spf13/cobra"
8 | "github.com/spf13/viper"
9 | "vAdmin/apis/deploy"
10 | "vAdmin/database"
11 | "vAdmin/router"
12 | "vAdmin/tools"
13 | config2 "vAdmin/tools/config"
14 | "io/ioutil"
15 | "log"
16 | "net/http"
17 | "os"
18 | "os/signal"
19 | "time"
20 | )
21 |
22 |
23 |
24 | var (
25 | config string
26 | port string
27 | mode string
28 | StartCmd = &cobra.Command{
29 | Use: "server",
30 | Short: "Start API server",
31 | Example: "main server config/settings.yml",
32 | PreRun: func(cmd *cobra.Command, args []string) {
33 | usage()
34 | setup()
35 | },
36 | RunE: func(cmd *cobra.Command, args []string) error {
37 | return run()
38 | },
39 | }
40 | )
41 |
42 | func init() {
43 | StartCmd.PersistentFlags().StringVarP(&config, "config", "c", "config/settings.yml", "Start server with provided configuration file")
44 | StartCmd.PersistentFlags().StringVarP(&port, "port", "p", "8000", "Tcp port server listening on")
45 | StartCmd.PersistentFlags().StringVarP(&mode, "mode", "m", "dev", "server mode ; eg:dev,test,prod")
46 | }
47 |
48 | func usage() {
49 | usageStr := `starting api server`
50 | fmt.Printf("%s\n", usageStr)
51 | }
52 |
53 | func setup() {
54 |
55 | //1. 读取配置
56 | config2.ConfigSetup(config)
57 | //2. 设置日志
58 | tools.InitLogger()
59 | //3. 初始化数据库链接
60 | database.SetupMysql()
61 | //database.SetupDrill()
62 |
63 |
64 | }
65 |
66 | func run() error {
67 | if mode != "" {
68 | config2.SetConfig(config, "settings.application.mode", mode)
69 | }
70 | if viper.GetString("settings.application.mode") == string(tools.ModeProd) {
71 | gin.SetMode(gin.ReleaseMode)
72 | }
73 |
74 | r := router.InitRouter()
75 |
76 | defer database.Eloquent.Close()
77 | //defer database.Eloq.Close()
78 |
79 | if port != "" {
80 | config2.SetConfig(config, "settings.application.port", port)
81 | }
82 |
83 |
84 | srv := &http.Server{
85 | Addr: config2.ApplicationConfig.Host + ":" + config2.ApplicationConfig.Port,
86 | Handler: r,
87 | }
88 |
89 | go func() {
90 | // 服务连接
91 | if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
92 | log.Fatalf("listen: %s\n", err)
93 | }
94 | }()
95 | content, _ := ioutil.ReadFile("./static/go.txt")
96 | log.Println(string(content))
97 | log.Println("Server Run http://127.0.0.1:" + config2.ApplicationConfig.Port + "/")
98 | log.Println("Swagger URL http://127.0.0.1:" + config2.ApplicationConfig.Port + "/swagger/index.html")
99 |
100 | log.Println("Enter Control + C Shutdown Server")
101 | // 等待中断信号以优雅地关闭服务器(设置 5 秒的超时时间)
102 |
103 | deploy.InitWs()
104 |
105 | quit := make(chan os.Signal)
106 | signal.Notify(quit, os.Interrupt)
107 | <-quit
108 | log.Println("Shutdown Server ...")
109 |
110 | ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
111 | defer cancel()
112 | if err := srv.Shutdown(ctx); err != nil {
113 | log.Fatal("Server Shutdown:", err)
114 | }
115 | log.Println("Server exiting")
116 | return nil
117 | }
118 |
--------------------------------------------------------------------------------
/tools/gostring/string.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 syncd Author. All Rights Reserved.
2 | // Use of this source code is governed by a MIT-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package gostring
6 |
7 | import (
8 | "strings"
9 | "strconv"
10 | "math/rand"
11 | "time"
12 | "crypto/md5"
13 | "encoding/hex"
14 | "encoding/base64"
15 | "encoding/json"
16 | )
17 |
18 | func JoinStrings(multiString ...string) string {
19 | return strings.Join(multiString, "")
20 | }
21 |
22 | func JoinIntSlice2String(intSlice []int, sep string) string {
23 | return strings.Join(IntSlice2StrSlice(intSlice), sep)
24 | }
25 |
26 | func StrSplit2IntSlice(str, sep string) []int {
27 | return StrSlice2IntSlice(StrFilterSliceEmpty(strings.Split(str, sep)))
28 | }
29 |
30 | func Str2StrSlice(str, sep string) []string {
31 | return StrFilterSliceEmpty(strings.Split(str, sep))
32 | }
33 |
34 | func StrSlice2IntSlice(strSlice []string) []int {
35 | var intSlice []int
36 | for _, s := range strSlice {
37 | i, _ := strconv.Atoi(s)
38 | intSlice = append(intSlice, i)
39 | }
40 | return intSlice
41 | }
42 |
43 | func StrFilterSliceEmpty(strSlice []string) []string {
44 | var filterSlice []string
45 | for _, s := range strSlice {
46 | ss := strings.TrimSpace(s)
47 | if ss != "" {
48 | filterSlice = append(filterSlice, ss)
49 | }
50 | }
51 | return filterSlice
52 | }
53 |
54 | func IntSlice2StrSlice(intSlice []int) []string {
55 | var strSlice []string
56 | for _, i := range intSlice {
57 | s := strconv.Itoa(i)
58 | strSlice = append(strSlice, s)
59 | }
60 | return strSlice
61 | }
62 |
63 | func Str2Int(s string) int {
64 | i, _ := strconv.Atoi(s)
65 | return i
66 | }
67 |
68 | func Int2Str(i int) string {
69 | return strconv.Itoa(i)
70 | }
71 |
72 | func StrRandom(l int) string {
73 | str := "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
74 | bytes := []byte(str)
75 | result := []byte{}
76 | r := rand.New(rand.NewSource(time.Now().UnixNano()))
77 | for i := 0; i < l; i++ {
78 | result = append(result, bytes[r.Intn(len(bytes))])
79 | }
80 | return string(result)
81 | }
82 |
83 | func StrMd5(s string) string {
84 | md5Ctx := md5.New()
85 | md5Ctx.Write([]byte(s))
86 | return hex.EncodeToString(md5Ctx.Sum(nil))
87 | }
88 |
89 | func Base64Encode(b []byte) string {
90 | return base64.StdEncoding.EncodeToString(b)
91 | }
92 |
93 | func Base64Decode(s string) ([]byte, error) {
94 | ds, err := base64.StdEncoding.DecodeString(s)
95 | return ds, err
96 | }
97 |
98 | func Base64UrlEncode(b []byte) string {
99 | return base64.URLEncoding.EncodeToString(b)
100 | }
101 |
102 | func Base64UrlDecode(s string) ([]byte, error) {
103 | ds, err := base64.URLEncoding.DecodeString(s)
104 | return ds, err
105 | }
106 |
107 | func JsonEncode(obj interface{}) []byte {
108 | b, _ := json.Marshal(obj)
109 | return b
110 | }
111 |
112 | func JsonDecode(data []byte, obj interface{}) {
113 | json.Unmarshal(data, obj)
114 | }
115 |
--------------------------------------------------------------------------------
/apis/process/classify.go:
--------------------------------------------------------------------------------
1 | package process
2 |
3 | import (
4 | "errors"
5 | //orm "vAdmin/database"
6 | orm "vAdmin/database"
7 | process2 "vAdmin/models/process"
8 | "vAdmin/pkg/pagination"
9 | "vAdmin/tools"
10 | "vAdmin/tools/app"
11 |
12 | "github.com/gin-gonic/gin"
13 | )
14 |
15 | /*
16 | @Author : Rongxin Linghu
17 | */
18 |
19 | // 创建流程分类
20 | func CreateClassify(c *gin.Context) {
21 | var (
22 | err error
23 | classifyValue process2.Classify
24 | classifyCount int
25 | )
26 |
27 | err = c.ShouldBind(&classifyValue)
28 | if err != nil {
29 | app.Error(c, -1, err, "")
30 | return
31 | }
32 |
33 | // 判断创建的分类是否存在
34 | err = orm.Eloquent.Table("p_process_classify").
35 | Where("name = ?", classifyValue.Name).
36 | Where("`delete_time` IS NULL").
37 | Count(&classifyCount).Error
38 | if err != nil {
39 | app.Error(c, -1, err, "")
40 | return
41 | }
42 | if classifyCount > 0 {
43 | app.Error(c, -1, errors.New("创建的分类名称已经存在"), "")
44 | return
45 | }
46 |
47 | classifyValue.Creator = tools.GetUserId(c)
48 |
49 | err = orm.Eloquent.Table("p_process_classify").Create(&classifyValue).Error
50 | if err != nil {
51 | app.Error(c, -1, err, "")
52 | return
53 | }
54 |
55 | app.OK(c, "", "创建流程分类成功")
56 | }
57 |
58 | // 流程分类列表
59 | func ClassifyList(c *gin.Context) {
60 | type classifyValue struct {
61 | process2.Classify
62 | CreateUser string `json:"create_user"`
63 | CreateName string `json:"create_name"`
64 | }
65 |
66 | var (
67 | err error
68 | classifyList []*classifyValue
69 | )
70 |
71 | /*
72 | SearchParams := map[string]map[string]interface{}{
73 | "like": pagination.RequestParams(c),
74 | }
75 | */
76 | SearchParams := map[string]map[string]interface{}{}
77 |
78 | db := orm.Eloquent.Model(&process2.Classify{}).Joins("left join sys_user on sys_user.user_id = p_process_classify.creator").
79 | Select("p_process_classify.*, sys_user.username as create_user, sys_user.nick_name as create_name").
80 | Where("p_process_classify.`delete_time` IS NULL")
81 |
82 | result, err := pagination.Paging(&pagination.Param{
83 | C: c,
84 | DB: db,
85 | }, &classifyList, SearchParams, "p_process_classify")
86 |
87 | if err != nil {
88 | app.Error(c, -1, err, "")
89 | return
90 | }
91 | app.OK(c, result, "获取分类列表成功")
92 | }
93 |
94 | // 更新流程分类
95 | func UpdateClassify(c *gin.Context) {
96 | var (
97 | err error
98 | classifyValue process2.Classify
99 | )
100 |
101 | err = c.ShouldBind(&classifyValue)
102 | if err != nil {
103 | app.Error(c, -1, err, "")
104 | return
105 | }
106 |
107 | // 更新
108 | err = orm.Eloquent.Model(&classifyValue).
109 | Where("id = ?", classifyValue.Id).
110 | Update("name", classifyValue.Name).Error
111 | if err != nil {
112 | app.Error(c, -1, err, "")
113 | return
114 | }
115 |
116 | app.OK(c, classifyValue, "流程分类更新成功")
117 | }
118 |
119 | // 删除流程分类
120 | func DeleteClassify(c *gin.Context) {
121 | classifyId := c.DefaultQuery("classifyId", "")
122 | if classifyId == "" {
123 | app.Error(c, -1, errors.New("参数传递失败,请确认classifyId是否传递"), "")
124 | return
125 | }
126 |
127 | err := orm.Eloquent.Delete(process2.Classify{}, "id = ?", classifyId).Error
128 | if err != nil {
129 | app.Error(c, -1, err, "")
130 | return
131 | }
132 |
133 | app.OK(c, "", "流程分类删除成功")
134 | }
135 |
--------------------------------------------------------------------------------
/apis/system/post.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "vAdmin/models"
6 | "vAdmin/tools"
7 | "vAdmin/tools/app"
8 | )
9 |
10 | // @Summary 职位列表数据
11 | // @Description 获取JSON
12 | // @Tags 职位
13 | // @Param name query string false "name"
14 | // @Param id query string false "id"
15 | // @Param position query string false "position"
16 | // @Success 200 {object} app.Response "{"code": 200, "data": [...]}"
17 | // @Router /api/v1/post [get]
18 | // @Security Bearer
19 | func GetPostList(c *gin.Context) {
20 | var data models.Post
21 | var err error
22 | var pageSize = 10
23 | var pageIndex = 1
24 |
25 | if size := c.Request.FormValue("pageSize"); size != "" {
26 | pageSize = tools.StrToInt(err, size)
27 | }
28 |
29 | if index := c.Request.FormValue("pageIndex"); index != "" {
30 | pageIndex = tools.StrToInt(err, index)
31 | }
32 |
33 | data.PostName = c.Request.FormValue("postName")
34 | id := c.Request.FormValue("postId")
35 | data.PostId, _ = tools.StringToInt(id)
36 |
37 | data.PostName = c.Request.FormValue("postName")
38 | data.DataScope = tools.GetUserIdStr(c)
39 | result, count, err := data.GetPage(pageSize, pageIndex)
40 | tools.HasError(err, "", -1)
41 | app.PageOK(c, result, count, pageIndex, pageSize, "")
42 | }
43 |
44 | func GetPost(c *gin.Context) {
45 | var Post models.Post
46 | Post.PostId, _ = tools.StringToInt(c.Param("postId"))
47 | result, err := Post.Get()
48 | tools.HasError(err, "抱歉未找到相关信息", -1)
49 | app.OK(c,result,"")
50 | }
51 |
52 | // @Summary 添加职位
53 | // @Description 获取JSON
54 | // @Tags 职位
55 | // @Accept application/json
56 | // @Product application/json
57 | // @Param data body models.Post true "data"
58 | // @Success 200 {string} string "{"code": 200, "message": "添加成功"}"
59 | // @Success 200 {string} string "{"code": -1, "message": "添加失败"}"
60 | // @Router /api/v1/post [post]
61 | // @Security Bearer
62 | func InsertPost(c *gin.Context) {
63 | var data models.Post
64 | err := c.Bind(&data)
65 | data.CreateBy = tools.GetUserIdStr(c)
66 | tools.HasError(err, "", 500)
67 | result, err := data.Create()
68 | tools.HasError(err, "", -1)
69 | app.OK(c,result,"")
70 | }
71 |
72 | // @Summary 修改职位
73 | // @Description 获取JSON
74 | // @Tags 职位
75 | // @Accept application/json
76 | // @Product application/json
77 | // @Param data body models.Dept true "body"
78 | // @Success 200 {string} string "{"code": 200, "message": "添加成功"}"
79 | // @Success 200 {string} string "{"code": -1, "message": "添加失败"}"
80 | // @Router /api/v1/post/ [put]
81 | // @Security Bearer
82 | func UpdatePost(c *gin.Context) {
83 | var data models.Post
84 |
85 | err := c.Bind(&data)
86 | data.UpdateBy = tools.GetUserIdStr(c)
87 | tools.HasError(err, "", -1)
88 | result, err := data.Update(data.PostId)
89 | tools.HasError(err, "", -1)
90 | app.OK(c,result,"修改成功")
91 | }
92 |
93 | // @Summary 删除职位
94 | // @Description 删除数据
95 | // @Tags 职位
96 | // @Param id path int true "id"
97 | // @Success 200 {string} string "{"code": 200, "message": "删除成功"}"
98 | // @Success 200 {string} string "{"code": -1, "message": "删除失败"}"
99 | // @Router /api/v1/post/{postId} [delete]
100 | func DeletePost(c *gin.Context) {
101 | var data models.Post
102 | data.UpdateBy = tools.GetUserIdStr(c)
103 | IDS := tools.IdsStrToIdsIntGroup("postId", c)
104 | result, err := data.BatchDelete(IDS)
105 | tools.HasError(err, "删除失败", 500)
106 | app.OK(c,result,"删除成功")
107 | }
108 |
--------------------------------------------------------------------------------
/module/deploy/build.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 syncd Author. All Rights Reserved.
2 | // Use of this source code is governed by a MIT-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package deploy
6 |
7 | import (
8 | "errors"
9 | "time"
10 |
11 | "github.com/dreamans/syncd/model"
12 | )
13 |
14 | type Build struct{
15 | ID int `json:"id"`
16 | ApplyId int `json:"apply_id"`
17 | StartTime int `json:"start_time"`
18 | FinishTime int `json:"finish_time"`
19 | Status int `json:"status"`
20 | Tar string `json:"tar"`
21 | Output string `json:"Output"`
22 | Errmsg string `json:"errmsg"`
23 | Ctime int `json:"ctime"`
24 | }
25 |
26 | const (
27 | BUILD_STATUS_NONE = 0
28 | BUILD_STATUS_START = 1
29 | BUILD_STATUS_SUCCESS = 2
30 | BUILD_STATUS_FAILED = 3
31 | )
32 |
33 | func (b *Build) Create() error {
34 | build := &model.DeployBuild{
35 | ApplyId: b.ApplyId,
36 | Status: b.Status,
37 | StartTime: int(time.Now().Unix()),
38 | }
39 | if ok := build.Create(); !ok {
40 | return errors.New("create deploy build failed")
41 | }
42 | return nil
43 | }
44 |
45 | func (b *Build) CreateFull() error {
46 | build := &model.DeployBuild{
47 | ApplyId: b.ApplyId,
48 | StartTime: b.StartTime,
49 | FinishTime: b.FinishTime,
50 | Status: b.Status,
51 | Tar: b.Tar,
52 | Output: b.Output,
53 | Errmsg: b.Errmsg,
54 | }
55 | if ok := build.Create(); !ok {
56 | return errors.New("create deploy build failed")
57 | }
58 | return nil
59 | }
60 |
61 | func (b *Build) Detail() error {
62 | build := &model.DeployBuild{}
63 | if ok := build.GetByApplyId(b.ApplyId); !ok {
64 | return errors.New("get deploy build detail failed")
65 | }
66 | if build.ID == 0 {
67 | build.Status = BUILD_STATUS_NONE
68 | return nil
69 | }
70 | b.ID = build.ID
71 | b.Status = build.Status
72 | b.StartTime = build.StartTime
73 | b.FinishTime = build.FinishTime
74 | b.Tar = build.Tar
75 | b.Output = build.Output
76 | b.Errmsg = build.Errmsg
77 | b.Ctime = build.Ctime
78 |
79 | return nil
80 | }
81 |
82 | func (b *Build) Exists() (bool, error) {
83 | if err := b.Detail(); err != nil {
84 | return false, err
85 | }
86 | if b.ID == 0 {
87 | return false, nil
88 | }
89 | return true, nil
90 | }
91 |
92 | func (b *Build) Finish() error {
93 | build := &model.DeployBuild{}
94 | updateData := map[string]interface{}{
95 | "status": b.Status,
96 | "tar": b.Tar,
97 | "output": b.Output,
98 | "finish_time": int(time.Now().Unix()),
99 | "errmsg": b.Errmsg,
100 | }
101 | if ok := build.UpdateByFields(updateData, model.QueryParam{
102 | Where:[]model.WhereParam{
103 | model.WhereParam{
104 | Field: "apply_id",
105 | Prepare: b.ApplyId,
106 | },
107 | },
108 | }); !ok {
109 | return errors.New("update deploy build failed")
110 | }
111 | return nil
112 | }
113 |
114 | func (b *Build) Delete() error {
115 | build := &model.DeployBuild{
116 | ID: b.ID,
117 | }
118 | if ok := build.Delete(); !ok {
119 | return errors.New("remove deploy build failed")
120 | }
121 | return nil
122 | }
123 |
--------------------------------------------------------------------------------
/models/loginlog.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import (
4 | orm "vAdmin/database"
5 | "time"
6 | )
7 |
8 | type LoginLog struct {
9 | InfoId int `json:"infoId" gorm:"primary_key;AUTO_INCREMENT"` //主键
10 | Username string `json:"username" gorm:"type:varchar(128);"` //用户名
11 | Status string `json:"status" gorm:"type:int(1);"` //状态
12 | Ipaddr string `json:"ipaddr" gorm:"type:varchar(255);"` //ip地址
13 | LoginLocation string `json:"loginLocation" gorm:"type:varchar(255);"` //归属地
14 | Browser string `json:"browser" gorm:"type:varchar(255);"` //浏览器
15 | Os string `json:"os" gorm:"type:varchar(255);"` //系统
16 | Platform string `json:"platform" gorm:"type:varchar(255);"` // 固件
17 | LoginTime time.Time `json:"loginTime" gorm:"type:timestamp;"` //登录时间
18 | CreateBy string `json:"createBy" gorm:"type:varchar(128);"` //创建人
19 | UpdateBy string `json:"updateBy" gorm:"type:varchar(128);"` //更新者
20 | DataScope string `json:"dataScope" gorm:"-"` //数据
21 | Params string `json:"params" gorm:"-"` //
22 | Remark string `json:"remark" gorm:"type:varchar(255);"` //备注
23 | Msg string `json:"msg" gorm:"type:varchar(255);"`
24 | BaseModel
25 | }
26 |
27 | func (LoginLog) TableName() string {
28 | return "sys_loginlog"
29 | }
30 |
31 | func (e *LoginLog) Get() (LoginLog, error) {
32 | var doc LoginLog
33 |
34 | table := orm.Eloquent.Table(e.TableName())
35 | if e.Ipaddr != "" {
36 | table = table.Where("ipaddr = ?", e.Ipaddr)
37 | }
38 | if e.InfoId != 0 {
39 | table = table.Where("info_id = ?", e.InfoId)
40 | }
41 |
42 | if err := table.First(&doc).Error; err != nil {
43 | return doc, err
44 | }
45 | return doc, nil
46 | }
47 |
48 | func (e *LoginLog) GetPage(pageSize int, pageIndex int) ([]LoginLog, int, error) {
49 | var doc []LoginLog
50 |
51 | table := orm.Eloquent.Select("*").Table(e.TableName())
52 | if e.Ipaddr != "" {
53 | table = table.Where("ipaddr = ?", e.Ipaddr)
54 | }
55 | if e.Status != "" {
56 | table = table.Where("status = ?", e.Status)
57 | }
58 | if e.Username != "" {
59 | table = table.Where("userName = ?", e.Username)
60 | }
61 |
62 | var count int
63 |
64 | if err := table.Order("info_id desc").Offset((pageIndex - 1) * pageSize).Limit(pageSize).Find(&doc).Error; err != nil {
65 | return nil, 0, err
66 | }
67 | table.Where("`deleted_at` IS NULL").Count(&count)
68 | return doc, count, nil
69 | }
70 |
71 | func (e *LoginLog) Create() (LoginLog, error) {
72 | var doc LoginLog
73 | e.CreateBy = "0"
74 | e.UpdateBy = "0"
75 | result := orm.Eloquent.Table(e.TableName()).Create(&e)
76 | if result.Error != nil {
77 | err := result.Error
78 | return doc, err
79 | }
80 | doc = *e
81 | return doc, nil
82 | }
83 |
84 | func (e *LoginLog) Update(id int) (update LoginLog, err error) {
85 |
86 | if err = orm.Eloquent.Table(e.TableName()).First(&update, id).Error; err != nil {
87 | return
88 | }
89 |
90 | //参数1:是要修改的数据
91 | //参数2:是修改的数据
92 | if err = orm.Eloquent.Table(e.TableName()).Model(&update).Updates(&e).Error; err != nil {
93 | return
94 | }
95 | return
96 | }
97 |
98 | func (e *LoginLog) BatchDelete(id []int) (Result bool, err error) {
99 | if err = orm.Eloquent.Table(e.TableName()).Where("info_id in (?)", id).Delete(&LoginLog{}).Error; err != nil {
100 | return
101 | }
102 | Result = true
103 | return
104 | }
105 |
--------------------------------------------------------------------------------
/apis/log/operlog.go:
--------------------------------------------------------------------------------
1 | package log
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/gin-gonic/gin/binding"
6 | "vAdmin/models"
7 | "vAdmin/tools"
8 | "vAdmin/tools/app"
9 | "net/http"
10 | )
11 |
12 | // @Summary 登录日志列表
13 | // @Description 获取JSON
14 | // @Tags 登录日志
15 | // @Param status query string false "status"
16 | // @Param dictCode query string false "dictCode"
17 | // @Param dictType query string false "dictType"
18 | // @Param pageSize query int false "页条数"
19 | // @Param pageIndex query int false "页码"
20 | // @Success 200 {object} app.Response "{"code": 200, "data": [...]}"
21 | // @Router /api/v1/operloglist [get]
22 | // @Security Bearer
23 | func GetOperLogList(c *gin.Context) {
24 | var data models.SysOperLog
25 | var err error
26 | var pageSize = 10
27 | var pageIndex = 1
28 |
29 | size := c.Request.FormValue("pageSize")
30 | if size != "" {
31 | pageSize = tools.StrToInt(err, size)
32 | }
33 |
34 | index := c.Request.FormValue("pageIndex")
35 | if index != "" {
36 | pageIndex = tools.StrToInt(err, index)
37 | }
38 |
39 | data.OperName = c.Request.FormValue("operName")
40 | data.Status = c.Request.FormValue("status")
41 | data.OperIp = c.Request.FormValue("operIp")
42 | result, count, err := data.GetPage(pageSize, pageIndex)
43 | tools.HasError(err, "", -1)
44 |
45 | var mp = make(map[string]interface{}, 3)
46 | mp["list"] = result
47 | mp["count"] = count
48 | mp["pageIndex"] = pageIndex
49 | mp["pageSize"] = pageSize
50 |
51 | var res app.Response
52 | res.Data = mp
53 |
54 | c.JSON(http.StatusOK, res.ReturnOK())
55 | }
56 |
57 | // @Summary 通过编码获取登录日志
58 | // @Description 获取JSON
59 | // @Tags 登录日志
60 | // @Param infoId path int true "infoId"
61 | // @Success 200 {object} app.Response "{"code": 200, "data": [...]}"
62 | // @Router /api/v1/operlog/{infoId} [get]
63 | // @Security Bearer
64 | func GetOperLog(c *gin.Context) {
65 | var OperLog models.SysOperLog
66 | OperLog.OperId, _ = tools.StringToInt(c.Param("operId"))
67 | result, err := OperLog.Get()
68 | tools.HasError(err, "抱歉未找到相关信息", -1)
69 | var res app.Response
70 | res.Data = result
71 | c.JSON(http.StatusOK, res.ReturnOK())
72 | }
73 |
74 | // @Summary 添加操作日志
75 | // @Description 获取JSON
76 | // @Tags 操作日志
77 | // @Accept application/json
78 | // @Product application/json
79 | // @Param data body models.SysOperLog true "data"
80 | // @Success 200 {string} string "{"code": 200, "message": "添加成功"}"
81 | // @Success 200 {string} string "{"code": -1, "message": "添加失败"}"
82 | // @Router /api/v1/operlog [post]
83 | // @Security Bearer
84 | func InsertOperLog(c *gin.Context) {
85 | var data models.SysOperLog
86 | err := c.BindWith(&data, binding.JSON)
87 | tools.HasError(err, "", 500)
88 | result, err := data.Create()
89 | tools.HasError(err, "", -1)
90 | var res app.Response
91 | res.Data = result
92 | c.JSON(http.StatusOK, res.ReturnOK())
93 | }
94 |
95 | // @Summary 批量删除操作日志
96 | // @Description 删除数据
97 | // @Tags 操作日志
98 | // @Param operId path string true "以逗号(,)分割的operId"
99 | // @Success 200 {string} string "{"code": 200, "message": "删除成功"}"
100 | // @Success 200 {string} string "{"code": -1, "message": "删除失败"}"
101 | // @Router /api/v1/operlog/{operId} [delete]
102 | func DeleteOperLog(c *gin.Context) {
103 | var data models.SysOperLog
104 | data.UpdateBy = tools.GetUserIdStr(c)
105 | IDS := tools.IdsStrToIdsIntGroup("operId", c)
106 | _, err := data.BatchDelete(IDS)
107 | tools.HasError(err, "删除失败", 500)
108 | var res app.Response
109 | res.Msg = "删除成功"
110 | c.JSON(http.StatusOK, res.ReturnOK())
111 | }
112 |
--------------------------------------------------------------------------------
/models/article.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import (
4 | orm "vAdmin/database"
5 | "vAdmin/tools"
6 | _ "time"
7 | )
8 |
9 | type Article struct {
10 |
11 | ArticleId int `json:"articleId" gorm:"type:int(11);primary_key"` // 编码
12 | Title string `json:"title" gorm:"type:varchar(128);"` // 标题
13 | Author string `json:"author" gorm:"type:varchar(128);"` // 作者
14 | Content string `json:"content" gorm:"type:varchar(255);"` // 内容
15 | CreateBy string `json:"createBy" gorm:"type:varchar(128);"` // 创建人
16 | UpdateBy string `json:"updateBy" gorm:"type:varchar(128);"` // 更新人
17 | DataScope string `json:"dataScope" gorm:"-"`
18 | Params string `json:"params" gorm:"-"`
19 | BaseModel
20 | }
21 |
22 | func (Article) TableName() string {
23 | return "article"
24 | }
25 |
26 | // 创建Article
27 | func (e *Article) Create() (Article, error) {
28 | var doc Article
29 | result := orm.Eloquent.Table(e.TableName()).Create(&e)
30 | if result.Error != nil {
31 | err := result.Error
32 | return doc, err
33 | }
34 | doc = *e
35 | return doc, nil
36 | }
37 |
38 |
39 | // 获取Article
40 | func (e *Article) Get() (Article, error) {
41 | var doc Article
42 | table := orm.Eloquent.Table(e.TableName())
43 |
44 |
45 | if e.ArticleId != 0 {
46 | table = table.Where("article_id = ?", e.ArticleId)
47 | }
48 |
49 | if e.Title != "" {
50 | table = table.Where("title = ?", e.Title)
51 | }
52 |
53 |
54 | if e.Author != "" {
55 | table = table.Where("author = ?", e.Author)
56 | }
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 | if err := table.First(&doc).Error; err != nil {
66 | return doc, err
67 | }
68 | return doc, nil
69 | }
70 |
71 | // 获取Article带分页
72 | func (e *Article) GetPage(pageSize int, pageIndex int) ([]Article, int, error) {
73 | var doc []Article
74 |
75 | table := orm.Eloquent.Select("*").Table(e.TableName())
76 |
77 | if e.ArticleId != 0 {
78 | table = table.Where("article_id = ?", e.ArticleId)
79 | }
80 |
81 | if e.Title != "" {
82 | table = table.Where("title = ?", e.Title)
83 | }
84 |
85 | if e.Author != "" {
86 | table = table.Where("author = ?", e.Author)
87 | }
88 |
89 |
90 | // 数据权限控制(如果不需要数据权限请将此处去掉)
91 | dataPermission := new(DataPermission)
92 | dataPermission.UserId, _ = tools.StringToInt(e.DataScope)
93 | table,err := dataPermission.GetDataScope(e.TableName(), table)
94 | if err != nil {
95 | return nil, 0, err
96 | }
97 | var count int
98 |
99 | if err := table.Offset((pageIndex - 1) * pageSize).Limit(pageSize).Find(&doc).Error; err != nil {
100 | return nil, 0, err
101 | }
102 | table.Where("`deleted_at` IS NULL").Count(&count)
103 | return doc, count, nil
104 | }
105 |
106 | // 更新Article
107 | func (e *Article) Update(id int) (update Article, err error) {
108 | if err = orm.Eloquent.Table(e.TableName()).Where("article_id = ?", id).First(&update).Error; err != nil {
109 | return
110 | }
111 |
112 | //参数1:是要修改的数据
113 | //参数2:是修改的数据
114 | if err = orm.Eloquent.Table(e.TableName()).Model(&update).Updates(&e).Error; err != nil {
115 | return
116 | }
117 | return
118 | }
119 |
120 | // 删除Article
121 | func (e *Article) Delete(id int) (success bool, err error) {
122 | if err = orm.Eloquent.Table(e.TableName()).Where("article_id = ?", id).Delete(&Article{}).Error; err != nil {
123 | success = false
124 | return
125 | }
126 | success = true
127 | return
128 | }
129 |
130 | //批量删除
131 | func (e *Article) BatchDelete(id []int) (Result bool, err error) {
132 | if err = orm.Eloquent.Table(e.TableName()).Where("article_id in (?)", id).Delete(&Article{}).Error; err != nil {
133 | return
134 | }
135 | Result = true
136 | return
137 | }
--------------------------------------------------------------------------------
/models/tools/syscolumns.go:
--------------------------------------------------------------------------------
1 | package tools
2 |
3 | import (
4 | orm "vAdmin/database"
5 | "vAdmin/models"
6 | )
7 |
8 | type SysColumns struct {
9 | ColumnId int `gorm:"primary_key;auto_increment" json:"columnId"`
10 | TableId int `gorm:"type:int(11);" json:"tableId"`
11 | ColumnName string `gorm:"type:varchar(128);" json:"columnName"`
12 | ColumnComment string `gorm:"column:column_comment;type:varchar(128);" json:"columnComment"`
13 | ColumnType string `gorm:"column:column_type;type:varchar(128);" json:"columnType"`
14 | GoType string `gorm:"column:go_type;type:varchar(128);" json:"goType"`
15 | GoField string `gorm:"column:go_field;type:varchar(128);" json:"goField"`
16 | JsonField string `gorm:"column:json_field;type:varchar(128);" json:"jsonField"`
17 | IsPk string `gorm:"column:is_pk;type:char(4);" json:"isPk"`
18 | IsIncrement string `gorm:"column:is_increment;type:char(4);" json:"isIncrement"`
19 | IsRequired string `gorm:"column:is_required;type:char(4);" json:"isRequired"`
20 | IsInsert string `gorm:"column:is_insert;type:char(4);" json:"isInsert"`
21 | IsEdit string `gorm:"column:is_edit;type:char(4);" json:"isEdit"`
22 | IsList string `gorm:"column:is_list;type:char(4);" json:"isList"`
23 | IsQuery string `gorm:"column:is_query;type:char(4);" json:"isQuery"`
24 | QueryType string `gorm:"column:query_type;type:varchar(128);" json:"queryType"`
25 | HtmlType string `gorm:"column:html_type;type:varchar(128);" json:"htmlType"`
26 | DictType string `gorm:"column:dict_type;type:varchar(128);" json:"dictType"`
27 | Sort int `gorm:"column:sort;type:int(4);" json:"sort"`
28 | List string `gorm:"column:list;type:char(1);" json:"list"`
29 | Pk bool `gorm:"column:pk;type:char(1);" json:"pk"`
30 | Required bool `gorm:"column:required;type:char(1);" json:"required"`
31 | SuperColumn bool `gorm:"column:super_column;type:char(1);" json:"superColumn"`
32 | UsableColumn bool `gorm:"column:usable_column;type:char(1);" json:"usableColumn"`
33 | Increment bool `gorm:"column:increment;type:char(1);" json:"increment"`
34 | Insert bool `gorm:"column:insert;type:char(1);" json:"insert"`
35 | Edit bool `gorm:"column:edit;type:char(1);" json:"edit"`
36 | Query bool `gorm:"column:query;type:char(1);" json:"query"`
37 | Remark string `gorm:"column:remark;type:varchar(255);" json:"remark"`
38 | CreateBy string `gorm:"column:create_by;type:varchar(128);" json:"createBy"`
39 | UpdateBy string `gorm:"column:update_By;type:varchar(128);" json:"updateBy"`
40 |
41 | models.BaseModel
42 | }
43 |
44 | func (SysColumns) TableName() string {
45 | return "sys_columns"
46 | }
47 |
48 | func (e *SysColumns) GetList() ([]SysColumns, error) {
49 | var doc []SysColumns
50 |
51 | table := orm.Eloquent.Select("*").Table("sys_columns")
52 |
53 | table = table.Where("table_id = ?", e.TableId)
54 |
55 | if err := table.Find(&doc).Error; err != nil {
56 | return nil, err
57 | }
58 | return doc, nil
59 | }
60 |
61 | func (e *SysColumns) Create() (SysColumns, error) {
62 | var doc SysColumns
63 | result := orm.Eloquent.Table("sys_columns").Create(&e)
64 | if result.Error != nil {
65 | err := result.Error
66 | return doc, err
67 | }
68 | doc = *e
69 | return doc, nil
70 | }
71 |
72 | func (e *SysColumns) Update() (update SysColumns, err error) {
73 | if err = orm.Eloquent.Table("sys_columns").First(&update, e.ColumnId).Error; err != nil {
74 | return
75 | }
76 |
77 | //参数1:是要修改的数据
78 | //参数2:是修改的数据
79 | if err = orm.Eloquent.Table("sys_columns").Model(&update).Updates(&e).Error; err != nil {
80 | return
81 | }
82 |
83 | return
84 | }
85 |
--------------------------------------------------------------------------------
/module/deploy/apply.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 syncd Author. All Rights Reserved.
2 | // Use of this source code is governed by a MIT-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package deploy
6 |
7 | import (
8 | "errors"
9 | "time"
10 | "vAdmin/models"
11 | )
12 |
13 | type Apply struct {
14 | ID int `json:"id"`
15 | DemandId string `json:"demand_id"`
16 | OnlineCluster []int `json:"online_cluster"`
17 | CommitVersion string `json:"commit_version"`
18 | Description string `json:"description"`
19 | AuditStatus string `json:"audit_status"`
20 | AuditRefusalReasion string `json:"audit_refusal_reasion"`
21 | Status string `json:"status"`
22 | DeployUser string `json:"deploy_user"`
23 | DeployMode string `json:"deploy_mode"`
24 | CreateBy string `json:"create_by"`
25 | UpdateBy string `json:"update_by"`
26 | CreateByname string `json:"create_byname"`
27 | CreatePhone string `json:"create_phone"`
28 | //RollbackStatus string `json:"rollback_status"`
29 | }
30 |
31 | const (
32 | AUDIT_STATUS_PENDING = "unaudit"
33 | AUDIT_STATUS_OK = "audit_pass"
34 | AUDIT_STATUS_REFUSE = "audit_denied"
35 | )
36 |
37 | const (
38 | APPLY_STATUS_NONE = "not_online"
39 | APPLY_STATUS_ING = "onlineing"
40 | APPLY_STATUS_SUCCESS = "online_success"
41 | APPLY_STATUS_FAILED = "online_failed"
42 | APPLY_STATUS_DROP = "deprecated"
43 | APPLY_STATUS_ROLLBACK = "rollback"
44 | )
45 |
46 | func (a *Apply) Detail() error {
47 | apply := &models.DeployApp{}
48 | if ok := apply.GetPram(a.ID); !ok {
49 | return errors.New("get deploy apply detail failed")
50 | }
51 | if apply.ID == 0 {
52 | return errors.New("deploy apply detail not exists")
53 | }
54 | a.DemandId = apply.DemandId
55 | a.Description = apply.Description
56 | a.CommitVersion = apply.CommitVersion
57 | a.AuditStatus = apply.AuditStatus
58 | a.Status = apply.Status
59 | a.DeployMode = apply.DeployMode
60 | a.CreateBy = apply.CreateBy
61 | a.CreateByname = apply.CreateByname
62 | a.CreatePhone = apply.CreatePhone
63 | return nil
64 | }
65 |
66 | func (a *Apply) UpdateStatus() error {
67 | apply := &models.DeployApp{}
68 | updateData := map[string]interface{}{
69 | "status": a.Status,
70 | }
71 | if ok := apply.UpdateByFields(updateData, models.QueryParam{
72 | Where: []models.WhereParam{
73 | models.WhereParam{
74 | Field: "id",
75 | Prepare: a.ID,
76 | },
77 | },
78 | }); !ok {
79 | return errors.New("update deploy apply status failed")
80 | }
81 |
82 | return nil
83 | }
84 |
85 |
86 | func (a *Apply) CheckHaveDeploying() (bool, error) {
87 | apply := &models.DeployApp{}
88 | count, ok := apply.Count(models.QueryParam{
89 | Where: []models.WhereParam{
90 | models.WhereParam{
91 | Field: "id",
92 | Tag: "!=",
93 | Prepare: a.ID,
94 | },
95 | models.WhereParam{
96 | Field: "status",
97 | Prepare: APPLY_STATUS_ING,
98 | },
99 | models.WhereParam{
100 | Field: "created_at",
101 | Tag: ">=",
102 | Prepare: int(time.Now().Unix()) - 86400,
103 | },
104 | },
105 | })
106 | if !ok {
107 | return false, errors.New("get apply count failed")
108 | }
109 |
110 | return count == 0, nil
111 | }
--------------------------------------------------------------------------------
/test/api.go.template:
--------------------------------------------------------------------------------
1 | package apis
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/gin-gonic/gin/binding"
6 | "vAdmin/models"
7 | "vAdmin/pkg"
8 | "vAdmin/utils"
9 | "net/http"
10 | )
11 |
12 | // @Summary 配置列表数据
13 | // @Description 获取JSON
14 | // @Tags 配置
15 | // @Param configKey query string false "configKey"
16 | // @Param configName query string false "configName"
17 | // @Param configType query string false "configType"
18 | // @Param pageSize query int false "页条数"
19 | // @Param pageIndex query int false "页码"
20 | // @Success 200 {object} models.Response "{"code": 200, "data": [...]}"
21 | // @Router /api/v1/configList [get]
22 | // @Security Bearer
23 | func Get{{.ClassName}}List(c *gin.Context) {
24 | var data models.{{.ClassName}}
25 | var err error
26 | var pageSize = 10
27 | var pageIndex = 1
28 |
29 | if size := c.Request.FormValue("pageSize"); size != "" {
30 | pageSize = pkg.StrToInt(err, size)
31 | }
32 |
33 | if index := c.Request.FormValue("pageIndex"); index != "" {
34 | pageIndex = pkg.StrToInt(err, index)
35 | }
36 |
37 | {{ range .Columns -}}
38 | {{$z := .IsQuery}}
39 | {{- if ($z) -}}
40 | data.{{.GoField}} = c.Request.FormValue("{{.JsonField}}")
41 | {{ end }}
42 | {{- end -}}
43 |
44 | data.DataScope = utils.GetUserIdStr(c)
45 | result, count, err := data.GetPage(pageSize, pageIndex)
46 | pkg.HasError(err, "", -1)
47 |
48 | var mp = make(map[string]interface{}, 3)
49 | mp["list"] = result
50 | mp["count"] = count
51 | mp["pageIndex"] = pageIndex
52 | mp["pageIndex"] = pageSize
53 |
54 | var res models.Response
55 | res.Data = mp
56 |
57 | c.JSON(http.StatusOK, res.ReturnOK())
58 | }
59 |
60 | // @Summary 获取配置
61 | // @Description 获取JSON
62 | // @Tags 配置
63 | // @Param configId path int true "配置编码"
64 | // @Success 200 {object} models.Response "{"code": 200, "data": [...]}"
65 | // @Router /api/v1/config/{configId} [get]
66 | // @Security Bearer
67 | func Get{{.ClassName}}(c *gin.Context) {
68 | var data models.{{.ClassName}}
69 | data.{{.PkGoField}}, _ = utils.StringToInt(c.Param("{{.PkJsonField}}"))
70 | result, err := data.Get()
71 | pkg.HasError(err, "抱歉未找到相关信息", -1)
72 |
73 | var res models.Response
74 | res.Data = result
75 |
76 | c.JSON(http.StatusOK, res.ReturnOK())
77 | }
78 |
79 | // @Summary 添加配置
80 | // @Description 获取JSON
81 | // @Tags 配置
82 | // @Accept application/json
83 | // @Product application/json
84 | // @Param data body models.{{.ClassName}} true "data"
85 | // @Success 200 {string} string "{"code": 200, "message": "添加成功"}"
86 | // @Success 200 {string} string "{"code": -1, "message": "添加失败"}"
87 | // @Router /api/v1/dict/data [post]
88 | // @Security Bearer
89 | func Insert{{.ClassName}}(c *gin.Context) {
90 | var data models.{{.ClassName}}
91 | err := c.BindWith(&data, binding.JSON)
92 | data.CreateBy = utils.GetUserIdStr(c)
93 | pkg.HasError(err, "", 500)
94 | result, err := data.Create()
95 | pkg.HasError(err, "", -1)
96 |
97 | var res models.Response
98 | res.Data = result
99 | c.JSON(http.StatusOK, res.ReturnOK())
100 |
101 | }
102 |
103 | func Update{{.ClassName}}(c *gin.Context) {
104 | var data models.{{.ClassName}}
105 | err := c.BindWith(&data, binding.JSON)
106 | pkg.HasError(err, "数据解析失败", -1)
107 | data.UpdateBy = utils.GetUserIdStr(c)
108 | result, err := data.Update(data.{{.PkGoField}})
109 | pkg.HasError(err, "", -1)
110 |
111 | var res models.Response
112 | res.Data = result
113 | c.JSON(http.StatusOK, res.ReturnOK())
114 | }
115 |
116 | func Delete{{.ClassName}}(c *gin.Context) {
117 | var data models.{{.ClassName}}
118 | id, err := utils.StringToInt(c.Param("{{.PkJsonField}}"))
119 | data.UpdateBy = utils.GetUserIdStr(c)
120 | _, err = data.Delete(id)
121 | pkg.HasError(err, "修改失败", 500)
122 |
123 | var res models.Response
124 | res.Msg = "删除成功"
125 | c.JSON(http.StatusOK, res.ReturnOK())
126 | }
--------------------------------------------------------------------------------
/module/deploy/cmdexe.go:
--------------------------------------------------------------------------------
1 | package deploy
2 |
3 | import (
4 | "bufio"
5 | "fmt"
6 | "io"
7 | "log"
8 | "os"
9 | "os/exec"
10 | "runtime"
11 | "strings"
12 | )
13 |
14 | func AsyncLog(reader io.ReadCloser, ResultChan chan string, ExitChan chan int)error {
15 | cache := "" //缓存不足一行的日志信息
16 | buf := make([]byte, 1024)
17 | for {
18 | num, err := reader.Read(buf)
19 | if err != nil && err!=io.EOF{
20 | return err
21 | }
22 | if err == io.EOF {
23 | ExitChan <- 1 // 记录协程管斌
24 | }
25 | if num > 0 {
26 | b := buf[:num]
27 | s := strings.Split(string(b), "\n")
28 | line := strings.Join(s[:len(s)-1], "\n") //取出整行的日志
29 | fmt.Printf("%s%s\n", cache, line)
30 | ResultChan <- line
31 | cache = s[len(s)-1]
32 | }
33 | }
34 | return nil
35 | }
36 |
37 | func Execute(CMD string,ResultExecChan chan string, ExitExecChan chan int) error {
38 | var (
39 | ResultChan = make(chan string, 1000)
40 | ExitChan = make(chan int)
41 | )
42 | fmt.Println("CMD:",CMD)
43 | //cmd := exec.Command("sh", "-c", CMD)
44 | cmd := exec.Command("cmd", "/C", "dir D: /s/b")
45 | // 命令的错误输出和标准输出都连接到同一个管道
46 | // stdout, err := cmd.StdoutPipe()
47 | // cmd.Stderr = cmd.Stdout
48 |
49 | stdout, _ := cmd.StdoutPipe()
50 | cmd.Stderr = cmd.Stdout
51 | //stderr, _ := cmd.StderrPipe()
52 |
53 | if err := cmd.Start(); err != nil {
54 | log.Printf("Error starting command: %s......", err.Error())
55 | return err
56 | }
57 |
58 | go AsyncLog(stdout,ResultChan,ExitChan)
59 | //go AsyncLog(stderr,ResultChan,ExitChan)
60 |
61 | go func() {
62 | for i := 0; i < 1; i++ { // 从exitchan管道中获取到1次goroute完成完毕记录才放行
63 | a := <-ExitChan // 没有记录的话会堵塞,会等下次的记录被插入才会放行
64 | if a == 1 {
65 | fmt.Println("AsyncLog goroute结束")
66 | }
67 | }
68 | close(ResultChan) // 1次循环结束代表1个收集结果的goroute全部完成完毕了,此时才能关闭resultchan,为的是让下面for循环取完resultchan管道中值的时可以正常退出
69 | }()
70 |
71 | for v := range ResultChan {
72 | //fmt.Println(v)
73 | ResultExecChan <- v
74 | }
75 |
76 | ExitExecChan <- 1 // 记录协程管斌
77 |
78 | if err := cmd.Wait(); err != nil {
79 | log.Printf("Error waiting for command execution: %s......", err.Error())
80 | return err
81 | }
82 | return nil
83 | }
84 |
85 | func ExecuteToLog(CMD string, Filename string, ExitExecChan chan int) error {
86 | // open the out file for writing
87 | outfile, err := os.Create(Filename)
88 | if err != nil {
89 | panic(err)
90 | }
91 | defer outfile.Close()
92 |
93 | fmt.Println("CMD:",CMD)
94 | sysType := runtime.GOOS
95 | switch sysType {
96 | case "linux":
97 | cmd := exec.Command("sh", "-c", CMD)
98 | stdout, _ := cmd.StdoutPipe()
99 | cmd.Stderr = cmd.Stdout
100 | //stderr, _ := cmd.StderrPipe()
101 |
102 | if err := cmd.Start(); err != nil {
103 | log.Printf("Error starting command: %s......", err.Error())
104 | return err
105 | }
106 | writer := bufio.NewWriter(outfile)
107 | go io.Copy(writer, stdout)
108 |
109 | if err := cmd.Wait(); err != nil {
110 | log.Printf("Error waiting for command execution: %s......", err.Error())
111 | return err
112 | }
113 | case "windows":
114 | //cmd := exec.Command("cmd", "/C", "del", "D:\\a.txt")
115 | cmd := exec.Command("cmd", "/C", "dir D: /s/b")
116 | stdout, _ := cmd.StdoutPipe()
117 | cmd.Stderr = cmd.Stdout
118 | //stderr, _ := cmd.StderrPipe()
119 |
120 | if err := cmd.Start(); err != nil {
121 | log.Printf("Error starting command: %s......", err.Error())
122 | return err
123 | }
124 | writer := bufio.NewWriter(outfile)
125 | go io.Copy(writer, stdout)
126 |
127 | if err := cmd.Wait(); err != nil {
128 | log.Printf("Error waiting for command execution: %s......", err.Error())
129 | return err
130 | }
131 | }
132 | // 命令的错误输出和标准输出都连接到同一个管道
133 | // stdout, err := cmd.StdoutPipe()
134 | // cmd.Stderr = cmd.Stdout
135 |
136 | ExitExecChan <- 1 // 记录协程管斌
137 | return nil
138 | }
--------------------------------------------------------------------------------