Просмотр исходного кода

Revert "wangshanxiugai"

This reverts commit ad9620ea2080b77b44f897ce14ce7668c9de9aec.
lianbingjie 11 месяцев назад
Родитель
Сommit
c8a9c93b44
100 измененных файлов с 2109 добавлено и 9857 удалено
  1. 2 1
      .gitignore
  2. 1 1
      doc/2.3.15版本/bushData/main.go
  3. BIN
      doc/src/img.png
  4. BIN
      doc/src/img_1.png
  5. BIN
      doc/src/img_2.png
  6. BIN
      doc/src/img_3.png
  7. 9 0
      doc/v2.4.4/调整.md
  8. 86 4
      readme.md
  9. 2 2
      refundSync/main.go
  10. 2 2
      returnSync/main.go
  11. 42 0
      src/Makefile
  12. 149 0
      src/commonApi/workDayApi.go
  13. 159 22
      src/config.json
  14. 84 20
      src/config/config.go
  15. 222 0
      src/config/db.go
  16. 126 0
      src/customerService/advancedProjectService.go
  17. 115 0
      src/customerService/advancedProjectsController.go
  18. 12 15
      src/customerService/customController.go
  19. 88 182
      src/customerService/customService.go
  20. 7 7
      src/customerService/dataExportLogController.go
  21. 92 114
      src/customerService/dataExportLogService.go
  22. 86 41
      src/customerService/newsController.go
  23. 32 380
      src/customerService/newsService.go
  24. 9 2
      src/customerService/router.go
  25. 354 0
      src/customerService/sendMsgService.go
  26. 11 0
      src/doc/public/consts.go
  27. 49 0
      src/doc/public/init.go
  28. 84 0
      src/doc/public/recDoc.go
  29. 56 0
      src/doc/public/stdDocRpc.go
  30. 124 0
      src/doc/recommend/recommend.go
  31. 77 0
      src/doc/router.go
  32. 21 0
      src/doc/test.http
  33. 8 11
      src/export_log/exportLog.go
  34. 0 224
      src/github.com/baiy/Cadmin-server-go/admin/context.go
  35. 0 14
      src/github.com/baiy/Cadmin-server-go/admin/db.go
  36. 0 93
      src/github.com/baiy/Cadmin-server-go/admin/dispatch.go
  37. 0 25
      src/github.com/baiy/Cadmin-server-go/admin/log.go
  38. 0 22
      src/github.com/baiy/Cadmin-server-go/go.mod
  39. 0 67
      src/github.com/baiy/Cadmin-server-go/go.sum
  40. 0 66
      src/github.com/baiy/Cadmin-server-go/main.go
  41. 0 80
      src/github.com/baiy/Cadmin-server-go/models/auth/auth.go
  42. 0 124
      src/github.com/baiy/Cadmin-server-go/models/menu/menu.go
  43. 0 63
      src/github.com/baiy/Cadmin-server-go/models/menuRelate/menuRelate.go
  44. 0 29
      src/github.com/baiy/Cadmin-server-go/models/model.go
  45. 0 80
      src/github.com/baiy/Cadmin-server-go/models/request/request.go
  46. 0 51
      src/github.com/baiy/Cadmin-server-go/models/requestRelate/requestRelate.go
  47. 0 81
      src/github.com/baiy/Cadmin-server-go/models/token/token.go
  48. 0 196
      src/github.com/baiy/Cadmin-server-go/models/user/user.go
  49. 0 75
      src/github.com/baiy/Cadmin-server-go/models/userGroup/userGroup.go
  50. 0 65
      src/github.com/baiy/Cadmin-server-go/models/userGroupRelate/userGroupRelate.go
  51. 0 51
      src/github.com/baiy/Cadmin-server-go/models/userRelate/userRelate.go
  52. 0 310
      src/github.com/baiy/Cadmin-server-go/system/auth/auth.go
  53. 0 290
      src/github.com/baiy/Cadmin-server-go/system/index/index.go
  54. 0 56
      src/github.com/baiy/Cadmin-server-go/system/menu/menu.go
  55. 0 95
      src/github.com/baiy/Cadmin-server-go/system/request/request.go
  56. 0 52
      src/github.com/baiy/Cadmin-server-go/system/router.go
  57. 0 163
      src/github.com/baiy/Cadmin-server-go/system/user/user.go
  58. 0 157
      src/github.com/baiy/Cadmin-server-go/system/userGroup/userGroup.go
  59. 0 24
      src/github.com/baiy/Cadmin-server-go/system/utils/page.go
  60. 0 1
      src/github.com/coreos/etcd/.dockerignore
  61. 0 7
      src/github.com/coreos/etcd/.github/ISSUE_TEMPLATE.md
  62. 0 5
      src/github.com/coreos/etcd/.github/PULL_REQUEST_TEMPLATE.md
  63. 0 20
      src/github.com/coreos/etcd/.gitignore
  64. 0 1
      src/github.com/coreos/etcd/.godir
  65. 0 13
      src/github.com/coreos/etcd/.header
  66. 0 66
      src/github.com/coreos/etcd/.travis.yml
  67. 0 46
      src/github.com/coreos/etcd/.words
  68. 0 63
      src/github.com/coreos/etcd/CODE_OF_CONDUCT.md
  69. 0 62
      src/github.com/coreos/etcd/CONTRIBUTING.md
  70. 0 36
      src/github.com/coreos/etcd/DCO
  71. 0 6
      src/github.com/coreos/etcd/Dockerfile
  72. 0 53
      src/github.com/coreos/etcd/Dockerfile-functional-tester
  73. 0 18
      src/github.com/coreos/etcd/Dockerfile-release
  74. 0 18
      src/github.com/coreos/etcd/Dockerfile-release.arm64
  75. 0 18
      src/github.com/coreos/etcd/Dockerfile-release.ppc64le
  76. 0 58
      src/github.com/coreos/etcd/Dockerfile-test
  77. 0 1
      src/github.com/coreos/etcd/Documentation/README.md
  78. 0 3
      src/github.com/coreos/etcd/Documentation/_index.md
  79. 0 3
      src/github.com/coreos/etcd/Documentation/benchmarks/_index.md
  80. 0 56
      src/github.com/coreos/etcd/Documentation/benchmarks/etcd-2-1-0-alpha-benchmarks.md
  81. 0 71
      src/github.com/coreos/etcd/Documentation/benchmarks/etcd-2-2-0-benchmarks.md
  82. 0 76
      src/github.com/coreos/etcd/Documentation/benchmarks/etcd-2-2-0-rc-benchmarks.md
  83. 0 51
      src/github.com/coreos/etcd/Documentation/benchmarks/etcd-2-2-0-rc-memory-benchmarks.md
  84. 0 46
      src/github.com/coreos/etcd/Documentation/benchmarks/etcd-3-demo-benchmarks.md
  85. 0 79
      src/github.com/coreos/etcd/Documentation/benchmarks/etcd-3-watch-memory-benchmark.md
  86. 0 100
      src/github.com/coreos/etcd/Documentation/benchmarks/etcd-storage-memory-benchmark.md
  87. 0 28
      src/github.com/coreos/etcd/Documentation/branch_management.md
  88. 0 456
      src/github.com/coreos/etcd/Documentation/demo.md
  89. 0 3
      src/github.com/coreos/etcd/Documentation/dev-guide/_index.md
  90. 0 170
      src/github.com/coreos/etcd/Documentation/dev-guide/api_concurrency_reference_v3.md
  91. 0 137
      src/github.com/coreos/etcd/Documentation/dev-guide/api_grpc_gateway.md
  92. 0 987
      src/github.com/coreos/etcd/Documentation/dev-guide/api_reference_v3.md
  93. 0 2525
      src/github.com/coreos/etcd/Documentation/dev-guide/apispec/swagger/rpc.swagger.json
  94. 0 334
      src/github.com/coreos/etcd/Documentation/dev-guide/apispec/swagger/v3election.swagger.json
  95. 0 146
      src/github.com/coreos/etcd/Documentation/dev-guide/apispec/swagger/v3lock.swagger.json
  96. 0 9
      src/github.com/coreos/etcd/Documentation/dev-guide/experimental_apis.md
  97. 0 67
      src/github.com/coreos/etcd/Documentation/dev-guide/grpc_naming.md
  98. 0 499
      src/github.com/coreos/etcd/Documentation/dev-guide/interacting_v3.md
  99. 0 11
      src/github.com/coreos/etcd/Documentation/dev-guide/limit.md
  100. 0 151
      src/github.com/coreos/etcd/Documentation/dev-guide/local_cluster.md

+ 2 - 1
.gitignore

@@ -4,4 +4,5 @@ src/*.exe
 src/.idea/*
 pkg/*
 src/go_build_main_go
-
+.output
+/src/jylog/

+ 1 - 1
doc/2.3.15版本/bushData/main.go

@@ -1,11 +1,11 @@
 package main
 
 import (
+	qu "app.yhyue.com/moapp/jybase/common"
 	"fmt"
 	_ "github.com/go-sql-driver/mysql"
 	"github.com/xormplus/xorm"
 	"log"
-	qu "qfw/util"
 )
 
 type sysConfig struct {

BIN
doc/src/img.png


BIN
doc/src/img_1.png


BIN
doc/src/img_2.png


BIN
doc/src/img_3.png


+ 9 - 0
doc/v2.4.4/调整.md

@@ -0,0 +1,9 @@
+### 用户同步程序改动
+
+- 用户同步增加用户类型字段
+
+### qmx_admin 改动 
+- 创建编辑订单移除订单时间字段,创建订单调整原订单时间字段为创建时间,系统取当前时间(历史数据刷库处理,规则详见需求文档)
+- 销售需求新增一级分类其他,二级分类 活动分类、内部员工赠送、豁免员工赠送
+- 新增我的订单列表、订单详情
+- 其他改动具体内容参考p192 补录与审核需求文档

+ 86 - 4
readme.md

@@ -1,7 +1,89 @@
-v2.4.3
-商品标准化一期后端接口实现、用户同步、mgo用户表同步到mysql
+### 注意
+由于依赖的common包更新,1.13.8版本的go编译会报错,可更新至1.16及以上版本
 
+## 嵌入外部服务
+### 开发接入步骤及注意事项
+1、若新增平台需要开发代码实现接口
+```go
+type OutServerInterface interface {
+	GetProxyUrl() *url.URL
+	AutoLogin() error                        //自动登录
+	RequestLogin(r *http.Request) error      //请求添加登陆状态
+	CheckLoginOut(r *http.Request) bool      //状态是否过期
+	Filter(r *http.Request) error            //过滤器
+	UnLoginSetErr(resp *http.Response) error //挂载外部服务,当未登录时,通过处罚异常尝试重新加载
+}
+```
+2、在配置文件中新增接入平台配置,key为路由前缀、内容根据自己所需配置
+```json
+  "outServer": {
+    "/succbi/": {
+    "addr": "http://192.168.3.11:8012",
+    "user": "jianyuback",
+    "password": "jianyuback.123456",
+      "blackUrl": [
+      "/succbi/",
+      "/succbi/JYYSJH/"
+      ]
+    },
+    "/newProxy/":{
+      "key":"value"
+    }
+  }
+```
+3、在nginx中添加对应前缀、指向本服务
+![img_3.png](doc%2Fsrc%2Fimg_3.png)
+### 添加外部服务(赛思)菜单流程
 
-### 注意
+#### 一.无权限验证的菜单
++ 1、新增菜单
+  系统设置》权限管理》菜单》添加菜单,输入菜单名字、链接后保存菜单即可。
+ ⚠️链接需要新增`/outServer`前缀
+  ![img_2.png](doc%2Fsrc%2Fimg_2.png)
++ 2、给用户分发菜单权限(此菜单没有权限校验、所有人都可以访问)
+
+
+#### 二.带权限验证的菜单
++ 1、新增菜单
+  系统设置》权限管理》菜单》添加菜单,输入菜单名字、链接后保存菜单即可。
+  ⚠️链接需要新增`/outServer`前缀
+  ![img_2.png](doc%2Fsrc%2Fimg_2.png)
++ 2.权限管理》请求》添加(注意ACTION地址不要添加参数)
+![img.png](doc%2Fsrc%2Fimg.png)
++ 3.权限管理》权限》关联请求
+![img_1.png](doc%2Fsrc%2Fimg_1.png)
++ 4、给用户分发菜单权限(此菜单有权限验证、无权限返回`暂无权限`)
+
+> ⚠️赛思地址屏蔽
+ 
+因赛思地址路由包含层级关系、报表上层地址不因该被展示。所以增加了赛思地址禁止访问列表
+配置位置在 `config.json>outServer>/succbi/`下
+例如 `/succbi/JYYSJH/ana/财务分析/剑鱼应收报表.rpt`地址,`/succbi/`、 `/succbi/JYYSJH/`、`/succbi/JYYSJH/ana`都不应该被访问 ,
+新增菜单时要注意把地址的上层路由都添加到`blackUrl`列表中、防止部分用户通过上层链接访问其他模块儿报表
+
+```json
+ {
+      "addr": "http://192.168.3.11:8012",
+      "user": "jianyuback",
+      "password": "jianyuback.123456",
+      "blackUrl": [
+        "/succbi/",
+        "/succbi/JYYSJH/",
+        "/succbi/JYYSJH/ana",
+        "/succbi/JYYSJH/ana/财务分析",
+        "/succbi/JYYSJH/ana/2023营收分析"
+      ]
+}
+```
+
+## 合同盖章
+```shell
+#安装word转换工具
+sudo yum install libreoffice
+
+#图片转换工具
+sudo yum install ImageMagick
+
+```
+ 
 
-由于依赖的common包更新,1.13.8版本的go编译会报错,可更新至1.16及以上版本

+ 2 - 2
refundSync/main.go

@@ -1,9 +1,9 @@
 package main
 
 import (
+	qu "app.yhyue.com/moapp/jybase/common"
+	"app.yhyue.com/moapp/jybase/mysql"
 	"log"
-	qu "qfw/util"
-	"qfw/util/mysql"
 )
 
 type sysConfig struct {

+ 2 - 2
returnSync/main.go

@@ -1,10 +1,10 @@
 package main
 
 import (
+	qu "app.yhyue.com/moapp/jybase/common"
+	"app.yhyue.com/moapp/jybase/mysql"
 	"encoding/json"
 	"log"
-	qu "qfw/util"
-	"qfw/util/mysql"
 )
 
 type sysConfig struct {

+ 42 - 0
src/Makefile

@@ -0,0 +1,42 @@
+# make deploy 部署程序到240开发服务器
+# 修改文件后 服务器上的makefile也替换一下
+# 可以配置免密登录 不用每次输密码
+NAME=qmx_admin_linux # 编译后文件名称
+NAME2=qmx_admin_linux2# 上传后的临时名称
+OUTPUT=../.output/# 编译后文件名称
+DIR="/home/jydevelop/qmx_admin" # 上传目录  这个是webdev环境的
+UserHost=root@192.168.3.240 # 用户名和地址
+DIR2="/home/jydevelop/qmx_admin/qmx_admin_linux2" # 上传后的目录
+output = ${OUTPUT}${NAME}
+
+.PHONY: obj
+obj:
+	set GOOS=linux&go build -o ${output}
+
+.PHONY: scp_file
+scp_file:
+	scp ${output} root@192.168.3.240:${DIR2}
+
+.PHONY: deploy
+deploy:
+	git pull
+	make obj
+	make scp_file
+	ssh ${UserHost} 'cd ${DIR} && make rename && make reload'
+
+.PHONY: rename
+rename:
+ifneq ($(wildcard ),${NAME})
+	rm ${NAME}
+endif
+	mv ${NAME2} ${NAME}
+	chmod 777 ${NAME}
+
+.PHONY: reload
+reload:
+	chmod 777 restart.sh
+	./restart.sh &echo "end" &exit
+
+
+
+

+ 149 - 0
src/commonApi/workDayApi.go

@@ -0,0 +1,149 @@
+package commonApi
+
+import (
+	"app.yhyue.com/moapp/jybase/date"
+	"encoding/json"
+	"fmt"
+	"io"
+	"log"
+	"net/http"
+	"sync"
+	"time"
+)
+
+type (
+	holidaysManager struct {
+		holidayCache map[int]map[time.Time]bool
+		sync.Mutex
+	}
+)
+
+func (hm *holidaysManager) GetEndTime(currentDate time.Time, workDays int) (string, error) {
+	for workDays > 0 {
+		currentDate = currentDate.AddDate(0, 0, 1)
+		yMap := hm.getHolidaysByYear(currentDate.Year())
+		if yMap != nil && !yMap[currentDate] {
+			fmt.Println(currentDate.Format(date.Date_Short_Layout), "工作日")
+			workDays--
+		}
+	}
+	return currentDate.Format(date.Date_Short_Layout), nil
+}
+
+func (hm *holidaysManager) getHolidaysByYear(year int) map[time.Time]bool {
+	hm.Lock()
+	rData := hm.holidayCache[year]
+	hm.Unlock()
+	if len(rData) > 0 {
+		return rData
+	}
+	newData := requestHolidayApi(year)
+	if len(newData) > 0 {
+		//hm.Lock()
+		//defer hm.Unlock()
+		hm.holidayCache[year] = newData
+	}
+	return newData
+}
+
+func requestHolidayApi(year int) map[time.Time]bool {
+	client := http.Client{}
+	req, _ := http.NewRequest("GET", fmt.Sprintf("https://timor.tech/api/holiday/year/%d?type=Y&week=Y", year), nil)
+	req.Header.Add("Accept", "application/json")
+	req.Header.Add("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36")
+	for i := 0; i < 5; i++ {
+		holidayTime := func() map[time.Time]bool {
+			res, err := client.Do(req)
+			defer res.Body.Close()
+			if err != nil {
+				return nil
+			}
+
+			bytes, err := io.ReadAll(res.Body)
+			if err != nil {
+				return nil
+			}
+			type holidayApiRes struct {
+				Code    int `json:"code"`
+				Holiday map[string]struct {
+					Holiday bool   `json:"holiday"`
+					Name    string `json:"name"`
+					Wage    int    `json:"wage"`
+					Date    string `json:"date"`
+					Rest    int    `json:"rest"`
+				} `json:"holiday"`
+			}
+			hRes := &holidayApiRes{}
+			err = json.Unmarshal(bytes, hRes)
+			if err != nil {
+				return nil
+			}
+
+			rData := map[time.Time]bool{}
+			for _, s := range hRes.Holiday {
+				if s.Holiday {
+					t, err := time.Parse(date.Date_Short_Layout, s.Date)
+					if err != nil {
+						continue
+					}
+					rData[t] = true
+				}
+			}
+			return rData
+		}()
+		if len(holidayTime) > 0 {
+			return holidayTime
+		}
+	}
+	return nil
+}
+
+var hManager *holidaysManager
+
+func init() {
+	hManager = &holidaysManager{
+		holidayCache: map[int]map[time.Time]bool{},
+	}
+}
+
+func RegisterCalculateWorkDayApi() {
+	http.HandleFunc("/api/admin/getWorkDay", func(w http.ResponseWriter, r *http.Request) {
+		mData, err := func() (interface{}, error) {
+			reqBytes, _ := io.ReadAll(r.Body)
+			if len(reqBytes) == 0 {
+				return nil, fmt.Errorf("参数异常")
+			}
+
+			type calculateWorkDay struct {
+				InputTime  string `json:"startDay" doc:"开始时间"`
+				WorkDayNum int    `json:"workDayNum" doc:"工作日"`
+				start, end time.Time
+			}
+
+			cwd := &calculateWorkDay{}
+			if err := json.Unmarshal(reqBytes, cwd); err != nil {
+				log.Println("反序列化异常", err)
+				return nil, fmt.Errorf("参数格式异常")
+			}
+
+			if cwd.WorkDayNum < 0 {
+				return nil, fmt.Errorf("请输入正确工作日数量")
+			}
+			t, err := time.Parse(date.Date_Short_Layout, cwd.InputTime)
+			if err != nil {
+				return nil, fmt.Errorf("开始时间格式异常")
+			}
+			return hManager.GetEndTime(t, cwd.WorkDayNum)
+		}()
+		resData := map[string]interface{}{}
+		if err != nil {
+			resData["error_msg"] = err.Error()
+			resData["error_code"] = -1
+		} else {
+			resData["error_code"] = 0
+			resData["data"] = mData
+		}
+		resBytes, _ := json.Marshal(resData)
+		w.Write(resBytes)
+	})
+}

+ 159 - 22
src/config.json

@@ -1,37 +1,43 @@
 {
-  "web_port": ":8002",
+  "web_port": ":8987",
   "domain": "http://kf-xzh.jianyu360.cn",
   "adminMysql": {
     "username": "root",
-    "password": "Topnet123",
-    "address": "192.168.3.11:3366",
+    "password": "=PDT49#80Z!RVv52_z",
+    "address": "192.168.3.217:4000",
     "dbName": "cadmin"
   },
   "jyMysql": {
     "username": "root",
-    "password": "Topnet123",
-    "address": "192.168.3.11:3366",
+    "password": "=PDT49#80Z!RVv52_z",
+    "address": "192.168.3.217:4000",
     "dbName": "jianyu"
   },
   "cbsMysql": {
     "username": "root",
-    "password": "Topnet123",
-    "address": "192.168.3.11:3366",
+    "password": "=PDT49#80Z!RVv52_z",
+    "address": "192.168.3.217:4000",
     "dbName": "cadmin"
   },
+  "subjectdbMysql": {
+    "username": "readuser",
+    "password": "jyTi_R202403",
+    "address": "192.168.3.71:4003",
+    "dbName": "Jianyu_subjectdb"
+  },
   "qyfwMgo": {
     "addr": "192.168.3.128:27080",
     "size": 15,
     "dbName": "jyqyfw"
   },
-  "mongodbServers": "192.168.3.206:27080",
+  "mongodbServers": "192.168.3.149:27180",
   "mongodbPoolSize": 5,
   "mongodbName": "qfw",
-  "jyWebDomain": "https://web2-jytest.jianyu360.cn",
+  "jyWebDomain": "https://jybx-webtest.jydev.jianyu360.com",
   "qmxWebDomain": "https://web-qmxtest.jianyu360.cn",
   "invoiceInterfaceAddress": "http://192.168.3.14:7080/Invoice/Add",
   "jyAppWebDomain": "https://app2-jytest.jianyu360.cn",
-  "redisServers": "qmx_filter=192.168.3.206:6379,other=127.0.0.1:6379,clab=192.168.3.206:1712",
+  "redisServers": "qmx_filter=192.168.3.206:5002,other=192.168.3.149:1712,clab=192.168.3.206:2711,newother=192.168.3.149:1712",
   "noCheck": [
     112,
     168,
@@ -53,14 +59,14 @@
   "errTimes": 4,
   "jypayrpc": "192.168.3.11:84",
   "uploadPath": "./web/staticres/file/",
-  "companyIp": "1.192.60.,1.192.61.,1.192.62.,1.192.63.",
+  "companyIp": "1.192.60.,1.192.61.,1.192.62.,1.192.63.,1.192.60.",
   "weixinRpcServer": "192.168.3.11:8202",
   "weixinPushUser": "1,2,3,4",
   "workerNum": 10,
   "jobNum": 20,
   "webdomain": "http://web-jydev-wh.jianyu360.cn",
   "bigmemberKey": "bigmember_power_",
-  "jyOrderApi": "http://192.168.3.240:1234",
+  "jyOrderApi": "http://192.168.3.206:1234",
   "jyRedis": "bigmember_power_",
   "jyResources": "http://127.0.0.1:8889",
   "unitPrice_normal": 1,
@@ -96,8 +102,8 @@
     "bulkGetByCustomerId": "https://api.huiju.cool/v2/customerIdentityService/bulkGetByCustomerId?access_token=%s"
   },
   "messageCenter": {
-    "sendMsgUrl": "http://192.168.3.11:891/messageCenter/SendMsg",
-    "MultipleSaveMsgUrl": "http://192.168.3.11:891/messageCenter/MultipleSaveMsg"
+    "bitmapSaveMsgUrl": "http://127.0.0.1:8911/messageCenter/BitmapSaveMsg",
+    "bitmapMsgSummaryUrl": "http://127.0.0.1:8911/messageCenter/UpdateMsgSummary"
   },
   "userIdMap": {
     "5c91f2a4c9ebc24597ab9ef1": "61669a331427bcac24e99aa7",
@@ -108,8 +114,7 @@
     "192.168.3.240:2379",
     "192.168.3.240:2379"
   ],
-  "pushGrpcServer": "192.168.3.11:5565",
-  "tidb": "jianyu:top@123@tcp(192.168.3.109:4000)/convertlabsync?charset=utf8mb4&parseTime=true&loc=Local",
+  "pushGrpcServer": "192.168.3.11:5566",
   "jyInfo": {
     "infoList": "http://192.168.3.240:8001/jyinfo/manage/infoList",
     "infoDetail": "http://192.168.3.240:8001/jyinfo/manage/infoDetail",
@@ -122,7 +127,7 @@
     "entInfo": "http://192.168.3.206:999/userCenter/ent/info",
     "examineInfo": "http://192.168.3.206:999/userCenter/ent/examineInfo",
     "entUpdate": "http://192.168.3.206:999/userCenter/ent/update",
-    "entList": "http://192.168.3.206:999/userCenter/ent/list",
+    "entList": "http://192.168.3.206:999/userCenter/ent/list"
   },
   "smsServiceRpc": "127.0.0.1:932",
   "orderInterval": "0 0 0/1 * * ? ",
@@ -134,15 +139,147 @@
   },
   "cusTidbMysql": {
     "username": "root",
-    "password": "Tidb#20220214",
-    "address": "192.168.3.109:4000",
+    "password": "=PDT49#80Z!RVv52_z",
+    "address": "192.168.3.217:4000",
     "dbName": "callCenter"
   },
   "tokenInterval": "0 0 0/1 * * ? ",
   "wxxdAppId": "wx68e590dcddf958be",
   "wxxdSecret": "2cff318bd9414e2003182382115cdaca",
   "wxxdHost": "https://api.weixin.qq.com",
-  "vipStateTask": "0 0 0 * * ? *",
-  "appId": "10000"
-
+  "vipStateTask": "0 0 0 * * ? ",
+  "appId": "10000",
+  "userCenterUrl": "http://192.168.3.206:999",
+  "vipGiving": {
+    "cycleUnit": [
+      1,
+      2,
+      3
+    ],
+    "cycleCount": [
+      0,
+      1,
+      2,
+      3
+    ]
+  },
+  "copyHref": {
+    "VIP订阅": "/weixin/frontPage/vipIntro/free/order_detail"
+  },
+  "shortLinkService": "http://192.168.21.51:8000/short/get",
+  "couponUpdate": "http://192.168.3.240:8093/lotteryStateChange",
+  "baseMysql": {
+    "username": "root",
+    "password": "=PDT49#80Z!RVv52_z",
+    "address": "192.168.3.217:4000",
+    "dbName": "base_service"
+  },
+  "creatEntRpc": "192.168.3.149:8699",
+  "globalCommonData": {
+    "username": "root",
+    "password": "=PDT49#80Z!RVv52_z",
+    "address": "192.168.3.217:4000",
+    "dbName": "global_common_data"
+  },
+  "lookAllProject": {
+    "高翔": true,
+    "沈炳毅": true,
+    "jianyu@admin": true
+  },
+  "outServer": {
+    "/succbi/": {
+      "addr": "http://192.168.3.11:8012",
+      "user": "jianyuback",
+      "password": "jianyuback.123456",
+      "blackUrl": [
+        "/succbi/",
+        "/succbi/JYYSJH/",
+        "/succbi/JYYSJH/ana",
+        "/succbi/JYYSJH/ana/财务分析"
+      ]
+    },
+    "/succbi2/": {
+      "addr": "http://192.168.3.11:8012",
+      "user": "jianyuback",
+      "password": "jianyuback.123456",
+      "blackUrl": [
+        "/succbi/",
+        "/succbi/JYYSJH/",
+        "/succbi/JYYSJH/ana",
+        "/succbi/JYYSJH/ana/财务分析"
+      ]
+    }
+  },
+  "convertlabUserMysql": {
+    "username": "root",
+    "password": "=PDT49#80Z!RVv52_z",
+    "address": "192.168.3.217:4000",
+    "dbName": "convertlabsync"
+  },
+  "msgUrl": {
+    "pc": "/swordfish/messageDetail?msgLogId=%s",
+    "mobile": "/jy_mobile/message/msgDetail?msgLogId=%s"
+  },
+  "saveMsgChanPool": 1,
+  "msgMysql": {
+    "username": "root",
+    "password": "=PDT49#80Z!RVv52_z",
+    "address": "192.168.3.217:4000",
+    "dbName": "messageCenter"
+  },
+  "equityInfoMsgType": 13,
+  "entAnalysis": 19,
+  "vipPrice": {
+    "nationwide": 599,
+    "SingleProvince": 38
+  },
+  "releaseTime": 1709568000,
+  "tasktime": 3,
+  "stampedInterest": [
+    "冯慧洋"
+  ],
+  "entPrice": 2000,
+  "invoiceStartTime": 1713715200,
+  "mongodbLogServers": "192.168.3.206:27080",
+  "mongodbLogPoolSize": 5,
+  "mongodbLogName": "qfw",
+  "mongodbLogUserName": "admin",
+  "mongodbLogPassword": "123456",
+  "productTypeMap": {
+    "VIP订阅": "超级订阅",
+    "医械通": "",
+    "大会员-AI中标预测包": "",
+    "大会员-招标文件解读": "",
+    "招投标课程": ""
+  },
+  "docScreen": {
+    "region": [
+      "剑鱼首页-剑鱼文库",
+      "文库首页-热门文档",
+      "文库首页-会员免费文档",
+      "文库首页-精选推荐"
+    ],
+    "VIP订阅":"超级订阅",
+    "医械通":"",
+    "大会员-AI中标预测包":"",
+    "大会员-招标文件解读":"",
+    "招投标课程":""
+  },
+  "appid": "10000",
+  "rpcServers": {
+    "stdDoc": {
+      "key": "jydocs.stdlib.rpc",
+      "address": [
+        "192.168.3.207:2379"
+      ],
+      "timeout": 15000
+    }
+  },
+  "docRec": {
+    "queryCount": 200,
+    "recCount": 20
+  },
+  "indexDocClass": {
+    "办公文档": "招标投标"
+  }
 }

+ 84 - 20
src/config/config.go

@@ -1,7 +1,8 @@
 package config
 
 import (
-	"qfw/util"
+	"app.yhyue.com/moapp/jybase/common"
+	"app.yhyue.com/moapp/jybase/mail"
 )
 
 type SysConfig struct {
@@ -9,6 +10,7 @@ type SysConfig struct {
 	AdminMysql              map[string]interface{} `json:"adminMysql"`
 	JyMysql                 map[string]interface{} `json:"jyMysql"`
 	CbsMysql                map[string]interface{} `json:"cbsMysql"`
+	SubjectdbMysql          map[string]interface{} `json:"subjectdbMysql"`
 	Domain                  string                 `json:"domain"`
 	MongoDBServer           string                 `json:"mongodbServers"`
 	MongodbPoolSize         int                    `json:"mongodbPoolSize"`
@@ -46,28 +48,81 @@ type SysConfig struct {
 		Normal_discount float64 `json:"normal_discount"`
 		Senior_discount float64 `json:"senior_discount"`
 	} `json:"packs_showList"` //在售数据包列表
-	UserIdMap      map[string]string      `json:"userIdMap"`
-	Etcd           []string               `json:"etcd"`
-	PushGrpcServer string                 `json:"pushGrpcServer"`
-	Tidb           string                 `json:"tidb"`
-	JyInfo         map[string]string      `json:"jyInfo"`
-	UserCenter     map[string]string      `json:"userCenter"`
-	OrdreInterval  string                 `json:"orderInterval"`
-	TokenInterval  string                 `json:"tokenInterval"`
-	WxxdAppId      string                 `json:"wxxdAppId"`
-	WxxdSecret     string                 `json:"wxxdSecret"`
-	WxxdHost       string                 `json:"wxxdHost"`
-	LookAllMsg     map[string]bool        `json:"lookAllMsg"`
-	CusTidbMysql   map[string]interface{} `json:"cusTidbMysql"`
-	SmsServiceRpc  string                 `json:"smsServiceRpc"`
-	VipStateTask   string                 `json:"vipStateTask"`
-	AppId          string                 `json:"appId"`
+	UserIdMap           map[string]string      `json:"userIdMap"`
+	Etcd                []string               `json:"etcd"`
+	PushGrpcServer      string                 `json:"pushGrpcServer"`
+	JyInfo              map[string]string      `json:"jyInfo"`
+	UserCenter          map[string]string      `json:"userCenter"`
+	OrdreInterval       string                 `json:"orderInterval"`
+	TokenInterval       string                 `json:"tokenInterval"`
+	WxxdAppId           string                 `json:"wxxdAppId"`
+	WxxdSecret          string                 `json:"wxxdSecret"`
+	WxxdHost            string                 `json:"wxxdHost"`
+	LookAllMsg          map[string]bool        `json:"lookAllMsg"`
+	CusTidbMysql        map[string]interface{} `json:"cusTidbMysql"`
+	SmsServiceRpc       string                 `json:"smsServiceRpc"`
+	VipStateTask        string                 `json:"vipStateTask"`
+	AppId               string                 `json:"appId"`
+	UserCenterUrl       string                 `json:"userCenterUrl"`
+	VipGiving           map[string][]int       `json:"vipGiving"`
+	CopyHref            map[string]string      `json:"copyHref"`
+	ShortLinkService    string                 `json:"shortLinkService"`
+	CouponUpdate        string                 `json:"couponUpdate"`
+	BaseMysql           map[string]interface{} `json:"baseMysql"`
+	MessageMysql        map[string]interface{} `json:"messageMysql"`
+	CreatEntRpc         string                 `json:"creatEntRpc"` //ent 创建rpc地址
+	LookAllProject      map[string]bool        `json:"lookAllProject"`
+	GlobalCommonData    map[string]interface{} `json:"globalCommonData"`
+	ConvertlabUserMysql map[string]interface{} `json:"convertlabUserMysql"` //荟聚用户同步数据库
+	OutServer           map[string]interface{} `json:"outServer"`
+	MsgUrl              map[string]interface{} `json:"msgUrl"`
+	SaveMsgChanPool     int                    `json:"saveMsgChanPool"`
+	MsgMysql            map[string]interface{} `json:"msgMysql"`
+	Mail                []struct {
+		Addr string
+		Port int
+		Pwd  string
+		User string
+	}
+	EquityInfoMsgType  int                    `json:"equityInfoMsgType"`
+	EntAnalysis        int                    `json:"entAnalysis"` //服务列表企业分析服务去掉一条数据
+	VipPrice           map[string]interface{} `json:"vipPrice"`
+	ReleaseTime        int64                  `json:"releaseTime"`
+	Tasktime           int                    `json:"tasktime"`
+	StampedInterest    []string               `json:"stampedInterest"`
+	EntPrice           int                    `json:"entPrice"` //专家版2.0大会员年价格
+	InvoiceStartTime   int64                  `json:"invoiceStartTime"`
+	MongodbLogServer   string                 `json:"mongodbLogServers"`
+	MongodbLogPoolSize int                    `json:"mongodbLogPoolSize"`
+	MongodbLogName     string                 `json:"mongodbLogName"`
+	MongodbLogUserName string                 `json:"mongodbLogUserName"`
+	MongodbLogPassword string                 `json:"mongodbLogPassword"`
+	ProductTypeMap     map[string]string      `json:"productTypeMap"`
+	DocScreen          struct {
+		Region []string `json:"region"`
+	} `json:"docScreen"`
+	RpcServers struct {
+		StdDoc struct {
+			Key     string   `json:"key"`
+			Address []string `json:"address"`
+			Timeout int      `json:"timeout"`
+		} `json:"stdDoc"`
+	} `json:"rpcServers"`
+	DocRec struct {
+		QueryCount int `json:"queryCount"`
+		RecCount   int `json:"recCount"`
+	} `json:"docRec"`
+
+	IndexDocClass map[string]string `json:"indexDocClass"`
 }
 
+var GmailAuth []*mail.GmailAuth
 var SysConfigs SysConfig
 var SubVipPrice subVipPrice
+var BigMemberCombo map[int]int
+var BigServiceMap map[int]map[string]interface{}
 
-//价格表
+// 价格表
 type subVipPrice struct {
 	Old struct {
 		Month struct {
@@ -115,7 +170,16 @@ type subVipPrice struct {
 }
 
 func init() {
-	util.ReadConfig("./config.json", &SysConfigs)
-	util.ReadConfig("./subvip_price.json", &SubVipPrice)
+	common.ReadConfig("./config.json", &SysConfigs)
+	common.ReadConfig("./subvip_price.json", &SubVipPrice)
+	for _, v := range SysConfigs.Mail {
+		mail := &mail.GmailAuth{
+			SmtpHost: v.Addr,
+			SmtpPort: v.Port,
+			User:     v.User,
+			Pwd:      v.Pwd,
+		}
+		GmailAuth = append(GmailAuth, mail)
+	}
 
 }

+ 222 - 0
src/config/db.go

@@ -0,0 +1,222 @@
+package config
+
+import (
+	"app.yhyue.com/moapp/jybase/common"
+	"app.yhyue.com/moapp/jybase/mongodb"
+	"app.yhyue.com/moapp/jybase/mysql"
+	"app.yhyue.com/moapp/jybase/redis"
+	"database/sql"
+	"fmt"
+	_ "github.com/go-sql-driver/mysql"
+	"log"
+	"os"
+	//clickhouseDriver "github.com/ClickHouse/clickhouse-go/v2/lib/driver"
+	"qmx_admin/src/otherPackage/baiy/Cadmin-server-go/admin"
+	"qmx_admin/src/otherPackage/mongo_util"
+)
+
+var JysqlDB *mysql.Mysql
+var SubjectdbMysql *mysql.Mysql
+var AdminDB *mysql.Mysql
+var CusTiDb *mysql.Mysql
+var CbsDB *mysql.Mysql
+var BaseDB *mysql.Mysql
+var ConvertlabDB *mysql.Mysql
+var MsgTidb *mysql.Mysql
+
+//var ClickhouseConn clickhouseDriver.Conn
+
+// var Tidb *xorm.Engine
+var admindb *sql.DB
+var MQFW *mongodb.MongodbSim
+var MQFWLog *mongodb.MongodbSim
+var JyqyfwMgo *mongodb.MongodbSim
+
+// var EtcdCli *clientv3.Client
+var GlobalCommonDataDB *mysql.Mysql
+
+var (
+	NewMgo *mongo_util.MongoUtil
+)
+
+const (
+	TableJyLeadsRecord = "jy_leads_record" // 销售线索上传记录表
+	TableJyLeads       = "jy_leads"        // 销售线索表
+	TableAdminUser     = "admin_user"      // 剑鱼后台用户表
+)
+
+func init() {
+	var err error
+	// 连接Cadmin权限菜单数据库
+	sqlUrl := SysConfigs.AdminMysql["username"].(string) + ":" + SysConfigs.AdminMysql["password"].(string) + "@tcp(" + SysConfigs.AdminMysql["address"].(string) + ")/" + SysConfigs.AdminMysql["dbName"].(string) + "?charset=utf8mb4&parseTime=True&loc=Local"
+	admindb, err = sql.Open("mysql", sqlUrl)
+
+	if err != nil {
+		log.Println("open mysql connection error:", err.Error())
+		os.Exit(1)
+	} else {
+		log.Println("数据库初始化成功")
+	}
+
+	JysqlDB = &mysql.Mysql{
+		Address:      SysConfigs.JyMysql["address"].(string),
+		UserName:     SysConfigs.JyMysql["username"].(string),
+		PassWord:     SysConfigs.JyMysql["password"].(string),
+		DBName:       SysConfigs.JyMysql["dbName"].(string),
+		MaxOpenConns: common.IntAll(SysConfigs.JyMysql["maxOpenConns"]),
+		MaxIdleConns: common.IntAll(SysConfigs.JyMysql["maxIdleConns"]),
+	}
+	JysqlDB.Init()
+
+	AdminDB = &mysql.Mysql{
+		Address:      SysConfigs.AdminMysql["address"].(string),
+		UserName:     SysConfigs.AdminMysql["username"].(string),
+		PassWord:     SysConfigs.AdminMysql["password"].(string),
+		DBName:       SysConfigs.AdminMysql["dbName"].(string),
+		MaxOpenConns: common.IntAll(SysConfigs.AdminMysql["maxOpenConns"]),
+		MaxIdleConns: common.IntAll(SysConfigs.AdminMysql["maxIdleConns"]),
+	}
+	AdminDB.Init()
+
+	CbsDB = &mysql.Mysql{
+		Address:      SysConfigs.CbsMysql["address"].(string),
+		UserName:     SysConfigs.CbsMysql["username"].(string),
+		PassWord:     SysConfigs.CbsMysql["password"].(string),
+		DBName:       SysConfigs.CbsMysql["dbName"].(string),
+		MaxOpenConns: common.IntAll(SysConfigs.CbsMysql["maxOpenConns"]),
+		MaxIdleConns: common.IntAll(SysConfigs.CbsMysql["maxIdleConns"]),
+	}
+	CbsDB.Init()
+
+	SubjectdbMysql = &mysql.Mysql{
+		Address:      SysConfigs.SubjectdbMysql["address"].(string),
+		UserName:     SysConfigs.SubjectdbMysql["username"].(string),
+		PassWord:     SysConfigs.SubjectdbMysql["password"].(string),
+		DBName:       SysConfigs.SubjectdbMysql["dbName"].(string),
+		MaxOpenConns: common.IntAll(SysConfigs.SubjectdbMysql["maxOpenConns"]),
+		MaxIdleConns: common.IntAll(SysConfigs.SubjectdbMysql["maxIdleConns"]),
+	}
+	SubjectdbMysql.Init()
+
+	CusTiDb = &mysql.Mysql{
+		Address:      SysConfigs.CusTidbMysql["address"].(string),
+		UserName:     SysConfigs.CusTidbMysql["username"].(string),
+		PassWord:     SysConfigs.CusTidbMysql["password"].(string),
+		DBName:       SysConfigs.CusTidbMysql["dbName"].(string),
+		MaxOpenConns: common.IntAll(SysConfigs.CusTidbMysql["maxOpenConns"]),
+		MaxIdleConns: common.IntAll(SysConfigs.CusTidbMysql["maxIdleConns"]),
+	}
+	CusTiDb.Init()
+
+	// 设置数据库操作对象
+	admin.SetDb(admindb)
+
+	//新工具类
+	fmt.Println(SysConfigs.MongoDBServer, uint64(SysConfigs.MongodbPoolSize))
+	err, NewMgo = mongo_util.NewMongoUtil("mongodb://"+SysConfigs.MongoDBServer, 20000, uint64(SysConfigs.MongodbPoolSize), false)
+
+	if err != nil {
+		log.Println(err)
+	}
+
+	//连接MongoDB数据库
+	MQFW = &mongodb.MongodbSim{
+		MongodbAddr: SysConfigs.MongoDBServer,
+		DbName:      SysConfigs.MongodbName,
+		Size:        SysConfigs.MongodbPoolSize,
+	}
+	MQFW.InitPool()
+	MQFWLog = &mongodb.MongodbSim{
+		MongodbAddr: SysConfigs.MongodbLogServer,
+		DbName:      SysConfigs.MongodbLogName,
+		Size:        SysConfigs.MongodbLogPoolSize,
+		UserName:    SysConfigs.MongodbLogUserName,
+		Password:    SysConfigs.MongodbLogPassword,
+	}
+	MQFWLog.InitPool()
+	qyfwMgoMap := SysConfigs.QyfwMgo
+	JyqyfwMgo = &mongodb.MongodbSim{
+		MongodbAddr: common.ObjToString(qyfwMgoMap["addr"]),
+		DbName:      common.ObjToString(qyfwMgoMap["dbName"]),
+		Size:        common.IntAll(qyfwMgoMap["size"]),
+	}
+	JyqyfwMgo.InitPool()
+	redis.InitRedis(SysConfigs.RedisServer)
+
+	/*EtcdCli, err = clientv3.New(clientv3.Config{
+		Endpoints:   SysConfigs.Etcd,
+		DialTimeout: 5 * time.Second,
+	})
+	if err != nil {
+		// handle error!
+		log.Printf("connect to etcd failed, err:%v\n", err)
+		return
+	}
+	log.Println("connect to etcd success")*/
+	BaseDB = &mysql.Mysql{
+		Address:      SysConfigs.BaseMysql["address"].(string),
+		UserName:     SysConfigs.BaseMysql["username"].(string),
+		PassWord:     SysConfigs.BaseMysql["password"].(string),
+		DBName:       SysConfigs.BaseMysql["dbName"].(string),
+		MaxOpenConns: common.IntAll(SysConfigs.BaseMysql["maxOpenConns"]),
+		MaxIdleConns: common.IntAll(SysConfigs.BaseMysql["maxIdleConns"]),
+	}
+	BaseDB.Init()
+
+	GlobalCommonDataDB = &mysql.Mysql{
+		Address:      SysConfigs.GlobalCommonData["address"].(string),
+		UserName:     SysConfigs.GlobalCommonData["username"].(string),
+		PassWord:     SysConfigs.GlobalCommonData["password"].(string),
+		DBName:       SysConfigs.GlobalCommonData["dbName"].(string),
+		MaxOpenConns: common.IntAll(SysConfigs.GlobalCommonData["maxOpenConns"]),
+		MaxIdleConns: common.IntAll(SysConfigs.GlobalCommonData["maxIdleConns"]),
+	}
+	GlobalCommonDataDB.Init()
+	ConvertlabDB = &mysql.Mysql{
+		Address:      SysConfigs.ConvertlabUserMysql["address"].(string),
+		UserName:     SysConfigs.ConvertlabUserMysql["username"].(string),
+		PassWord:     SysConfigs.ConvertlabUserMysql["password"].(string),
+		DBName:       SysConfigs.ConvertlabUserMysql["dbName"].(string),
+		MaxOpenConns: common.IntAll(SysConfigs.ConvertlabUserMysql["maxOpenConns"]),
+		MaxIdleConns: common.IntAll(SysConfigs.ConvertlabUserMysql["maxIdleConns"]),
+	}
+	ConvertlabDB.Init()
+	MsgTidb = &mysql.Mysql{
+		Address:      SysConfigs.MsgMysql["address"].(string),
+		UserName:     SysConfigs.MsgMysql["username"].(string),
+		PassWord:     SysConfigs.MsgMysql["password"].(string),
+		DBName:       SysConfigs.MsgMysql["dbName"].(string),
+		MaxOpenConns: common.IntAll(SysConfigs.MsgMysql["maxOpenConns"]),
+		MaxIdleConns: common.IntAll(SysConfigs.MsgMysql["maxIdleConns"]),
+	}
+	MsgTidb.Init()
+	/*err = connectClickhouse()
+	if err != nil {
+		log.Println("初始化clickhouse出错:", err)
+	}*/
+	GetBigCombo()
+	GetService()
+}
+
+func GetBigCombo() {
+	bigCombo := map[int]int{}
+	combo := JysqlDB.SelectBySql("SELECT * FROM bigmember_combo WHERE 1=1")
+	if combo != nil && len(*combo) > 0 {
+		for _, val := range *combo {
+			bigCombo[common.IntAll(val["id"])] = common.IntAll(val["i_price"])
+		}
+		BigMemberCombo = bigCombo
+	}
+}
+
+func GetService() {
+	bigService := map[int]map[string]interface{}{}
+	//查询所选服务的价格
+	serviceList := JysqlDB.SelectBySql("SELECT * FROM bigmember_service WHERE 1=1")
+	if serviceList != nil && len(*serviceList) > 0 {
+		for _, val := range *serviceList {
+			bigService[common.IntAll(val["id"])] = val
+		}
+	}
+	BigServiceMap = bigService
+}

+ 126 - 0
src/customerService/advancedProjectService.go

@@ -0,0 +1,126 @@
+package customerService
+
+import (
+	"app.yhyue.com/moapp/jybase/common"
+	"app.yhyue.com/moapp/jybase/encrypt"
+	"errors"
+	"fmt"
+	"log"
+	"net/url"
+	"qmx_admin/src/config"
+	"qmx_admin/src/order"
+	"qmx_admin/src/public"
+	"qmx_admin/src/util"
+	"strings"
+	"time"
+)
+
+// GetTitleService 信息id获取
+func GetTitleService(noticeAddress string) (string, string) {
+	//分割字符串
+	//noticeAddress = "https://www.jianyu360.cn/page_workDesktop/work-bench/page?aside=0&link=https%3A%2F%2Fwww.jianyu360.cn%2Farticle%2Fcontent%2FABCY1xFfTxYBSMsJGt5ZAcJIzMJQCZmdmNjKw4FLS4geGpzVRlUCRw%253D.html%3Faside%3D0"
+	urlAddress, err := url.QueryUnescape(noticeAddress) //登录后的url转译
+	if err != nil {
+		log.Printf("公告地址url转译失败;err:%s", err.Error())
+		return "", ""
+	}
+	ids := strings.Split(urlAddress, ".html") //区分html前后数据
+	firstArr := strings.Split(ids[0], "/")
+	if len(firstArr) == 0 {
+		return "", ""
+	}
+	infoIdStr := firstArr[len(firstArr)-1] // 获取id
+	infoId := encrypt.DecodeArticleId2ByCheck(infoIdStr)[0]
+	if infoId == "" {
+		return "", ""
+	}
+	baseData := config.GlobalCommonDataDB.FindOne(util.BsaeInfo, map[string]interface{}{"infoId": infoId}, "title", "")
+	if baseData == nil {
+		return "", ""
+	}
+	return infoId, common.InterfaceToStr((*baseData)["title"])
+}
+func ProjectSaveService(param *Project, userName, infoId, title string, userId int) (bool, error) {
+	//userId获取
+	userData := config.BaseDB.FindOne(util.BaseUser, map[string]interface{}{"phone": param.Phone}, "id", "")
+	if userData == nil {
+		return false, errors.New("该手机号用户不存在")
+	}
+	//信息保存
+	ok := config.BaseDB.Insert(util.LeadprojectPush, map[string]interface{}{
+		"info_id":       infoId,
+		"user_id":       (*userData)["id"],
+		"ispush":        param.IsSend,
+		"create_person": userName,
+		"create_time":   time.Now().Format("2006-01-02 15:04:05"),
+	})
+	if ok <= 0 {
+		return false, errors.New("数据存储失败")
+	}
+	//信息发送
+	if param.IsSend == 1 {
+		//mongo库userId查找
+		mongoUserId := order.GetUserIdByPhone(param.Phone)
+		url := "/article/advancedProject/" + encrypt.EncodeArticleId2ByCheck(infoId) + ".html"
+		appUrl := "/jyapp/article/advancedProject/" + encrypt.EncodeArticleId2ByCheck(infoId) + ".html"
+		messageParam := &SendMessage{
+			UserIds:      mongoUserId,
+			MsgType:      public.BlackNameType["商机情报"],
+			SendTime:     time.Now().Format("2006-01-02 15:04:05"),
+			CallPlatform: "超前项目推送",
+			Title:        "超前项目推送:您有超前项目还未查看,成单商机不要错过!",
+			Content:      fmt.Sprintf("您的专属超前项目:%s,提前介入了解需求,中标率更高!点击免费查看》》", title),
+			Link:         url,
+			AndroidUrl:   appUrl,
+			IosUrl:       appUrl,
+			WeChatUrl:    url,
+			SendMode:     2,
+		}
+		pushMsg(messageParam, 4)
+	}
+	return true, nil
+}
+
+func ProjectListService(param *ProjectListData, isAll bool, userName string) (*[]map[string]interface{}, int64) {
+	//信息查询
+	//sql拼接
+	findSql := "SELECT c.phone,b.title,a.info_id,a.ispush,a.create_time,a.create_person,a.visit_count,a.lastvisit_time"
+	sql := " FROM %s a STRAIGHT_JOIN %s c on  a.user_id=c.id %s STRAIGHT_JOIN %s b on a.info_id=b.infoid    %s where  1=1 %s"
+	phoneSql := ""
+	titleSql := ""
+	querys := []string{}
+	if param.Phone != "" {
+		phoneSql = fmt.Sprintf("and c.phone like '%s' ", "%"+param.Phone+"%")
+	}
+	if param.Title != "" {
+		titleSql = fmt.Sprintf("and b.title like '%s' ", "%"+param.Title+"%")
+
+	}
+	if isAll {
+		if param.CreatePerson != "" {
+			//全部不用创建人标识
+			querys = append(querys, fmt.Sprintf(" and  a.create_person like '%s' ", "%"+param.CreatePerson+"%"))
+		}
+	} else {
+		//查询个人数据
+		querys = append(querys, fmt.Sprintf(" and  a.create_person ='%s'", userName))
+	}
+	if param.StratTime != "" {
+		querys = append(querys, fmt.Sprintf("  and  a.lastvisit_time >='%s'", param.StratTime))
+	}
+	if param.EntTime != "" {
+		querys = append(querys, fmt.Sprintf("  and  a.lastvisit_time <='%s'", param.EntTime))
+	}
+	sql = fmt.Sprintf(sql, util.LeadprojectPush, util.BaseUser, phoneSql, util.BsaeInfo, titleSql, strings.Join(querys, "  "))
+	count := config.BaseDB.CountBySql("select  count(a.id) " + sql)
+	sql += fmt.Sprintf(" ORDER BY a.create_time desc limit  %d ,%d", param.Offset, param.PageSize)
+	list := config.BaseDB.SelectBySql(findSql + sql)
+	if list != nil && len(*list) > 0 {
+		for i := 0; i < len(*list); i++ {
+			(*list)[i]["oldUrl"] = config.SysConfigs.JyWebDomain + "/article/content/" + encrypt.EncodeArticleId2ByCheck(common.InterfaceToStr((*list)[i]["info_id"])) + ".html"
+			(*list)[i]["newUrl"] = config.SysConfigs.JyWebDomain + "/article/advancedProject/" + encrypt.EncodeArticleId2ByCheck(common.InterfaceToStr((*list)[i]["info_id"])) + ".html"
+			(*list)[i]["info_id"] = ""
+		}
+	}
+	return list, count
+}

+ 115 - 0
src/customerService/advancedProjectsController.go

@@ -0,0 +1,115 @@
+package customerService
+
+import (
+	"errors"
+	"qmx_admin/src/config"
+	"qmx_admin/src/otherPackage/baiy/Cadmin-server-go/admin"
+	"qmx_admin/src/util"
+)
+
+type Project struct {
+	Phone         string `form:"phone"`
+	NoticeAddress string `form:"noticeAddress"`
+	IsSend        int64  `form:"isSend"`
+}
+type ProjectListData struct {
+	Phone        string `form:"phone"`
+	CreatePerson string `form:"createPerson"`
+	StratTime    string `form:"stratTime"`
+	EntTime      string `form:"endTime"`
+	Title        string `form:"title"`
+	Offset       int64  `form:"offset"`
+	PageSize     int64  `form:"pageSize"`
+}
+
+// 超前项目列表
+func ProjectList(context *admin.Context) (interface{}, error) {
+	param := &ProjectListData{}
+	err := context.Form(param)
+	if err != nil {
+		return nil, err
+	}
+	//获取登陆用户名,沈炳毅、高翔、超级管理员账号可查看全部已发送的消息
+	isLookAll := false
+	lookAllMsgUser := config.SysConfigs.LookAllProject
+	loginUserName := context.User.Username
+	//判断是否能查看所有
+	if ok := lookAllMsgUser[loginUserName]; ok {
+		isLookAll = true
+	}
+	data, count := ProjectListService(param, isLookAll, loginUserName)
+	return map[string]interface{}{
+		"lists": data,
+		"total": count,
+	}, nil
+}
+
+// 超前项目记保存消息
+func ProjectSave(context *admin.Context) (interface{}, error) {
+	param := &Project{}
+	err := context.Form(param)
+	if err != nil {
+		return nil, err
+	}
+	if param.NoticeAddress == "" {
+		return nil, errors.New("超前项目地址必填")
+	}
+	if param.Phone == "" {
+		return nil, errors.New("手机号必填")
+	}
+	infoId, title := GetTitleService(param.NoticeAddress)
+	if infoId == "" && title == "" {
+		return nil, errors.New("该公告不存在")
+	}
+	status, err := ProjectSaveService(param, context.User.Username, infoId, title, context.User.Id)
+	return map[string]interface{}{
+		"status": status,
+	}, err
+}
+
+// 公告标题获取
+func GetTitle(context *admin.Context) (interface{}, error) {
+	param := new(struct {
+		NoticeAddress string `form:"noticeAddress"`
+	})
+	err := context.Form(param)
+	if err != nil {
+		return nil, nil
+	}
+	if param.NoticeAddress == "" {
+		return nil, errors.New("超前项目地址必填")
+	}
+	infoId, title := GetTitleService(param.NoticeAddress)
+	if infoId == "" && title == "" {
+		return nil, errors.New("该公告不存在")
+	}
+
+	//地址换取信息标题
+	return map[string]interface{}{
+		"title": title,
+	}, err
+}
+
+// 用户信息获取
+func GetUser(context *admin.Context) (interface{}, error) {
+	param := new(struct {
+		Phone string `form:"phone"`
+	})
+	err := context.Form(param)
+
+	if err != nil {
+		return nil, nil
+	}
+	if param.Phone == "" {
+		return nil, errors.New("手机号必填")
+	}
+	//userId获取
+	userData := config.BaseDB.FindOne(util.BaseUser, map[string]interface{}{"phone": param.Phone}, "id", "")
+	if userData == nil {
+		return nil, errors.New("该手机号用户不存在")
+	} else {
+		return map[string]interface{}{
+			"status": true,
+		}, err
+	}
+}

+ 12 - 15
src/customerService/customController.go

@@ -1,14 +1,14 @@
 package customerService
 
 import (
+	"app.yhyue.com/moapp/jybase/common"
 	"errors"
-	"github.com/baiy/Cadmin-server-go/admin"
-	"github.com/baiy/Cadmin-server-go/system/utils"
 	"github.com/tealeg/xlsx"
 	"io/ioutil"
 	"log"
-	qutil "qfw/util"
-	"util"
+	"qmx_admin/src/config"
+	"qmx_admin/src/otherPackage/baiy/Cadmin-server-go/admin"
+	"qmx_admin/src/otherPackage/baiy/Cadmin-server-go/system/utils"
 )
 
 type customMsg struct {
@@ -26,6 +26,7 @@ type customMsg struct {
 	UserArr      []map[string]interface{} `form:"userArr"`      //已选择的用户信息集合
 	UserAddWay   int                      `form:"userAddWay"`   //添加用户的方式
 	TemplateName string                   `form:"templateName"` //模板名称 - 自定义消息
+	MenuName     string                   `form:"menuname"`     // search:搜索 subscribe:订阅 box:百宝箱 me:我的 other:新的webview  消息中心 message
 }
 
 // CustomSendMsg 自定义发送消息
@@ -40,8 +41,6 @@ func CustomSendMsg(context *admin.Context) (interface{}, error) {
 	if param.SendMode == 2 {
 		sendStatus = 4
 	}
-	//拼接link
-	param.Link = param.Link + "," + param.AndroidUrl + "," + param.IosUrl + "," + param.WeChatUrl
 	status, err := CustomSendMsgService(param, sendStatus, context.User.Username, context.User.Id)
 	return map[string]interface{}{
 		"status": status,
@@ -62,7 +61,6 @@ func MyCustomerList(context *admin.Context) (interface{}, error) {
 	if err != nil {
 		return nil, err
 	}
-	log.Println(param)
 	adminPhone := context.User.Phone
 	count, data := MyCustomerService(param.State, param.UpdateTimeStart, param.UpdateTimeEnd, param.CompanyName, param.Phone, adminPhone, param.Page.Offset, param.Page.PageSize)
 	return map[string]interface{}{
@@ -82,13 +80,13 @@ func SingleAdd(context *admin.Context) (interface{}, error) {
 	}
 	//判断是否是剑鱼用户
 	//userData := &map[string]interface{}{}
-	userData, ok := util.MQFW.FindById("user", param.UserId, `"s_phone":1,"s_m_phone":1`)
+	userData, ok := config.MQFW.FindById("user", param.UserId, `"s_phone":1,"s_m_phone":1`)
 	if userData != nil && len(*userData) > 0 && ok {
 		phone := ""
-		if qutil.ObjToString((*userData)["s_phone"]) != "" {
-			phone = qutil.ObjToString((*userData)["s_phone"])
+		if common.ObjToString((*userData)["s_phone"]) != "" {
+			phone = common.ObjToString((*userData)["s_phone"])
 		} else {
-			phone = qutil.ObjToString((*userData)["s_m_phone"])
+			phone = common.ObjToString((*userData)["s_m_phone"])
 		}
 		return map[string]interface{}{
 			"userId":       param.UserId,
@@ -137,7 +135,6 @@ func ImportUser(context *admin.Context) (interface{}, error) {
 	var saveData [][]interface{}            // 用于写入错误原因文件的数据   数据结构: [[userId,errReason],...]
 	var selectUser []map[string]interface{} // 用户选择的数据  数据结构[{userId:"1",phone:"18238182402"}...]
 	//遍历用户id 验证数据有效性
-	log.Println(userData)
 	for _, v := range userData {
 		recordCount++ // 记录读取到的条数
 		// 判断是否超过2000条数据,原因:超过2000条以后的数据导入失败。
@@ -154,10 +151,10 @@ func ImportUser(context *admin.Context) (interface{}, error) {
 		var phone string
 		if b == true && userRs != nil && len(*userRs) > 0 {
 			//获取用户手机号信息
-			if qutil.ObjToString((*userRs)["s_phone"]) != "" {
-				phone = qutil.ObjToString((*userRs)["s_phone"])
+			if common.ObjToString((*userRs)["s_phone"]) != "" {
+				phone = common.ObjToString((*userRs)["s_phone"])
 			} else {
-				phone = qutil.ObjToString((*userRs)["s_m_phone"])
+				phone = common.ObjToString((*userRs)["s_m_phone"])
 			}
 
 		} else {

+ 88 - 182
src/customerService/customService.go

@@ -1,178 +1,120 @@
 package customerService
 
 import (
-	"config"
+	"app.yhyue.com/moapp/jybase/common"
+	"app.yhyue.com/moapp/jybase/date"
 	"database/sql"
 	"errors"
 	"fmt"
-	"github.com/tealeg/xlsx"
 	"log"
-	"order"
 	"os"
-	qutil "qfw/util"
+	"qmx_admin/src/config"
+	"qmx_admin/src/order"
+	"qmx_admin/src/public"
+	"qmx_admin/src/util"
 	"strconv"
-	"strings"
 	"sync"
-	"task"
 	"time"
-	"util"
+
+	"github.com/tealeg/xlsx"
 )
 
 func CustomSendMsgService(param *customMsg, sendStatus int, loginUserName string, loginUserId int) (int, error) {
 	var userIdArr []string
 	var msgLogId string
 	if param.SendMode == 2 {
-		param.SendTime = time.Now().Format(qutil.Date_Full_Layout)
+		param.SendTime = time.Now().Format(date.Date_Full_Layout)
 	}
+	links := param.Link + "," + param.AndroidUrl + "," + param.IosUrl + "," + param.WeChatUrl
+	groupId := public.MsgTypeToGroupId[param.MsgType]
 	fields := []string{"user_id", "register_phone", "call_center_company", "call_center_phone", "createtime", "msg_id"}
+	setData := map[string]interface{}{
+		"send_usergroup_id":   "",
+		"send_usergroup_name": "",
+		"receive_user_id":     "",
+		"msg_type":            param.MsgType,
+		"title":               param.Title,
+		"content":             param.Content,
+		"send_mode":           param.SendMode,
+		"send_time":           param.SendTime,
+		"send_status":         sendStatus,
+		"update_time":         time.Now().Format(date.Date_Full_Layout),
+		"link":                links,
+		"isdel":               1,
+		"user_add_way":        param.UserAddWay,
+		"template_name":       param.TemplateName,
+		"update_user":         loginUserName,
+		"menu_name":           param.MenuName,
+		"group_id":            groupId,
+	}
 	// 更新消息
 	if param.Id != 0 {
 		msgLogId = strconv.Itoa(param.Id)
-		isOk := util.JysqlDB.ExecTx("更新消息出错", func(tx *sql.Tx) bool {
-			ok1 := util.JysqlDB.Delete("sendmsg_customer_info", map[string]interface{}{"msg_id": param.Id})
+		isOk := config.JysqlDB.ExecTx("更新消息出错", func(tx *sql.Tx) bool {
+			ok1 := config.JysqlDB.DeleteByTx(tx, "sendmsg_customer_info", map[string]interface{}{"msg_id": param.Id})
 			var args []interface{}
-			log.Println("前端传入用户数量:", len(param.UserArr))
 			for _, val := range param.UserArr {
-				userIdArr = append(userIdArr, qutil.ObjToString(val["user_id"]))
+				userIdArr = append(userIdArr, common.ObjToString(val["user_id"]))
 				args = append(args, val["user_id"])
 				args = append(args, val["register_phone"])
 				args = append(args, val["call_center_company"])
 				args = append(args, val["call_center_phone"])
-				args = append(args, time.Now().Format(qutil.Date_Full_Layout))
+				args = append(args, time.Now().Format(date.Date_Full_Layout))
 				args = append(args, param.Id)
 			}
-			log.Println(fields)
-			log.Println(args)
-			count, _ := util.JysqlDB.InsertBatch("sendmsg_customer_info", fields, args)
-			ok := util.JysqlDB.Update("message_send_log", map[string]interface{}{"id": param.Id}, map[string]interface{}{
-				"send_usergroup_id":   "",
-				"send_usergroup_name": "",
-				"receive_user_id":     param.UserIds,
-				"msg_type":            param.MsgType,
-				"title":               param.Title,
-				"content":             param.Content,
-				"send_mode":           param.SendMode,
-				"send_time":           param.SendTime,
-				"send_status":         sendStatus,
-				"update_time":         time.Now().Format(qutil.Date_Full_Layout),
-				"link":                param.Link,
-				"isdel":               1,
-				"send_userid":         loginUserId,
-				"user_add_way":        param.UserAddWay,
-				"template_name":       param.TemplateName,
-				"update_user":         loginUserName,
-			})
+			count, _ := config.JysqlDB.InsertBatchByTx(tx, "sendmsg_customer_info", fields, args)
+			ok := config.JysqlDB.UpdateByTx(tx, "message_send_log", map[string]interface{}{"id": param.Id}, setData)
 			return ok1 && ok && count > 0
 		})
-
 		if !isOk {
 			return 0, errors.New("发送消息出错")
 		}
 		if param.SendMode == 1 {
-			now := time.Now()
-			sendTime := param.SendTime
-			_, err := time.ParseInLocation(qutil.Date_Full_Layout, sendTime, now.Location())
-			if err != nil {
-				sendTime = param.SendTime + ":00"
-			}
-			key := strconv.Itoa(param.Id)
-			log.Println("定时时间", sendTime)
-			if _, t := util.OnTimeSendMap.Load(key + sendTime); !t {
-				sendTime2, _ := time.ParseInLocation(qutil.Date_Full_Layout, sendTime, now.Location())
-				execTime := sendTime2.Unix() - now.Unix()
-				log.Println(execTime, sendTime, now.Format(qutil.Date_Full_Layout), sendTime2.Unix(), now.Unix())
-				util.OnTimeSendMap.Store(key+sendTime, true)
-				log.Println("打印信息。。。。。。。", time.Duration(execTime)*time.Second)
-				time.AfterFunc(time.Duration(execTime)*time.Second, func() {
-					// 执行任务
-					log.Println("创建、修改添加定时任务")
-					log.Println(param.Id, sendTime)
-					task.CustomTask(param.Id, sendTime, param.AndroidUrl, param.IosUrl)
-				})
-			}
+			OnTimeSendMsgService(int64(param.Id), param.SendTime, true)
 			return 1, nil
 		}
-		//return 1, nil
-	} else {
-		//保存发送的消息
+	} else { //保存发送的消息
 		var msgId int64
-		log.Println("发送消息发送时间:", param.SendTime)
-		isOk := util.JysqlDB.ExecTx("更新消息出错", func(tx *sql.Tx) bool {
-			msgId = util.JysqlDB.Insert("message_send_log", map[string]interface{}{
-				"send_usergroup_id":   "",
-				"send_usergroup_name": "",
-				// "receive_user_id":     userIdStr,
-				"msg_type":      param.MsgType,
-				"title":         param.Title,
-				"content":       param.Content,
-				"send_mode":     param.SendMode,
-				"send_time":     param.SendTime,
-				"send_status":   sendStatus,
-				"update_time":   time.Now().Format(qutil.Date_Full_Layout),
-				"createtime":    time.Now().Format(qutil.Date_Full_Layout),
-				"link":          param.Link,
-				"isdel":         1,
-				"send_userid":   loginUserId,
-				"send_name":     loginUserName,
-				"sign":          1,
-				"user_add_way":  param.UserAddWay,
-				"template_name": param.TemplateName,
-				"update_user":   loginUserName,
-			})
-
+		setData["createtime"] = time.Now().Format(date.Date_Full_Layout)
+		setData["send_userid"] = loginUserId
+		setData["send_name"] = loginUserName
+		setData["sign"] = 1
+		isOk := config.JysqlDB.ExecTx("更新消息出错", func(tx *sql.Tx) bool {
+			msgId = config.JysqlDB.Insert("message_send_log", setData)
 			var args []interface{}
-			log.Println("前端传入用户数量:", len(param.UserArr))
 			for _, val := range param.UserArr {
-				userIdArr = append(userIdArr, qutil.ObjToString(val["user_id"]))
+				userIdArr = append(userIdArr, common.ObjToString(val["user_id"]))
 				args = append(args, val["user_id"])
 				args = append(args, val["register_phone"])
 				args = append(args, val["call_center_company"])
 				args = append(args, val["call_center_phone"])
-				args = append(args, time.Now().Format(qutil.Date_Full_Layout))
+				args = append(args, time.Now().Format(date.Date_Full_Layout))
 				args = append(args, msgId)
 			}
-			log.Println(fields)
-			log.Println(args)
-			count, _ := util.JysqlDB.InsertBatch("sendmsg_customer_info", fields, args)
+			count, _ := config.JysqlDB.InsertBatch("sendmsg_customer_info", fields, args)
 			return msgId > -1 && count > 0
 		})
 		if !isOk {
-			return 0, errors.New("保存消息出错")
+			return 0, errors.New("保存消息记录出错")
 		}
 		msgLogId = strconv.FormatInt(msgId, 10)
 		//如果是定时发送
 		if param.SendMode == 1 {
 			if msgId > 0 {
-				msgId := qutil.IntAll(msgId)
-				sendTime, _ := time.ParseInLocation(qutil.Date_Full_Layout, param.SendTime+":00", time.Now().Location())
-				now := time.Now()
-				days := sendTime.Sub(now)
-				log.Println("时间:", days)
-				util.OnTimeSendMap.Store(strconv.Itoa(msgId)+param.SendTime+":00", true)
-				time.AfterFunc(days, func() {
-					// 执行任务
-					//log.Println("创建、修改添加定时任务")
-					log.Println(msgId, sendTime)
-					task.CustomTask(msgId, sendTime.Format("2006-01-02 15:04:05"), param.AndroidUrl, param.IosUrl)
-				})
+				OnTimeSendMsgService(msgId, param.SendTime, false)
 				return 1, nil
 			}
 		}
+		err := util.BitmapMsgSummaryPost(msgId, int64(groupId), int64(param.MsgType)) //更新消息汇总表
+		if err != nil {
+			return 0, err
+		}
 	}
-	log.Println("发送消息记录id*********", msgLogId)
 	//立即发送
+	param.Link, param.AndroidUrl, param.IosUrl, param.WeChatUrl = public.GetMsgUrlString(param.Link, param.AndroidUrl, param.IosUrl, param.WeChatUrl, msgLogId)
 	if param.SendMode == 2 {
 		projectIdMap := sync.Map{}
-		orm := util.Tidb.NewSession()
-		err := orm.Begin()
-		if err != nil {
-			log.Println("建立数据库连接出错:", err)
-		}
-		log.Println("--------", sendStatus)
-		userNames := ""
-		userIds := ""
-		i := 0
-		j := 0
+		userIds, i, j := "", 0, 0
 		msgType := strconv.Itoa(param.MsgType)
 		msg := map[string]interface{}{
 			"sendUserId": loginUserId,
@@ -183,6 +125,9 @@ func CustomSendMsgService(param *customMsg, sendStatus int, loginUserName string
 			"link":       param.Link,
 			"appid":      util.AppId,
 			"msgLogId":   msgLogId,
+			"appPushUrl": param.AndroidUrl,
+			"wxPushUrl":  param.WeChatUrl,
+			"iosPushUrl": param.IosUrl,
 		}
 		for _, val := range userIdArr {
 			userId := val
@@ -190,82 +135,49 @@ func CustomSendMsgService(param *customMsg, sendStatus int, loginUserName string
 				userId = config.SysConfigs.UserIdMap[userId]
 			}
 			if _, ok := projectIdMap.Load(userId); ok {
-				log.Println("########################已发送,本次跳过。。。。。。。。。。。。。", userId)
+				log.Println("########################已发送,本次跳过", userId)
 				continue
 			} else {
 				projectIdMap.Store(userId, true)
 			}
-			i++
 			j++
-			userIds += userId + ","
-
 			//查询mongo库用户信息
 			userData := &map[string]interface{}{}
 			ok := false
-			var otherPushId, jgPushId, phoneType, name = "", "", "", ""
-			appVersion := ""
-			userData, ok = util.MQFW.FindById("user", userId, `"s_name":1,"s_opushid":1,"s_jpushid":1,"s_appponetype":1,"s_appversion":1`)
-			if userData != nil && len(*userData) > 0 && ok {
-				otherPushId = qutil.ObjToString((*userData)["s_opushid"])
-				jgPushId = qutil.ObjToString((*userData)["s_jpushid"])
-				phoneType = qutil.ObjToString((*userData)["s_appponetype"])
-				appVersion = qutil.ObjToString((*userData)["s_appversion"])
-			}
-			userNames += name + ","
-			appPushUrl := "/jyapp/frontPage/messageCenter/sess/index"
-			if strings.Contains(phoneType, "iPhone") {
-				if param.IosUrl != "" {
-					appPushUrl = param.IosUrl
-				}
-			} else {
-				if param.AndroidUrl != "" {
-					appPushUrl = param.AndroidUrl
-				}
-			}
-			//实时发送发送时间为当前时间
-			param.SendTime = time.Now().Format(qutil.Date_Full_Layout)
-			dt := map[string]interface{}{
-				"receiveUserId": userId,
-				"receiveName":   name,
-				"sendUserId":    loginUserId,
-				"sendName":      loginUserName,
-				"title":         param.Title,
-				"content":       param.Content,
-				"msgType":       msgType,
-				"link":          param.Link,
-				"appid":         util.AppId,
+			userData, ok = config.MQFW.FindById("user", userId, public.MsgUserInfoField)
+			if userData == nil || len(*userData) == 0 || !ok {
+				continue
 			}
-			//推送消息
-			if appVersion > "3.0.3" {
-				go util.AppGrpcPush(dt, otherPushId, jgPushId, phoneType, appPushUrl)
+			i++
+			if i != 1 {
+				userIds += ","
 			}
-			if i == 100 {
+			userIds += userId
+			if i >= 10000 {
 				//调用消息中台
-				log.Println("发送用户id", userIds)
-				util.MultipleSaveMessage(msg, userIds, userNames)
-				userNames = ""
+				util.BitmapSaveMessage(msg, userIds, "")
 				userIds = ""
 				i = 0
 			}
-
 		}
 		if i > 0 {
 			//调用中台接口
-			util.MultipleSaveMessage(msg, userIds, userNames)
-			userNames = ""
+			util.BitmapSaveMessage(msg, userIds, "")
 			userIds = ""
 			i = 0
 		}
 		log.Println("发送完成,一共发送用户数量:", j)
+		//更新消息链接
+		config.JysqlDB.Update("message_send_log", map[string]interface{}{"id": msgLogId}, map[string]interface{}{"link": param.Link})
 		return 1, nil
 	}
 	return 0, errors.New("发送消息出错")
 }
 
 func MyCustomerService(state, updateTimeStart, updateTimeEnd, companyName, phone, adminPhone string, offSet, pageSize int) (count int64, data []map[string]interface{}) {
-	salesperson := util.CusTiDb.FindOne("jy_salesperson_info", map[string]interface{}{"phone": adminPhone}, "seatNumber", "")
+	salesperson := config.CusTiDb.FindOne("jy_salesperson_info", map[string]interface{}{"phone": adminPhone}, "seatNumber", "")
 	if salesperson != nil && len(*salesperson) > 0 {
-		code := qutil.ObjToString((*salesperson)["seatNumber"])
+		code := common.ObjToString((*salesperson)["seatNumber"])
 		sqlStr := "SELECT company,id,phone,status999,lastUpdateTime FROM customer where owner in (" + code + ") "
 		str := ""
 		sqlc := "SELECT COUNT(*) FROM customer where owner in (" + code + ") "
@@ -290,22 +202,20 @@ func MyCustomerService(state, updateTimeStart, updateTimeEnd, companyName, phone
 			sqlc += str
 		}
 		sqlStr += " order by lastUpdateTime desc limit " + fmt.Sprint(offSet) + " " + "," + " " + fmt.Sprint(pageSize)
-		log.Println("sql:", sqlStr)
-		log.Println("sqlc:", sqlc)
-		count = util.CusTiDb.CountBySql(sqlc)
+		count = config.CusTiDb.CountBySql(sqlc)
 		if count > 0 {
-			res := util.CusTiDb.SelectBySql(sqlStr)
+			res := config.CusTiDb.SelectBySql(sqlStr)
 			if res != nil && len(*res) > 0 {
 				for _, v := range *res {
-					userId := qutil.ObjToString(v["id"])
+					userId := common.ObjToString(v["id"])
 					//获取用户注册手机号
 					if userId != "" {
-						userData, ok := util.MQFW.FindById("user", userId, `"s_phone":1,"s_m_phone":1`)
+						userData, ok := config.MQFW.FindById("user", userId, `"s_phone":1,"s_m_phone":1`)
 						if userData != nil && len(*userData) > 0 && ok {
-							if qutil.ObjToString((*userData)["s_phone"]) != "" {
-								v["registePhone"] = qutil.ObjToString((*userData)["s_phone"])
+							if common.ObjToString((*userData)["s_phone"]) != "" {
+								v["registePhone"] = common.ObjToString((*userData)["s_phone"])
 							} else {
-								v["registePhone"] = qutil.ObjToString((*userData)["s_m_phone"])
+								v["registePhone"] = common.ObjToString((*userData)["s_m_phone"])
 							}
 						} else {
 							v["registePhone"] = ""
@@ -340,7 +250,6 @@ func SaveFile(rdata [][]interface{}, templatePath string, savePath string, saveN
 		row := sh.AddRow()
 		for j := 0; j < len(data); j++ {
 			row.AddCell().SetValue(data[j])
-			log.Println(data[j], "写入文件")
 		}
 	}
 	now := time.Now()
@@ -356,35 +265,32 @@ func SaveFile(rdata [][]interface{}, templatePath string, savePath string, saveN
 	t2 := fmt.Sprintf("%d%d%d%d%d%d", now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second())
 
 	fileName := saveName + t2 + ".xlsx"
-	log.Println(dir + fileName)
 	err = xf.Save(dir + fileName)
-	log.Println(err)
-	url = qutil.ObjToString(config.SysConfigs.Domain) + dirs + fileName
+	url = common.ObjToString(config.SysConfigs.Domain) + dirs + fileName
 	return url, err
 }
 
 func GetUserById(id string) (userData *map[string]interface{}, ok bool) {
-	userData, ok = util.MQFW.FindById("user", id, `phone,s_phone`)
-	//log.Println(userData, ok)
+	userData, ok = config.MQFW.FindById("user", id, `phone,s_phone`)
 	return userData, ok
 }
 
 func FindUserInfo(msgId int, offSet, pageSize int) (*[]map[string]interface{}, int64) {
-	users := util.JysqlDB.SelectBySql("SELECT user_id AS userId,register_phone AS registePhone,call_center_company,call_center_phone,msg_id FROM sendmsg_customer_info WHERE msg_id = ?", msgId)
-	//users := util.JysqlDB.Find("sendmsg_customer_info", map[string]interface{}{"msg_id": msgId}, "", "createtime desc", offSet, pageSize)
-	total := util.JysqlDB.Count("sendmsg_customer_info", map[string]interface{}{"msg_id": msgId})
+	users := config.JysqlDB.SelectBySql("SELECT user_id AS userId,register_phone AS registePhone,call_center_company,call_center_phone,msg_id FROM sendmsg_customer_info WHERE msg_id = ?", msgId)
+	//users := config.JysqlDB.Find("sendmsg_customer_info", map[string]interface{}{"msg_id": msgId}, "", "createtime desc", offSet, pageSize)
+	total := config.JysqlDB.Count("sendmsg_customer_info", map[string]interface{}{"msg_id": msgId})
 	return users, total
 }
 
 func FindUserIds(msgId int) string {
-	users := util.JysqlDB.Find("sendmsg_customer_info", map[string]interface{}{"msg_id": msgId}, "user_id", "createtime desc", -1, -1)
+	users := config.JysqlDB.Find("sendmsg_customer_info", map[string]interface{}{"msg_id": msgId}, "user_id", "createtime desc", -1, -1)
 	userIds := ""
 	if users != nil && len(*users) > 0 {
 		for k, val := range *users {
 			if k == len(*users)-1 {
-				userIds += qutil.ObjToString(val["user_id"])
+				userIds += common.ObjToString(val["user_id"])
 			} else {
-				userIds += qutil.ObjToString(val["user_id"]) + ","
+				userIds += common.ObjToString(val["user_id"]) + ","
 			}
 		}
 	}

+ 7 - 7
src/customerService/dataExportLogController.go

@@ -1,12 +1,13 @@
 package customerService
 
 import (
-	"github.com/baiy/Cadmin-server-go/admin"
 	"log"
-	//"github.com/baiy/Cadmin-server-go/system/utils"
+
+	"qmx_admin/src/otherPackage/baiy/Cadmin-server-go/admin"
+	//"qmx_admin/src/otherPackage/baiy/Cadmin-server-go/system/utils"
 )
 
-//导出记录返回值
+// 导出记录返回值
 type ExportLog struct {
 	UserName      string `json:"username"`
 	Phone         string `json:"phone"`
@@ -24,7 +25,7 @@ type ExportLog struct {
 	DownloadUrl   string `json:"downloadUrl"`   //下载链接
 }
 
-//导出记录详情
+// 导出记录详情
 func ExportLogDetails(context *admin.Context) (interface{}, error) {
 	param := new(struct {
 		Id     int `form:"id"`
@@ -51,7 +52,7 @@ func ExportLogList(context *admin.Context) (interface{}, error) {
 		EntName   string `form:"entName"`   //企业名称
 		StartTime int    `form:"startTime"` //开始时间
 		EndTime   int    `form:"endTime"`   //结束时间
-		PageNum   int    `form:"offset"`   //页面
+		PageNum   int    `form:"offset"`    //页面
 		PageSize  int    `form:"pageSize"`  //
 	}
 	param := Params{}
@@ -65,9 +66,8 @@ func ExportLogList(context *admin.Context) (interface{}, error) {
 		log.Println(err)
 		return nil, err
 	}
-	log.Println(param)
 	data, totalCount := FindExportLogList(param.Phone, param.NickName, param.EntName, param.StartTime, param.EndTime, param.PageNum, param.PageSize)
-	if data == nil{
+	if data == nil {
 		data = []map[string]interface{}{}
 	}
 	return map[string]interface{}{

+ 92 - 114
src/customerService/dataExportLogService.go

@@ -1,20 +1,19 @@
 package customerService
 
 import (
-	"config"
+	"app.yhyue.com/moapp/jybase/common"
+	"app.yhyue.com/moapp/jybase/mongodb"
+	"app.yhyue.com/moapp/jybase/redis"
 	"encoding/json"
 	"errors"
 	"fmt"
 	"io/ioutil"
 	"log"
-	"mongodb"
 	"net/http"
 	"net/url"
-	qutil "qfw/util"
-	"qfw/util/redis"
+	"qmx_admin/src/config"
 	"strings"
 	"time"
-	"util"
 )
 
 const (
@@ -30,11 +29,9 @@ func FindOnePartner(uid string, id int) (res map[string]interface{}) {
 	return nil
 }
 
-//查询商机管理企业账户余额
+// 查询商机管理企业账户余额
 func getCurrEntCount(entName, entPhone string) int {
-	log.Println("查找余额条件", entName, entPhone)
-	current, ok := util.JyqyfwMgo.FindOne("user", map[string]interface{}{"phone": entPhone, "username": entName})
-	log.Println(current, ok, "查找余额结果")
+	current, ok := config.JyqyfwMgo.FindOne("user", map[string]interface{}{"phone": entPhone, "username": entName})
 	if current == nil || !ok {
 		return 0
 	}
@@ -42,7 +39,7 @@ func getCurrEntCount(entName, entPhone string) int {
 	if !planOk {
 		return 0
 	}
-	return qutil.IntAll(plan["current"])
+	return common.IntAll(plan["current"])
 }
 
 func FindExportLogList(phoneIn, userNameIn, entNameIn string, startTimeIn, endTimeIn, pageNum, pageSize int) (returnList []map[string]interface{}, totalCount int) {
@@ -58,17 +55,17 @@ func FindExportLogList(phoneIn, userNameIn, entNameIn string, startTimeIn, endTi
 	//entNameIdList := []interface{}{}
 	if userNameIn != "" {
 		// 模糊查询出用户列表
-		userTmpRs, ok := util.MQFW.Find("user", map[string]interface{}{"s_nickname": map[string]interface{}{
+		userTmpRs, ok := config.MQFW.Find("user", map[string]interface{}{"s_nickname": map[string]interface{}{
 			"$regex": userNameIn,
 		}}, `{"createtime":-1}`, nil, false, -1, -1)
 		if ok && userTmpRs != nil && len(*userTmpRs) > 0 {
 			for _, v := range *userTmpRs {
-				if qutil.ObjToString(v["s_phone"]) != "" {
+				if common.ObjToString(v["s_phone"]) != "" {
 					nick1List = append(nick1List, "?")
-					nickPhoneList = append(nickPhoneList, qutil.ObjToString(v["s_phone"]))
-				} else if qutil.ObjToString(v["s_m_phone"]) != "" {
+					nickPhoneList = append(nickPhoneList, common.ObjToString(v["s_phone"]))
+				} else if common.ObjToString(v["s_m_phone"]) != "" {
 					nick1List = append(nick1List, "?")
-					nickPhoneList = append(nickPhoneList, qutil.ObjToString(v["s_m_phone"]))
+					nickPhoneList = append(nickPhoneList, common.ObjToString(v["s_m_phone"]))
 				}
 				nick2List = append(nick2List, "?")
 				nickIdList = append(nickIdList, mongodb.BsonIdToSId(v["_id"]))
@@ -81,7 +78,7 @@ func FindExportLogList(phoneIn, userNameIn, entNameIn string, startTimeIn, endTi
 	if entNameIn != "" {
 		// 根据企业名称模糊查询出主账户id 列表
 		// 处理查询条件
-		masterTmpRs, ok := util.MQFW.Find("member", map[string]interface{}{"entname": map[string]interface{}{
+		masterTmpRs, ok := config.MQFW.Find("member", map[string]interface{}{"entname": map[string]interface{}{
 			"$regex": entNameIn,
 		}}, `{"createtime":-1}`, nil, false, -1, -1)
 
@@ -117,13 +114,13 @@ func FindExportLogList(phoneIn, userNameIn, entNameIn string, startTimeIn, endTi
 		if phoneIn != "" || userNameIn != "" {
 			searchMgId := ""
 			if phoneIn != "" {
-				userRs, ok := util.MQFW.FindOne("user", map[string]interface{}{"s_phone": phoneIn})
+				userRs, ok := config.MQFW.FindOne("user", map[string]interface{}{"s_phone": phoneIn})
 				if ok && userRs != nil && len(*userRs) > 0 {
 					searchMgId = mongodb.BsonIdToSId((*userRs)["_id"])
 					nick2List = append(nick2List, "?")
 					nickIdList = append(nickIdList, searchMgId)
 				} else {
-					userRs, oks := util.MQFW.FindOne("user", map[string]interface{}{"s_m_phone": phoneIn})
+					userRs, oks := config.MQFW.FindOne("user", map[string]interface{}{"s_m_phone": phoneIn})
 					if oks && userRs != nil && len(*userRs) > 0 {
 						searchMgId = mongodb.BsonIdToSId((*userRs)["_id"])
 						nick2List = append(nick2List, "?")
@@ -153,7 +150,6 @@ func FindExportLogList(phoneIn, userNameIn, entNameIn string, startTimeIn, endTi
 				if len(tmpFilterList) > 0 {
 					tmpFilterSql = fmt.Sprintf(" where %s ", strings.Join(tmpFilterList, " and "))
 				}
-				//log.Println(888888, tmpFilterSql)
 				datapackSql = fmt.Sprintf("(SELECT id AS log_id,'' AS ent_id,useid AS user_id,master_id AS master_id,date AS exportDate,type AS data_from,export_num AS export_num,'2' AS source,'' AS phone,'' AS ent_name,'' AS admin_phone,isSenior as isSenior  FROM datapacket_record %s)  ", tmpFilterSql)
 				searchStrList = append(searchStrList, datapackSql)
 			}
@@ -173,7 +169,6 @@ func FindExportLogList(phoneIn, userNameIn, entNameIn string, startTimeIn, endTi
 			if len(tmpFilterList) > 0 {
 				tmpFilterSql = fmt.Sprintf(" where %s ", strings.Join(tmpFilterList, " and "))
 			}
-			//log.Println(888888, tmpFilterSql)
 			datapackSql = fmt.Sprintf("(SELECT id AS log_id,'' AS ent_id,useid AS user_id,master_id AS master_id,date AS exportDate,type AS data_from,export_num AS export_num,'2' AS source,'' AS phone ,'' AS ent_name,'' as admin_phone,isSenior as isSenior FROM datapacket_record %s)  ", tmpFilterSql)
 			searchStrList = append(searchStrList, datapackSql)
 		}
@@ -185,7 +180,6 @@ func FindExportLogList(phoneIn, userNameIn, entNameIn string, startTimeIn, endTi
 
 	// 处理手机号或者昵称条件匹配到的用户id
 	// 根据昵称匹配到了用户 拿到了用户手机号才能去查商机管理表
-	//log.Println(userNameIn)
 	if userNameIn != "" {
 		if len(nickPhoneList) > 0 {
 			if startTimeIn != 0 {
@@ -212,7 +206,6 @@ func FindExportLogList(phoneIn, userNameIn, entNameIn string, startTimeIn, endTi
 			if len(tmpFilterList2) > 0 {
 				tmpFilterSql2 = fmt.Sprintf(" and %s ", strings.Join(tmpFilterList2, " and "))
 			}
-			//log.Println(tmpFilterSql2, "99888888")
 			// 数据流量包(线下)
 			entnicheSql = fmt.Sprintf("(SELECT a.id AS log_id, a.ent_id AS ent_id,a.user_id AS user_id,'' AS master_id,UNIX_TIMESTAMP( a.export_time ) AS exportDate,0 AS data_from,a.export_num AS export_num,'1' AS source,a.phone as phone ,b.NAME AS ent_name,b.phone as admin_phone ,'' as isSenior FROM entniche_export_log AS a,entniche_info AS b WHERE a.ent_id = b.id  %s)", tmpFilterSql2)
 			searchStrList = append(searchStrList, entnicheSql)
@@ -252,7 +245,7 @@ func FindExportLogList(phoneIn, userNameIn, entNameIn string, startTimeIn, endTi
 	b := fmt.Sprintf("SELECT * FROM (%s) AS alldata ORDER BY exportDate DESC  LIMIT ?,? ", searchSql)
 
 	//   返回totalCount
-	totalCount = util.JysqlDB.QueryCount(fmt.Sprintf("SELECT count(*) FROM (%s) AS alldata  ", searchSql), searchValueList...)
+	totalCount = config.JysqlDB.QueryCount(fmt.Sprintf("SELECT count(*) FROM (%s) AS alldata  ", searchSql), searchValueList...)
 
 	//  追加翻页参数
 	searchValueList = append(searchValueList, pageNum, pageSize)
@@ -273,9 +266,7 @@ func FindExportLogList(phoneIn, userNameIn, entNameIn string, startTimeIn, endTi
 		"FROM  (%s) AS finalData", b)
 	//查询
 	// 补充字段  支付方式 处理单日限量包   用户微信昵称  单日限量包和数据流量包线上需要补充 用户手机号
-	log.Println(c)
-	log.Println(searchValueList)
-	resultList := util.JysqlDB.Query(c, searchValueList...)
+	resultList := config.JysqlDB.Query(c, searchValueList...)
 
 	if resultList == nil || len(*resultList) == 0 {
 		log.Println("未查询到结果")
@@ -286,35 +277,28 @@ func FindExportLogList(phoneIn, userNameIn, entNameIn string, startTimeIn, endTi
 	for _, row := range *resultList {
 		//  根据类型查询  mongo 库
 		//	商机管理的根据手机号查询mongo库   获取用户微信昵称  source  0商机管理的数据  1  datapack的数据
-		//log.Println(row)
 		if row["source"] == "1" {
 
-			userData, ok := util.MQFW.FindOne("user", map[string]interface{}{"s_phone": row["phone"]})
+			userData, ok := config.MQFW.FindOne("user", map[string]interface{}{"s_phone": row["phone"]})
 			if ok && userData != nil && len(*userData) > 0 {
-				//log.Println("11", userData)
 				row["nickname"] = (*userData)["s_nickname"]
 			} else {
-				userDatas, oks := util.MQFW.FindOne("user", map[string]interface{}{"s_m_phone": row["phone"]})
+				userDatas, oks := config.MQFW.FindOne("user", map[string]interface{}{"s_m_phone": row["phone"]})
 				if oks && userDatas != nil && len(*userDatas) > 0 {
-					//log.Println("22", userData)
 					row["nickname"] = (*userDatas)["s_nickname"]
 				} else {
 					log.Println("未找到对应信息2")
 				}
 			}
-			//log.Println("5555555",userData,row)
 			//	商机管理查询用户余额
-			log.Println(row["ent_name"], row["admin_phone"], "查找企业余额")
-			leftCount := getCurrEntCount(qutil.ObjToString(row["ent_name"]), qutil.ObjToString(row["admin_phone"]))
+			leftCount := getCurrEntCount(common.ObjToString(row["ent_name"]), common.ObjToString(row["admin_phone"]))
 			row["leftCount"] = leftCount
 		} else {
 			//	单日限量包和数据流量包线上的根据用户id查询mongo库  获取用户微信昵称和手机号
-			log.Println(row["user_id"])
-			data, ok := util.MQFW.FindOne("user", map[string]interface{}{"_id": mongodb.StringTOBsonId(qutil.ObjToString(row["user_id"]))})
-			log.Println(data, "补充用户手机号")
+			data, ok := config.MQFW.FindOne("user", map[string]interface{}{"_id": mongodb.StringTOBsonId(common.ObjToString(row["user_id"]))})
 			if ok && data != nil && len(*data) > 0 {
 				row["nickname"] = (*data)["s_nickname"]
-				if qutil.ObjToString((*data)["s_phone"]) == "" {
+				if common.ObjToString((*data)["s_phone"]) == "" {
 					row["phone"] = (*data)["s_m_phone"]
 				} else {
 					row["phone"] = (*data)["s_phone"]
@@ -326,15 +310,14 @@ func FindExportLogList(phoneIn, userNameIn, entNameIn string, startTimeIn, endTi
 				row["pay_way"] = "每日限量包"
 			}
 			//	单日限量包  当日限额
-			if qutil.IntAll(row["data_from"]) == 1 {
+			if common.IntAll(row["data_from"]) == 1 {
 				// 查主账号余额
-				dayUse := redis.GetInt(RedisCacheDb, fmt.Sprintf(DataPacketUsedNum,qutil.ObjToString(row["master_id"]), time.Now().Day()))
-				//log.Println(dayUse)
-				todayLimit:= GetDailyNum(qutil.ObjToString(row["master_id"]))
+				dayUse := redis.GetInt(RedisCacheDb, fmt.Sprintf(DataPacketUsedNum, common.ObjToString(row["master_id"]), time.Now().Day()))
+				todayLimit := GetDailyNum(common.ObjToString(row["master_id"]))
 				row["leftCount"] = todayLimit - dayUse
 
 				//  补充公司名称  根据master_id 去member表里 mongo 查数据
-				companyRs, ok := util.MQFW.FindOne("member", map[string]interface{}{
+				companyRs, ok := config.MQFW.FindOne("member", map[string]interface{}{
 					"userid": row["master_id"],
 				})
 				if ok && companyRs != nil && len(*companyRs) > 0 {
@@ -347,14 +330,14 @@ func FindExportLogList(phoneIn, userNameIn, entNameIn string, startTimeIn, endTi
 				//  数据流量包(线上) 调用中台接口
 				//balance := 0 //剩余量
 				resourceType := ""
-				if qutil.IntAll(row["isSenior"]) == 1 {
+				if common.IntAll(row["isSenior"]) == 1 {
 					resourceType = "标准字段包"
 				} else {
 					resourceType = "高级字段包"
 				}
 				//调用资源中台服务获取剩余量
 				resMap, err := CommonPost(config.SysConfigs.FindBalance, url.Values{
-					"accountId": []string{qutil.ObjToString(row["user_id"])}, //账户标识*
+					"accountId": []string{common.ObjToString(row["user_id"])}, //账户标识*
 				})
 				if err != nil {
 					return
@@ -370,8 +353,8 @@ func FindExportLogList(phoneIn, userNameIn, entNameIn string, startTimeIn, endTi
 						log.Println("packAccountQuery 请求中台返回数据结构异常")
 						return
 					}
-					if qutil.ObjToString(obj["resourceType"]) == resourceType {
-						row["leftCount"] = qutil.IntAll(obj["number"])
+					if common.ObjToString(obj["resourceType"]) == resourceType {
+						row["leftCount"] = common.IntAll(obj["number"])
 						break
 					}
 				}
@@ -380,18 +363,15 @@ func FindExportLogList(phoneIn, userNameIn, entNameIn string, startTimeIn, endTi
 		}
 		returnList = append(returnList, row)
 	}
-	//log.Println(resultList)
 	return
 }
 func GetDailyNum(masterId string) (dailyNum int) {
-	serviceList := util.JysqlDB.Find(BigmemberUserPowerTable, map[string]interface{}{"s_userid": masterId, "i_status": 0}, "DISTINCT(s_serviceid),i_frequency", "", -1, -1)
-	//log.Println("啊 =====",serviceList)
+	serviceList := config.JysqlDB.Find(BigmemberUserPowerTable, map[string]interface{}{"s_userid": masterId, "i_status": 0}, "DISTINCT(s_serviceid),i_frequency", "", -1, -1)
 	if serviceList != nil && len(*serviceList) != 0 {
-		//log.Println(serviceList,"呜呜呜")
 		for _, item := range *serviceList {
-			serviceid := qutil.IntAll(item["s_serviceid"])
+			serviceid := common.IntAll(item["s_serviceid"])
 			if serviceid == 17 || serviceid == 18 { //每日数据包
-				dailyNum = qutil.IntAll(item["i_frequency"])
+				dailyNum = common.IntAll(item["i_frequency"])
 			}
 		}
 
@@ -411,14 +391,14 @@ func packAccountQuery(accountId string) (total int, err error) {
 	}
 
 	for _, obj := range listObj {
-		packMap := qutil.ObjToMap(obj)
+		packMap := common.ObjToMap(obj)
 		if packMap == nil || len(*packMap) == 0 {
 			continue
 		}
-		if packType := qutil.ObjToString((*packMap)["name"]); packType != PACKNAME {
+		if packType := common.ObjToString((*packMap)["name"]); packType != PACKNAME {
 			continue
 		}
-		total = qutil.IntAll((*packMap)["number"]) //总量
+		total = common.IntAll((*packMap)["number"]) //总量
 
 	}
 	return
@@ -433,12 +413,11 @@ func CommonPost(path string, param url.Values) (map[string]interface{}, error) {
 	defer res.Body.Close()
 	bs, _ := ioutil.ReadAll(res.Body)
 	resMap := map[string]interface{}{}
-	log.Println("req", param.Encode(), "body:", string(bs), "err", err)
 	err = json.Unmarshal(bs, &resMap)
 	if err != nil {
 		return nil, fmt.Errorf("%s 请求中台返回内容异常 %s", path, string(bs))
 	}
-	if qutil.IntAll(resMap["code"]) != 1 {
+	if common.IntAll(resMap["code"]) != 1 {
 		return nil, fmt.Errorf("%s 请求中台请求出错 %v", path, resMap["message"])
 	}
 	return resMap, nil
@@ -447,19 +426,19 @@ func CommonPost(path string, param url.Values) (map[string]interface{}, error) {
 func FindExportLog(id, source int) (result ExportLog, err error) {
 	//result := ExportLog{}
 	if source == 1 { //查询商机管理数据导出记录表
-		exportLog := util.JysqlDB.FindOne("entniche_export_log", map[string]interface{}{"id": id}, ``, "")
+		exportLog := config.JysqlDB.FindOne("entniche_export_log", map[string]interface{}{"id": id}, ``, "")
 		if exportLog != nil && len(*exportLog) > 0 {
 			//查询条件处理
-			str := qutil.ObjToString((*exportLog)["filter"])
+			str := common.ObjToString((*exportLog)["filter"])
 			filterMap := map[string]interface{}{}
 			err := json.Unmarshal([]byte(str), &filterMap)
 			if err != nil {
 				return result, err
 			}
 			filter := ""
-			if qutil.ObjToString(filterMap["FilterId"]) != "" {
+			if common.ObjToString(filterMap["FilterId"]) != "" {
 				//查询搜索条件
-				queryMap, ok := util.MQFW.FindById("export_search", qutil.ObjToString(filterMap["FilterId"]), nil)
+				queryMap, ok := config.MQFW.FindById("export_search", common.ObjToString(filterMap["FilterId"]), nil)
 				if queryMap == nil && !ok {
 					return result, errors.New("查询export_search出错")
 				}
@@ -481,16 +460,16 @@ func FindExportLog(id, source int) (result ExportLog, err error) {
 				_filter, _ := json.Marshal(queryMap)
 				filter = string(_filter)
 			}
-			userId := qutil.Int64All((*exportLog)["user_id"])
-			//exportTime := qutil.ObjToString((*exportLog)["export_time"])
-			phone := qutil.ObjToString((*exportLog)["phone"])
+			userId := common.Int64All((*exportLog)["user_id"])
+			//exportTime := common.ObjToString((*exportLog)["export_time"])
+			phone := common.ObjToString((*exportLog)["phone"])
 			//查询用户信息
-			userData, ok := util.MQFW.FindOne("user", map[string]interface{}{"s_phone": phone})
+			userData, ok := config.MQFW.FindOne("user", map[string]interface{}{"s_phone": phone})
 			if ok && userData != nil && len(*userData) > 0 {
 				(*exportLog)["userName"] = (*userData)["s_nickname"]
 				//(*exportLog)["email"] = (*userData)["s_email"]
 			} else {
-				userDatas, oks := util.MQFW.FindOne("user", map[string]interface{}{"s_m_phone": phone})
+				userDatas, oks := config.MQFW.FindOne("user", map[string]interface{}{"s_m_phone": phone})
 				if oks && userDatas != nil && len(*userDatas) > 0 {
 					(*exportLog)["userName"] = (*userDatas)["s_nickname"]
 					//(*exportLog)["email"] = (*userDatas)["s_email"]
@@ -498,99 +477,98 @@ func FindExportLog(id, source int) (result ExportLog, err error) {
 			}
 			//查询用户每日导出限额
 			todayLimit, exportNums := 0, 0
-			limitData := util.JysqlDB.FindOne("entniche_export_limit", map[string]interface{}{"user_id": userId}, ``, "")
+			limitData := config.JysqlDB.FindOne("entniche_export_limit", map[string]interface{}{"user_id": userId}, ``, "")
 			if limitData != nil && len(*limitData) > 0 {
 				//查询企业信息
-				entData := util.JysqlDB.FindOne("entniche_info", map[string]interface{}{"id": qutil.IntAll((*exportLog)["ent_id"])}, `name,phone`, "")
+				entData := config.JysqlDB.FindOne("entniche_info", map[string]interface{}{"id": common.IntAll((*exportLog)["ent_id"])}, `name,phone`, "")
 				if entData != nil && len(*entData) > 0 {
 					(*exportLog)["entName"] = (*entData)["name"]
-					entPhone := qutil.ObjToString((*entData)["phone"])
+					entPhone := common.ObjToString((*entData)["phone"])
 					//根据企业名称和企业手机号查询商机管理企业剩余条数
-					(*exportLog)["balance"] = getCurrEntCount(qutil.ObjToString((*entData)["name"]), entPhone)
+					(*exportLog)["balance"] = getCurrEntCount(common.ObjToString((*entData)["name"]), entPhone)
 				}
-				todayLimit = qutil.IntAll((*limitData)["data_limit"])  //每日限额
-				exportNums = qutil.IntAll((*limitData)["export_nums"]) //今日已导出
+				todayLimit = common.IntAll((*limitData)["data_limit"])  //每日限额
+				exportNums = common.IntAll((*limitData)["export_nums"]) //今日已导出
 			}
 			result = ExportLog{
-				UserName:      qutil.ObjToString((*exportLog)["userName"]),
-				Email:         qutil.ObjToString((*exportLog)["export_mail"]),
-				Phone:         qutil.ObjToString((*exportLog)["phone"]),
-				CompanyName:   qutil.ObjToString((*exportLog)["entName"]),
+				UserName:      common.ObjToString((*exportLog)["userName"]),
+				Email:         common.ObjToString((*exportLog)["export_mail"]),
+				Phone:         common.ObjToString((*exportLog)["phone"]),
+				CompanyName:   common.ObjToString((*exportLog)["entName"]),
 				PayWay:        1,
 				DataType:      "高级字段包",
-				Balance:       qutil.IntAll((*exportLog)["balance"]),
-				ExportNum:     qutil.IntAll((*exportLog)["export_num"]),
-				RepetitionNum: qutil.IntAll((*exportLog)["export_num"]) - qutil.IntAll((*exportLog)["deduct_num"]),
-				DeductNum:     qutil.IntAll((*exportLog)["deduct_num"]),
+				Balance:       common.IntAll((*exportLog)["balance"]),
+				ExportNum:     common.IntAll((*exportLog)["export_num"]),
+				RepetitionNum: common.IntAll((*exportLog)["export_num"]) - common.IntAll((*exportLog)["deduct_num"]),
+				DeductNum:     common.IntAll((*exportLog)["deduct_num"]),
 				DayLimit:      todayLimit,
 				DayExportNum:  exportNums,
 				Filter:        filter,
-				DownloadUrl:   config.SysConfigs.JyWebDomain + qutil.ObjToString((*exportLog)["download_url"]),
+				DownloadUrl:   config.SysConfigs.JyWebDomain + common.ObjToString((*exportLog)["download_url"]),
 			}
 			return result, nil
 		}
 	} else {
 		//查询流量包导出记录
-		packExportLog := util.JysqlDB.FindOne("datapacket_record", map[string]interface{}{"id": id}, ``, "")
+		packExportLog := config.JysqlDB.FindOne("datapacket_record", map[string]interface{}{"id": id}, ``, "")
 		if packExportLog != nil && len(*packExportLog) > 0 {
-			userId := qutil.ObjToString((*packExportLog)["useid"]) //user表数据id
-			queryId := qutil.ObjToString((*packExportLog)["query_id"])
+			userId := common.ObjToString((*packExportLog)["useid"]) //user表数据id
+			queryId := common.ObjToString((*packExportLog)["query_id"])
 			//查询用户信息
-			userData, oks := util.MQFW.FindById("user", userId, nil)
+			userData, oks := config.MQFW.FindById("user", userId, nil)
 			if userData != nil && len(*userData) > 0 && oks {
 				(*packExportLog)["userName"] = (*userData)["s_nickname"]
-				if qutil.ObjToString((*userData)["s_phone"]) == "" {
+				if common.ObjToString((*userData)["s_phone"]) == "" {
 					(*packExportLog)["phone"] = (*userData)["s_m_phone"]
 				} else {
 					(*packExportLog)["phone"] = (*userData)["s_phone"]
 				}
 			}
 			//查询搜索条件
-			queryData, ok := util.MQFW.FindById("export_search", queryId, nil)
+			queryData, ok := config.MQFW.FindById("export_search", queryId, nil)
 			if queryData == nil && !ok {
 				return result, errors.New("查询export_search出错")
 			}
 			_filter, _ := json.Marshal(queryData)
 			filter := string(_filter)
-			if qutil.IntAll((*packExportLog)["type"]) == 1 { //单日限量包
+			if common.IntAll((*packExportLog)["type"]) == 1 { //单日限量包
 				todayLimit := 0
 				balance := 0
 				//todayExport := 0
 				//查询用户单日限量额度
-				data := util.JysqlDB.SelectBySql("SELECT s.s_count_month,u.i_frequency FROM bigmember_service_user u LEFT JOIN bigmember_service s ON u.s_serviceid = s.id WHERE u.s_userid = ? and (s.id = 17 or s.id = 18)", userId)
+				data := config.JysqlDB.SelectBySql("SELECT s.s_count_month,u.i_frequency FROM bigmember_service_user u LEFT JOIN bigmember_service s ON u.s_serviceid = s.id WHERE u.s_userid = ? and (s.id = 17 or s.id = 18)", userId)
 				if data != nil && len(*data) > 0 {
-					todayLimit = qutil.IntAll((*data)[0]["i_frequency"])
+					todayLimit = common.IntAll((*data)[0]["i_frequency"])
 					//计算今日已导出
-					//frequency = qutil.IntAll((*data)[0]["i_frequency"]) //今日剩余数量
+					//frequency = common.IntAll((*data)[0]["i_frequency"]) //今日剩余数量
 					//todayExport = todayLimit - frequency                //今日已导出数量
 				}
 				//今日已导出数量
-				dayUse := redis.GetInt(RedisCacheDb, fmt.Sprintf(DataPacketUsedNum, qutil.ObjToString((*packExportLog)["master_id"]), time.Now().Day()))
-				//log.Println(dayUse)
+				dayUse := redis.GetInt(RedisCacheDb, fmt.Sprintf(DataPacketUsedNum, common.ObjToString((*packExportLog)["master_id"]), time.Now().Day()))
 				balance = todayLimit - dayUse
 				//查询企业名称
 				companyName := ""
-				entInfo, ok := util.MQFW.FindOne("member", map[string]interface{}{"userid": userId})
+				entInfo, ok := config.MQFW.FindOne("member", map[string]interface{}{"userid": userId})
 				if entInfo != nil && len(*entInfo) > 0 && ok {
-					companyName = qutil.ObjToString((*entInfo)["entname"])
+					companyName = common.ObjToString((*entInfo)["entname"])
 				}
 				result = ExportLog{
-					UserName:    qutil.ObjToString((*packExportLog)["userName"]),
-					Email:       qutil.ObjToString((*packExportLog)["mail"]),
-					Phone:       qutil.ObjToString((*packExportLog)["phone"]),
+					UserName:    common.ObjToString((*packExportLog)["userName"]),
+					Email:       common.ObjToString((*packExportLog)["mail"]),
+					Phone:       common.ObjToString((*packExportLog)["phone"]),
 					CompanyName: companyName,
 					PayWay:      2,
 					//DataType:      "高级字段包",
 					Balance:       balance,
-					ExportNum:     qutil.IntAll((*packExportLog)["export_num"]),
-					RepetitionNum: qutil.IntAll((*packExportLog)["export_num"]) - qutil.IntAll((*packExportLog)["deduct_num"]),
-					DeductNum:     qutil.IntAll((*packExportLog)["deduct_num"]),
+					ExportNum:     common.IntAll((*packExportLog)["export_num"]),
+					RepetitionNum: common.IntAll((*packExportLog)["export_num"]) - common.IntAll((*packExportLog)["deduct_num"]),
+					DeductNum:     common.IntAll((*packExportLog)["deduct_num"]),
 					DayLimit:      todayLimit,
 					DayExportNum:  dayUse,
-					DownloadUrl:   config.SysConfigs.JyWebDomain + qutil.ObjToString((*packExportLog)["path"]),
+					DownloadUrl:   config.SysConfigs.JyWebDomain + common.ObjToString((*packExportLog)["path"]),
 					Filter:        filter,
 				}
-				if qutil.IntAll((*packExportLog)["isSenior"]) == 1 {
+				if common.IntAll((*packExportLog)["isSenior"]) == 1 {
 					result.DataType = "标准字段包"
 				} else {
 					result.DataType = "高级字段包"
@@ -599,7 +577,7 @@ func FindExportLog(id, source int) (result ExportLog, err error) {
 			} else { //数据流量包
 				balance := 0 //剩余量
 				resourceType := ""
-				if qutil.IntAll((*packExportLog)["isSenior"]) == 1 {
+				if common.IntAll((*packExportLog)["isSenior"]) == 1 {
 					resourceType = "标准字段包"
 				} else {
 					resourceType = "高级字段包"
@@ -620,25 +598,25 @@ func FindExportLog(id, source int) (result ExportLog, err error) {
 					if !ok {
 						return result, fmt.Errorf("packAccountQuery 请求中台返回数据结构异常")
 					}
-					if qutil.ObjToString(obj["resourceType"]) == resourceType {
-						balance = qutil.IntAll(obj["number"])
+					if common.ObjToString(obj["resourceType"]) == resourceType {
+						balance = common.IntAll(obj["number"])
 						break
 					}
 				}
 				result = ExportLog{
-					UserName:      qutil.ObjToString((*packExportLog)["userName"]),
-					Email:         qutil.ObjToString((*packExportLog)["mail"]),
-					Phone:         qutil.ObjToString((*packExportLog)["phone"]),
+					UserName:      common.ObjToString((*packExportLog)["userName"]),
+					Email:         common.ObjToString((*packExportLog)["mail"]),
+					Phone:         common.ObjToString((*packExportLog)["phone"]),
 					CompanyName:   "",
 					PayWay:        3,
 					DataType:      resourceType,
 					Balance:       balance,
-					ExportNum:     qutil.IntAll((*packExportLog)["export_num"]),
-					RepetitionNum: qutil.IntAll((*packExportLog)["export_num"]) - qutil.IntAll((*packExportLog)["deduct_num"]),
-					DeductNum:     qutil.IntAll((*packExportLog)["deduct_num"]),
+					ExportNum:     common.IntAll((*packExportLog)["export_num"]),
+					RepetitionNum: common.IntAll((*packExportLog)["export_num"]) - common.IntAll((*packExportLog)["deduct_num"]),
+					DeductNum:     common.IntAll((*packExportLog)["deduct_num"]),
 					DayLimit:      0,
 					DayExportNum:  0,
-					DownloadUrl:   config.SysConfigs.JyWebDomain + qutil.ObjToString((*packExportLog)["path"]),
+					DownloadUrl:   config.SysConfigs.JyWebDomain + common.ObjToString((*packExportLog)["path"]),
 					Filter:        filter,
 				}
 				return result, nil

+ 86 - 41
src/customerService/newsController.go

@@ -1,13 +1,15 @@
 package customerService
 
 import (
-	"config"
+	"app.yhyue.com/moapp/jybase/common"
 	"errors"
-	"log"
+	"qmx_admin/src/config"
+	"qmx_admin/src/public"
 	"strconv"
+	"strings"
 
-	"github.com/baiy/Cadmin-server-go/admin"
-	"github.com/baiy/Cadmin-server-go/system/utils"
+	"qmx_admin/src/otherPackage/baiy/Cadmin-server-go/admin"
+	"qmx_admin/src/otherPackage/baiy/Cadmin-server-go/system/utils"
 )
 
 type MsgListParam struct {
@@ -25,34 +27,28 @@ type MsgListParam struct {
 	utils.Page
 }
 
-type Message struct {
-	Id            int    `form:"id"`            //消息id
-	UserGroupId   string `form:"userGroupId"`   //用户分组标识
-	UserGroupName string `form:"userGroupName"` //用户分组名称
-	MsgType       int    `form:"msgType"`       //消息类型
-	Title         string `form:"title"`         //标题
-	Content       string `form:"content"`       //内容
-	Link          string `form:"link"`          //链接
-	SendMode      int    `form:"sendMode"`      //发送时效 发送模式  1- 定时 2-实时
-	SendTime      string `form:"sendTime"`      // 发送时间
-	AndroidUrl    string `form:"androidUrl"`    //安卓连接
-	IosUrl        string `form:"iosUrl"`        //ios连接
-	WeChatUrl     string `form:"weChatUrl"`     //微信连接
-}
 type SendMessage struct {
-	UserIds    string `form:"userIds"`
-	MsgType    int    `form:"msgType"`    //消息类型
-	Title      string `form:"title"`      //标题
-	Content    string `form:"content"`    //内容
-	Link       string `form:"link"`       //链接
-	SendMode   int    `form:"sendMode"`   //发送时效 发送模式  1- 定时 2-实时
-	SendTime   string `form:"sendTime"`   // 发送时间
-	AndroidUrl string `form:"androidUrl"` //安卓连接
-	IosUrl     string `form:"iosUrl"`     //ios连接
-	WeChatUrl  string `form:"weChatUrl"`  //微信连接
+	UserIds      string `form:"userIds"`
+	MsgType      int    `form:"msgType"`      //消息类型
+	Title        string `form:"title"`        //标题
+	Content      string `form:"content"`      //内容
+	Link         string `form:"link"`         //链接
+	SendMode     int    `form:"sendMode"`     //发送时效 发送模式  1- 定时 2-实时
+	SendTime     string `form:"sendTime"`     // 发送时间
+	AndroidUrl   string `form:"androidUrl"`   //安卓连接
+	IosUrl       string `form:"iosUrl"`       //ios连接
+	WeChatUrl    string `form:"weChatUrl"`    //微信连接
+	CallPlatform string `form:"callPlatform"` //调用平台
+	MenuName     string `form:"menuname"`     // search:搜索 subscribe:订阅 box:百宝箱 me:我的 other:新的webview  消息中心 message
+	PositionIds  string `form:"positionIds"`  // 职位id 逗号分割 如果部分不需要,也需要逗号分割占位 例 11,,3,4;如果全部不需要,可传空字符串例如""
+
+	Name       string `form:"name"`       //代销售下单微信模板商品名称
+	Orderid    string `form:"orderid"`    //代销售下单微信模板订单编号
+	Ordermoney string `form:"ordermoney"` //代销售下单微信模板订单金额
+	Identity   string `form:"identity"`   //代销售下单-用于区分用户身份
 }
 
-//查看消息内容
+// 查看消息内容
 func MessageDetails(context *admin.Context) (interface{}, error) {
 	param := new(struct {
 		Id int `form:"id"`
@@ -103,7 +99,6 @@ func MessageList(context *admin.Context) (interface{}, error) {
 			}
 		}
 	}
-	log.Println(isLookAll)
 	data, count := MsgList(param, isLookAll, loginUserId, loginUserName)
 	return map[string]interface{}{
 		"lists": data,
@@ -113,24 +108,64 @@ func MessageList(context *admin.Context) (interface{}, error) {
 
 // MessageSave 保存消息
 func MessageSave(context *admin.Context) (interface{}, error) {
-	param := &Message{}
+	param := &public.Message{}
 	err := context.Form(param)
 	if err != nil {
 		return nil, nil
 	}
-	//发送状态
-	sendStatus := 1 //
-	if param.SendMode == 2 {
+	if param.ShowBuoy == 1 && param.ShowContent == "" {
+		return nil, errors.New("展示浮标内容不能为空")
+	}
+	//发送状态 1- 待发送 2-发送中 3-发送失败 4-已发送
+	sendStatus := 1
+	if param.SendMode == 2 { //实时发送
+		sendStatus = 2
+	}
+	if param.Sign == 4 {
 		sendStatus = 4
+		param.UserGroupName = "新用户"
 	}
-	//拼接link
-	param.Link = param.Link + "," + param.AndroidUrl + "," + param.IosUrl + "," + param.WeChatUrl
 	status, err := SendMsg(param, sendStatus, context.User.Username, context.User.Id)
 	return map[string]interface{}{
 		"status": status,
 	}, err
 }
 
+// MessageShow 新用户消息回显
+func MessageShow(context *admin.Context) (interface{}, error) {
+	data := config.JysqlDB.FindOne("message_send_log", map[string]interface{}{"sign": 4}, "", "createtime desc")
+	if data != nil && len(*data) > 0 {
+		(*data)["userGroupName"] = (*data)["send_usergroup_name"]
+		(*data)["msgType"] = (*data)["msg_type"]
+		(*data)["sendMode"] = (*data)["send_mode"]
+		(*data)["sendTime"] = (*data)["send_status"]
+		link := common.ObjToString((*data)["link"])
+		arr := strings.Split(link, ",")
+		if len(arr) == 4 {
+			(*data)["link"] = arr[0]
+			(*data)["androidUrl"] = arr[1]
+			(*data)["iosUrl"] = arr[2]
+			(*data)["weChatUrl"] = arr[3]
+		} else {
+			(*data)["link"] = arr[0]
+			(*data)["androidUrl"] = ""
+			(*data)["iosUrl"] = ""
+			(*data)["weChatUrl"] = ""
+		}
+		(*data)["send_usergroup_name"] = "新用户"
+
+		(*data)["showBuoy"] = (*data)["show_buoy"]
+		(*data)["showContent"] = (*data)["show_content"]
+		if common.ObjToString((*data)["menu_name"]) != "" {
+			(*data)["menuname"] = (*data)["menu_name"]
+		} else {
+			(*data)["menuname"] = "message"
+		}
+		return data, nil
+	}
+	return nil, nil
+}
+
 // GetGroup 获取分组
 func GetGroup(context *admin.Context) (interface{}, error) {
 	group, err := GetGroupData()
@@ -140,15 +175,14 @@ func GetGroup(context *admin.Context) (interface{}, error) {
 	return group, nil
 }
 
-//对外提供接口
+// 对外提供接口
 func SendMessageApi(context *admin.Context) (interface{}, error) {
 	param := &SendMessage{}
 	err := context.Form(param)
 	if err != nil {
 		return nil, nil
 	}
-	log.Println(param)
-	log.Println(param.UserIds)
+
 	if param.UserIds == "" {
 		return nil, errors.New("用户id为空,请确认参数是否完整")
 	}
@@ -157,10 +191,21 @@ func SendMessageApi(context *admin.Context) (interface{}, error) {
 	if param.SendMode == 2 {
 		sendStatus = 4
 	}
-	//拼接link
-	param.Link = param.Link + "," + param.AndroidUrl + "," + param.IosUrl + "," + param.WeChatUrl
 	status, err := pushMsg(param, sendStatus)
 	return map[string]interface{}{
 		"status": status,
 	}, err
 }
+
+func GetMsgType(context *admin.Context) (interface{}, error) {
+	types := config.MsgTidb.SelectBySql("SELECT msg_type,msg_name AS name,group_id FROM `message_class` WHERE background_send = 1 ")
+	if types != nil && len(*types) > 0 {
+		tp := []map[string]interface{}{}
+		for _, v := range *types {
+			v["msg_type"] = common.InterfaceToStr(v["msg_type"])
+			tp = append(tp, v)
+		}
+		return types, nil
+	}
+	return nil, errors.New("未查询到分类")
+}

+ 32 - 380
src/customerService/newsService.go

@@ -1,19 +1,17 @@
 package customerService
 
 import (
-	"config"
+	"app.yhyue.com/moapp/jybase/common"
 	"errors"
 	"fmt"
 	"log"
-	qutil "qfw/util"
+	"qmx_admin/src/config"
 	"strconv"
 	"strings"
-	"sync"
-	"task"
-	"time"
-	"util"
 )
 
+var Str = "a.send_usergroup_name,a.msg_type,a.group_id,a.title,a.content,a.send_mode,a.send_time,a.send_status,a.update_time,a.createtime,a.link,a.isdel,a.send_name,a.send_usergroup_id,a.sign,a.user_add_way,a.template_name,a.user_add_way"
+
 type Group struct {
 	Id          int    `json:"id"`
 	Name        string `json:"name"`
@@ -35,21 +33,20 @@ type CustomerId struct {
 	Id []int
 }
 
-//删除消息
+// MsgDelete 删除消息
 func MsgDelete(id string) (int, error) {
-	ok := util.JysqlDB.UpdateOrDeleteBySql("UPDATE message_send_log SET isdel = -1 WHERE id = ?", id)
-	log.Println("修改结果", ok)
+	ok := config.JysqlDB.UpdateOrDeleteBySql("UPDATE message_send_log SET isdel = -1 WHERE id = ?", id)
 	if ok < 0 {
 		return 0, errors.New("修改isDel删除状态出错")
 	}
 	return 1, nil
 }
 
+// MsgDetail 消息详情
 func MsgDetail(id int) (*map[string]interface{}, error) {
-	info := util.JysqlDB.FindOne("message_send_log", map[string]interface{}{"id": id}, "", "")
+	info := config.JysqlDB.FindOne("message_send_log", map[string]interface{}{"id": id}, "", "")
 	if info != nil && len(*info) > 0 {
-		link := qutil.ObjToString((*info)["link"])
-		log.Println("详情连接:", link)
+		link := common.ObjToString((*info)["link"])
 		arr := strings.Split(link, ",")
 		if len(arr) == 4 {
 			(*info)["link"] = arr[0]
@@ -62,18 +59,20 @@ func MsgDetail(id int) (*map[string]interface{}, error) {
 			(*info)["iosUrl"] = ""
 			(*info)["weChatUrl"] = ""
 		}
-		if qutil.IntAll((*info)["sign"]) == 1 || qutil.IntAll((*info)["sign"]) == 1 {
+		if common.IntAll((*info)["sign"]) == 1 || common.IntAll((*info)["sign"]) == 1 {
 			(*info)["send_usergroup_name"] = "自定义"
 		}
-		log.Println("消息详情信息:", *info)
+		if common.ObjToString((*info)["menu_name"]) != "" {
+			(*info)["menuname"] = (*info)["menu_name"]
+		} else {
+			(*info)["menuname"] = "message"
+		}
 		return info, nil
 	}
 	return nil, errors.New("查询出错")
 }
 
-var Str = "a.send_usergroup_name,a.msg_type,a.title,a.content,a.send_mode,a.send_time,a.send_status,a.update_time,a.createtime,a.link,a.isdel,a.send_name,a.send_usergroup_id,a.sign,a.user_add_way,a.template_name,a.user_add_way"
-
-//消息列表查询
+// MsgList 消息列表查询
 func MsgList(param *MsgListParam, isLookAllMsg, loginUserId int, loginUserName string) (*[]map[string]interface{}, int) {
 	sql := "SELECT DISTINCT(a.id)," + Str + " FROM message_send_log as a LEFT JOIN sendmsg_customer_info as b on a.id = b.msg_id "
 	str := ""
@@ -86,7 +85,7 @@ func MsgList(param *MsgListParam, isLookAllMsg, loginUserId int, loginUserName s
 		}
 	}
 	if param.MsgType != 0 {
-		str += " a.msg_type = " + strconv.Itoa(param.MsgType) + " and"
+		str += " a.group_id = " + strconv.Itoa(param.MsgType) + " and"
 	}
 	if param.Title != "" {
 		str += " a.title like " + "'%" + param.Title + "%' and"
@@ -106,11 +105,9 @@ func MsgList(param *MsgListParam, isLookAllMsg, loginUserId int, loginUserName s
 	if param.UpdateTimeEnd != "" {
 		str += " a.update_time <= '" + param.UpdateTimeEnd + " 23:59:59" + "' and"
 	}
-	log.Println("isLookAllMsg", isLookAllMsg)
 	if isLookAllMsg == 0 {
 		str += " a.send_userid = " + strconv.Itoa(loginUserId) + " and"
 	} else if isLookAllMsg == 1 {
-		log.Println("查询创建人为:", param.Creator)
 		if param.Creator != "" {
 			str += " a.send_name like '%" + param.Creator + "%' and"
 		}
@@ -134,369 +131,24 @@ func MsgList(param *MsgListParam, isLookAllMsg, loginUserId int, loginUserName s
 	}
 	sql += page
 	//sql += " ORDER BY id DESC"
-	log.Println("查询sql:", sql)
-	log.Println("统计sql:", sqlc)
-	data := util.JysqlDB.SelectBySql(sql)
-	count := util.JysqlDB.CountBySql(sqlc)
+	data := config.JysqlDB.SelectBySql(sql)
+	count := config.JysqlDB.CountBySql(sqlc)
 	return data, int(count)
 
 }
 
-//调用convertlab接口获取用户分组
+// GetGroupData 获取分组下的用户
 func GetGroupData() ([]map[string]string, error) {
-	data := []map[string]string{}
-	err := util.Tidb.Table("groups").Select("groupid as id,groupname as name").Find(&data)
-	if err != nil {
-		log.Println("获取分组出错----------- ", err)
-	}
-	return data, nil
-}
-
-func SendMsg(param *Message, sendStatus int, loginUserName string, loginUserId int) (int, error) {
-	var msgLogId string
-	if param.SendMode == 2 {
-		param.SendTime = time.Now().Format(qutil.Date_Full_Layout)
-	}
-	// 更新消息
-	if param.Id != 0 {
-		msgLogId = strconv.Itoa(param.Id)
-		ok := util.JysqlDB.Update("message_send_log", map[string]interface{}{"id": param.Id}, map[string]interface{}{
-			"send_usergroup_id":   param.UserGroupId,
-			"send_usergroup_name": param.UserGroupName,
-			// "receive_user_id":     userIdStr,
-			"msg_type":    param.MsgType,
-			"title":       param.Title,
-			"content":     param.Content,
-			"send_mode":   param.SendMode,
-			"send_time":   param.SendTime,
-			"send_status": sendStatus,
-			"update_time": time.Now().Format(qutil.Date_Full_Layout),
-			"link":        param.Link,
-			"isdel":       1,
-			"send_userid": loginUserId,
-			"update_user": loginUserName,
-		})
-		if !ok {
-			return 0, errors.New("发送消息出错")
-		}
-		if param.SendMode == 1 {
-			now := time.Now()
-			sendTime := param.SendTime
-			_, err := time.ParseInLocation(qutil.Date_Full_Layout, sendTime, now.Location())
-			if err != nil {
-				sendTime = param.SendTime + ":00"
-			}
-			key := strconv.Itoa(param.Id)
-			if _, t := util.OnTimeSendMap.Load(key + sendTime); !t {
-				sendTime2, _ := time.ParseInLocation(qutil.Date_Full_Layout, sendTime, now.Location())
-				execTime := sendTime2.Unix() - now.Unix()
-				log.Println(execTime, sendTime, now.Format(qutil.Date_Full_Layout), sendTime2.Unix(), now.Unix())
-				util.OnTimeSendMap.Store(key+sendTime, true)
-				time.AfterFunc(time.Duration(execTime)*time.Second, func() {
-					// 执行任务
-					log.Println("创建、修改添加定时任务")
-					log.Println(param.Id, sendTime)
-					task.Task(param.Id, sendTime, param.AndroidUrl, param.IosUrl)
-				})
-			}
-			return 1, nil
-		}
-		//return 1, nil
-	} else {
-		//保存发送的消息
-		log.Println("发送消息发送时间:", param.SendTime)
-		msgId := util.JysqlDB.Insert("message_send_log", map[string]interface{}{
-			"send_usergroup_id":   param.UserGroupId,
-			"send_usergroup_name": param.UserGroupName,
-			// "receive_user_id":     userIdStr,
-			"msg_type":    param.MsgType,
-			"title":       param.Title,
-			"content":     param.Content,
-			"send_mode":   param.SendMode,
-			"send_time":   param.SendTime,
-			"send_status": sendStatus,
-			"update_time": time.Now().Format(qutil.Date_Full_Layout),
-			"createtime":  time.Now().Format(qutil.Date_Full_Layout),
-			"link":        param.Link,
-			"isdel":       1,
-			"send_userid": loginUserId,
-			"send_name":   loginUserName,
-			"sign":        0,
-			"update_user": loginUserName,
-		})
-		msgLogId = strconv.FormatInt(msgId, 10)
-		//如果是定时发送
-		if param.SendMode == 1 {
-			if msgId > 0 {
-				msgId := qutil.IntAll(msgId)
-				//log.Println("前端时间:", param.SendTime)
-				sendTime, _ := time.ParseInLocation(qutil.Date_Full_Layout, param.SendTime+":00", time.Now().Location())
-				now := time.Now()
-				days := sendTime.Sub(now)
-				log.Println("时间:", days)
-				util.OnTimeSendMap.Store(strconv.Itoa(msgId)+param.SendTime+":00", true)
-				time.AfterFunc(days, func() {
-					// 执行任务
-					//log.Println("创建、修改添加定时任务")
-					log.Println(msgId, sendTime)
-					task.Task(msgId, sendTime.Format("2006-01-02 15:04:05"), param.AndroidUrl, param.IosUrl)
-				})
-				return 1, nil
-			}
-		}
-	}
-	log.Println("*********", msgLogId)
-	//立即发送
-	if param.SendMode == 2 {
-		j := 0
-		projectIdMap := sync.Map{}
-		orm := util.Tidb.NewSession()
-		err := orm.Begin()
-		if err != nil {
-			log.Println("简历数据库连接出错:", err)
-		}
-		log.Println("--------", param.UserGroupId, sendStatus)
-		userNames := ""
-		userIds := ""
-		i := 0
-		msgType := strconv.Itoa(param.MsgType)
-		msg := map[string]interface{}{
-			"sendUserId": loginUserId,
-			"sendName":   loginUserName,
-			"title":      param.Title,
-			"content":    param.Content,
-			"msgType":    msgType,
-			"link":       param.Link,
-			"appid":      util.AppId,
-			"msgLogId":   msgLogId,
-		}
-		//本次次改不调用荟聚接口,改为直接查mysql
-		user := new(struct {
-			UserId string `xorm:"userid"`
-		})
-		rows, err := orm.Table("groupcustomers g").Select("u.userid").Join("LEFT", "customers_user u", "g.customerid = u.customerid").In("g.groupid ", strings.Split(param.UserGroupId, ",")).Rows(user)
-		if err != nil || rows == nil {
-			log.Println("查询tidb中剑鱼用户出错:", err)
-			return 0, err
-		}
-		log.Println("rows", rows)
-		defer rows.Close()
-		for rows.Next() {
-			j++
-			err = rows.Scan(user)
-			if err != nil {
-				log.Println("迭代数据出错", err)
-			}
-
-			userId := user.UserId
-			if config.SysConfigs.UserIdMap[userId] != "" {
-				userId = config.SysConfigs.UserIdMap[userId]
-			}
-			if _, ok := projectIdMap.Load(userId); ok {
-				log.Println("########################已发送,本次跳过。。。。。。。。。。。。。", userId)
-				continue
-			} else {
-				projectIdMap.Store(userId, true)
-			}
-			log.Println("单条数据用户id:", user.UserId)
-			i++
-			userIds += userId + ","
-
-			//查询mongo库用户信息
-			userData := &map[string]interface{}{}
-			ok := false
-			var otherPushId, jgPushId, phoneType, name = "", "", "", ""
-			appVersion := ""
-			userData, ok = util.MQFW.FindById("user", userId, `"s_name":1,"s_opushid":1,"s_jpushid":1,"s_appponetype":1,"s_appversion":1`)
-			if userData != nil && len(*userData) > 0 && ok {
-				otherPushId = qutil.ObjToString((*userData)["s_opushid"])
-				jgPushId = qutil.ObjToString((*userData)["s_jpushid"])
-				phoneType = qutil.ObjToString((*userData)["s_appponetype"])
-				name = qutil.ObjToString((*userData)["s_name"])
-				appVersion = qutil.ObjToString((*userData)["s_appversion"])
-			}
-			userNames += name + ","
-			appPushUrl := "/jyapp/frontPage/messageCenter/sess/index"
-			if strings.Contains(phoneType, "iPhone") {
-				if param.IosUrl != "" {
-					appPushUrl = param.IosUrl
-				}
-			} else {
-				if param.AndroidUrl != "" {
-					appPushUrl = param.AndroidUrl
-				}
-			}
-			//实时发送发送时间为当前时间
-			param.SendTime = time.Now().Format(qutil.Date_Full_Layout)
-			dt := map[string]interface{}{
-				"receiveUserId": userId,
-				"receiveName":   name,
-				"sendUserId":    loginUserId,
-				"sendName":      loginUserName,
-				"title":         param.Title,
-				"content":       param.Content,
-				"msgType":       msgType,
-				"link":          param.Link,
-				"appid":         util.AppId,
-			}
-			//推送消息
-			if appVersion > "3.0.3" {
-				go util.AppGrpcPush(dt, otherPushId, jgPushId, phoneType, appPushUrl)
-			}
-			log.Println("用户数量:", i)
-			if i == 100 {
-				log.Println("100用户开始发送消息:", len(userIds))
-				//调用消息中台
-				util.MultipleSaveMessage(msg, userIds, userNames)
-				log.Println("100个用户发送消息完成......")
-				userNames = ""
-				userIds = ""
-				i = 0
-			}
-
-		}
-		if i > 0 {
-			log.Println("最后一批用户开始发送消息:", len(userIds))
-			//调用中台接口
-			util.MultipleSaveMessage(msg, userIds, userNames)
-			log.Println("最后一批用户发送消息:完成")
-			userNames = ""
-			userIds = ""
-			i = 0
-		}
-		log.Println("********************总数:", j)
-		return 1, nil
-	}
-	return 0, errors.New("发送消息出错")
-}
-
-//呼叫中心发送消息
-func pushMsg(param *SendMessage, sendStatus int) (int, error) {
-	var msgLogId string
-	if param.SendMode == 2 {
-		param.SendTime = time.Now().Format(qutil.Date_Full_Layout)
-	}
-	//保存发送的消息
-	log.Println("发送消息发送时间:", param.SendTime)
-	msgId := util.JysqlDB.Insert("message_send_log", map[string]interface{}{
-		"send_usergroup_id":   "",
-		"send_usergroup_name": "",
-		"msg_type":            param.MsgType,
-		"title":               param.Title,
-		"content":             param.Content,
-		"send_mode":           param.SendMode,
-		"send_time":           param.SendTime,
-		"send_status":         sendStatus,
-		"update_time":         time.Now().Format(qutil.Date_Full_Layout),
-		"createtime":          time.Now().Format(qutil.Date_Full_Layout),
-		"link":                param.Link,
-		"isdel":               1,
-		"send_userid":         "hjzx", //呼叫中心
-		"sign":                3,
-	})
-	msgLogId = strconv.FormatInt(msgId, 10)
-	//立即发送
-	if param.SendMode == 2 {
-		//j := 0
-		projectIdMap := sync.Map{}
-		orm := util.Tidb.NewSession()
-		err := orm.Begin()
-		if err != nil {
-			log.Println("简历数据库连接出错:", err)
-		}
-		userNames := ""
-		userIds := ""
-		i := 0
-		msgType := strconv.Itoa(param.MsgType)
-		msg := map[string]interface{}{
-			"sendUserId": "hjzx",
-			"sendName":   "呼叫中心",
-			"title":      param.Title,
-			"content":    param.Content,
-			"msgType":    msgType,
-			"link":       param.Link,
-			"appid":      util.AppId,
-			"msgLogId":   msgLogId,
-		}
-		userIdsArr := strings.Split(param.UserIds, ",")
-		for _, v := range userIdsArr {
-
-			userId := v
-
-			if config.SysConfigs.UserIdMap[userId] != "" {
-				userId = config.SysConfigs.UserIdMap[userId]
-			}
-			if _, ok := projectIdMap.Load(userId); ok {
-				log.Println("########################已发送,本次跳过。。。。。。。。。。。。。", userId)
-				continue
-			} else {
-				projectIdMap.Store(userId, true)
-			}
-			i++
-			userIds += userId + ","
-
-			//查询mongo库用户信息
-			userData := &map[string]interface{}{}
-			ok := false
-			var otherPushId, jgPushId, phoneType, name = "", "", "", ""
-			appVersion := ""
-			userData, ok = util.MQFW.FindById("user", userId, `"s_name":1,"s_opushid":1,"s_jpushid":1,"s_appponetype":1,"s_appversion":1`)
-			if userData != nil && len(*userData) > 0 && ok {
-				otherPushId = qutil.ObjToString((*userData)["s_opushid"])
-				jgPushId = qutil.ObjToString((*userData)["s_jpushid"])
-				phoneType = qutil.ObjToString((*userData)["s_appponetype"])
-				name = qutil.ObjToString((*userData)["s_name"])
-				appVersion = qutil.ObjToString((*userData)["s_appversion"])
-			}
-			userNames += name + ","
-			appPushUrl := "/jyapp/frontPage/messageCenter/sess/index"
-			if strings.Contains(phoneType, "iPhone") {
-				if param.IosUrl != "" {
-					appPushUrl = param.IosUrl
-				}
-			} else {
-				if param.AndroidUrl != "" {
-					appPushUrl = param.AndroidUrl
-				}
-			}
-			//实时发送发送时间为当前时间
-			param.SendTime = time.Now().Format(qutil.Date_Full_Layout)
-			dt := map[string]interface{}{
-				"receiveUserId": userId,
-				"receiveName":   name,
-				"sendUserId":    "qmx",
-				"sendName":      "剑鱼后台",
-				"title":         param.Title,
-				"content":       param.Content,
-				"msgType":       msgType,
-				"link":          param.Link,
-				"appid":         util.AppId,
-			}
-			//推送消息
-			if appVersion > "3.0.3" {
-				go util.AppGrpcPush(dt, otherPushId, jgPushId, phoneType, appPushUrl)
-			}
-			if i == 100 {
-				//调用消息中台
-				log.Println("100个用户开始发送消息:", i)
-				util.MultipleSaveMessage(msg, userIds, userNames)
-				log.Println("100个用户发送消息完成")
-				userNames = ""
-				userIds = ""
-				i = 0
-			}
-
-		}
-		if i > 0 {
-			//调用中台接口
-			log.Println("最后一批用户开始发送消息:", i)
-			util.MultipleSaveMessage(msg, userIds, userNames)
-			log.Println("最后一批用户发送消息完成")
-			userNames = ""
-			userIds = ""
-			i = 0
-		}
-		return 1, nil
-	}
-	return 0, errors.New("发送消息出错")
+	groups := []map[string]string{}
+	data := config.ConvertlabDB.SelectBySql("select groupid as id,groupname as name from `groups`")
+	if data != nil && len(*data) > 0 {
+		for _, v := range *data {
+			log.Println(v)
+			groups = append(groups, map[string]string{
+				"id":   common.InterfaceToStr(v["id"]),
+				"name": common.ObjToString(v["name"]),
+			})
+		}
+	}
+	return groups, nil
 }

+ 9 - 2
src/customerService/router.go

@@ -4,7 +4,7 @@ import (
 	"errors"
 	"fmt"
 
-	. "github.com/baiy/Cadmin-server-go/admin"
+	. "qmx_admin/src/otherPackage/baiy/Cadmin-server-go/admin"
 )
 
 // 调度器接口
@@ -59,7 +59,8 @@ func RegisterSales(methods map[string]DataManageDispatcherHandleMethod) {
 func (d *SalesDispatchers) Register(methods map[string]DataManageDispatcherHandleMethod) {
 	for name, method := range methods {
 		if _, is := d.HandleMethod[name]; is {
-			panic("[%s] 对应的处理方法已经存在")
+			var msg interface{} = "[%s] 对应的处理方法已经存在"
+			panic(msg)
 		}
 		d.HandleMethod[name] = method
 	}
@@ -74,6 +75,7 @@ func init() {
 		"Baiy.Cadmin.Message.messageDetails":         MessageDetails,
 		"Baiy.Cadmin.Message.getGroup":               GetGroup,
 		"Baiy.Cadmin.Message.messageSave":            MessageSave,
+		"Baiy.Cadmin.Message.messageShow":            MessageShow,
 		"Baiy.Cadmin.Message.customSendMsg":          CustomSendMsg,
 		"Baiy.Cadmin.Message.singleAdd":              SingleAdd,
 		"Baiy.Cadmin.Message.importUser":             ImportUser,
@@ -81,6 +83,11 @@ func init() {
 		"Baiy.Cadmin.Message.getUserInfo":            GetUserInfo,
 		"Baiy.Cadmin.Message.sendMessageApi":         SendMessageApi,
 		"Baiy.Cadmin.Message.getUserIds":             GetUserIds,
+		"Baiy.Cadmin.AvancedProject.projectList":     ProjectList,
+		"Baiy.Cadmin.AvancedProject.projectSave":     ProjectSave,
+		"Baiy.Cadmin.AvancedProject.getUser":         GetUser,
+		"Baiy.Cadmin.AvancedProject.getTitle":        GetTitle,
+		"Baiy.Cadmin.Message.getMsgType":             GetMsgType,
 	})
 	RegisterDispatch(SalesDispatcher)
 }

+ 354 - 0
src/customerService/sendMsgService.go

@@ -0,0 +1,354 @@
+package customerService
+
+import (
+	"app.yhyue.com/moapp/jybase/common"
+	"app.yhyue.com/moapp/jybase/date"
+	"app.yhyue.com/moapp/jybase/redis"
+	"errors"
+	"fmt"
+	"log"
+	"qmx_admin/src/config"
+	"qmx_admin/src/public"
+	"qmx_admin/src/task"
+	"qmx_admin/src/util"
+	"strconv"
+	"strings"
+	"sync"
+	"time"
+)
+
+// SendMsg 保存消息
+func SendMsg(param *public.Message, sendStatus int, loginUserName string, loginUserId int) (int, error) {
+	var msgId int64
+	if param.SendMode == 2 {
+		param.SendTime = time.Now().Format(date.Date_Full_Layout)
+	}
+	groupId := public.MsgTypeToGroupId[param.MsgType]
+	saveData := map[string]interface{}{
+		"send_usergroup_id":   param.UserGroupId,
+		"send_usergroup_name": param.UserGroupName,
+		"msg_type":            param.MsgType,
+		"title":               param.Title,
+		"content":             param.Content,
+		"send_mode":           param.SendMode,
+		"send_time":           param.SendTime,
+		"send_status":         sendStatus,
+		"update_time":         time.Now().Format(date.Date_Full_Layout),
+		"link":                param.Link + "," + param.AndroidUrl + "," + param.IosUrl + "," + param.WeChatUrl,
+		"isdel":               1,
+		"send_userid":         loginUserId,
+		"update_user":         loginUserName,
+		"show_buoy":           param.ShowBuoy,
+		"show_content":        param.ShowContent,
+		"Sign":                param.Sign,
+		"menu_name":           param.MenuName,
+		"group_id":            groupId,
+	}
+	// 更新消息 新用户注册消息不能更新
+	if param.Id != 0 && param.Sign != 4 {
+		msgId = int64(param.Id)
+		ok := config.JysqlDB.Update("message_send_log", map[string]interface{}{"id": param.Id}, saveData)
+		if !ok {
+			return 0, errors.New("UPDATE message_send_log出错")
+		}
+		if param.SendMode == 1 {
+			OnTimeSendMsgService(msgId, param.SendTime, true)
+			return 1, nil
+		}
+	} else {
+		//保存发送的消息
+		saveData["createtime"] = time.Now().Format(date.Date_Full_Layout)
+		saveData["send_name"] = loginUserName
+		msgId = config.JysqlDB.Insert("message_send_log", saveData)
+		//立即发送 新用户发送消息走nsq通知  直接返回
+		if param.Sign == 4 {
+			return 1, nil
+		}
+		if msgId <= 0 {
+			return 0, errors.New("INSTERT message_send_log 出错")
+		}
+		//如果是定时发送
+		if param.SendMode == 1 && msgId > 0 {
+			OnTimeSendMsgService(msgId, param.SendTime, false)
+			return 1, nil
+		}
+		err := util.BitmapMsgSummaryPost(msgId, int64(groupId), int64(param.MsgType)) //更新消息汇总表
+		if err != nil {
+			return 0, err
+		}
+	}
+
+	param.Link, param.AndroidUrl, param.IosUrl, param.WeChatUrl = public.GetMsgUrlString(param.Link, param.AndroidUrl, param.IosUrl, param.WeChatUrl, common.InterfaceToStr(msgId))
+	if param.SendMode == 2 && param.Sign != 4 {
+		//监听redis值,做暂停功能
+		key := fmt.Sprintf(public.Redis_msg_send_switch, msgId)
+		redis.Put(util.AdminRedisModule, key, 1, 60*60*24*5)
+		if param.UserGroupId == public.AllUserCode {
+			// 全部用户发送消息 直接查询mongo库用户
+			go public.AllUserSendMsg(param, loginUserId, loginUserName, common.InterfaceToStr(msgId), false)
+		} else {
+			// 分组用户发消息
+			go GroupSendMsg(param, sendStatus, loginUserId, loginUserName, common.InterfaceToStr(msgId))
+		}
+		return 1, nil
+	}
+	return 0, errors.New("发送消息出错")
+}
+
+// 呼叫中心发送消息
+func pushMsg(param *SendMessage, sendStatus int) (int, error) {
+	var msgLogId string
+	if param.SendMode == 2 {
+		param.SendTime = time.Now().Format(date.Date_Full_Layout)
+	}
+	if param.CallPlatform == "" {
+		param.CallPlatform = "hjzx"
+	}
+	groupId := public.MsgTypeToGroupId[param.MsgType]
+	idStr := ""
+	if param.Identity != "" {
+		idStr = "&identity=" + param.Identity
+		param.AndroidUrl = param.AndroidUrl + idStr
+		param.IosUrl = param.IosUrl + idStr
+	}
+	//保存发送的消息
+	links := param.Link + "," + param.AndroidUrl + "," + param.IosUrl + "," + param.WeChatUrl
+	log.Println("*****************************", param.UserIds)
+	content := param.Content
+	if param.MsgType == config.SysConfigs.EquityInfoMsgType {
+		equityRs := strings.Split(param.Content, "#jy#")
+		if len(equityRs) != 3 {
+			log.Println("消息内容格式有误:", param.Content)
+			return 0, errors.New("无效的消息内容格式")
+		}
+		content = equityRs[0]
+	}
+	msgId := config.JysqlDB.Insert("message_send_log", map[string]interface{}{
+		"send_usergroup_id":   "",
+		"send_usergroup_name": "",
+		"msg_type":            param.MsgType,
+		"title":               param.Title,
+		"content":             content,
+		"send_mode":           param.SendMode,
+		"send_time":           param.SendTime,
+		"send_status":         sendStatus,
+		"update_time":         time.Now().Format(date.Date_Full_Layout),
+		"createtime":          time.Now().Format(date.Date_Full_Layout),
+		"link":                links,
+		"isdel":               1,
+		"send_userid":         param.CallPlatform, //呼叫中心
+		"sign":                3,
+		"menu_name":           param.MenuName,
+		"group_id":            groupId,
+	})
+	msgLogId = common.InterfaceToStr(msgId)
+	//立即发送
+	if param.SendMode == 2 && msgId > -1 {
+		//更新消息汇总表
+		err := util.BitmapMsgSummaryPost(msgId, int64(groupId), int64(param.MsgType)) //更新消息汇总表
+		if err != nil {
+			return 0, err
+		}
+		projectIdMap := sync.Map{}
+		userIds, positionIds, currentIndex := "", "", 0
+		msgType := strconv.Itoa(param.MsgType)
+		param.Link, param.AndroidUrl, param.IosUrl, param.WeChatUrl = public.GetMsgUrlString(param.Link, param.AndroidUrl, param.IosUrl, param.WeChatUrl, msgLogId)
+		msg := map[string]interface{}{
+			"sendUserId": param.CallPlatform,
+			"sendName":   param.CallPlatform,
+			"title":      param.Title,
+			"content":    param.Content,
+			"msgType":    msgType,
+			"link":       param.Link,
+			"appid":      util.AppId,
+			"msgLogId":   msgLogId,
+		}
+		userIdsArr := strings.Split(param.UserIds, ",")
+		positionIdArr := strings.Split(param.PositionIds, ",")
+		var insertPosition bool
+		if len(positionIdArr) == len(userIdsArr) {
+			insertPosition = true
+		}
+		for i := 0; i < len(userIdsArr); i++ {
+			userId := userIdsArr[i]
+			if config.SysConfigs.UserIdMap[userId] != "" {
+				userId = config.SysConfigs.UserIdMap[userId]
+			}
+			if _, ok := projectIdMap.Load(userId); ok {
+				continue
+			} else {
+				projectIdMap.Store(userId, true)
+			}
+			if insertPosition {
+				positionId := positionIdArr[i]
+				positionIds += positionId + ","
+			}
+			//查询mongo库用户信息
+			userData := &map[string]interface{}{}
+			ok := false
+			userData, ok = config.MQFW.FindById("user", userId, public.MsgUserInfoField)
+			if userData == nil || len(*userData) == 0 || !ok {
+				continue
+			}
+			if param.Name != "" && param.Orderid != "" && param.Ordermoney != "" && param.Identity != "" {
+				msg["productName"] = param.Name
+				msg["orderId"] = param.Orderid
+				msg["orderMoney"] = param.Ordermoney
+				msg["appPushUrl"] = param.AndroidUrl + "&identity=" + param.Identity
+				msg["wxPushUrl"] = param.WeChatUrl
+				msg["iosPushUrl"] = param.IosUrl + "&identity=" + param.Identity
+			} else {
+				msg["appPushUrl"] = param.AndroidUrl
+				msg["wxPushUrl"] = param.WeChatUrl
+				msg["iosPushUrl"] = param.IosUrl
+			}
+
+			//消息存储用bitmap
+			currentIndex++
+			userIds += userId + ","
+			if currentIndex >= 10000 {
+				//调用消息中台
+				util.BitmapSaveMessage(msg, userIds, "")
+				userIds = ""
+				positionIds = ""
+				currentIndex = 0
+			}
+		}
+		if currentIndex > 0 {
+			//调用中台接口
+			util.BitmapSaveMessage(msg, userIds, "")
+			userIds = ""
+			positionIds = ""
+			currentIndex = 0
+		}
+		ok := config.JysqlDB.Update("message_send_log", map[string]interface{}{"id": common.IntAll(msgLogId)}, map[string]interface{}{"link": param.Link})
+		if ok {
+			return 1, nil
+		}
+		log.Println("消息发送完毕,更新发送记录出错,消息发送记录为:", msgLogId)
+	}
+	return 0, errors.New("发送消息出错")
+}
+
+// GroupSendMsg 分组用户发送消息
+func GroupSendMsg(param *public.Message, sendStatus int, loginUserId int, loginUserName string, msgLogId string) {
+	i, userIds, lastUserId := 0, "", ""
+	projectIdMap := sync.Map{}
+	msgType := strconv.Itoa(param.MsgType)
+	msg := map[string]interface{}{
+		"sendUserId":  loginUserId,
+		"sendName":    loginUserName,
+		"title":       param.Title,
+		"content":     param.Content,
+		"msgType":     msgType,
+		"link":        param.Link,
+		"appid":       util.AppId,
+		"msgLogId":    msgLogId,
+		"showBuoy":    param.ShowBuoy,
+		"showContent": param.ShowContent,
+		"appPushUrl":  param.AndroidUrl,
+		"wxPushUrl":   param.WeChatUrl,
+		"iosPushUrl":  param.IosUrl,
+	}
+	for f := 0; f < 5; f++ {
+		j := 0
+		lastUserId = common.InterfaceToStr(redis.Get(util.AdminRedisModule, fmt.Sprintf(public.Redis_lastUserId_key, msgLogId)))
+		//先查出总量
+		var sqlStr string
+		if lastUserId != "" {
+			sqlStr = fmt.Sprintf(` WHERE b.userid > "%s"`, lastUserId)
+		} else {
+			sqlStr = " WHERE b.userid != ''"
+		}
+		count := config.ConvertlabDB.CountBySql(fmt.Sprintf("SELECT count(DISTINCT(b.userid)) FROM (SELECT DISTINCT (customerid) AS customerid FROM `groupcustomers` WHERE groupid IN (%s)) a LEFT JOIN `customers_user` b ON a.customerid = b.customerid %s ORDER BY b.userid ASC", param.UserGroupId, sqlStr))
+		log.Println("分组发送消息,查询用户总量为:", count)
+		if count > 0 {
+			sql := fmt.Sprintf("SELECT DISTINCT ( b.userid ) FROM (SELECT DISTINCT (customerid) AS customerid FROM `groupcustomers` WHERE groupid IN (%s)) a LEFT JOIN `customers_user` b ON a.customerid = b.customerid %s ORDER BY b.userid ASC", param.UserGroupId, sqlStr)
+			users := config.ConvertlabDB.SelectBySql(sql)
+			if users != nil && len(*users) > 0 {
+				for _, v := range *users {
+					j++
+					userId := common.ObjToString(v["userid"])
+					lastUserId = userId
+					if config.SysConfigs.UserIdMap[userId] != "" {
+						userId = config.SysConfigs.UserIdMap[userId]
+					}
+					if _, ok := projectIdMap.Load(userId); ok {
+						continue
+					} else {
+						projectIdMap.Store(userId, true)
+					}
+					//查询mongo库用户信息
+					userData, ok := config.MQFW.FindById("user", userId, public.MsgUserInfoField)
+					if userData == nil || len(*userData) == 0 || !ok {
+						continue
+					}
+					i++
+					if i != 1 {
+						userIds += ","
+					}
+					userIds += userId
+					if i >= 10000 {
+						//调用消息中台
+						util.BitmapSaveMessage(msg, userIds, "")
+						userIds = ""
+						i = 0
+					}
+					switchs := redis.Get(util.AdminRedisModule, fmt.Sprintf(public.Redis_msg_send_switch, common.IntAll(msgLogId)))
+					if (j >= 2000 && j%2000 == 0) || switchs == 0 {
+						//定时存发送到哪一位用户
+						redis.Put(util.AdminRedisModule, fmt.Sprintf(public.Redis_lastUserId_key, msgLogId), userId, 604800)
+					}
+				}
+			}
+		}
+		if j == common.IntAll(count) {
+			break
+		}
+		log.Println("********************总数:", j)
+	}
+	if i > 0 {
+		//调用中台接口
+		util.BitmapSaveMessage(msg, userIds, "")
+		userIds = ""
+		i = 0
+	}
+	//实时发送,消息发送完毕,发送记录发送状态更新为 4 发送完成
+	if param.SendMode == 2 {
+		ok := config.JysqlDB.Update("message_send_log", map[string]interface{}{"id": common.IntAll(msgLogId)}, map[string]interface{}{"send_status": 4, "lastUserId": lastUserId, "link": param.Link})
+		if !ok {
+			log.Println("消息发送完毕,更新发送记录出错,消息发送记录为:", msgLogId)
+		}
+	}
+	return
+}
+
+func OnTimeSendMsgService(msgId int64, paramSendTime string, isUpdate bool) {
+	now := time.Now()
+	if isUpdate {
+		sendTime := paramSendTime
+		_, err := time.ParseInLocation(date.Date_Full_Layout, sendTime, now.Location())
+		if err != nil {
+			sendTime = paramSendTime + ":00"
+		}
+		key := common.InterfaceToStr(msgId)
+		if _, t := util.OnTimeSendMap.Load(key + sendTime); !t {
+			sendTime2, _ := time.ParseInLocation(date.Date_Full_Layout, sendTime, now.Location())
+			execTime := sendTime2.Unix() - now.Unix()
+			util.OnTimeSendMap.Store(key+sendTime, true)
+			time.AfterFunc(time.Duration(execTime)*time.Second, func() {
+				// 执行任务
+				task.Task(int(msgId), sendTime)
+			})
+		}
+	} else {
+		sendTime, _ := time.ParseInLocation(date.Date_Full_Layout, paramSendTime+":00", time.Now().Location())
+		//now := time.Now()
+		days := sendTime.Sub(now)
+		util.OnTimeSendMap.Store(strconv.Itoa(common.IntAll(msgId))+paramSendTime+":00", true)
+		time.AfterFunc(days, func() {
+			// 执行任务
+			task.Task(common.IntAll(msgId), sendTime.Format("2006-01-02 15:04:05"))
+		})
+	}
+}

+ 11 - 0
src/doc/public/consts.go

@@ -0,0 +1,11 @@
+package public
+
+var (
+	RegionStateHotJY      = 1 //1:剑鱼首页;
+	RegionStateHot        = 2 //2:文库首页热门文档;
+	RegionStateMemberFree = 3 // 3:文库首页会员免费文档;
+	RegionStatePremium    = 4 // 4:文库首页精选推荐
+	ProductTypeMemberFree = 1 // 商品类型 会员免费
+	ProductTypePremium    = 2 // 商品类型 精品文档
+)
+var DocFileType = map[int]string{1: "doc", 2: "pdf", 3: "xls", 4: "ppt", 5: "txt", 6: "其他"}

+ 49 - 0
src/doc/public/init.go

@@ -0,0 +1,49 @@
+package public
+
+import (
+	"app.yhyue.com/moapp/jy_docs/rpc/stdlib/stdlib"
+	"app.yhyue.com/moapp/jybase/common"
+	"github.com/zeromicro/go-zero/core/discov"
+	"github.com/zeromicro/go-zero/zrpc"
+	"qmx_admin/src/config"
+)
+
+type screenInfo struct {
+	DocClass  map[string]string
+	DocRegion map[string]int
+}
+
+var (
+	ScreenInfo = screenInfo{
+		DocClass:  map[string]string{},
+		DocRegion: map[string]int{},
+	}
+	// 标准库RPC接口
+	JyStdDocStdlib stdlib.Stdlib
+)
+
+func init() {
+	docClassData := config.BaseDB.SelectBySql("SELECT dc.name as name,dc.code as code FROM jydocs.doc_class_statistics dcs left join jydocs.doc_class dc on (dcs.code = dc.code and dcs.state = dc.state )  where  dc.`level`=1  order by total desc")
+	if docClassData != nil && len(*docClassData) > 0 {
+		for _, dv := range *docClassData {
+			name := common.InterfaceToStr(dv["name"])
+			code := common.InterfaceToStr(dv["code"])
+			if name != "" && code != "" {
+				ScreenInfo.DocClass[name] = code
+			}
+		}
+	}
+	if len(config.SysConfigs.DocScreen.Region) > 0 {
+		for rk, rv := range config.SysConfigs.DocScreen.Region {
+			ScreenInfo.DocRegion[rv] = rk + 1
+		}
+	}
+
+	JyStdDocStdlib = stdlib.NewStdlib(zrpc.MustNewClient(zrpc.RpcClientConf{
+		Etcd: discov.EtcdConf{
+			Key:   config.SysConfigs.RpcServers.StdDoc.Key,
+			Hosts: config.SysConfigs.RpcServers.StdDoc.Address,
+		},
+		Timeout: int64(config.SysConfigs.RpcServers.StdDoc.Timeout),
+	}))
+}

+ 84 - 0
src/doc/public/recDoc.go

@@ -0,0 +1,84 @@
+package public
+
+import (
+	"app.yhyue.com/moapp/jybase/date"
+	"app.yhyue.com/moapp/jybase/redis"
+	"fmt"
+	"log"
+	"qmx_admin/src/config"
+	"strings"
+)
+
+// GetRecDoc 获取文库推荐列表
+func GetRecDoc(regionState int, docClassCode string) (recList []map[string]interface{}) {
+	query := ""
+	values := []interface{}{regionState}
+
+	qBase := `SELECT d.id as docId,d.docName,d.docFileType,d.productType,d.source,d.docFileSize,d.docPageSize,ds.viewTimes,d.docTags,d.uploadDate FROM jydocs.doc_recommend  dr left join jydocs.doc_statistics ds  on(dr.doc_id=ds.docId)     left join jydocs.doc  d on  dr.doc_id=d.id  where  dr.region_state=? %s   order by dr.create_date desc ,dr.id desc`
+	and := ""
+	if docClassCode != "" {
+		and = "	and dr.doc_class_code=?"
+		values = append(values, docClassCode)
+	}
+	query = fmt.Sprintf(qBase, and)
+	rs := config.BaseDB.SelectBySql(query, values...)
+	if rs == nil || len(*rs) == 0 {
+		return []map[string]interface{}{}
+	}
+	return *rs
+}
+
+// 更新文库推荐列表
+func UpdateRecDoc(regionState int, docClassCode string, docIds string) (err error) {
+	// 计算新增数量
+	docIdList := strings.Split(docIds, ",")
+	if len(docIdList) > config.SysConfigs.DocRec.RecCount {
+		docIdList = docIdList[:config.SysConfigs.DocRec.RecCount]
+	}
+	// 新增的数量
+	addCount := len(docIdList)
+	// 查数量
+	existCount := 0
+	if docClassCode != "" {
+		existCount = int(config.BaseDB.CountBySql("SELECT count(*) FROM jydocs.doc_recommend where region_state=? and doc_class_code=?;", regionState, docClassCode))
+	} else {
+		existCount = int(config.BaseDB.CountBySql("SELECT count(*) FROM jydocs.doc_recommend where region_state=? ", regionState))
+	}
+	delCount := 0
+	// 判断
+	if existCount+addCount > config.SysConfigs.DocRec.RecCount {
+		delCount = (existCount + addCount) - config.SysConfigs.DocRec.RecCount
+	}
+	// 删除
+	if delCount > 0 {
+		if docClassCode != "" {
+			_, err := config.BaseDB.ExecBySql("delete FROM jydocs.doc_recommend where region_state=? and doc_class_code=? order by id limit ?;", regionState, docClassCode, delCount)
+			if err != nil {
+				log.Println("UpdateRecDoc 删除异常", err, regionState, docClassCode, delCount)
+				return fmt.Errorf("删除多余数据失败,稍后再试")
+			}
+		} else {
+			_, err := config.BaseDB.ExecBySql("delete FROM jydocs.doc_recommend where region_state=? order by id limit ?  ", regionState, delCount)
+			if err != nil {
+				log.Println("UpdateRecDoc 删除异常", err, regionState, docClassCode, delCount)
+				return fmt.Errorf("删除多余数据失败,稍后再试")
+			}
+		}
+	}
+	for i := 0; i < len(docIdList); i++ {
+		saveDoc := map[string]interface{}{
+			"region_state":   regionState,
+			"doc_class_code": docClassCode,
+			"doc_id":         docIdList[i],
+			"create_date":    date.NowFormat(date.Date_Full_Layout),
+		}
+		config.BaseDB.Insert("jydocs.doc_recommend", saveDoc)
+	}
+	// 清除缓存
+	topKey := fmt.Sprintf("jydoc_RecCache_%d_%s", regionState, docClassCode)
+	if regionState == 1 {
+		topKey = "jy_index_docs_info" // 剑鱼首页推荐文档的缓存key单独处理
+	}
+	redis.Del("newother", topKey)
+	return
+}

+ 56 - 0
src/doc/public/stdDocRpc.go

@@ -0,0 +1,56 @@
+package public
+
+import (
+	"app.yhyue.com/moapp/jy_docs/rpc/stdlib/stdlib"
+	"context"
+	"fmt"
+	"log"
+	"qmx_admin/src/config"
+)
+
+/*
+检索文库
+param
+
+	userId  用户id
+	keyWord 关键词
+	tag	分类
+	pageNum 页码
+	pageSize 每页数量
+	tSort 时间排序
+	dSort 下载排序
+	vSort 浏览量排序
+*/
+func GetDocQuery(userId, keyWord, tag string, pageNum, pageSize int64, sort string, productType, docFileType int64) ([]*stdlib.Doc, int64, error) {
+	param := &stdlib.DocQueryRequest{
+		AppId:       config.SysConfigs.AppId,
+		KeyWord:     keyWord,
+		PageSize:    pageSize,
+		PageNum:     pageNum,
+		ProductType: productType,
+		DocFileType: docFileType,
+	}
+	if tag != "" {
+		param.DocTag = []string{tag}
+	}
+	sortArr := []string{}
+	switch sort { //倒序字段前加-,uploadDate:上架时间 viewTimes:浏览量 downTimes:下载量
+	case "dSort": //下载量倒叙
+		sortArr = append(sortArr, "-downTimes")
+	case "vSort": //浏览量倒叙
+		sortArr = append(sortArr, "-viewTimes")
+	default: // "tSort"上传时间倒叙
+		sortArr = append(sortArr, "-uploadDate")
+	}
+	param.Sort = sortArr
+	resp, err := JyStdDocStdlib.DocQuery(context.Background(), param)
+	if err != nil {
+		log.Printf("%s SetUserCollect call error %v\n", userId, err)
+		return nil, -1, err
+	}
+	if resp.Code != 1 {
+		log.Printf("%s SetUserCollect fail Message %v\n", userId, resp.Msg)
+		return nil, -1, fmt.Errorf("查询失败")
+	}
+	return resp.Docs, resp.Total, nil
+}

+ 124 - 0
src/doc/recommend/recommend.go

@@ -0,0 +1,124 @@
+package recommend
+
+import (
+	"app.yhyue.com/moapp/jy_docs/rpc/stdlib/type/stdlib"
+	"app.yhyue.com/moapp/jybase/common"
+	"fmt"
+	"log"
+	"qmx_admin/src/config"
+	"qmx_admin/src/doc/public"
+	"qmx_admin/src/otherPackage/baiy/Cadmin-server-go/admin"
+)
+
+// List 文库推荐列表
+func List(context *admin.Context) (interface{}, error) {
+	param := new(struct {
+		Module   string `form:"module" validate:"required"` //  "剑鱼首页-剑鱼文库","文库首页-热门文档","文库首页-会员免费文档","文库首页-精选推荐"
+		DocClass string `form:"docClass"`                   // 分类
+	})
+	err := context.Form(param)
+	if err != nil {
+		return nil, err
+	}
+	// code 转换
+	code := ""
+	module := public.ScreenInfo.DocRegion[param.Module]
+	if module == 0 || ((module == public.RegionStateHotJY || module == public.RegionStateHot) && param.DocClass == "") {
+		return nil, fmt.Errorf("缺失参数")
+	}
+	if param.DocClass != "" {
+		code = public.ScreenInfo.DocClass[param.DocClass]
+		if module == public.RegionStateHotJY {
+			if subTag, ok := config.SysConfigs.IndexDocClass[param.DocClass]; ok {
+				param.DocClass = subTag
+			}
+		}
+	}
+	productType := 0
+	// 商品
+	if module == public.RegionStateMemberFree {
+		productType = public.ProductTypeMemberFree
+	} else if module == public.RegionStatePremium {
+		productType = public.ProductTypePremium
+	}
+	var (
+		selectedMap = map[string]bool{}
+		list        = public.GetRecDoc(module, code)
+		selectList  []*stdlib.Doc
+	)
+	// 选择列表
+	data, _, err := public.GetDocQuery("", "", param.DocClass, 1, int64(config.SysConfigs.DocRec.QueryCount+config.SysConfigs.DocRec.RecCount), "vSort", int64(productType), 0)
+	if err != nil {
+		data = []*stdlib.Doc{}
+		log.Println("GetDocQuery err:", data)
+	}
+	if len(list) > 0 {
+		for i := 0; i < len(list); i++ {
+			docId := common.InterfaceToStr(list[i]["docId"])
+			docFileType := public.DocFileType[common.IntAll((list)[i]["docFileType"])]
+			list[i]["docFileType"] = docFileType
+			selectedMap[docId] = true
+		}
+		var sk int
+		for _, sv := range data {
+			if selectedMap[(*sv).DocId] {
+				continue
+			}
+			selectList = append(selectList, sv)
+			sk++
+			if sk == config.SysConfigs.DocRec.QueryCount {
+				break
+			}
+		}
+	} else {
+		selectList = data
+	}
+	rs := map[string]interface{}{
+		"list":       list,
+		"selectList": selectList,
+	}
+	return rs, nil
+}
+
+// DocScreen 文库分类筛选项
+func DocScreen(context *admin.Context) (interface{}, error) {
+	var res = struct {
+		DocClass  []string `json:"docClass"`
+		DocRegion []string `json:"docRegion"`
+	}{}
+	res.DocRegion = config.SysConfigs.DocScreen.Region
+	if public.ScreenInfo.DocClass != nil {
+		for ck := range public.ScreenInfo.DocClass {
+			res.DocClass = append(res.DocClass, ck)
+		}
+	}
+	return res, nil
+}
+
+// Update 更新文库推荐
+func Update(context *admin.Context) (interface{}, error) {
+	param := new(struct {
+		Module   string `form:"module" validate:"required"` //  "剑鱼首页-剑鱼文库","文库首页-热门文档","文库首页-会员免费文档","文库首页-精选推荐"
+		DocIds   string `form:"docIds" validate:"required"` //  "剑鱼首页-剑鱼文库","文库首页-热门文档","文库首页-会员免费文档","文库首页-精选推荐"
+		DocClass string `form:"docClass"`                   // 分类
+	})
+	err := context.Form(param)
+	if err != nil {
+		return nil, err
+	}
+	// code 转换
+	code := ""
+	module := public.ScreenInfo.DocRegion[param.Module]
+	if module == 0 {
+		return nil, fmt.Errorf("缺失参数")
+	}
+	if param.DocClass != "" {
+		code = public.ScreenInfo.DocClass[param.DocClass]
+	}
+	err = public.UpdateRecDoc(module, code, param.DocIds)
+	if err != nil {
+		return nil, err
+	}
+	return nil, nil
+
+}

+ 77 - 0
src/doc/router.go

@@ -0,0 +1,77 @@
+package Doc
+
+import (
+	"errors"
+	"fmt"
+	"qmx_admin/src/doc/recommend"
+
+	. "qmx_admin/src/otherPackage/baiy/Cadmin-server-go/admin"
+)
+
+// 调度器接口
+type AllDispatch interface {
+	// 调度器标识
+	Key() string
+	// 调度器名称
+	Name() string
+	// 调度器描述
+	Description() string
+	// 请求调度方法
+	Call(*Context) (interface{}, error)
+}
+
+type DocDispatchers struct {
+	HandleMethod map[string]DocDispatcherHandleMethod
+}
+
+type DocDispatcherHandleMethod func(*Context) (interface{}, error)
+
+var DocDispatcher = &DocDispatchers{HandleMethod: make(map[string]DocDispatcherHandleMethod)}
+
+func (d *DocDispatchers) Key() string {
+	return "doc"
+}
+
+func (d *DocDispatchers) Name() string {
+	return "剑鱼文库"
+}
+
+func (d *DocDispatchers) Description() string {
+	return "剑鱼文库请求调度器"
+}
+
+func (d *DocDispatchers) Call(c *Context) (interface{}, error) {
+	method, is := d.HandleMethod[c.Request.Call]
+	if !is {
+		return nil, errors.New(fmt.Sprintf("[%s 未注册对应的处理方法]", c.Request.Action))
+	}
+	r, err := method(c)
+	if err != nil {
+		return nil, err
+	}
+	return r, nil
+}
+
+// 注册调度器请求处理方法
+func RegisterDoc(methods map[string]DocDispatcherHandleMethod) {
+	DocDispatcher.Register(methods)
+}
+
+func (d *DocDispatchers) Register(methods map[string]DocDispatcherHandleMethod) {
+	for name, method := range methods {
+		if _, is := d.HandleMethod[name]; is {
+			var anyMsg interface{} = fmt.Sprintf("[%s] ", "对应的处理方法已经存在")
+			panic(anyMsg)
+		}
+		d.HandleMethod[name] = method
+	}
+}
+
+func init() {
+	RegisterDoc(map[string]DocDispatcherHandleMethod{
+		"Baiy.Cadmin.Doc.Recommend.List":      recommend.List,
+		"Baiy.Cadmin.Doc.Recommend.DocScreen": recommend.DocScreen,
+		"Baiy.Cadmin.Doc.Recommend.Update":    recommend.Update,
+	})
+	RegisterDispatch(DocDispatcher)
+}

+ 21 - 0
src/doc/test.http

@@ -0,0 +1,21 @@
+POST  http://127.0.0.1:8987/api/admin/?_action=/docRecommend/list&_token=f761c78e97265ac10a4a79e3520a5aba
+Content-Type: application/x-www-form-urlencoded
+
+module=剑鱼首页-剑鱼文库&docClass=法律法规
+
+###
+POST  http://127.0.0.1:8987/api/admin/?_action=/docRecommend/list&_token=f761c78e97265ac10a4a79e3520a5aba
+Content-Type: application/x-www-form-urlencoded
+
+module=文库首页-会员免费文档
+
+###
+POST  http://127.0.0.1:8987/api/admin/?_action=/docRecommend/update&_token=f761c78e97265ac10a4a79e3520a5aba
+Content-Type: application/x-www-form-urlencoded
+
+module=文库首页-会员免费文档&docIds=9e5e3f2e-88f2-11eb-8b3b-0050568f51e7
+
+###
+POST  http://127.0.0.1:8987/api/admin/?_action=/docRecommend/docScreen&_token=f761c78e97265ac10a4a79e3520a5aba
+Content-Type: application/x-www-form-urlencoded
+

+ 8 - 11
src/export_log/exportLog.go

@@ -1,17 +1,16 @@
 package export_log
 
 import (
-
-
-	"github.com/go-xweb/xweb"
-	"log"
-	qutil "qfw/util"
+	"qmx_admin/src/util"
 	"time"
+
+	. "app.yhyue.com/moapp/jybase/api"
+	"app.yhyue.com/moapp/jybase/go-xweb/xweb"
 )
 
 /*
- 	商机管理-用户导出日志
-    对应数据库表 entniche_export_log
+		商机管理-用户导出日志
+	   对应数据库表 entniche_export_log
 */
 type ExportLog struct {
 	UserName    string    `json:"user_name"`    //用户名称
@@ -32,8 +31,7 @@ type Action struct {
 }
 
 func (a *Action) Query() {
-	entId := qutil.IntAll(a.GetSession("entId"))
-	log.Println("entniche_export_log Query entId:", entId)
+	//entId := common.IntAll(a.GetSession("entId"))
 	phone := a.GetString("phone")            //用户手机号
 	userName := a.GetString("userName")      //用户姓名
 	startTimeStr := a.GetString("startTime") //开始时间
@@ -56,7 +54,6 @@ func (a *Action) Query() {
 		sql += " and TIMESTAMP(export_time)<?"
 		val = append(val, startTimeStr)
 	}
-	data := util.Mysql.SelectBySql(sql, val...)
+	data := config.JysqlDB.SelectBySql(sql, val...)
 	a.ServeJson(Result{Data: data})
 }
-

+ 0 - 224
src/github.com/baiy/Cadmin-server-go/admin/context.go

@@ -1,224 +0,0 @@
-package admin
-
-import (
-	"errors"
-	"fmt"
-	"net/http"
-	"strconv"
-	"time"
-
-	"github.com/go-xweb/xweb"
-
-	"github.com/baiy/Cadmin-server-go/models/request"
-	"github.com/baiy/Cadmin-server-go/models/token"
-	"github.com/baiy/Cadmin-server-go/models/user"
-	"github.com/go-playground/form"
-	"github.com/go-playground/locales/zh"
-	ut "github.com/go-playground/universal-translator"
-	"gopkg.in/go-playground/validator.v9"
-	zhTranslations "gopkg.in/go-playground/validator.v9/translations/zh"
-)
-
-var (
-	validate *validator.Validate
-	decoder  *form.Decoder
-	uni      *ut.UniversalTranslator
-	trans    ut.Translator
-)
-
-// 请求标识变量名
-var ActionName = "_action"
-
-// 请求token变量名
-var TokenName = "_token"
-
-// 无需登录的请求ID
-var NoCheckLoginRequestIds = []int{1}
-
-// 无需检查权限/只需要登录的请求ID
-var OnlyLoginRequestIds = []int{2, 3, 4}
-
-// 添加无需登录的请求ID
-func AddNoCheckLoginRequestId(ids ...int) {
-	NoCheckLoginRequestIds = append(NoCheckLoginRequestIds, ids...)
-}
-
-// 添加无需检查权限/只需要登录的请求ID
-func AddOnlyLoginRequestId(ids ...int) {
-	OnlyLoginRequestIds = append(OnlyLoginRequestIds, ids...)
-}
-
-func init() {
-	zhTranslator := zh.New()
-	uni = ut.New(zhTranslator, zhTranslator)
-	trans, _ = uni.GetTranslator("zh")
-	validate = validator.New()
-	_ = zhTranslations.RegisterDefaultTranslations(validate, trans)
-	decoder = form.NewDecoder()
-}
-
-type Context struct {
-	Action             string
-	Token              string
-	HttpResponseWriter http.ResponseWriter
-	HttpRequest        *http.Request
-	Request            *request.Model
-	User               *user.Model
-	Response           *Response
-	Xweb               *xweb.Action
-}
-
-func (c *Context) run() {
-	defer func() {
-		if r := recover(); r != nil {
-			c.SetResponse(errorResponse(fmt.Sprint(r), nil))
-		}
-	}()
-
-	if err := c.initRequest(); err != nil {
-		c.SetResponse(errorResponse(err.Error(), nil))
-		return
-	}
-	_ = c.initUser()
-
-	if err := c.checkAccess(); err != nil {
-		c.SetResponse(errorResponse(err.Error(), nil))
-		return
-	}
-	result, err := c.call()
-	if err != nil {
-		c.SetResponse(errorResponse(err.Error(), result))
-		return
-	}
-	c.SetResponse(succeeResponse(result))
-	return
-}
-
-func (c *Context) SetResponse(r *Response) {
-	if LogCallback != nil {
-		LogCallback(LogContent{User: c.User, Request: c.Request, Response: c.Response, Time: time.Now()})
-	}
-	c.Response = r
-}
-
-func (c *Context) Output() error {
-	return c.Response.JsonResponse(c.HttpResponseWriter)
-}
-
-func (c *Context) initRequest() error {
-	c.Action = c.HttpRequest.URL.Query().Get(ActionName)
-	if c.Action == "" {
-		return errors.New("action参数错误")
-	}
-	req, err := request.GetByAction(c.Action)
-	if err != nil {
-		return err
-	}
-	c.Request = req
-	return nil
-}
-
-func (c *Context) initUser() error {
-	c.Token = c.HttpRequest.URL.Query().Get(TokenName)
-	if c.Token == "" {
-		return errors.New("token 为空")
-	}
-	req, err := token.GetByToken(c.Token)
-	if err != nil {
-		return err
-	}
-	if req.IsExpire() {
-		return errors.New("登录状态已过期")
-	}
-	//在验证过token是否过期后为token续期
-	renew := time.Time(req.ExpireTime).AddDate(0, 0, -1)
-	if time.Time(renew).Before(time.Now()) {
-		token.Update(req.AdminUserId, c.Token)
-	}
-
-	c.User, err = user.GetById(req.AdminUserId)
-	if err != nil {
-		return err
-	}
-	return nil
-}
-
-func (c *Context) checkAccess() error {
-	if inSliceInt(c.Request.Id, NoCheckLoginRequestIds) {
-		return nil
-	}
-	if c.User == nil {
-		return errors.New("未登录系统")
-	}
-
-	if c.User.IsDisabled() {
-		return errors.New("用户已被禁用")
-	}
-	if inSliceInt(c.Request.Id, OnlyLoginRequestIds) {
-		return nil
-	}
-
-	err := user.CheckAuth(c.User.Id, c.Request.Id)
-	if err != nil {
-		return err
-	}
-	return nil
-}
-
-func (c *Context) call() (interface{}, error) {
-	dispatcher, err := GetDispatcher(c.Request.Type)
-	if err != nil {
-		return nil, err
-	}
-	return dispatcher.Call(c)
-}
-
-func (c *Context) InputInt(name string, def ...int) (int, error) {
-	strv := c.HttpRequest.Form.Get(name)
-	if len(strv) == 0 && len(def) > 0 {
-		return def[0], nil
-	}
-	return strconv.Atoi(strv)
-}
-
-func (c *Context) Input(name string, def ...string) string {
-	if v := c.HttpRequest.Form.Get(name); v != "" {
-		return v
-	}
-	if len(def) > 0 {
-		return def[0]
-	}
-	return ""
-}
-
-func (c *Context) Form(parameter interface{}) error {
-	err := decoder.Decode(parameter, c.HttpRequest.Form)
-	if err != nil {
-		return err
-	}
-	err = validate.Struct(parameter)
-	if err != nil {
-		for _, value := range err.(validator.ValidationErrors).Translate(trans) {
-			return errors.New(value)
-		}
-	}
-	return nil
-}
-
-// 请求入口方法
-func NewContext(rw http.ResponseWriter, r *http.Request) *Context {
-	_ = r.ParseForm()
-	_ = r.ParseMultipartForm(128)
-	context := &Context{HttpResponseWriter: rw, HttpRequest: r}
-	context.run()
-	return context
-}
-
-func inSliceInt(n int, list []int) bool {
-	for _, i := range list {
-		if i == n {
-			return true
-		}
-	}
-	return false
-}

+ 0 - 14
src/github.com/baiy/Cadmin-server-go/admin/db.go

@@ -1,14 +0,0 @@
-package admin
-
-import (
-	"database/sql"
-	"github.com/baiy/Cadmin-server-go/models"
-)
-
-var Db *sql.DB
-
-// 设置数据库操作对象
-func SetDb(d *sql.DB) {
-	Db = d
-	models.InitDb(Db)
-}

+ 0 - 93
src/github.com/baiy/Cadmin-server-go/admin/dispatch.go

@@ -1,93 +0,0 @@
-package admin
-
-import (
-	"errors"
-	"fmt"
-	"strings"
-)
-
-// 调度器接口
-type Dispatch interface {
-	// 调度器标识
-	Key() string
-	// 调度器名称
-	Name() string
-	// 调度器描述
-	Description() string
-	// 请求调度方法
-	Call(*Context) (interface{}, error)
-}
-
-var dispatchers = make(map[string]Dispatch)
-
-func RegisterDispatch(dispatcher Dispatch) {
-	dispatchers[strings.ToLower(dispatcher.Key())] = dispatcher
-}
-
-func GetDispatcher(type_ string) (Dispatch, error) {
-	type_ = strings.ToLower(type_)
-	dispatcher, is := dispatchers[type_]
-	if !is {
-		return nil, errors.New(fmt.Sprintf("未找到请求类型(%s)对应的调度程序", type_))
-	}
-	return dispatcher, nil
-}
-
-func AllDispatcher() map[string]Dispatch {
-	return dispatchers
-}
-
-func AllDispatcherLength() int {
-	return len(dispatchers)
-}
-
-// 默认调度器
-type defaultDispatcher struct {
-	HandleMethod map[string]DefaultDispatcherHandleMethod
-}
-
-func (d *defaultDispatcher) Key() string {
-	return "default"
-}
-
-func (d *defaultDispatcher) Name() string {
-	return "默认"
-}
-
-func (d *defaultDispatcher) Description() string {
-	return "Cadmin系统内置的默认请求调度器"
-}
-
-func (d *defaultDispatcher) Call(c *Context) (interface{}, error) {
-	method, is := d.HandleMethod[c.Request.Call]
-	if !is {
-		return nil, errors.New(fmt.Sprintf("[%s 未注册对应的处理方法]", c.Request.Action))
-	}
-	r, err := method(c)
-	if err != nil {
-		return nil, err
-	}
-	return r, nil
-}
-
-func (d *defaultDispatcher) Register(methods map[string]DefaultDispatcherHandleMethod) {
-	for name, method := range methods {
-		if _, is := d.HandleMethod[name]; is {
-			panic("[%s] 对应的处理方法已经存在")
-		}
-		d.HandleMethod[name] = method
-	}
-}
-
-type DefaultDispatcherHandleMethod func(*Context) (interface{}, error)
-
-var DefaultDispatcher = &defaultDispatcher{HandleMethod: make(map[string]DefaultDispatcherHandleMethod)}
-
-// 注册默认调度器请求处理方法
-func RegisterDefaultDispatcherHandleMethod(methods map[string]DefaultDispatcherHandleMethod) {
-	DefaultDispatcher.Register(methods)
-}
-
-func init() {
-	RegisterDispatch(DefaultDispatcher)
-}

+ 0 - 25
src/github.com/baiy/Cadmin-server-go/admin/log.go

@@ -1,25 +0,0 @@
-package admin
-
-import (
-	"github.com/baiy/Cadmin-server-go/models/request"
-	"github.com/baiy/Cadmin-server-go/models/user"
-	"time"
-)
-
-type LogContent struct {
-	// 用户
-	User *user.Model
-	// 请求
-	Request *request.Model
-	// 响应
-	Response *Response
-	// 响应时间
-	Time time.Time
-}
-
-var LogCallback func(content LogContent)
-
-// 注册密码生成器
-func RegisterLogCallback(callback func(content LogContent)) {
-	LogCallback = callback
-}

+ 0 - 22
src/github.com/baiy/Cadmin-server-go/go.mod

@@ -1,22 +0,0 @@
-module Cadmin-server-go
-
-go 1.13
-
-require (
-	github.com/baiy/Cadmin-server-go v0.0.0-20191115084152-074ff86af5f2
-	github.com/deckarep/golang-set v1.7.1
-	github.com/doug-martin/goqu/v9 v9.3.0
-	github.com/go-playground/form v3.1.4+incompatible
-	github.com/go-playground/locales v0.12.1
-	github.com/go-playground/universal-translator v0.16.0
-	github.com/go-sql-driver/mysql v1.4.1
-	github.com/kr/pretty v0.1.0 // indirect
-	github.com/leodido/go-urn v1.1.0 // indirect
-	github.com/stretchr/objx v0.1.1 // indirect
-	google.golang.org/appengine v1.6.4 // indirect
-	gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
-	gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
-	gopkg.in/go-playground/validator.v9 v9.29.1
-)
-
-replace github.com/baiy/Cadmin-server-go => /Users/Shared/D/workspace/qmx_admin/Cadmin-server-go

+ 0 - 67
src/github.com/baiy/Cadmin-server-go/go.sum

@@ -1,67 +0,0 @@
-github.com/DATA-DOG/go-sqlmock v1.3.3 h1:CWUqKXe0s8A2z6qCgkP4Kru7wC11YoAnoupUKFDnH08=
-github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
-github.com/baiy/Cadmin-server-go v0.0.0-20191115084152-074ff86af5f2 h1:doMwRlkBGMRE9G3xuCgEzk2pkdVbB6NQVoGkpM4VBcA=
-github.com/baiy/Cadmin-server-go v0.0.0-20191115084152-074ff86af5f2/go.mod h1:SNVW4myFLJMfrzYuIHsC64ZM4dqgX1ABMEyiEFq//8g=
-github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
-github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ=
-github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ=
-github.com/doug-martin/goqu/v9 v9.3.0 h1:hpwksFfkywPNM4vQfqoTzkaWAGa36QnWYjZCXmEqjIA=
-github.com/doug-martin/goqu/v9 v9.3.0/go.mod h1:GPZzBWikLe6aaCT2uBT5X3MTseGBYevzWiVjMl2wIWk=
-github.com/go-playground/form v3.1.4+incompatible h1:lvKiHVxE2WvzDIoyMnWcjyiBxKt2+uFJyZcPYWsLnjI=
-github.com/go-playground/form v3.1.4+incompatible/go.mod h1:lhcKXfTuhRtIZCIKUeJ0b5F207aeQCPbZU09ScKjwWg=
-github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc=
-github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
-github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM=
-github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
-github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
-github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
-github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
-github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
-github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
-github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8=
-github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
-github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0=
-github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
-github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q=
-github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
-github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
-github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
-github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 h1:58fnuSXlxZmFdJyvtTFVmVhcMLU6v5fEb/ok4wyqtNU=
-golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190603091049-60506f45cf65 h1:+rhAzEzT3f4JtomfC371qB+0Ola2caSKcY69NUBZrRQ=
-golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
-golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
-golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
-golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-google.golang.org/appengine v1.6.2 h1:j8RI1yW0SkI+paT6uGwMlrMI/6zwYA6/CFil8rxOzGI=
-google.golang.org/appengine v1.6.2/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
-google.golang.org/appengine v1.6.4 h1:WiKh4+/eMB2HaY7QhCfW/R7MuRAoA8QMCSJA6jP5/fo=
-google.golang.org/appengine v1.6.4/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
-gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
-gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
-gopkg.in/go-playground/validator.v9 v9.29.1 h1:SvGtYmN60a5CVKTOzMSyfzWDeZRxRuGvRQyEAKbw1xc=
-gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
-gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

+ 0 - 66
src/github.com/baiy/Cadmin-server-go/main.go

@@ -1,66 +0,0 @@
-package main
-
-import (
-	"database/sql"
-	"fmt"
-	"net/http"
-
-	_ "Cadmin-server-go/order"
-	_ "Cadmin-server-go/system" // 注册内置请求处理方法
-
-	"github.com/baiy/Cadmin-server-go/admin"
-
-	_ "github.com/go-sql-driver/mysql"
-)
-
-var db *sql.DB
-
-// 初始化数据库
-func initDb() {
-	var err error
-	db, err = sql.Open("mysql", "root:994520@/jianyu?charset=utf8mb4&parseTime=True&loc=Local")
-	if err != nil {
-		panic(err)
-	}
-}
-
-// func log(content admin.LogContent) {
-// 	fmt.Println(content.Request.Action, content.Time)
-// }
-
-func main() {
-	initDb()
-
-	// 设置数据库操作对象
-	admin.SetDb(db)
-	// [可选] 注册自定义调度器
-	// admin.RegisterDispatch()
-	// [可选] 设置自定义密码生成器
-	// admin.RegisterPassword()
-	// [可选] 无需校验权限的api
-	// admin.AddNoCheckLoginRequestId()
-	// [可选] 只需登录即可访问的api
-	// admin.AddOnlyLoginRequestId()
-	// [可选] 设置请求标识变量名
-	admin.ActionName = "_action"
-	// [可选] 设置请求token变量名
-	admin.TokenName = "_token"
-	// [可选] 设置请求日志记录回调函数
-	// admin.RegisterLogCallback(log)
-
-	http.HandleFunc("/api/admin/", func(writer http.ResponseWriter, request *http.Request) {
-		// 前后端分离项目一般会有跨域问题 自行处理
-		writer.Header().Add("Access-Control-Allow-Origin", "*")
-		writer.Header().Add("Access-Control-Allow-Headers", "Content-Type")
-
-		context := admin.NewContext(writer, request)
-		if err := context.Output(); err != nil {
-			fmt.Println(err)
-		}
-	})
-	fmt.Println("http://127.0.0.1:8001")
-	err := http.ListenAndServe(":8001", nil)
-	if err != nil {
-		fmt.Println("ListenAndServe error", err)
-	}
-}

+ 0 - 80
src/github.com/baiy/Cadmin-server-go/models/auth/auth.go

@@ -1,80 +0,0 @@
-package auth
-
-import (
-	"errors"
-	"github.com/baiy/Cadmin-server-go/models"
-	"github.com/baiy/Cadmin-server-go/models/menuRelate"
-	"github.com/baiy/Cadmin-server-go/models/requestRelate"
-	"github.com/baiy/Cadmin-server-go/models/userGroupRelate"
-	"github.com/doug-martin/goqu/v9"
-	"time"
-)
-
-type Model struct {
-	models.Model
-	Name        string `json:"name"`
-	Description string `json:"description"`
-}
-
-func (m Model) RequestIds() []int {
-	return requestRelate.RequestIds([]int{m.Id})
-}
-
-func (m Model) MenuIds() []int {
-	return menuRelate.MenuIds([]int{m.Id})
-}
-
-func (m Model) UserGroupIds() []int {
-	return userGroupRelate.UserGroupIds([]int{m.Id})
-}
-
-func Add(name, description string) error {
-	createTime := time.Now().Format("2006-01-02 15:04:05")
-	_, err := models.Db.Insert("admin_auth").Rows(
-		goqu.Record{"name": name, "description": description, "create_time": createTime},
-	).Executor().Exec()
-	return err
-}
-
-func Updata(id int, name, description string) error {
-	_, err := models.Db.Update("admin_auth").Set(goqu.Record{"name": name, "description": description}).Where(goqu.Ex{
-		"id": id,
-	}).Executor().Exec()
-	return err
-}
-
-func Remove(id int) error {
-	_, err := models.Db.Delete("admin_auth").Where(goqu.Ex{
-		"id": id,
-	}).Executor().Exec()
-	if err == nil {
-		_ = requestRelate.Remove(0, id)
-		_ = userGroupRelate.Remove(0, id)
-		_ = menuRelate.Remove(0, id)
-	}
-	return err
-}
-
-func GetById(id int) (model *Model, err error) {
-	model = new(Model)
-	found, err := models.Db.From("admin_auth").Where(goqu.Ex{
-		"id": id,
-	}).ScanStruct(model)
-	if err == nil {
-		if !found {
-			err = errors.New("权限不存在")
-		}
-	}
-	return
-}
-
-func GetLists(ids []int) ([]*Model, error) {
-	model := make([]*Model, 0)
-	if len(ids) == 0 {
-		return model, nil
-	}
-	err := models.Db.From("admin_auth").Where(goqu.Ex{
-		"id": ids,
-	}).ScanStructs(&model)
-	return model, err
-}

+ 0 - 124
src/github.com/baiy/Cadmin-server-go/models/menu/menu.go

@@ -1,124 +0,0 @@
-package menu
-
-import (
-	"errors"
-	"github.com/baiy/Cadmin-server-go/models"
-	"github.com/baiy/Cadmin-server-go/models/menuRelate"
-	"github.com/doug-martin/goqu/v9"
-	"time"
-)
-
-type Model struct {
-	models.Model
-	ParentId    int    `json:"parent_id"`
-	Name        string `json:"name"`
-	Url         string `json:"url"`
-	Icon        string `json:"icon"`
-	Description string `json:"description"`
-	Sort        int    `json:"sort"`
-}
-
-func Add(parentId int, name, url, icon, description string) error {
-	if parentId != 0 {
-		exist, err := GetById(parentId)
-		if err != nil {
-			return errors.New("父菜单不存在")
-		}
-		if exist.Url != "" {
-			return errors.New("父菜单不是目录类型菜单")
-		}
-	}
-	createTime := time.Now().Format("2006-01-02 15:04:05")
-	_, err := models.Db.Insert("admin_menu").Rows(
-		goqu.Record{
-			"parent_id":   parentId,
-			"name":        name,
-			"url":         url,
-			"icon":        icon,
-			"description": description,
-			"sort":        getNewSort(parentId),
-			"create_time": createTime,
-		},
-	).Executor().Exec()
-	return err
-}
-
-func Updata(id int, parentId int, name, url, icon, description string) error {
-	if parentId != 0 {
-		exist, err := GetById(parentId)
-		if err != nil {
-			return errors.New("父菜单不存在")
-		}
-		if exist.Url != "" {
-			return errors.New("父菜单不是目录类型菜单")
-		}
-	}
-	_, err := models.Db.Update("admin_menu").Where(goqu.Ex{"id": id}).Set(
-		goqu.Record{
-			"parent_id":   parentId,
-			"name":        name,
-			"url":         url,
-			"icon":        icon,
-			"description": description,
-		},
-	).Executor().Exec()
-	return err
-}
-
-func Remove(id int) error {
-	_, err := models.Db.Delete("admin_menu").Where(goqu.Ex{
-		"id": id,
-	}).Executor().Exec()
-	if err == nil {
-		_ = menuRelate.Remove(id, 0)
-	}
-	return err
-}
-
-func All() ([]*Model, error) {
-	m := make([]*Model, 0)
-	err := models.Db.From("admin_menu").ScanStructs(&m)
-	return m, err
-}
-
-func Sort(id, sort int) error {
-	_, err := models.Db.Update("admin_menu").Set(goqu.Record{"sort": sort}).Where(goqu.Ex{
-		"id": id,
-	}).Executor().Exec()
-	return err
-}
-
-func getNewSort(parentId int) int {
-	model := new(Model)
-	found, err := models.Db.From("admin_menu").Where(goqu.Ex{
-		"parent_id": parentId,
-	}).Order(goqu.I("sort").Desc()).ScanStruct(model)
-	if err == nil && found {
-		return model.Sort + 1
-	}
-	return 0
-}
-
-func GetById(id int) (model *Model, err error) {
-	model = new(Model)
-	found, err := models.Db.From("admin_menu").Where(goqu.Ex{
-		"id": id,
-	}).ScanStruct(model)
-	if err == nil {
-		if !found {
-			err = errors.New("菜单不存在")
-		}
-	}
-	return
-}
-
-func GetLists(ids []int) ([]*Model, error) {
-	model := make([]*Model, 0)
-	if len(ids) == 0 {
-		return model, nil
-	}
-	err := models.Db.From("admin_menu").Order(goqu.I("sort").Asc()).Where(goqu.Ex{
-		"id": ids,
-	}).ScanStructs(&model)
-	return model, err
-}

+ 0 - 63
src/github.com/baiy/Cadmin-server-go/models/menuRelate/menuRelate.go

@@ -1,63 +0,0 @@
-package menuRelate
-
-import (
-	"errors"
-	"github.com/baiy/Cadmin-server-go/models"
-	"github.com/doug-martin/goqu/v9"
-)
-
-type Model struct {
-	models.Model
-	AdminMenuId int `json:"admin_menu_id"`
-	AdminAuthId int `json:"admin_auth_id"`
-}
-
-func MenuIds(authIds []int) []int {
-	ids := make([]int, 0)
-	_ = models.Db.From("admin_menu_relate").Select("admin_menu_id").Where(goqu.Ex{
-		"admin_auth_id": authIds,
-	}).ScanVals(&ids)
-	return ids
-}
-
-func Add(menuId, authId int) error {
-	_, err := models.Db.Insert("admin_menu_relate").Rows(
-		goqu.Record{"admin_menu_id": menuId, "admin_auth_id": authId},
-	).Executor().Exec()
-	return err
-}
-
-func AddMultiple(menuIds []int, authId int) error {
-	rows := make([]goqu.Record, len(menuIds))
-	for key, menuId := range menuIds {
-		rows[key] = goqu.Record{
-			"admin_menu_id": menuId,
-			"admin_auth_id": authId,
-		}
-	}
-	_, err := models.Db.Insert("admin_menu_relate").Rows(rows).Executor().Exec()
-	return err
-}
-
-func RemoveMultiple(menuIds []int, authId int) error {
-	_, err := models.Db.Delete("admin_menu_relate").Where(goqu.Ex{
-		"admin_auth_id": authId,
-		"admin_menu_id": menuIds,
-	}).Executor().Exec()
-	return err
-}
-
-func Remove(menuId, authId int) error {
-	if menuId == 0 && authId == 0 {
-		return errors.New("参数错误")
-	}
-	where := make(goqu.Ex)
-	if menuId != 0 {
-		where["admin_menu_id"] = menuId
-	}
-	if authId != 0 {
-		where["admin_auth_id"] = authId
-	}
-	_, err := models.Db.Delete("admin_menu_relate").Where(where).Executor().Exec()
-	return err
-}

+ 0 - 29
src/github.com/baiy/Cadmin-server-go/models/model.go

@@ -1,29 +0,0 @@
-package models
-
-import (
-	"database/sql"
-	"github.com/baiy/Cadmin-server-go/models/utils"
-	"github.com/doug-martin/goqu/v9"
-	_ "github.com/doug-martin/goqu/v9/dialect/mysql"
-	_ "github.com/go-sql-driver/mysql"
-	"regexp"
-	"strings"
-)
-
-var Db *goqu.Database
-
-type Model struct {
-	Id         int        `db:"id" json:"id" goqu:"skipinsert,skipupdate"`
-	CreateTime utils.Time `db:"create_time" json:"create_time" goqu:"skipinsert,skipupdate"`
-	UpdateTime utils.Time `db:"update_time" json:"update_time" goqu:"skipinsert,skipupdate"`
-}
-
-func InitDb(d *sql.DB) {
-	// 设置列名自动转换规则
-	goqu.SetColumnRenameFunction(func(s string) string {
-		snake := regexp.MustCompile("([a-z0-9])([A-Z])").ReplaceAllString(s, "${1}_${2}")
-		return strings.ToLower(snake)
-	})
-	dialect := goqu.Dialect("mysql")
-	Db = dialect.DB(d)
-}

+ 0 - 80
src/github.com/baiy/Cadmin-server-go/models/request/request.go

@@ -1,80 +0,0 @@
-package request
-
-import (
-	"errors"
-	"fmt"
-	"github.com/baiy/Cadmin-server-go/models"
-	"github.com/baiy/Cadmin-server-go/models/requestRelate"
-	"github.com/doug-martin/goqu/v9"
-)
-
-type Model struct {
-	models.Model
-	Type   string `json:"type"`
-	Name   string `json:"name"`
-	Action string `json:"action"`
-	Call   string `json:"call"`
-}
-
-func (m Model) AuthIds() []int {
-	return requestRelate.AuthIds([]int{m.Id})
-}
-
-func Add(name, action, type_, call string) error {
-	exist, _ := GetByAction(action)
-	if exist.Id > 0 {
-		return errors.New(fmt.Sprintf("[%s] 请求已经存在", action))
-	}
-	_, err := models.Db.Insert("admin_request").Rows(
-		goqu.Record{"name": name, "action": action, "type": type_, "call": call},
-	).Executor().Exec()
-	return err
-}
-
-func Updata(id int, name, action, type_, call string) error {
-	exist, _ := GetByAction(action)
-	if exist.Id > 0 && exist.Id != id {
-		return errors.New(fmt.Sprintf("[%s] 请求已经存在", action))
-	}
-	_, err := models.Db.Update("admin_request").Where(goqu.Ex{"id": id}).Set(
-		goqu.Record{"name": name, "action": action, "type": type_, "call": call},
-	).Executor().Exec()
-	return err
-}
-
-func Remove(id int) error {
-	_, err := models.Db.Delete("admin_request").Where(goqu.Ex{
-		"id": id,
-	}).Executor().Exec()
-	if err == nil {
-		_ = requestRelate.Remove(id, 0)
-	}
-	return err
-}
-
-func GetByAction(action string) (model *Model, err error) {
-	model = new(Model)
-	found, err := models.Db.From("admin_request").Where(goqu.Ex{
-		"action": action,
-	}).ScanStruct(model)
-	if err == nil {
-		if !found {
-			err = errors.New("请求不存在")
-		}
-	}
-	return
-}
-
-func GetLists(ids []int) ([]*Model, error) {
-	model := make([]*Model, 0)
-	if len(ids) == 0 {
-		return model, nil
-	}
-	if len(ids) == 0 {
-		return model, nil
-	}
-	err := models.Db.From("admin_request").Where(goqu.Ex{
-		"id": ids,
-	}).ScanStructs(&model)
-	return model, err
-}

+ 0 - 51
src/github.com/baiy/Cadmin-server-go/models/requestRelate/requestRelate.go

@@ -1,51 +0,0 @@
-package requestRelate
-
-import (
-	"errors"
-	"github.com/baiy/Cadmin-server-go/models"
-	"github.com/doug-martin/goqu/v9"
-)
-
-type Model struct {
-	models.Model
-	AdminRequestId int `json:"admin_request_id"`
-	AdminAuthId    int `json:"admin_auth_id"`
-}
-
-func AuthIds(requestIds []int) []int {
-	ids := make([]int, 0)
-	_ = models.Db.From("admin_request_relate").Select("admin_auth_id").Where(goqu.Ex{
-		"admin_request_id": requestIds,
-	}).ScanVals(&ids)
-	return ids
-}
-
-func RequestIds(authIds []int) []int {
-	ids := make([]int, 0)
-	_ = models.Db.From("admin_request_relate").Select("admin_request_id").Where(goqu.Ex{
-		"admin_auth_id": authIds,
-	}).ScanVals(&ids)
-	return ids
-}
-
-func Add(requestId, authId int) error {
-	_, err := models.Db.Insert("admin_request_relate").Rows(
-		goqu.Record{"admin_request_id": requestId, "admin_auth_id": authId},
-	).Executor().Exec()
-	return err
-}
-
-func Remove(requestId, authId int) error {
-	if requestId == 0 && authId == 0 {
-		return errors.New("参数错误")
-	}
-	where := make(goqu.Ex)
-	if requestId != 0 {
-		where["admin_request_id"] = requestId
-	}
-	if authId != 0 {
-		where["admin_auth_id"] = authId
-	}
-	_, err := models.Db.Delete("admin_request_relate").Where(where).Executor().Exec()
-	return err
-}

+ 0 - 81
src/github.com/baiy/Cadmin-server-go/models/token/token.go

@@ -1,81 +0,0 @@
-package token
-
-import (
-	"crypto/md5"
-	"encoding/hex"
-	"errors"
-	"fmt"
-	"math/rand"
-	"time"
-
-	"github.com/baiy/Cadmin-server-go/models"
-	"github.com/baiy/Cadmin-server-go/models/utils"
-
-	"github.com/doug-martin/goqu/v9"
-)
-
-type Model struct {
-	models.Model
-	Token       string     `json:"token"`
-	AdminUserId int        `json:"admin_user_id"`
-	ExpireTime  utils.Time `json:"expire_time"`
-}
-
-func (m *Model) IsExpire() bool {
-	return time.Time(m.ExpireTime).Before(time.Now())
-}
-
-func GetByToken(token string) (model *Model, err error) {
-	model = new(Model)
-	found, err := models.Db.From("admin_token").Where(goqu.Ex{
-		"token": token,
-	}).ScanStruct(model)
-	if err == nil {
-		if !found {
-			err = errors.New("token不存在")
-		}
-	}
-	return
-}
-
-func Clear() {
-	_, _ = models.Db.Delete("admin_token").
-		Where(goqu.Ex{"expire_time": goqu.Op{"lt": time.Now().Format("2006-01-02 15:04:05")}}).
-		Executor().Exec()
-}
-
-func Remove(t string) {
-	_, _ = models.Db.Delete("admin_token").
-		Where(goqu.Ex{"token": t}).
-		Executor().Exec()
-}
-
-func Add(userId int) string {
-	tokenStr := generate()
-	dd, _ := time.ParseDuration("48h")
-	_, _ = models.Db.Insert("admin_token").Rows(map[string]interface{}{
-		"admin_user_id": userId,
-		"token":         tokenStr,
-		"expire_time":   time.Now().Add(dd).Format("2006-01-02 15:04:05"),
-	}).Executor().Exec()
-	return tokenStr
-}
-
-func Update(userId int, token string) error {
-	dd, _ := time.ParseDuration("48h")
-	record := goqu.Record{"expire_time": time.Now().Add(dd).Format("2006-01-02 15:04:05")}
-	_, err := models.Db.Update("admin_token").Set(record).Where(goqu.Ex{
-		"admin_user_id": userId,
-		"token":         token,
-	}).Executor().Exec()
-	return err
-}
-
-func generate() string {
-	rand.Seed(time.Now().UnixNano())
-	str := fmt.Sprintf("%d%d", time.Now().UnixNano(), rand.Intn(9999))
-
-	h := md5.New()
-	h.Write([]byte(str))
-	return hex.EncodeToString(h.Sum(nil))
-}

+ 0 - 196
src/github.com/baiy/Cadmin-server-go/models/user/user.go

@@ -1,196 +0,0 @@
-package user
-
-import (
-	"errors"
-	"fmt"
-	"time"
-
-	"github.com/baiy/Cadmin-server-go/models"
-
-	"github.com/baiy/Cadmin-server-go/models/menuRelate"
-	"github.com/baiy/Cadmin-server-go/models/requestRelate"
-	"github.com/baiy/Cadmin-server-go/models/userGroupRelate"
-	"github.com/baiy/Cadmin-server-go/models/userRelate"
-	"github.com/baiy/Cadmin-server-go/models/utils"
-
-	"github.com/doug-martin/goqu/v9"
-)
-
-const (
-	Enable  = 1 // 启用
-	Disable = 2 // 禁用
-)
-
-type Model struct {
-	models.Model
-	Username      string      `json:"username"`
-	Password      string      `json:"-"`
-	LastLoginIp   string      `json:"last_login_ip"`
-	LastLoginTime *utils.Time `json:"last_login_time"`
-	Status        int         `json:"status"`
-	Description   string      `json:"description"`
-	Phone         string      `json:"phone"`
-}
-
-func (m *Model) IsDisabled() bool {
-	return m.Status == Disable
-}
-
-func (m *Model) LoginUpdate(ip string) {
-	_, _ = models.Db.Update("admin_user").Where(goqu.Ex{
-		"id": m.Id,
-	}).Set(map[string]interface{}{
-		"last_login_ip":   ip,
-		"last_login_time": time.Now().Format("2006-01-02 15:04:05"),
-	}).Executor().Exec()
-}
-
-func (m Model) UserGroupIds() []int {
-	return userRelate.GroupIds([]int{m.Id})
-}
-
-func (m Model) AuthIds() []int {
-	return userGroupRelate.AuthIds(m.UserGroupIds())
-}
-
-func (m Model) MenuIds() []int {
-	return menuRelate.MenuIds(m.AuthIds())
-}
-
-func (m Model) RequestIds() []int {
-	return requestRelate.RequestIds(m.AuthIds())
-}
-
-func Add(username, password string, status int, description string, phone string) error {
-	exist, _ := GetByUserName(username)
-	if exist.Id > 0 {
-		return errors.New(fmt.Sprintf("[%s] 用户已经存在", username))
-	}
-	phoneExist, _ := GetByPhone(phone)
-	if phoneExist.Id > 0 {
-		return errors.New(fmt.Sprintf("[%s] 手机号已经存在", phone))
-	}
-	_, err := models.Db.Insert("admin_user").Rows(
-		goqu.Record{"username": username, "password": password, "status": status, "description": description, "phone": phone},
-	).Executor().Exec()
-	return err
-}
-
-func Updata(id int, username, password string, status int, description string, phone string) error {
-	exist, _ := GetByUserName(username)
-	if exist.Id > 0 && exist.Id != id {
-		return errors.New(fmt.Sprintf("[%s] 用户已经存在", username))
-	}
-	phoneExist, _ := GetByPhone(phone)
-	if phoneExist.Id > 0 && phoneExist.Id != id {
-		return errors.New(fmt.Sprintf("[%s] 手机号已经存在", phone))
-	}
-	record := goqu.Record{"username": username, "status": status, "description": description, "phone": phone}
-
-	if password != "" {
-		record["password"] = password
-	}
-	_, err := models.Db.Update("admin_user").Set(record).Where(goqu.Ex{
-		"id": id,
-	}).Executor().Exec()
-	return err
-}
-
-func SelfUpdata(id int, username, password string) error {
-	exist, _ := GetByUserName(username)
-	if exist.Id > 0 && exist.Id != id {
-		return errors.New(fmt.Sprintf("[%s] 用户已经存在", username))
-	}
-	record := goqu.Record{"username": username}
-	if password != "" {
-		record["password"] = password
-	}
-	_, err := models.Db.Update("admin_user").Set(record).Where(goqu.Ex{
-		"id": id,
-	}).Executor().Exec()
-	return err
-}
-
-func Remove(id int) error {
-	_, err := models.Db.Delete("admin_user").Where(goqu.Ex{
-		"id": id,
-	}).Executor().Exec()
-	if err == nil {
-		_ = userRelate.Remove(0, id)
-	}
-	return err
-}
-
-// 检查用户权限
-func CheckAuth(id int, requestId int) error {
-	userGroupIds := userRelate.GroupIds([]int{id})
-	if len(userGroupIds) == 0 {
-		return errors.New("用户未分配用户组")
-	}
-
-	authIds := requestRelate.AuthIds([]int{requestId})
-	if len(authIds) == 0 {
-		return errors.New("请求未分配权限组")
-	}
-
-	if !userGroupRelate.Check(authIds, userGroupIds) {
-		return errors.New("暂无权限")
-	}
-	return nil
-}
-
-func All() ([]*Model, error) {
-	m := make([]*Model, 0)
-	err := models.Db.From("admin_user").ScanStructs(&m)
-	return m, err
-}
-
-func GetById(id int) (model *Model, err error) {
-	model = new(Model)
-	found, err := models.Db.From("admin_user").Where(goqu.Ex{
-		"id": id,
-	}).ScanStruct(model)
-	if err == nil {
-		if !found {
-			err = errors.New("用户不存在")
-		}
-	}
-	return
-}
-
-func GetByUserName(username string) (model *Model, err error) {
-	model = new(Model)
-	found, err := models.Db.From("admin_user").Where(goqu.Ex{
-		"username": username,
-	}).ScanStruct(model)
-	if err == nil {
-		if !found {
-			err = errors.New("用户不存在")
-		}
-	}
-	return
-}
-
-func GetByPhone(phone string) (model *Model, err error) {
-	model = new(Model)
-	found, err := models.Db.From("admin_user").Where(goqu.Ex{
-		"phone": phone,
-	}).ScanStruct(model)
-	if err == nil {
-		if !found {
-			err = errors.New("手机号不存在")
-		}
-	}
-	return
-}
-
-func GetLists(ids []int) ([]*Model, error) {
-	model := make([]*Model, 0)
-	if len(ids) == 0 {
-		return model, nil
-	}
-	err := models.Db.From("admin_user").Where(goqu.Ex{
-		"id": ids,
-	}).ScanStructs(&model)
-	return model, err
-}

+ 0 - 75
src/github.com/baiy/Cadmin-server-go/models/userGroup/userGroup.go

@@ -1,75 +0,0 @@
-package userGroup
-
-import (
-	"errors"
-	"github.com/baiy/Cadmin-server-go/models"
-	"github.com/baiy/Cadmin-server-go/models/userGroupRelate"
-	"github.com/baiy/Cadmin-server-go/models/userRelate"
-	"github.com/doug-martin/goqu/v9"
-	"time"
-)
-
-type Model struct {
-	models.Model
-	Name        string `json:"name"`
-	Description string `json:"description"`
-}
-
-func (m Model) AuthIds() []int {
-	return userGroupRelate.AuthIds([]int{m.Id})
-}
-
-func (m Model) UserIds() []int {
-	return userRelate.UserIds([]int{m.Id})
-}
-
-func Add(name, description string) error {
-	createTime := time.Now().Format("2006-01-02 15:04:05")
-	_, err := models.Db.Insert("admin_user_group").Rows(
-		goqu.Record{"name": name, "description": description, "create_time": createTime},
-	).Executor().Exec()
-	return err
-}
-
-func Updata(id int, name, description string) error {
-	updataTime := time.Now().Format("2006-01-02 15:04:05")
-	_, err := models.Db.Update("admin_user_group").Set(goqu.Record{"name": name, "description": description, "update_time": updataTime}).Where(goqu.Ex{
-		"id": id,
-	}).Executor().Exec()
-	return err
-}
-
-func Remove(id int) error {
-	_, err := models.Db.Delete("admin_user_group").Where(goqu.Ex{
-		"id": id,
-	}).Executor().Exec()
-	if err == nil {
-		_ = userRelate.Remove(id, 0)
-		_ = userGroupRelate.Remove(id, 0)
-	}
-	return err
-}
-
-func GetById(id int) (model *Model, err error) {
-	model = new(Model)
-	found, err := models.Db.From("admin_user_group").Where(goqu.Ex{
-		"id": id,
-	}).ScanStruct(model)
-	if err == nil {
-		if !found {
-			err = errors.New("用户组不存在")
-		}
-	}
-	return
-}
-
-func GetLists(ids []int) ([]*Model, error) {
-	model := make([]*Model, 0)
-	if len(ids) == 0 {
-		return model, nil
-	}
-	err := models.Db.From("admin_user_group").Where(goqu.Ex{
-		"id": ids,
-	}).ScanStructs(&model)
-	return model, err
-}

+ 0 - 65
src/github.com/baiy/Cadmin-server-go/models/userGroupRelate/userGroupRelate.go

@@ -1,65 +0,0 @@
-package userGroupRelate
-
-import (
-	"errors"
-	"github.com/baiy/Cadmin-server-go/models"
-	"github.com/baiy/Cadmin-server-go/utils/set"
-	"github.com/doug-martin/goqu/v9"
-)
-
-type Model struct {
-	models.Model
-	AdminUserGroupId string `json:"admin_user_group_id"`
-	AdminAuthId      string `json:"admin_auth_id"`
-}
-
-func AuthIds(userGroupIds []int) []int {
-	ids := make([]int, 0)
-	_ = models.Db.From("admin_user_group_relate").Select("admin_auth_id").Where(goqu.Ex{
-		"admin_user_group_id": userGroupIds,
-	}).ScanVals(&ids)
-	return ids
-}
-
-func UserGroupIds(authIds []int) []int {
-	ids := make([]int, 0)
-	_ = models.Db.From("admin_user_group_relate").Select("admin_user_group_id").Where(goqu.Ex{
-		"admin_auth_id": authIds,
-	}).ScanVals(&ids)
-	return ids
-}
-
-// 用户分组权限检查
-func Check(authIds []int, userGroupIds []int) bool {
-	if len(authIds) == 0 || len(userGroupIds) == 0 {
-		return false
-	}
-	existAuthIds := AuthIds(userGroupIds)
-
-	if len(existAuthIds) == 0 {
-		return false
-	}
-	return len(set.IntSliceIntersect(existAuthIds, authIds)) != 0
-}
-
-func Add(userGroupId, authId int) error {
-	_, err := models.Db.Insert("admin_user_group_relate").Rows(
-		goqu.Record{"admin_user_group_id": userGroupId, "admin_auth_id": authId},
-	).Executor().Exec()
-	return err
-}
-
-func Remove(userGroupId, authId int) error {
-	if userGroupId == 0 && authId == 0 {
-		return errors.New("参数错误")
-	}
-	where := make(goqu.Ex)
-	if userGroupId != 0 {
-		where["admin_user_group_id"] = userGroupId
-	}
-	if authId != 0 {
-		where["admin_auth_id"] = authId
-	}
-	_, err := models.Db.Delete("admin_user_group_relate").Where(where).Executor().Exec()
-	return err
-}

+ 0 - 51
src/github.com/baiy/Cadmin-server-go/models/userRelate/userRelate.go

@@ -1,51 +0,0 @@
-package userRelate
-
-import (
-	"errors"
-	"github.com/baiy/Cadmin-server-go/models"
-	"github.com/doug-martin/goqu/v9"
-)
-
-type Model struct {
-	models.Model
-	AdminUserId      int `json:"admin_user_id"`
-	AdminUserGroupId int `json:"admin_user_group_id"`
-}
-
-func GroupIds(userIds []int) []int {
-	ids := make([]int, 0)
-	_ = models.Db.From("admin_user_relate").Select("admin_user_group_id").Where(goqu.Ex{
-		"admin_user_id": userIds,
-	}).ScanVals(&ids)
-	return ids
-}
-
-func UserIds(groupIds []int) []int {
-	ids := make([]int, 0)
-	_ = models.Db.From("admin_user_relate").Select("admin_user_id").Where(goqu.Ex{
-		"admin_user_group_id": groupIds,
-	}).ScanVals(&ids)
-	return ids
-}
-
-func Add(groupId, userId int) error {
-	_, err := models.Db.Insert("admin_user_relate").Rows(
-		goqu.Record{"admin_user_id": userId, "admin_user_group_id": groupId},
-	).Executor().Exec()
-	return err
-}
-
-func Remove(groupId, userId int) error {
-	if groupId == 0 && userId == 0 {
-		return errors.New("参数错误")
-	}
-	where := make(goqu.Ex)
-	if groupId != 0 {
-		where["admin_user_group_id"] = groupId
-	}
-	if userId != 0 {
-		where["admin_user_id"] = userId
-	}
-	_, err := models.Db.Delete("admin_user_relate").Where(where).Executor().Exec()
-	return err
-}

+ 0 - 310
src/github.com/baiy/Cadmin-server-go/system/auth/auth.go

@@ -1,310 +0,0 @@
-package auth
-
-import (
-	"github.com/baiy/Cadmin-server-go/models"
-
-	thisModel "github.com/baiy/Cadmin-server-go/models/auth"
-
-	"github.com/baiy/Cadmin-server-go/models/menu"
-	"github.com/baiy/Cadmin-server-go/models/menuRelate"
-	"github.com/baiy/Cadmin-server-go/models/request"
-	"github.com/baiy/Cadmin-server-go/models/requestRelate"
-	"github.com/baiy/Cadmin-server-go/models/userGroup"
-	"github.com/baiy/Cadmin-server-go/models/userGroupRelate"
-	"github.com/baiy/Cadmin-server-go/system/utils"
-	"github.com/baiy/Cadmin-server-go/utils/set"
-
-	"github.com/baiy/Cadmin-server-go/admin"
-	"github.com/doug-martin/goqu/v9"
-)
-
-func Lists(context *admin.Context) (interface{}, error) {
-	param := new(struct {
-		utils.Page
-		Keyword string `form:"keyword"`
-	})
-	err := context.Form(param)
-	if err != nil {
-		return nil, err
-	}
-
-	lists := make([]struct {
-		thisModel.Model
-		Request   []*request.Model   `db:"-" json:"request"`
-		Menu      []*menu.Model      `db:"-" json:"menu"`
-		UserGroup []*userGroup.Model `db:"-" json:"userGroup"`
-	}, 0)
-	where := make(goqu.Ex)
-	if param.Keyword != "" {
-		where["name"] = goqu.Op{"like": "%" + param.Keyword + "%"}
-	}
-	total, err := param.Select("admin_auth", &lists, where)
-	if err != nil {
-		return nil, err
-	}
-
-	for index := range lists {
-		lists[index].Request, _ = request.GetLists(lists[index].RequestIds())
-		lists[index].Menu, _ = menu.GetLists(lists[index].MenuIds())
-		lists[index].UserGroup, _ = userGroup.GetLists(lists[index].UserGroupIds())
-	}
-
-	return map[string]interface{}{
-		"lists": lists,
-		"total": total,
-	}, nil
-}
-
-func Save(context *admin.Context) (interface{}, error) {
-	param := new(struct {
-		Id          int    `form:"id"`
-		Name        string `form:"name" validate:"required"`
-		Description string `form:"description"`
-	})
-
-	err := context.Form(param)
-	if err != nil {
-		return nil, err
-	}
-	if param.Id == 0 {
-		return nil, thisModel.Add(param.Name, param.Description)
-	}
-	return nil, thisModel.Updata(param.Id, param.Name, param.Description)
-}
-
-func Remove(context *admin.Context) (interface{}, error) {
-	id, err := context.InputInt("id")
-	if err != nil {
-		return nil, err
-	}
-	return nil, thisModel.Remove(id)
-}
-
-func GetRequest(context *admin.Context) (interface{}, error) {
-	param := new(struct {
-		utils.Page
-		Id      int    `form:"id" validate:"required"`
-		Keyword string `form:"keyword"`
-	})
-	err := context.Form(param)
-	if err != nil {
-		return nil, err
-	}
-	current, err := thisModel.GetById(param.Id)
-	if err != nil {
-		return nil, err
-	}
-
-	noAssign := make([]request.Model, 0)
-	exist := current.RequestIds()
-	where := make(goqu.ExOr)
-	if param.Keyword != "" {
-		where["name"] = goqu.Op{"like": "%" + param.Keyword + "%"}
-		where["action"] = goqu.Op{"like": "%" + param.Keyword + "%"}
-	}
-	total, err := param.Select("admin_request", &noAssign, where, goqu.Ex{
-		"id": goqu.Op{
-			"notin": append(append(exist, admin.OnlyLoginRequestIds...), admin.NoCheckLoginRequestIds...),
-		},
-	})
-	if err != nil {
-		return nil, err
-	}
-	assign := make([]request.Model, 0)
-	err = models.Db.From(goqu.T("admin_request").As("req")).
-		Select("req.*").
-		InnerJoin(
-			goqu.T("admin_request_relate").As("rel"),
-			goqu.On(goqu.Ex{
-				"rel.admin_request_id": goqu.I("req.id"),
-			}),
-		).
-		Where(goqu.Ex{"rel.admin_auth_id": param.Id}).
-		Order(goqu.I("rel.id").Desc()).ScanStructs(&assign)
-	if err != nil {
-		return nil, err
-	}
-	return map[string]interface{}{
-		"lists": map[string]interface{}{
-			"assign":   assign,
-			"noAssign": noAssign,
-		},
-		"total": total,
-	}, nil
-}
-
-func AssignRequest(context *admin.Context) (interface{}, error) {
-	param := new(struct {
-		Id        int `form:"id" validate:"required"`
-		RequestId int `form:"requestId" validate:"required"`
-	})
-	err := context.Form(param)
-	if err != nil {
-		return nil, err
-	}
-	return nil, requestRelate.Add(param.RequestId, param.Id)
-}
-
-func RemoveRequest(context *admin.Context) (interface{}, error) {
-	param := new(struct {
-		Id        int `form:"id" validate:"required"`
-		RequestId int `form:"requestId" validate:"required"`
-	})
-	err := context.Form(param)
-	if err != nil {
-		return nil, err
-	}
-	return nil, requestRelate.Remove(param.RequestId, param.Id)
-}
-
-func GetUserGroup(context *admin.Context) (interface{}, error) {
-	param := new(struct {
-		utils.Page
-		Id      int    `form:"id" validate:"required"`
-		Keyword string `form:"keyword"`
-	})
-	err := context.Form(param)
-	if err != nil {
-		return nil, err
-	}
-	current, err := thisModel.GetById(param.Id)
-	if err != nil {
-		return nil, err
-	}
-
-	noAssign := make([]userGroup.Model, 0)
-	exist := current.UserGroupIds()
-	where := make(goqu.Ex)
-	if param.Keyword != "" {
-		where["name"] = goqu.Op{"like": "%" + param.Keyword + "%"}
-	}
-	if len(exist) != 0 {
-		where["id"] = goqu.Op{"notin": exist}
-	}
-	total, err := param.Select("admin_user_group", &noAssign, where)
-	if err != nil {
-		return nil, err
-	}
-	assign := make([]userGroup.Model, 0)
-	err = models.Db.From(goqu.T("admin_user_group").As("ug")).
-		Select("ug.*").
-		InnerJoin(
-			goqu.T("admin_user_group_relate").As("rel"),
-			goqu.On(goqu.Ex{
-				"rel.admin_user_group_id": goqu.I("ug.id"),
-			}),
-		).
-		Where(goqu.Ex{"rel.admin_auth_id": param.Id}).
-		Order(goqu.I("rel.id").Desc()).ScanStructs(&assign)
-	if err != nil {
-		return nil, err
-	}
-	return map[string]interface{}{
-		"lists": map[string]interface{}{
-			"assign":   assign,
-			"noAssign": noAssign,
-		},
-		"total": total,
-	}, nil
-}
-
-func AssignUserGroup(context *admin.Context) (interface{}, error) {
-	param := new(struct {
-		Id          int `form:"id" validate:"required"`
-		UserGroupId int `form:"userGroupId" validate:"required"`
-	})
-	err := context.Form(param)
-	if err != nil {
-		return nil, err
-	}
-	return nil, userGroupRelate.Add(param.UserGroupId, param.Id)
-}
-
-func RemoveUserGroup(context *admin.Context) (interface{}, error) {
-	param := new(struct {
-		Id          int `form:"id" validate:"required"`
-		UserGroupId int `form:"userGroupId" validate:"required"`
-	})
-	err := context.Form(param)
-	if err != nil {
-		return nil, err
-	}
-	return nil, userGroupRelate.Remove(param.UserGroupId, param.Id)
-}
-
-func GetMenu(context *admin.Context) (interface{}, error) {
-	param := new(struct {
-		Id int `form:"id" validate:"required"`
-	})
-	err := context.Form(param)
-	if err != nil {
-		return nil, err
-	}
-
-	current, err := thisModel.GetById(param.Id)
-	if err != nil {
-		return nil, err
-	}
-
-	items := make([]struct {
-		menu.Model
-		Checked bool `db:"-" json:"checked"`
-	}, 0)
-
-	err = models.Db.From("admin_menu").ScanStructs(&items)
-	if err != nil {
-		return nil, err
-	}
-
-	exist := current.MenuIds()
-
-	for index := range items {
-		items[index].Checked = inSliceInt(items[index].Id, exist)
-	}
-	return items, nil
-}
-
-func AssignMenu(context *admin.Context) (interface{}, error) {
-	param := new(struct {
-		Id      int   `form:"id" validate:"required"`
-		MenuIds []int `form:"menuIds"`
-	})
-	err := context.Form(param)
-	if err != nil {
-		return nil, err
-	}
-
-	current, err := thisModel.GetById(param.Id)
-	if err != nil {
-		return nil, err
-	}
-
-	// 清空菜单
-	if len(param.MenuIds) == 0 {
-		return nil, menuRelate.Remove(0, current.Id)
-	}
-
-	exist := current.MenuIds()
-
-	// 删除
-	temp := set.IntSliceDifference(exist, param.MenuIds)
-	if len(temp) > 0 {
-		_ = menuRelate.RemoveMultiple(temp, param.Id)
-	}
-
-	// 添加
-	temp = set.IntSliceDifference(param.MenuIds, exist)
-	if len(temp) > 0 {
-		_ = menuRelate.AddMultiple(temp, param.Id)
-	}
-	return nil, nil
-}
-
-func inSliceInt(n int, list []int) bool {
-	for _, i := range list {
-		if i == n {
-			return true
-		}
-	}
-	return false
-}

+ 0 - 290
src/github.com/baiy/Cadmin-server-go/system/index/index.go

@@ -1,290 +0,0 @@
-package index
-
-import (
-	. "config"
-	"errors"
-	"log"
-	"net"
-	"net/http"
-	"qfw/util"
-	"qfw/util/redis"
-	"qfw/util/sms"
-	"strings"
-	"time"
-
-	"github.com/baiy/Cadmin-server-go/admin"
-	"github.com/baiy/Cadmin-server-go/models/auth"
-	"github.com/baiy/Cadmin-server-go/models/menu"
-	"github.com/baiy/Cadmin-server-go/models/request"
-	"github.com/baiy/Cadmin-server-go/models/token"
-	"github.com/baiy/Cadmin-server-go/models/user"
-	"github.com/baiy/Cadmin-server-go/models/userGroup"
-	"github.com/dchest/captcha"
-	"github.com/gorilla/sessions"
-)
-
-var store = sessions.NewCookieStore([]byte("something-very-secret"))
-
-func Login(context *admin.Context) (interface{}, error) {
-	param := new(struct {
-		// Username  string `form:"username"     validate:"required"`
-		// Password  string `form:"password"     validate:"required"`
-		Username  string `form:"username"`
-		Password  string `form:"password"`
-		Code      string `form:"code"`
-		PhoneCode string `form:"phoneCode"`
-		LoginType string `form:"loginType"`
-	})
-	err := context.Form(param)
-	if err != nil {
-		return nil, err
-	}
-	userIp := clientIP(context.HttpRequest)
-	if param.LoginType == "0" {
-		status := map[string]interface{}{"status": 1, "ip": ""}
-		for _, v := range strings.Split(SysConfigs.CompanyIp, ",") {
-			if strings.HasPrefix(userIp, v) {
-				status["ip"] = userIp
-				return status, nil
-			}
-		}
-		status["status"] = 2
-		return status, nil
-	}
-	//是否黑名单
-	ok, err := redis.Exists("qmx_filter", param.Username+"_禁止登录")
-	if ok {
-		return nil, errors.New("禁止登录")
-	} else if err != nil {
-		log.Println("redis查询错误")
-	}
-	u, err := user.GetByUserName(param.Username)
-	if err != nil {
-		return nil, err
-	}
-	//检测验证码
-	if param.LoginType != "3" {
-		session, err := store.Get(context.HttpRequest, "qmx_login_code")
-		if err != nil {
-			log.Println("session2获取失败")
-			return nil, nil
-		}
-		code := util.ObjToString(session.Values["qmx_login_code"])
-		if code == "" {
-			return nil, errors.New("验证码过期")
-		}
-		if !captcha.VerifyString(code, param.Code) {
-			return nil, errors.New("验证码错误")
-		}
-	}
-
-	if u.IsDisabled() {
-		return nil, errors.New("用户已经禁用")
-	}
-
-	if !admin.Passworder.Verify([]byte(param.Password), []byte(u.Password)) {
-		times := util.IntAll(redis.Get("qmx_filter", param.Username))
-		if times >= SysConfigs.ErrTimes-1 {
-			redis.Put("qmx_filter", param.Username+"_禁止登录", 1, SysConfigs.BanTime)
-			return nil, errors.New("禁止登录")
-		}
-		if times == 0 {
-			redis.Put("qmx_filter", param.Username, 1, SysConfigs.ErrSaveTime)
-		} else {
-			redis.Incr("qmx_filter", param.Username)
-		}
-		return nil, errors.New("密码错误")
-	}
-
-	if param.LoginType == "2" { //点击发送手机验证码
-		if u.Phone != "" {
-			if SendPhoneIdentCode(context, u.Phone) {
-				return map[string]interface{}{"status": 3}, nil
-			} else {
-				return nil, errors.New("手机验证码发送失败")
-			}
-		} else {
-			return nil, errors.New("未获取到手机号")
-		}
-	} else if param.LoginType == "3" { //验证手机验证码
-		session, err := store.Get(context.HttpRequest, "qmx_phone_code")
-		if err != nil {
-			log.Println("phone-session2获取失败")
-			return nil, nil
-		}
-		phoneCode := util.ObjToString(session.Values["code"])
-		log.Println("phoneCode", phoneCode)
-		log.Println("param.PhoneCode", param.PhoneCode)
-		phone := util.ObjToString(session.Values["phone"])
-
-		if phoneCode != param.PhoneCode || phone != u.Phone {
-			return nil, errors.New("手机验证码错误")
-		}
-	}
-
-	// 清理token
-	token.Clear()
-
-	// 添加token
-	t := token.Add(u.Id)
-	// 更新用户登陆
-	u.LoginUpdate(userIp)
-
-	return map[string]string{"token": t}, nil
-}
-
-func Logout(context *admin.Context) (interface{}, error) {
-	if context.Token == "" {
-		return nil, errors.New("token 错误")
-	}
-	token.Remove(context.Token)
-	return nil, nil
-}
-
-func Load(context *admin.Context) (interface{}, error) {
-	allUser, err := user.All()
-	if err != nil {
-		return nil, err
-	}
-	menus, err := menu.GetLists(context.User.MenuIds())
-	if err != nil {
-		return nil, err
-	}
-	requests, err := request.GetLists(context.User.RequestIds())
-	if err != nil {
-		return nil, err
-	}
-	auths, err := auth.GetLists(context.User.AuthIds())
-	if err != nil {
-		return nil, err
-	}
-	userGroups, err := userGroup.GetLists(context.User.UserGroupIds())
-	if err != nil {
-		return nil, err
-	}
-	return map[string]interface{}{
-		"user":      context.User,
-		"allUser":   allUser,
-		"menu":      menus,
-		"request":   requests,
-		"auth":      auths,
-		"userGroup": userGroups,
-	}, nil
-}
-
-func CurrentSetting(context *admin.Context) (interface{}, error) {
-	param := new(struct {
-		Username       string `form:"username" validate:"required"`
-		Password       string `form:"password"`
-		RepeatPassword string `form:"repeatPassword"`
-		OldPassword    string `form:"oldPassword"`
-	})
-
-	err := context.Form(param)
-	if err != nil {
-		return nil, err
-	}
-	password := ""
-	if param.Password != "" {
-		if param.Password != param.RepeatPassword {
-			return nil, errors.New("两次输入密码不一致")
-		}
-		password = string(admin.Passworder.Hash([]byte(param.Password)))
-	}
-	u, err := user.GetById(context.User.Id)
-	if err == nil {
-		//log.Println("原密码:", string(admin.Passworder.Hash([]byte(param.OldPassword))))
-		if !admin.Passworder.Verify([]byte(param.OldPassword), []byte(u.Password)) {
-			return nil, errors.New("原密码错误")
-		}
-	}
-
-	return nil, user.SelfUpdata(context.User.Id, param.Username, password)
-}
-
-func clientIP(r *http.Request) string {
-	xForwardedFor := r.Header.Get("X-Forwarded-For")
-	ip := strings.TrimSpace(strings.Split(xForwardedFor, ",")[0])
-	if ip != "" {
-		return ip
-	}
-
-	ip = strings.TrimSpace(r.Header.Get("X-Real-Ip"))
-	if ip != "" {
-		return ip
-	}
-
-	if ip, _, err := net.SplitHostPort(strings.TrimSpace(r.RemoteAddr)); err == nil {
-		return ip
-	}
-
-	return ""
-}
-
-func Code(context *admin.Context) (interface{}, error) {
-	id := captcha.NewLen(4)
-	r := context.HttpRequest
-	r.Header.Add("Cache-Control", "no-cache, no-store, must-revalidate")
-	r.Header.Add("Pragma", "no-cache")
-	r.Header.Add("Expires", "0")
-	r.Header.Add("Content-Type", "image/png")
-	w := context.HttpResponseWriter
-	session, err := store.Get(r, "qmx_login_code")
-	if err != nil {
-		log.Println("session1获取失败")
-		return nil, nil
-	}
-	session.Values["qmx_login_code"] = id
-	session.Options.MaxAge = 60
-	// log.Println("session111", session)
-	if err := session.Save(r, w); err != nil {
-		log.Println("session1保存错误,验证码 ", id)
-	}
-	// loginCode[id] = time.Now().Unix()
-	return nil, captcha.WriteImage(w, id, 90, 30)
-}
-
-//根据模板发送短信,模板是运营商设定的。
-//第三个参数是可变参数,可以传入多个,但要和模板相匹配
-//func SendSMS(tplcode /*模板代码*/, mobile /*手机号码*/ string, param map[string]string) {
-//	tmp := []string{}
-//	for k, v := range param {
-//		tmp = append(tmp, "#"+k+"#="+v)
-//	}
-//	text := strings.Join(tmp, "&")
-//	sms.SendSms(mobile, tplcode, text)
-//}
-
-func SendSMS(address, mobile string, params ...string) {
-	sms.SendSms(address, "01", mobile, params...)
-}
-
-//发送验证码
-func SendPhoneIdentCode(context *admin.Context, phone string) bool {
-	r := context.HttpRequest
-	w := context.HttpResponseWriter
-	session, err := store.Get(r, "qmx_phone_code")
-	if err != nil {
-		log.Println("phone-session1获取失败")
-		return false
-	}
-	lastSentTime := util.Int64All(session.Values["identCodeTime"])
-	//60秒之内不允许重复发
-	if lastSentTime > 0 && time.Now().Unix()-lastSentTime <= 60 {
-		return false
-	}
-	s_ranNum := util.GetRandom(6) //生成随机数
-
-	session.Values["code"] = s_ranNum
-	session.Values["phone"] = phone
-	session.Values["identCodeTime"] = time.Now().Unix()
-	session.Options.MaxAge = 300
-	if err := session.Save(r, w); err != nil {
-		log.Println("session1保存错误,验证码")
-	}
-	//发送短信
-	//param := map[string]string{"code": s_ranNum}
-	log.Println("短信验证码", phone, s_ranNum)
-	SendSMS(SysConfigs.SmsServiceRpc, phone, s_ranNum)
-	return true
-}

+ 0 - 56
src/github.com/baiy/Cadmin-server-go/system/menu/menu.go

@@ -1,56 +0,0 @@
-package menu
-
-import (
-	"github.com/baiy/Cadmin-server-go/admin"
-	thisModel "github.com/baiy/Cadmin-server-go/models/menu"
-)
-
-func Lists(context *admin.Context) (interface{}, error) {
-	return thisModel.All()
-}
-
-func Save(context *admin.Context) (interface{}, error) {
-	param := new(struct {
-		Id          int    `form:"id"`
-		ParentId    int    `form:"parent_id" validate:"min=0"`
-		Name        string `form:"name" validate:"required"`
-		Url         string `form:"url"`
-		Icon        string `form:"icon"`
-		Description string `form:"description"`
-	})
-
-	err := context.Form(param)
-	if err != nil {
-		return nil, err
-	}
-
-	if param.Id == 0 {
-		return nil, thisModel.Add(param.ParentId, param.Name, param.Url, param.Icon, param.Description)
-	}
-	return nil, thisModel.Updata(param.Id, param.ParentId, param.Name, param.Url, param.Icon, param.Description)
-}
-
-func Remove(context *admin.Context) (interface{}, error) {
-	id, err := context.InputInt("id")
-	if err != nil {
-		return nil, err
-	}
-	return nil, thisModel.Remove(id)
-}
-
-func Sort(context *admin.Context) (interface{}, error) {
-	param := new(struct {
-		Menus map[int]map[string]int `form:"menus"`
-	})
-	err := context.Form(param)
-	if err != nil {
-		return nil, err
-	}
-	for _, item := range param.Menus {
-		err = thisModel.Sort(item["id"], item["sort"])
-		if err != nil {
-			return nil, err
-		}
-	}
-	return nil, nil
-}

+ 0 - 95
src/github.com/baiy/Cadmin-server-go/system/request/request.go

@@ -1,95 +0,0 @@
-package request
-
-import (
-	"github.com/baiy/Cadmin-server-go/admin"
-	"github.com/baiy/Cadmin-server-go/models/auth"
-	thisModel "github.com/baiy/Cadmin-server-go/models/request"
-	"github.com/baiy/Cadmin-server-go/system/utils"
-	"github.com/doug-martin/goqu/v9"
-)
-
-type DispatchItem struct {
-	Type        string `json:"type"`
-	Name        string `json:"name"`
-	Description string `json:"description"`
-}
-
-func Lists(context *admin.Context) (interface{}, error) {
-	param := new(struct {
-		utils.Page
-		Keyword string `form:"keyword"`
-		Typ     string `form:"type"`
-	})
-	err := context.Form(param)
-	if err != nil {
-		return nil, err
-	}
-
-	lists := make([]struct {
-		thisModel.Model
-		Auth []*auth.Model `db:"-" json:"auth"`
-	}, 0)
-	where := make(goqu.ExOr)
-	if param.Keyword != "" {
-		where["name"] = goqu.Op{"like": "%" + param.Keyword + "%"}
-		where["action"] = goqu.Op{"like": "%" + param.Keyword + "%"}
-		where["call"] = goqu.Op{"like": "%" + param.Keyword + "%"}
-	}
-	if param.Typ != "" {
-		where["type"] = goqu.Op{"like": "%" + param.Typ + "%"}
-	}
-	total, err := param.Select("admin_request", &lists, where)
-	if err != nil {
-		return nil, err
-	}
-
-	for index := range lists {
-		lists[index].Auth, _ = auth.GetLists(lists[index].AuthIds())
-	}
-
-	return map[string]interface{}{
-		"lists": lists,
-		"total": total,
-	}, nil
-}
-
-func Save(context *admin.Context) (interface{}, error) {
-	param := new(struct {
-		Id     int    `form:"id"`
-		Name   string `form:"name" validate:"required"`
-		Action string `form:"action" validate:"required"`
-		Type   string `form:"type" validate:"required"`
-		Call   string `form:"call"`
-	})
-
-	err := context.Form(param)
-	if err != nil {
-		return nil, err
-	}
-
-	if param.Id == 0 {
-		return nil, thisModel.Add(param.Name, param.Action, param.Type, param.Call)
-	}
-	return nil, thisModel.Updata(param.Id, param.Name, param.Action, param.Type, param.Call)
-}
-
-func Remove(context *admin.Context) (interface{}, error) {
-	id, err := context.InputInt("id")
-	if err != nil {
-		return nil, err
-	}
-	return nil, thisModel.Remove(id)
-}
-func Type(context *admin.Context) (interface{}, error) {
-	lists := make([]DispatchItem, admin.AllDispatcherLength())
-	i := 0
-	for type_, value := range admin.AllDispatcher() {
-		lists[i] = DispatchItem{
-			Type:        type_,
-			Name:        value.Name(),
-			Description: value.Description(),
-		}
-		i++
-	}
-	return lists, nil
-}

+ 0 - 52
src/github.com/baiy/Cadmin-server-go/system/router.go

@@ -1,52 +0,0 @@
-// 请求处理方法注册
-
-package system
-
-import (
-	"github.com/baiy/Cadmin-server-go/system/auth"
-	"github.com/baiy/Cadmin-server-go/system/index"
-	"github.com/baiy/Cadmin-server-go/system/menu"
-	"github.com/baiy/Cadmin-server-go/system/request"
-	"github.com/baiy/Cadmin-server-go/system/user"
-	"github.com/baiy/Cadmin-server-go/system/userGroup"
-
-	"github.com/baiy/Cadmin-server-go/admin"
-)
-
-func init() {
-	admin.RegisterDefaultDispatcherHandleMethod(map[string]admin.DefaultDispatcherHandleMethod{
-		"Baiy.Cadmin.System.Index.login":          index.Login,
-		"Baiy.Cadmin.System.Index.logout":         index.Logout,
-		"Baiy.Cadmin.System.Index.load":           index.Load,
-		"Baiy.Cadmin.System.Index.code":           index.Code,
-		"Baiy.Cadmin.System.User.currentSetting":  index.CurrentSetting,
-		"Baiy.Cadmin.System.User.lists":           user.Lists,
-		"Baiy.Cadmin.System.User.save":            user.Save,
-		"Baiy.Cadmin.System.User.remove":          user.Remove,
-		"Baiy.Cadmin.System.UserGroup.lists":      userGroup.Lists,
-		"Baiy.Cadmin.System.UserGroup.save":       userGroup.Save,
-		"Baiy.Cadmin.System.UserGroup.remove":     userGroup.Remove,
-		"Baiy.Cadmin.System.UserGroup.getUser":    userGroup.GetUser,
-		"Baiy.Cadmin.System.UserGroup.assignUser": userGroup.AssignUser,
-		"Baiy.Cadmin.System.UserGroup.removeUser": userGroup.RemoveUser,
-		"Baiy.Cadmin.System.Request.lists":        request.Lists,
-		"Baiy.Cadmin.System.Request.save":         request.Save,
-		"Baiy.Cadmin.System.Request.remove":       request.Remove,
-		"Baiy.Cadmin.System.Request.type":         request.Type,
-		"Baiy.Cadmin.System.Menu.lists":           menu.Lists,
-		"Baiy.Cadmin.System.Menu.sort":            menu.Sort,
-		"Baiy.Cadmin.System.Menu.save":            menu.Save,
-		"Baiy.Cadmin.System.Menu.remove":          menu.Remove,
-		"Baiy.Cadmin.System.Auth.lists":           auth.Lists,
-		"Baiy.Cadmin.System.Auth.save":            auth.Save,
-		"Baiy.Cadmin.System.Auth.remove":          auth.Remove,
-		"Baiy.Cadmin.System.Auth.getRequest":      auth.GetRequest,
-		"Baiy.Cadmin.System.Auth.assignRequest":   auth.AssignRequest,
-		"Baiy.Cadmin.System.Auth.removeRequest":   auth.RemoveRequest,
-		"Baiy.Cadmin.System.Auth.getUserGroup":    auth.GetUserGroup,
-		"Baiy.Cadmin.System.Auth.assignUserGroup": auth.AssignUserGroup,
-		"Baiy.Cadmin.System.Auth.removeUserGroup": auth.RemoveUserGroup,
-		"Baiy.Cadmin.System.Auth.getMenu":         auth.GetMenu,
-		"Baiy.Cadmin.System.Auth.assignMenu":      auth.AssignMenu,
-	})
-}

+ 0 - 163
src/github.com/baiy/Cadmin-server-go/system/user/user.go

@@ -1,163 +0,0 @@
-package user
-
-import (
-	. "config"
-	"errors"
-	"github.com/gorilla/sessions"
-	"log"
-	"qfw/util"
-	"time"
-
-	thisModel "github.com/baiy/Cadmin-server-go/models/user"
-
-	"github.com/baiy/Cadmin-server-go/models/userGroup"
-	"github.com/baiy/Cadmin-server-go/system/utils"
-
-	"github.com/baiy/Cadmin-server-go/admin"
-	index_ "github.com/baiy/Cadmin-server-go/system/index"
-	"github.com/doug-martin/goqu/v9"
-)
-
-var store = sessions.NewCookieStore([]byte("something-very-secret-save"))
-
-func Lists(context *admin.Context) (interface{}, error) {
-	userId := context.User.Id
-	param := new(struct {
-		utils.Page
-		Keyword string `form:"keyword"`
-	})
-	err := context.Form(param)
-	if err != nil {
-		return nil, err
-	}
-	updateAuth := false
-	delAuth := false
-	if updateError := thisModel.CheckAuth(userId, 11); updateError == nil {
-		updateAuth = true
-	}
-	if delError := thisModel.CheckAuth(userId, 12); delError == nil {
-		delAuth = true
-	}
-	lists := make([]struct {
-		thisModel.Model
-		UserGroup []*userGroup.Model `db:"-" json:"userGroup"`
-	}, 0)
-	where := make(goqu.Ex)
-	if param.Keyword != "" {
-		where["username"] = goqu.Op{"like": "%" + param.Keyword + "%"}
-	}
-	total, err := param.Select("admin_user", &lists, where)
-	if err != nil {
-		return nil, err
-	}
-
-	for index := range lists {
-		lists[index].UserGroup, _ = userGroup.GetLists(lists[index].UserGroupIds())
-	}
-
-	return map[string]interface{}{
-		"lists":      lists,
-		"total":      total,
-		"updateAuth": updateAuth,
-		"delAuth":    delAuth,
-	}, nil
-}
-
-func Save(context *admin.Context) (interface{}, error) {
-	param := new(struct {
-		Id          int    `form:"id"`
-		Username    string `form:"username" validate:"required"`
-		Password    string `form:"password"`
-		Description string `form:"description"`
-		Status      int    `form:"status"  validate:"required"`
-		Phone       string `form:"phone" `
-		PhoneCode   string `form:"phoneCode"`
-		LoginType   string `form:"loginType"`
-	})
-
-	err := context.Form(param)
-	if err != nil {
-		return nil, err
-	}
-	password := ""
-	if param.Password != "" {
-		password = string(admin.Passworder.Hash([]byte(param.Password)))
-	}
-
-	if param.LoginType == "2" { //点击发送手机验证码
-		phoneExist, _ := thisModel.GetByPhone(param.Phone)
-		if phoneExist.Id > 0 {
-			if phoneExist.Id != param.Id {
-				return nil, errors.New("手机号已绑定其他账号")
-			} else {
-				return nil, errors.New("手机号与原手机号一致")
-			}
-		}
-		if SendPhoneIdentCode(context, param.Phone) {
-			return map[string]interface{}{"status": 3}, nil
-		} else {
-			return nil, errors.New("手机验证码发送失败")
-		}
-	} else if param.LoginType == "3" { //验证手机验证码
-		session, err := store.Get(context.HttpRequest, "qmx_phone_code_save")
-		if err != nil {
-			log.Println("phone-session2获取失败")
-			return nil, nil
-		}
-		if param.PhoneCode == "" {
-			return nil, errors.New("手机验证码不能为空")
-		}
-		phoneCode := util.ObjToString(session.Values["code"])
-		phone := util.ObjToString(session.Values["phone"])
-		if phone != param.Phone || phoneCode != param.PhoneCode {
-			return nil, errors.New("手机验证码错误")
-		}
-	}
-	if param.Id == 0 {
-		if param.Password == "" {
-			return nil, errors.New("添加用户密码不能为空")
-		}
-		if param.Phone == "" {
-			return nil, errors.New("添加用户手机号不能为空")
-		}
-		return nil, thisModel.Add(param.Username, password, param.Status, param.Description, param.Phone)
-	}
-	return nil, thisModel.Updata(param.Id, param.Username, password, param.Status, param.Description, param.Phone)
-}
-
-//发送验证码
-func SendPhoneIdentCode(context *admin.Context, phone string) bool {
-	r := context.HttpRequest
-	w := context.HttpResponseWriter
-	session, err := store.Get(r, "qmx_phone_code_save")
-	if err != nil {
-		log.Println("phone-session1获取失败")
-		return false
-	}
-	lastSentTime := util.Int64All(session.Values["identCodeTime"])
-	//60秒之内不允许重复发
-	if lastSentTime > 0 && time.Now().Unix()-lastSentTime <= 60 {
-		return false
-	}
-	s_ranNum := util.GetRandom(6) //生成随机数
-	session.Values["code"] = s_ranNum
-	session.Values["phone"] = phone
-	session.Values["identCodeTime"] = time.Now().Unix()
-	session.Options.MaxAge = 300
-	if err := session.Save(r, w); err != nil {
-		log.Println("session1保存错误,验证码")
-	}
-	//发送短信
-	//param := map[string]string{"code": s_ranNum}
-	log.Println("短信验证码", phone, s_ranNum)
-	index_.SendSMS(SysConfigs.SmsServiceRpc, phone, s_ranNum)
-	return true
-}
-
-func Remove(context *admin.Context) (interface{}, error) {
-	id, err := context.InputInt("id")
-	if err != nil {
-		return nil, err
-	}
-	return nil, thisModel.Remove(id)
-}

+ 0 - 157
src/github.com/baiy/Cadmin-server-go/system/userGroup/userGroup.go

@@ -1,157 +0,0 @@
-package userGroup
-
-import (
-	"github.com/baiy/Cadmin-server-go/admin"
-	"github.com/baiy/Cadmin-server-go/models"
-	"github.com/baiy/Cadmin-server-go/models/auth"
-	"github.com/baiy/Cadmin-server-go/models/user"
-	thisModel "github.com/baiy/Cadmin-server-go/models/userGroup"
-	"github.com/baiy/Cadmin-server-go/models/userRelate"
-	"github.com/baiy/Cadmin-server-go/system/utils"
-	"github.com/doug-martin/goqu/v9"
-)
-
-func Lists(context *admin.Context) (interface{}, error) {
-	userId := context.User.Id
-	param := new(struct {
-		utils.Page
-		Keyword string `form:"keyword"`
-	})
-	err := context.Form(param)
-	if err != nil {
-		return nil, err
-	}
-	updateAuth := false
-	delAuth := false
-	if updateError := user.CheckAuth(userId, 21); updateError == nil {
-		updateAuth = true
-	}
-	if delError := user.CheckAuth(userId, 22); delError == nil {
-		delAuth = true
-	}
-	lists := make([]struct {
-		thisModel.Model
-		Auth []*auth.Model `db:"-" json:"auth"`
-		User []*user.Model `db:"-" json:"user"`
-	}, 0)
-	where := make(goqu.Ex)
-	if param.Keyword != "" {
-		where["name"] = goqu.Op{"like": "%" + param.Keyword + "%"}
-	}
-	total, err := param.Select("admin_user_group", &lists, where)
-	if err != nil {
-		return nil, err
-	}
-
-	for index := range lists {
-		lists[index].Auth, _ = auth.GetLists(lists[index].AuthIds())
-		lists[index].User, _ = user.GetLists(lists[index].UserIds())
-	}
-
-	return map[string]interface{}{
-		"lists":      lists,
-		"total":      total,
-		"updateAuth": updateAuth,
-		"delAuth":    delAuth,
-	}, nil
-}
-
-func Save(context *admin.Context) (interface{}, error) {
-	param := new(struct {
-		Id          int    `form:"id"`
-		Name        string `form:"name" validate:"required"`
-		Description string `form:"description"`
-	})
-
-	err := context.Form(param)
-	if err != nil {
-		return nil, err
-	}
-	if param.Id == 0 {
-		return nil, thisModel.Add(param.Name, param.Description)
-	}
-	return nil, thisModel.Updata(param.Id, param.Name, param.Description)
-}
-
-func Remove(context *admin.Context) (interface{}, error) {
-	id, err := context.InputInt("id")
-	if err != nil {
-		return nil, err
-	}
-	return nil, thisModel.Remove(id)
-}
-
-func GetUser(context *admin.Context) (interface{}, error) {
-	param := new(struct {
-		utils.Page
-		Id      int    `form:"id" validate:"required"`
-		Keyword string `form:"keyword"`
-	})
-	err := context.Form(param)
-	if err != nil {
-		return nil, err
-	}
-	current, err := thisModel.GetById(param.Id)
-	if err != nil {
-		return nil, err
-	}
-
-	noAssign := make([]user.Model, 0)
-	exist := current.UserIds()
-	where := make(goqu.Ex)
-	if param.Keyword != "" {
-		where["username"] = goqu.Op{"like": "%" + param.Keyword + "%"}
-	}
-	if len(exist) != 0 {
-		where["id"] = goqu.Op{"notin": exist}
-	}
-	total, err := param.Select("admin_user", &noAssign, where)
-	if err != nil {
-		return nil, err
-	}
-	assign := make([]user.Model, 0)
-	err = models.Db.From(goqu.T("admin_user").As("user")).
-		Select("user.*").
-		InnerJoin(
-			goqu.T("admin_user_relate").As("rel"),
-			goqu.On(goqu.Ex{
-				"rel.admin_user_id": goqu.I("user.id"),
-			}),
-		).
-		Where(goqu.Ex{"rel.admin_user_group_id": param.Id}).
-		Order(goqu.I("rel.id").Desc()).ScanStructs(&assign)
-	if err != nil {
-		return nil, err
-	}
-	return map[string]interface{}{
-		"lists": map[string]interface{}{
-			"assign":   assign,
-			"noAssign": noAssign,
-		},
-		"total": total,
-	}, nil
-}
-
-func AssignUser(context *admin.Context) (interface{}, error) {
-	param := new(struct {
-		Id     int `form:"id" validate:"required"`
-		UserId int `form:"userId" validate:"required"`
-	})
-	err := context.Form(param)
-	if err != nil {
-		return nil, err
-	}
-	return nil, userRelate.Add(param.Id, param.UserId)
-}
-
-func RemoveUser(context *admin.Context) (interface{}, error) {
-	param := new(struct {
-		Id     int `form:"id" validate:"required"`
-		UserId int `form:"userId" validate:"required"`
-	})
-	err := context.Form(param)
-	if err != nil {
-		return nil, err
-	}
-	return nil, userRelate.Remove(param.Id, param.UserId)
-}

+ 0 - 24
src/github.com/baiy/Cadmin-server-go/system/utils/page.go

@@ -1,24 +0,0 @@
-package utils
-
-import (
-	"github.com/baiy/Cadmin-server-go/models"
-	"github.com/doug-martin/goqu/v9"
-	"github.com/doug-martin/goqu/v9/exp"
-)
-
-type Page struct {
-	Offset   int `form:"offset"`
-	PageSize int `form:"pageSize"`
-}
-
-func (p Page) Select(table string, lists interface{}, expressions ...exp.Expression) (total int, err error) {
-	count, err := models.Db.From(table).Where(expressions...).Count()
-	if err != nil {
-		return
-	}
-	total = int(count)
-	err = models.Db.From(table).Where(expressions...).
-		Offset(uint(p.Offset)).Limit(uint(p.PageSize)).
-		Order(goqu.I("id").Desc()).ScanStructs(lists)
-	return
-}

+ 0 - 1
src/github.com/coreos/etcd/.dockerignore

@@ -1 +0,0 @@
-.git

+ 0 - 7
src/github.com/coreos/etcd/.github/ISSUE_TEMPLATE.md

@@ -1,7 +0,0 @@
-# Bug reporting
-
-A good bug report has some very specific qualities, so please read over our short document on [reporting bugs][report_bugs] before submitting a bug report.
-
-To ask a question, go ahead and ignore this.
-
-[report_bugs]: https://github.com/coreos/etcd/blob/master/Documentation/reporting_bugs.md

+ 0 - 5
src/github.com/coreos/etcd/.github/PULL_REQUEST_TEMPLATE.md

@@ -1,5 +0,0 @@
-# Contributing guidelines
-
-Please read our [contribution workflow][contributing] before submitting a pull request.
-
-[contributing]: https://github.com/coreos/etcd/blob/master/CONTRIBUTING.md#contribution-flow

+ 0 - 20
src/github.com/coreos/etcd/.gitignore

@@ -1,20 +0,0 @@
-/agent-*
-/coverage
-/covdir
-/docs
-/gopath
-/gopath.proto
-/go-bindata
-/release
-/machine*
-/bin
-.vagrant
-*.etcd
-*.log
-/etcd
-*.swp
-/hack/insta-discovery/.env
-*.test
-hack/tls-setup/certs
-.idea
-*.bak

+ 0 - 1
src/github.com/coreos/etcd/.godir

@@ -1 +0,0 @@
-github.com/coreos/etcd

+ 0 - 13
src/github.com/coreos/etcd/.header

@@ -1,13 +0,0 @@
-// Copyright 2016 The etcd Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.

+ 0 - 66
src/github.com/coreos/etcd/.travis.yml

@@ -1,66 +0,0 @@
-language: go
-go_import_path: github.com/coreos/etcd
-
-sudo: required
-
-services: docker
-
-go:
-- 1.12.12
-
-env:
-- GO111MODULE=on
-
-notifications:
-  on_success: never
-  on_failure: never
-
-env:
-  matrix:
-  - TARGET=linux-amd64-integration-1-cpu
-  - TARGET=linux-amd64-integration-4-cpu
-  - TARGET=linux-amd64-functional
-  - TARGET=linux-amd64-unit
-  - TARGET=linux-amd64-e2e
-  - TARGET=all-build
-  - TARGET=linux-386-unit
-
-matrix:
-  fast_finish: true
-  allow_failures:
-  - go: 1.12.12
-    env: TARGET=linux-386-unit
-
-install:
-- go get -t -v -d ./...
-
-script:
- - echo "TRAVIS_GO_VERSION=${TRAVIS_GO_VERSION}"
- - >
-    case "${TARGET}" in
-      linux-amd64-integration-1-cpu)
-        GOARCH=amd64 CPU=1 PASSES='integration' ./test
-        ;;
-      linux-amd64-integration-4-cpu)
-        GOARCH=amd64 CPU=4 PASSES='integration' ./test
-        ;;
-      linux-amd64-functional)
-        ./build && GOARCH=amd64 PASSES='functional' ./test
-        ;;
-      linux-amd64-unit)
-        ./build && GOARCH=amd64 PASSES='unit' ./test
-        ;;
-      linux-amd64-e2e)
-        GOARCH=amd64 PASSES='build release e2e' MANUAL_VER=v3.3.13 ./test
-        ;;
-      all-build)
-        GOARCH=386 PASSES='build' ./test \
-          && GO_BUILD_FLAGS='-v' GOOS=darwin GOARCH=amd64 ./build \
-          && GO_BUILD_FLAGS='-v' GOARCH=arm ./build \
-          && GO_BUILD_FLAGS='-v' GOARCH=arm64 ./build \
-          && GO_BUILD_FLAGS='-v' GOARCH=ppc64le ./build
-        ;;
-      linux-386-unit)
-        GOARCH=386 ./build && GOARCH=386 PASSES='unit' ./test
-        ;;
-    esac

+ 0 - 46
src/github.com/coreos/etcd/.words

@@ -1,46 +0,0 @@
-DefaultMaxRequestBytes
-ErrCodeEnhanceYourCalm
-ErrTimeout
-GoAway
-KeepAlive
-Keepalive
-MiB
-ResourceExhausted
-RPC
-RPCs
-TODO
-backoff
-blackhole
-blackholed
-cancelable
-cancelation
-cluster_proxy
-defragment
-defragmenting
-etcd
-gRPC
-goroutine
-goroutines
-healthcheck
-iff
-inflight
-keepalive
-hasleader
-racey
-keepalives
-keyspace
-linearization
-localhost
-mutex
-prefetching
-protobuf
-prometheus
-rafthttp
-repin
-serializable
-teardown
-too_many_pings
-uncontended
-unprefixed
-unlisting
-WithDialer

+ 0 - 63
src/github.com/coreos/etcd/CODE_OF_CONDUCT.md

@@ -1,63 +0,0 @@
-## CoreOS Community Code of Conduct
-
-### Contributor Code of Conduct
-
-As contributors and maintainers of this project, and in the interest of
-fostering an open and welcoming community, we pledge to respect all people who
-contribute through reporting issues, posting feature requests, updating
-documentation, submitting pull requests or patches, and other activities.
-
-We are committed to making participation in this project a harassment-free
-experience for everyone, regardless of level of experience, gender, gender
-identity and expression, sexual orientation, disability, personal appearance,
-body size, race, ethnicity, age, religion, or nationality.
-
-Examples of unacceptable behavior by participants include:
-
-* The use of sexualized language or imagery
-* Personal attacks
-* Trolling or insulting/derogatory comments
-* Public or private harassment
-* Publishing others' private information, such as physical or electronic addresses, without explicit permission
-* Other unethical or unprofessional conduct.
-
-Project maintainers have the right and responsibility to remove, edit, or
-reject comments, commits, code, wiki edits, issues, and other contributions
-that are not aligned to this Code of Conduct. By adopting this Code of Conduct,
-project maintainers commit themselves to fairly and consistently applying these
-principles to every aspect of managing this project. Project maintainers who do
-not follow or enforce the Code of Conduct may be permanently removed from the
-project team.
-
-This code of conduct applies both within project spaces and in public spaces
-when an individual is representing the project or its community.
-
-Instances of abusive, harassing, or otherwise unacceptable behavior may be
-reported by contacting a project maintainer, Brandon Philips
-<brandon.philips@coreos.com>, and/or Meghan Schofield
-<meghan.schofield@coreos.com>.
-
-This Code of Conduct is adapted from the Contributor Covenant
-(http://contributor-covenant.org), version 1.2.0, available at
-http://contributor-covenant.org/version/1/2/0/
-
-### CoreOS Events Code of Conduct
-
-CoreOS events are working conferences intended for professional networking and
-collaboration in the CoreOS community. Attendees are expected to behave
-according to professional standards and in accordance with their employer’s
-policies on appropriate workplace behavior.
-
-While at CoreOS events or related social networking opportunities, attendees
-should not engage in discriminatory or offensive speech or actions including
-but not limited to gender, sexuality, race, age, disability, or religion.
-Speakers should be especially aware of these concerns.
-
-CoreOS does not condone any statements by speakers contrary to these standards.
-CoreOS reserves the right to deny entrance and/or eject from an event (without
-refund) any individual found to be engaging in discriminatory or offensive
-speech or actions.
-
-Please bring any concerns to the immediate attention of designated on-site
-staff, Brandon Philips <brandon.philips@coreos.com>, and/or Meghan Schofield
-<meghan.schofield@coreos.com>.

+ 0 - 62
src/github.com/coreos/etcd/CONTRIBUTING.md

@@ -1,62 +0,0 @@
-# How to contribute
-
-etcd is Apache 2.0 licensed and accepts contributions via GitHub pull requests. This document outlines some of the conventions on commit message formatting, contact points for developers, and other resources to help get contributions into etcd.
-
-# Email and chat
-
-- Email: [etcd-dev](https://groups.google.com/forum/?hl=en#!forum/etcd-dev)
-- IRC: #[etcd](irc://irc.freenode.org:6667/#etcd) IRC channel on freenode.org
-
-## Getting started
-
-- Fork the repository on GitHub
-- Read the README.md for build instructions
-
-## Reporting bugs and creating issues
-
-Reporting bugs is one of the best ways to contribute. However, a good bug report has some very specific qualities, so please read over our short document on [reporting bugs](https://github.com/coreos/etcd/blob/master/Documentation/reporting_bugs.md) before submitting a bug report. This document might contain links to known issues, another good reason to take a look there before reporting a bug.
-
-## Contribution flow
-
-This is a rough outline of what a contributor's workflow looks like:
-
-- Create a topic branch from where to base the contribution. This is usually master.
-- Make commits of logical units.
-- Make sure commit messages are in the proper format (see below).
-- Push changes in a topic branch to a personal fork of the repository.
-- Submit a pull request to coreos/etcd.
-- The PR must receive a LGTM from two maintainers found in the MAINTAINERS file.
-
-Thanks for contributing!
-
-### Code style
-
-The coding style suggested by the Golang community is used in etcd. See the [style doc](https://github.com/golang/go/wiki/CodeReviewComments) for details.
-
-Please follow this style to make etcd easy to review, maintain and develop.
-
-### Format of the commit message
-
-We follow a rough convention for commit messages that is designed to answer two
-questions: what changed and why. The subject line should feature the what and
-the body of the commit should describe the why.
-
-```
-scripts: add the test-cluster command
-
-this uses tmux to setup a test cluster that can easily be killed and started for debugging.
-
-Fixes #38
-```
-
-The format can be described more formally as follows:
-
-```
-<subsystem>: <what changed>
-<BLANK LINE>
-<why this change was made>
-<BLANK LINE>
-<footer>
-```
-
-The first line is the subject and should be no longer than 70 characters, the second line is always blank, and other lines should be wrapped at 80 characters. This allows the message to be easier to read on GitHub as well as in various git tools.

+ 0 - 36
src/github.com/coreos/etcd/DCO

@@ -1,36 +0,0 @@
-Developer Certificate of Origin
-Version 1.1
-
-Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
-660 York Street, Suite 102,
-San Francisco, CA 94110 USA
-
-Everyone is permitted to copy and distribute verbatim copies of this
-license document, but changing it is not allowed.
-
-
-Developer's Certificate of Origin 1.1
-
-By making a contribution to this project, I certify that:
-
-(a) The contribution was created in whole or in part by me and I
-    have the right to submit it under the open source license
-    indicated in the file; or
-
-(b) The contribution is based upon previous work that, to the best
-    of my knowledge, is covered under an appropriate open source
-    license and I have the right under that license to submit that
-    work with modifications, whether created in whole or in part
-    by me, under the same open source license (unless I am
-    permitted to submit under a different license), as indicated
-    in the file; or
-
-(c) The contribution was provided directly to me by some other
-    person who certified (a), (b) or (c) and I have not modified
-    it.
-
-(d) I understand and agree that this project and the contribution
-    are public and that a record of the contribution (including all
-    personal information I submit with it, including my sign-off) is
-    maintained indefinitely and may be redistributed consistent with
-    this project or the open source license(s) involved.

+ 0 - 6
src/github.com/coreos/etcd/Dockerfile

@@ -1,6 +0,0 @@
-FROM golang
-ADD . /go/src/github.com/coreos/etcd
-ADD cmd/vendor /go/src/github.com/coreos/etcd/vendor
-RUN go install github.com/coreos/etcd
-EXPOSE 2379 2380
-ENTRYPOINT ["etcd"]

+ 0 - 53
src/github.com/coreos/etcd/Dockerfile-functional-tester

@@ -1,53 +0,0 @@
-FROM ubuntu:17.10
-
-RUN rm /bin/sh && ln -s /bin/bash /bin/sh
-RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections
-
-RUN apt-get -y update \
-  && apt-get -y install \
-  build-essential \
-  gcc \
-  apt-utils \
-  pkg-config \
-  software-properties-common \
-  apt-transport-https \
-  libssl-dev \
-  sudo \
-  bash \
-  curl \
-  wget \
-  tar \
-  git \
-  && apt-get -y update \
-  && apt-get -y upgrade \
-  && apt-get -y autoremove \
-  && apt-get -y autoclean
-
-ENV GOROOT /usr/local/go
-ENV GOPATH /go
-ENV PATH ${GOPATH}/bin:${GOROOT}/bin:${PATH}
-ENV GO_VERSION REPLACE_ME_GO_VERSION
-ENV GO_DOWNLOAD_URL https://storage.googleapis.com/golang
-RUN rm -rf ${GOROOT} \
-  && curl -s ${GO_DOWNLOAD_URL}/go${GO_VERSION}.linux-amd64.tar.gz | tar -v -C /usr/local/ -xz \
-  && mkdir -p ${GOPATH}/src ${GOPATH}/bin \
-  && go version
-
-RUN mkdir -p ${GOPATH}/src/github.com/coreos/etcd
-ADD . ${GOPATH}/src/github.com/coreos/etcd
-
-RUN go get -v github.com/coreos/gofail \
-  && pushd ${GOPATH}/src/github.com/coreos/etcd \
-  && GO_BUILD_FLAGS="-v" ./build \
-  && cp ./bin/etcd /etcd \
-  && cp ./bin/etcdctl /etcdctl \
-  && GO_BUILD_FLAGS="-v" FAILPOINTS=1 ./build \
-  && cp ./bin/etcd /etcd-failpoints \
-  && ./tools/functional-tester/build \
-  && cp ./bin/etcd-agent /etcd-agent \
-  && cp ./bin/etcd-tester /etcd-tester \
-  && cp ./bin/etcd-runner /etcd-runner \
-  && go build -v -o /benchmark ./cmd/tools/benchmark \
-  && go build -v -o /etcd-test-proxy ./cmd/tools/etcd-test-proxy \
-  && popd \
-  && rm -rf ${GOPATH}/src/github.com/coreos/etcd

+ 0 - 18
src/github.com/coreos/etcd/Dockerfile-release

@@ -1,18 +0,0 @@
-# TODO: move to k8s.gcr.io/build-image/debian-base:bullseye-v1.y.z when patched
-FROM debian:bullseye-20210927
-
-ADD etcd /usr/local/bin/
-ADD etcdctl /usr/local/bin/
-RUN mkdir -p /var/etcd/
-RUN mkdir -p /var/lib/etcd/
-
-# Alpine Linux doesn't use pam, which means that there is no /etc/nsswitch.conf,
-# but Golang relies on /etc/nsswitch.conf to check the order of DNS resolving
-# (see https://github.com/golang/go/commit/9dee7771f561cf6aee081c0af6658cc81fac3918)
-# To fix this we just create /etc/nsswitch.conf and add the following line:
-RUN echo 'hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4' >> /etc/nsswitch.conf
-
-EXPOSE 2379 2380
-
-# Define default command.
-CMD ["/usr/local/bin/etcd"]

+ 0 - 18
src/github.com/coreos/etcd/Dockerfile-release.arm64

@@ -1,18 +0,0 @@
-# TODO: move to k8s.gcr.io/build-image/debian-base-arm64:bullseye-1.y.z when patched
-FROM arm64v8/debian:bullseye-20210927
-
-ADD etcd /usr/local/bin/
-ADD etcdctl /usr/local/bin/
-ADD var/etcd /var/etcd
-ADD var/lib/etcd /var/lib/etcd
-
-# Alpine Linux doesn't use pam, which means that there is no /etc/nsswitch.conf,
-# but Golang relies on /etc/nsswitch.conf to check the order of DNS resolving
-# (see https://github.com/golang/go/commit/9dee7771f561cf6aee081c0af6658cc81fac3918)
-# To fix this we just create /etc/nsswitch.conf and add the following line:
-RUN echo 'hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4' >> /etc/nsswitch.conf
-
-EXPOSE 2379 2380
-
-# Define default command.
-CMD ["/usr/local/bin/etcd"]

+ 0 - 18
src/github.com/coreos/etcd/Dockerfile-release.ppc64le

@@ -1,18 +0,0 @@
-# TODO: move to k8s.gcr.io/build-image/debian-base-ppc64le:bullseye-1.y.z when patched
-FROM ppc64le/debian:bullseye-20210927
-
-ADD etcd /usr/local/bin/
-ADD etcdctl /usr/local/bin/
-ADD var/etcd /var/etcd
-ADD var/lib/etcd /var/lib/etcd
-
-# Alpine Linux doesn't use pam, which means that there is no /etc/nsswitch.conf,
-# but Golang relies on /etc/nsswitch.conf to check the order of DNS resolving
-# (see https://github.com/golang/go/commit/9dee7771f561cf6aee081c0af6658cc81fac3918)
-# To fix this we just create /etc/nsswitch.conf and add the following line:
-RUN echo 'hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4' >> /etc/nsswitch.conf
-
-EXPOSE 2379 2380
-
-# Define default command.
-CMD ["/usr/local/bin/etcd"]

+ 0 - 58
src/github.com/coreos/etcd/Dockerfile-test

@@ -1,58 +0,0 @@
-FROM ubuntu:16.10
-
-RUN rm /bin/sh && ln -s /bin/bash /bin/sh
-RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections
-
-RUN apt-get -y update \
-  && apt-get -y install \
-  build-essential \
-  gcc \
-  apt-utils \
-  pkg-config \
-  software-properties-common \
-  apt-transport-https \
-  libssl-dev \
-  sudo \
-  bash \
-  curl \
-  wget \
-  tar \
-  git \
-  netcat \
-  libaspell-dev \
-  libhunspell-dev \
-  hunspell-en-us \
-  aspell-en \
-  shellcheck \
-  && apt-get -y update \
-  && apt-get -y upgrade \
-  && apt-get -y autoremove \
-  && apt-get -y autoclean
-
-ENV GOROOT /usr/local/go
-ENV GOPATH /go
-ENV PATH ${GOPATH}/bin:${GOROOT}/bin:${PATH}
-ENV GO_VERSION REPLACE_ME_GO_VERSION
-ENV GO_DOWNLOAD_URL https://storage.googleapis.com/golang
-RUN rm -rf ${GOROOT} \
-  && curl -s ${GO_DOWNLOAD_URL}/go${GO_VERSION}.linux-amd64.tar.gz | tar -v -C /usr/local/ -xz \
-  && mkdir -p ${GOPATH}/src ${GOPATH}/bin \
-  && go version
-
-RUN mkdir -p ${GOPATH}/src/github.com/coreos/etcd
-WORKDIR ${GOPATH}/src/github.com/coreos/etcd
-
-ADD ./scripts/install-marker.sh /tmp/install-marker.sh
-
-RUN go get -v -u -tags spell github.com/chzchzchz/goword \
-  && go get -v -u github.com/coreos/license-bill-of-materials \
-  && go get -v -u honnef.co/go/tools/cmd/gosimple \
-  && go get -v -u honnef.co/go/tools/cmd/unused \
-  && go get -v -u honnef.co/go/tools/cmd/staticcheck \
-  && go get -v -u github.com/gyuho/gocovmerge \
-  && go get -v -u github.com/gordonklaus/ineffassign \
-  && go get -v -u github.com/alexkohler/nakedret \
-  && /tmp/install-marker.sh amd64 \
-  && rm -f /tmp/install-marker.sh \
-  && curl -s https://codecov.io/bash >/codecov \
-  && chmod 700 /codecov

+ 0 - 1
src/github.com/coreos/etcd/Documentation/README.md

@@ -1 +0,0 @@
-docs.md

+ 0 - 3
src/github.com/coreos/etcd/Documentation/_index.md

@@ -1,3 +0,0 @@
----
-title: etcd version 3.3.12
----

+ 0 - 3
src/github.com/coreos/etcd/Documentation/benchmarks/_index.md

@@ -1,3 +0,0 @@
----
-title: Benchmarks
----

+ 0 - 56
src/github.com/coreos/etcd/Documentation/benchmarks/etcd-2-1-0-alpha-benchmarks.md

@@ -1,56 +0,0 @@
----
-title: Benchmarking etcd v2.1.0
----
-
-## Physical machines
-
-GCE n1-highcpu-2 machine type
-
-- 1x dedicated local SSD mounted under /var/lib/etcd
-- 1x dedicated slow disk for the OS
-- 1.8 GB memory
-- 2x CPUs
-- etcd version 2.1.0 alpha
-
-## etcd Cluster
-
-3 etcd members, each runs on a single machine
-
-## Testing
-
-Bootstrap another machine and use the [hey HTTP benchmark tool][hey] to send requests to each etcd member. Check the [benchmark hacking guide][hack-benchmark] for detailed instructions.
-
-## Performance
-
-### reading one single key
-
-| key size in bytes | number of clients | target etcd server | read QPS | 90th Percentile Latency (ms) |
-|-------------------|-------------------|--------------------|----------|---------------|
-| 64                | 1                 | leader only        | 1534     | 0.7        |
-| 64                | 64                | leader only        | 10125    | 9.1      |
-| 64                | 256               | leader only        | 13892    | 27.1      |
-| 256               | 1                 | leader only        | 1530     | 0.8       |
-| 256               | 64                | leader only        | 10106    | 10.1      |
-| 256               | 256               | leader only        | 14667    | 27.0      |
-| 64                | 64                | all servers        | 24200    | 3.9      |
-| 64                | 256               | all servers        | 33300    | 11.8      |
-| 256               | 64                | all servers        | 24800    | 3.9      |
-| 256               | 256               | all servers        | 33000    | 11.5      |
-
-### writing one single key
-
-| key size in bytes | number of clients | target etcd server | write QPS | 90th Percentile Latency (ms) |
-|-------------------|-------------------|--------------------|-----------|---------------|
-| 64                | 1                 | leader only        | 60        | 21.4 |
-| 64                | 64                | leader only        | 1742      | 46.8 |
-| 64                | 256               | leader only        | 3982      | 90.5 |
-| 256               | 1                 | leader only        | 58        | 20.3 |
-| 256               | 64                | leader only        | 1770      | 47.8 |
-| 256               | 256               | leader only        | 4157      | 105.3 |
-| 64                | 64                | all servers        | 1028      | 123.4 |
-| 64                | 256               | all servers        | 3260      | 123.8 |
-| 256               | 64                | all servers        | 1033      | 121.5 |
-| 256               | 256               | all servers        | 3061      | 119.3 |
-
-[hey]: https://github.com/rakyll/hey
-[hack-benchmark]: https://github.com/coreos/etcd/tree/master/hack/benchmark

+ 0 - 71
src/github.com/coreos/etcd/Documentation/benchmarks/etcd-2-2-0-benchmarks.md

@@ -1,71 +0,0 @@
----
-title: Benchmarking etcd v2.2.0
----
-
-## Physical Machines
-
-GCE n1-highcpu-2 machine type
-
-- 1x dedicated local SSD mounted as etcd data directory
-- 1x dedicated slow disk for the OS
-- 1.8 GB memory
-- 2x CPUs
-
-## etcd Cluster
-
-3 etcd 2.2.0 members, each runs on a single machine.
-
-Detailed versions:
-
-```
-etcd Version: 2.2.0
-Git SHA: e4561dd
-Go Version: go1.5
-Go OS/Arch: linux/amd64
-```
-
-## Testing
-
-Bootstrap another machine, outside of the etcd cluster, and run the [`hey` HTTP benchmark tool](https://github.com/rakyll/hey) with a connection reuse patch to send requests to each etcd cluster member. See the [benchmark instructions](../../hack/benchmark/) for the patch and the steps to reproduce our procedures.
-
-The performance is calculated through results of 100 benchmark rounds.
-
-## Performance
-
-### Single Key Read Performance
-
-| key size in bytes | number of clients | target etcd server | average read QPS | read QPS stddev | average 90th Percentile Latency (ms) | latency stddev |
-|-------------------|-------------------|--------------------|------------------|-----------------|--------------------------------------|----------------|
-| 64 | 1 | leader only | 2303 | 200 | 0.49 | 0.06 |
-| 64 | 64 | leader only | 15048 | 685 | 7.60 | 0.46 |
-| 64 | 256 | leader only | 14508 | 434 | 29.76 | 1.05 |
-| 256 | 1 | leader only | 2162 | 214 | 0.52 | 0.06 |
-| 256 | 64 | leader only | 14789 | 792 | 7.69| 0.48 |
-| 256 | 256 | leader only | 14424 | 512 | 29.92 | 1.42 |
-| 64 | 64 | all servers | 45752 | 2048 | 2.47 | 0.14 |
-| 64 | 256 | all servers | 46592 | 1273 | 10.14 | 0.59 |
-| 256 | 64 | all servers | 45332 | 1847 | 2.48| 0.12 |
-| 256 | 256 | all servers | 46485 | 1340 | 10.18 | 0.74 |
-
-### Single Key Write Performance
-
-| key size in bytes | number of clients | target etcd server | average write QPS | write QPS stddev | average 90th Percentile Latency (ms) | latency stddev |
-|-------------------|-------------------|--------------------|------------------|-----------------|--------------------------------------|----------------|
-| 64 | 1 | leader only | 55 | 4 | 24.51 | 13.26 |
-| 64 | 64 | leader only | 2139 | 125 | 35.23 | 3.40 |
-| 64 | 256 | leader only | 4581 | 581 | 70.53 | 10.22 |
-| 256 | 1 | leader only | 56 | 4 | 22.37| 4.33 |
-| 256 | 64 | leader only | 2052 | 151 | 36.83 | 4.20 |
-| 256 | 256 | leader only | 4442 | 560 | 71.59 | 10.03 |
-| 64 | 64 | all servers | 1625 | 85 | 58.51 | 5.14 |
-| 64 | 256 | all servers | 4461 | 298 | 89.47 | 36.48 |
-| 256 | 64 | all servers | 1599 | 94 | 60.11| 6.43 |
-| 256 | 256 | all servers | 4315 | 193 | 88.98 | 7.01 |
-
-## Performance Changes
-
-- Because etcd now records metrics for each API call, read QPS performance seems to see a minor decrease in most scenarios. This minimal performance impact was judged a reasonable investment for the breadth of monitoring and debugging information returned.
-
-- Write QPS to cluster leaders seems to be increased by a small margin. This is because the main loop and entry apply loops were decoupled in the etcd raft logic, eliminating several blocks between them.
-
-- Write QPS to all members seems to be increased by a significant margin, because followers now receive the latest commit index sooner, and commit proposals more quickly.

+ 0 - 76
src/github.com/coreos/etcd/Documentation/benchmarks/etcd-2-2-0-rc-benchmarks.md

@@ -1,76 +0,0 @@
----
-title: Benchmarking etcd v2.2.0-rc
----
-
-## Physical machine
-
-GCE n1-highcpu-2 machine type
-
-- 1x dedicated local SSD mounted under /var/lib/etcd
-- 1x dedicated slow disk for the OS
-- 1.8 GB memory
-- 2x CPUs
-
-## etcd Cluster
-
-3 etcd 2.2.0-rc members, each runs on a single machine.
-
-Detailed versions:
-
-```
-etcd Version: 2.2.0-alpha.1+git
-Git SHA: 59a5a7e
-Go Version: go1.4.2
-Go OS/Arch: linux/amd64
-```
-
-Also, we use 3 etcd 2.1.0 alpha-stage members to form cluster to get base performance. etcd's commit head is at [c7146bd5][c7146bd5], which is the same as the one that we use in [etcd 2.1 benchmark][etcd-2.1-benchmark].
-
-## Testing
-
-Bootstrap another machine and use the [hey HTTP benchmark tool][hey] to send requests to each etcd member. Check the [benchmark hacking guide][hack-benchmark] for detailed instructions.
-
-## Performance
-
-### reading one single key
-
-| key size in bytes | number of clients | target etcd server | read QPS | 90th Percentile Latency (ms) |
-|-------------------|-------------------|--------------------|----------|---------------|
-| 64                | 1                 | leader only        | 2804 (-5%) | 0.4 (+0%) |
-| 64                | 64                | leader only        | 17816 (+0%) | 5.7 (-6%) |
-| 64                | 256               | leader only        | 18667 (-6%) | 20.4 (+2%) |
-| 256               | 1                 | leader only        | 2181 (-15%) | 0.5 (+25%) |
-| 256               | 64                | leader only        | 17435 (-7%) | 6.0 (+9%) |
-| 256               | 256               | leader only        | 18180 (-8%) | 21.3 (+3%) |
-| 64                | 64                | all servers        | 46965 (-4%) | 2.1 (+0%) |
-| 64                | 256               | all servers        | 55286 (-6%) | 7.4 (+6%) |
-| 256               | 64                | all servers        | 46603 (-6%) | 2.1 (+5%) |
-| 256               | 256               | all servers        | 55291 (-6%) | 7.3 (+4%) |
-
-### writing one single key
-
-| key size in bytes | number of clients | target etcd server | write QPS | 90th Percentile Latency (ms) |
-|-------------------|-------------------|--------------------|-----------|---------------|
-| 64                | 1                 | leader only        | 76 (+22%)  | 19.4 (-15%) |
-| 64                | 64                | leader only        | 2461 (+45%) | 31.8 (-32%) |
-| 64                | 256               | leader only        | 4275 (+1%) | 69.6 (-10%) |
-| 256               | 1                 | leader only        | 64 (+20%)  | 16.7 (-30%) |
-| 256               | 64                | leader only        | 2385 (+30%) | 31.5 (-19%) |
-| 256               | 256               | leader only        | 4353 (-3%) | 74.0 (+9%) |
-| 64                | 64                | all servers        | 2005 (+81%) | 49.8 (-55%) |
-| 64                | 256               | all servers        | 4868 (+35%) | 81.5 (-40%) |
-| 256               | 64                | all servers        | 1925 (+72%) | 47.7 (-59%) |
-| 256               | 256               | all servers        | 4975 (+36%) | 70.3 (-36%) |
-
-### performance changes explanation
-
-- read QPS in most scenarios is decreased by 5~8%. The reason is that etcd records store metrics for each store operation. The metrics is important for monitoring and debugging, so this is acceptable.
-
-- write QPS to leader is increased by 20~30%. This is because we decouple raft main loop and entry apply loop, which avoids them blocking each other.
-
-- write QPS to all servers is increased by 30~80% because follower could receive latest commit index earlier and commit proposals faster.
-
-[hey]: https://github.com/rakyll/hey
-[c7146bd5]: https://github.com/coreos/etcd/commits/c7146bd5f2c73716091262edc638401bb8229144
-[etcd-2.1-benchmark]: etcd-2-1-0-alpha-benchmarks.md
-[hack-benchmark]: ../../hack/benchmark/

+ 0 - 51
src/github.com/coreos/etcd/Documentation/benchmarks/etcd-2-2-0-rc-memory-benchmarks.md

@@ -1,51 +0,0 @@
----
-title: Benchmarking etcd v2.2.0-rc-memory
----
-
-## Physical machine
-
-GCE n1-standard-2 machine type
-
-- 1x dedicated local SSD mounted under /var/lib/etcd
-- 1x dedicated slow disk for the OS
-- 7.5 GB memory
-- 2x CPUs
-
-## etcd
-
-```
-etcd Version: 2.2.0-rc.0+git
-Git SHA: 103cb5c
-Go Version: go1.5
-Go OS/Arch: linux/amd64
-```
-
-## Testing
-
-Start 3-member etcd cluster, each of which uses 2 cores.
-
-The length of key name is always 64 bytes, which is a reasonable length of average key bytes.
-
-## Memory Maximal Usage
-
-- etcd may use maximal memory if one follower is dead and the leader keeps sending snapshots.
-- `max RSS` is the maximal memory usage recorded in 3 runs.
-
-| value bytes | key number  | data size(MB) | max RSS(MB) | max RSS/data rate on leader |
-|-------------|-------------|---------------|-------------|-----------------------------|
-| 128  | 50000  | 6 | 433 | 72x |
-| 128  | 100000 | 12 | 659 | 54x |
-| 128  | 200000 | 24 | 1466 | 61x |
-| 1024 | 50000  | 48 | 1253 | 26x |
-| 1024 | 100000 | 96 | 2344 | 24x |
-| 1024 | 200000 | 192 | 4361 | 22x |
-
-## Data Size Threshold
-
-- When etcd reaches data size threshold, it may trigger leader election easily and drop part of proposals.
-- For most cases, the etcd cluster should work smoothly if it doesn't hit the threshold. If it doesn't work well due to insufficient resources, decrease its data size.
-
-| value bytes | key number limitation | suggested data size threshold(MB) | consumed RSS(MB) |
-|-------------|-----------------------|-----------------------------------|------------------|
-| 128 | 400K | 48 | 2400 |
-| 1024 | 300K | 292 | 6500 |

+ 0 - 46
src/github.com/coreos/etcd/Documentation/benchmarks/etcd-3-demo-benchmarks.md

@@ -1,46 +0,0 @@
----
-title: Benchmarking etcd v3
----
-
-## Physical machines
-
-GCE n1-highcpu-2 machine type
-
-- 1x dedicated local SSD mounted under /var/lib/etcd
-- 1x dedicated slow disk for the OS
-- 1.8 GB memory
-- 2x CPUs
-- etcd version 2.2.0
-
-## etcd Cluster
-
-1 etcd member running in v3 demo mode
-
-## Testing
-
-Use [etcd v3 benchmark tool][etcd-v3-benchmark].
-
-## Performance
-
-### reading one single key
-
-| key size in bytes | number of clients | read QPS | 90th Percentile Latency (ms) |
-|-------------------|-------------------|----------|---------------|
-| 256               | 1                 | 2716  | 0.4      |
-| 256               | 64                | 16623 | 6.1      |
-| 256               | 256               | 16622 | 21.7     |
-
-The performance is nearly the same as the one with empty server handler.
-
-### reading one single key after putting
-
-| key size in bytes | number of clients | read QPS | 90th Percentile Latency (ms) |
-|-------------------|-------------------|----------|---------------|
-| 256               | 1                 | 2269  | 0.5      |
-| 256               | 64                | 13582 | 8.6      |
-| 256               | 256               | 13262 | 47.5     |
-
-The performance with empty server handler is not affected by one put. So the
-performance downgrade should be caused by storage package.
-
-[etcd-v3-benchmark]: ../../tools/benchmark/

+ 0 - 79
src/github.com/coreos/etcd/Documentation/benchmarks/etcd-3-watch-memory-benchmark.md

@@ -1,79 +0,0 @@
----
-title: Watch Memory Usage Benchmark
----
-
-*NOTE*: The watch features are under active development, and their memory usage may change as that development progresses. We do not expect it to significantly increase beyond the figures stated below.
-
-A primary goal of etcd is supporting a very large number of watchers doing a massively large amount of watching. etcd aims to support O(10k) clients, O(100K) watch streams (O(10) streams per client) and O(10M) total watchings (O(100) watching per stream). The memory consumed by each individual watching accounts for the largest portion of etcd's overall usage, and is therefore the focus of current and future optimizations.
-
-
-Three related components of etcd watch consume physical memory: each `grpc.Conn`, each watch stream, and each instance of the watching activity. `grpc.Conn` maintains the actual TCP connection and other gRPC connection state. Each `grpc.Conn` consumes O(10kb) of memory, and might have multiple watch streams attached. 
-
-Each watch stream is an independent HTTP2 connection which consumes another O(10kb) of memory. 
-Multiple watchings might share one watch stream. 
-
-Watching is the actual struct that tracks the changes on the key-value store. Each watching should only consume < O(1kb).
-
-```
-                                          +-------+
-                                          | watch |
-                              +---------> | foo   |
-                              |           +-------+
-                       +------+-----+
-                       |   stream   |
-      +--------------> |            |
-      |                +------+-----+     +-------+
-      |                       |           | watch |
-      |                       +---------> | bar   |
-+-----+------+                            +-------+
-|            |         +------------+
-|   conn     +-------> |   stream   |
-|            |         |            |
-+-----+------+         +------------+
-      |
-      |
-      |
-      |                +------------+
-      +--------------> |   stream   |
-                       |            |
-                       +------------+
-```
-
-The theoretical memory consumption of watch can be approximated with the formula:
-`memory = c1 * number_of_conn + c2 * avg_number_of_stream_per_conn + c3 * avg_number_of_watch_stream`
-
-## Testing Environment
-
-etcd version
-- git head https://github.com/coreos/etcd/commit/185097ffaa627b909007e772c175e8fefac17af3
-
-GCE n1-standard-2 machine type
-- 7.5 GB memory
-- 2x CPUs
-
-## Overall memory usage
-
-The overall memory usage captures how much [RSS][rss] etcd consumes with the client watchers. While the result may vary by as much as 10%, it is still meaningful, since the goal is to learn about the rough memory usage and the pattern of allocations.
-
-With the benchmark result, we can calculate roughly that `c1 = 17kb`, `c2 = 18kb` and `c3 = 350bytes`. So each additional client connection consumes 17kb of memory and each additional stream consumes 18kb of memory, and each additional watching only cause 350bytes. A single etcd server can maintain millions of watchings with a few GB of memory in normal case.
-
-
-| clients | streams per client | watchings per stream | total watching | memory usage |
-|---------|---------|-----------|----------------|--------------|
-| 1k |  1 |   1 |   1k |   50MB |
-| 2k |  1 |   1 |   2k |   90MB |
-| 5k |  1 |   1 |   5k |  200MB |
-| 1k | 10 |   1 |  10k |  217MB |
-| 2k | 10 |   1 |  20k |  417MB |
-| 5k | 10 |   1 |  50k |  980MB |
-| 1k | 50 |   1 |  50k | 1001MB |
-| 2k | 50 |   1 | 100k | 1960MB |
-| 5k | 50 |   1 | 250k | 4700MB |
-| 1k | 50 |  10 | 500k | 1171MB |
-| 2k | 50 |  10 |   1M | 2371MB |
-| 5k | 50 |  10 | 2.5M | 5710MB |
-| 1k | 50 | 100 |   5M | 2380MB |
-| 2k | 50 | 100 |  10M | 4672MB |
-| 5k | 50 | 100 |  25M |  *OOM* |
-
-[rss]: https://en.wikipedia.org/wiki/Resident_set_size

+ 0 - 100
src/github.com/coreos/etcd/Documentation/benchmarks/etcd-storage-memory-benchmark.md

@@ -1,100 +0,0 @@
----
-title: Storage Memory Usage Benchmark
----
-
-<!---todo: link storage to storage design doc-->
-Two components of etcd storage consume physical memory. The etcd process allocates an *in-memory index* to speed key lookup. The process's *page cache*, managed by the operating system, stores recently-accessed data from disk for quick re-use.
-
-The in-memory index holds all the keys in a [B-tree][btree] data structure, along with pointers to the on-disk data (the values). Each key in the B-tree may contain multiple pointers, pointing to different versions of its values. The theoretical memory consumption of the in-memory index can hence be approximated with the formula:
-
-`N * (c1 + avg_key_size) + N * (avg_versions_of_key) * (c2 + size_of_pointer)`
-
-where `c1` is the key metadata overhead and `c2` is the version metadata overhead.
-
-The graph shows the detailed structure of the in-memory index B-tree.
-
-```
-
-
-                                In mem index
-
-                               +------------+
-                               | key || ... |
-  +--------------+             |     ||     |
-  |              |             +------------+
-  |              |             | v1  || ... |
-  |   disk    <----------------|     ||     | Tree Node
-  |              |             +------------+
-  |              |             | v2  || ... |
-  |           <----------------+     ||     |
-  |              |             +------------+
-  +--------------+       +-----+    |   |   |
-                         |     |    |   |   |
-                         |     +------------+
-                         |
-                         |
-                         ^
-                      ------+
-                      | ... |
-                      |     |
-                      +-----+
-                      | ... | Tree Node
-                      |     |
-                      +-----+
-                      | ... |
-                      |     |
-                      ------+
-```
-
-[Page cache memory][pagecache] is managed by the operating system and is not covered in detail in this document.
-
-## Testing Environment
-
-etcd version
-- git head https://github.com/coreos/etcd/commit/776e9fb7be7eee5e6b58ab977c8887b4fe4d48db
-
-GCE n1-standard-2 machine type
-
-- 7.5 GB memory
-- 2x CPUs
-
-## In-memory index memory usage
-
-In this test, we only benchmark the memory usage of the in-memory index. The goal is to find `c1` and `c2` mentioned above and to understand the hard limit of memory consumption of the storage.
-
-We calculate the memory usage consumption via the Go runtime.ReadMemStats. We calculate the total allocated bytes difference before creating the index and after creating the index. It cannot perfectly reflect the memory usage of the in-memory index itself but can show the rough consumption pattern. 
-
-| N    | versions | key size | memory usage |
-|------|----------|----------|--------------|
-| 100K | 1        | 64bytes  | 22MB         |
-| 100K | 5        | 64bytes  | 39MB         |
-| 1M   | 1        | 64bytes  | 218MB        |
-| 1M   | 5        | 64bytes  | 432MB        |
-| 100K | 1        | 256bytes | 41MB         |
-| 100K | 5        | 256bytes | 65MB         |
-| 1M   | 1        | 256bytes | 409MB        |
-| 1M   | 5        | 256bytes | 506MB        |
-
-
-Based on the result, we can calculate `c1=120bytes`, `c2=30bytes`. We only need two sets of data to calculate `c1` and `c2`, since they are the only unknown variable in the formula. The `c1=120bytes` and `c2=30bytes` are the average value of the 4 sets of `c1` and `c2` we calculated. The key metadata overhead is still relatively nontrivial (50%) for small key-value pairs. However, this is a significant improvement over the old store, which had at least 1000% overhead.
-
-## Overall memory usage
-
-The overall memory usage captures how much RSS etcd consumes with the storage. The value size should have very little impact on the overall memory usage of etcd, since we keep values on disk and only retain hot values in memory, managed by the OS page cache.
-
-| N    | versions | key size | value size | memory usage |
-|------|----------|----------|------------|--------------|
-| 100K | 1        | 64bytes  | 256bytes   | 40MB         |
-| 100K | 5        | 64bytes  | 256bytes   | 89MB         |
-| 1M   | 1        | 64bytes  | 256bytes   | 470MB        |
-| 1M   | 5        | 64bytes  | 256bytes   | 880MB        |
-| 100K | 1        | 64bytes  | 1KB        | 102MB        |
-| 100K | 5        | 64bytes  | 1KB        | 164MB        |
-| 1M   | 1        | 64bytes  | 1KB        | 587MB        |
-| 1M   | 5        | 64bytes  | 1KB        | 836MB        |
-
-Based on the result, we know the value size does not significantly impact the memory consumption. There is some minor increase due to more data held in the OS page cache.
-
-[btree]: https://en.wikipedia.org/wiki/B-tree
-[pagecache]: https://en.wikipedia.org/wiki/Page_cache
-

+ 0 - 28
src/github.com/coreos/etcd/Documentation/branch_management.md

@@ -1,28 +0,0 @@
----
-title: Branch management
----
-
-## Guide
-
-* New development occurs on the [master branch][master].
-* Master branch should always have a green build!
-* Backwards-compatible bug fixes should target the master branch and subsequently be ported to stable branches.
-* Once the master branch is ready for release, it will be tagged and become the new stable branch.
-
-The etcd team has adopted a *rolling release model* and supports two stable versions of etcd.
-
-### Master branch
-
-The `master` branch is our development branch. All new features land here first.
-
-To try new and experimental features, pull `master` and play with it. Note that `master` may not be stable because new features may introduce bugs.
-
-Before the release of the next stable version, feature PRs will be frozen. A [release manager](./dev-internal/release.md#release-management) will be assigned to major/minor version and will lead the etcd community in test, bug-fix and documentation of the release for one to two weeks.
-
-### Stable branches
-
-All branches with prefix `release-` are considered _stable_ branches.
-
-After every minor release (http://semver.org/), we will have a new stable branch for that release, managed by a [patch release manager](./dev-internal/release.md#release-management). We will keep fixing the backwards-compatible bugs for the latest two stable releases. A _patch_ release to each supported release branch, incorporating any bug fixes, will be once every two weeks, given any patches.
-
-[master]: https://github.com/coreos/etcd/tree/master

+ 0 - 456
src/github.com/coreos/etcd/Documentation/demo.md

@@ -1,456 +0,0 @@
----
-title: Demo
----
-
-This series of examples shows the basic procedures for working with an etcd cluster.
-
-## Set up a cluster
-
-<img src="https://storage.googleapis.com/etcd/demo/01_etcd_clustering_2016051001.gif" alt="01_etcd_clustering_2016050601"/>
-
-On each etcd node, specify the cluster members:
-
-```
-TOKEN=token-01
-CLUSTER_STATE=new
-NAME_1=machine-1
-NAME_2=machine-2
-NAME_3=machine-3
-HOST_1=10.240.0.17
-HOST_2=10.240.0.18
-HOST_3=10.240.0.19
-CLUSTER=${NAME_1}=http://${HOST_1}:2380,${NAME_2}=http://${HOST_2}:2380,${NAME_3}=http://${HOST_3}:2380
-```
-
-Run this on each machine:
-
-```
-# For machine 1
-THIS_NAME=${NAME_1}
-THIS_IP=${HOST_1}
-etcd --data-dir=data.etcd --name ${THIS_NAME} \
-	--initial-advertise-peer-urls http://${THIS_IP}:2380 --listen-peer-urls http://${THIS_IP}:2380 \
-	--advertise-client-urls http://${THIS_IP}:2379 --listen-client-urls http://${THIS_IP}:2379 \
-	--initial-cluster ${CLUSTER} \
-	--initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}
-
-# For machine 2
-THIS_NAME=${NAME_2}
-THIS_IP=${HOST_2}
-etcd --data-dir=data.etcd --name ${THIS_NAME} \
-	--initial-advertise-peer-urls http://${THIS_IP}:2380 --listen-peer-urls http://${THIS_IP}:2380 \
-	--advertise-client-urls http://${THIS_IP}:2379 --listen-client-urls http://${THIS_IP}:2379 \
-	--initial-cluster ${CLUSTER} \
-	--initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}
-
-# For machine 3
-THIS_NAME=${NAME_3}
-THIS_IP=${HOST_3}
-etcd --data-dir=data.etcd --name ${THIS_NAME} \
-	--initial-advertise-peer-urls http://${THIS_IP}:2380 --listen-peer-urls http://${THIS_IP}:2380 \
-	--advertise-client-urls http://${THIS_IP}:2379 --listen-client-urls http://${THIS_IP}:2379 \
-	--initial-cluster ${CLUSTER} \
-	--initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}
-```
-
-Or use our public discovery service:
-
-```
-curl https://discovery.etcd.io/new?size=3
-https://discovery.etcd.io/a81b5818e67a6ea83e9d4daea5ecbc92
-
-# grab this token
-TOKEN=token-01
-CLUSTER_STATE=new
-NAME_1=machine-1
-NAME_2=machine-2
-NAME_3=machine-3
-HOST_1=10.240.0.17
-HOST_2=10.240.0.18
-HOST_3=10.240.0.19
-DISCOVERY=https://discovery.etcd.io/a81b5818e67a6ea83e9d4daea5ecbc92
-
-THIS_NAME=${NAME_1}
-THIS_IP=${HOST_1}
-etcd --data-dir=data.etcd --name ${THIS_NAME} \
-	--initial-advertise-peer-urls http://${THIS_IP}:2380 --listen-peer-urls http://${THIS_IP}:2380 \
-	--advertise-client-urls http://${THIS_IP}:2379 --listen-client-urls http://${THIS_IP}:2379 \
-	--discovery ${DISCOVERY} \
-	--initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}
-
-THIS_NAME=${NAME_2}
-THIS_IP=${HOST_2}
-etcd --data-dir=data.etcd --name ${THIS_NAME} \
-	--initial-advertise-peer-urls http://${THIS_IP}:2380 --listen-peer-urls http://${THIS_IP}:2380 \
-	--advertise-client-urls http://${THIS_IP}:2379 --listen-client-urls http://${THIS_IP}:2379 \
-	--discovery ${DISCOVERY} \
-	--initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}
-
-THIS_NAME=${NAME_3}
-THIS_IP=${HOST_3}
-etcd --data-dir=data.etcd --name ${THIS_NAME} \
-	--initial-advertise-peer-urls http://${THIS_IP}:2380 --listen-peer-urls http://${THIS_IP}:2380 \
-	--advertise-client-urls http://${THIS_IP}:2379 --listen-client-urls http://${THIS_IP}:2379 \
-	--discovery ${DISCOVERY} \
-	--initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}
-```
-
-Now etcd is ready! To connect to etcd with etcdctl:
-
-```
-export ETCDCTL_API=3
-HOST_1=10.240.0.17
-HOST_2=10.240.0.18
-HOST_3=10.240.0.19
-ENDPOINTS=$HOST_1:2379,$HOST_2:2379,$HOST_3:2379
-
-etcdctl --endpoints=$ENDPOINTS member list
-```
-
-
-## Access etcd
-
-<img src="https://storage.googleapis.com/etcd/demo/02_etcdctl_access_etcd_2016051001.gif" alt="02_etcdctl_access_etcd_2016051001"/>
-
-`put` command to write:
-
-```
-etcdctl --endpoints=$ENDPOINTS put foo "Hello World!"
-```
-
-`get` to read from etcd:
-
-```
-etcdctl --endpoints=$ENDPOINTS get foo
-etcdctl --endpoints=$ENDPOINTS --write-out="json" get foo
-```
-
-
-## Get by prefix
-
-<img src="https://storage.googleapis.com/etcd/demo/03_etcdctl_get_by_prefix_2016050501.gif" alt="03_etcdctl_get_by_prefix_2016050501"/>
-
-```
-etcdctl --endpoints=$ENDPOINTS put web1 value1
-etcdctl --endpoints=$ENDPOINTS put web2 value2
-etcdctl --endpoints=$ENDPOINTS put web3 value3
-
-etcdctl --endpoints=$ENDPOINTS get web --prefix
-```
-
-
-## Delete
-
-<img src="https://storage.googleapis.com/etcd/demo/04_etcdctl_delete_2016050601.gif" alt="04_etcdctl_delete_2016050601"/>
-
-```
-etcdctl --endpoints=$ENDPOINTS put key myvalue
-etcdctl --endpoints=$ENDPOINTS del key
-
-etcdctl --endpoints=$ENDPOINTS put k1 value1
-etcdctl --endpoints=$ENDPOINTS put k2 value2
-etcdctl --endpoints=$ENDPOINTS del k --prefix
-```
-
-
-## Transactional write
-
-`txn` to wrap multiple requests into one transaction:
-
-<img src="https://storage.googleapis.com/etcd/demo/05_etcdctl_transaction_2016050501.gif" alt="05_etcdctl_transaction_2016050501"/>
-
-```
-etcdctl --endpoints=$ENDPOINTS put user1 bad
-etcdctl --endpoints=$ENDPOINTS txn --interactive
-
-compares:
-value("user1") = "bad"      
-
-success requests (get, put, delete):
-del user1  
-
-failure requests (get, put, delete):
-put user1 good
-```
-
-
-## Watch
-
-`watch` to get notified of future changes:
-
-<img src="https://storage.googleapis.com/etcd/demo/06_etcdctl_watch_2016050501.gif" alt="06_etcdctl_watch_2016050501"/>
-
-```
-etcdctl --endpoints=$ENDPOINTS watch stock1
-etcdctl --endpoints=$ENDPOINTS put stock1 1000
-
-etcdctl --endpoints=$ENDPOINTS watch stock --prefix
-etcdctl --endpoints=$ENDPOINTS put stock1 10
-etcdctl --endpoints=$ENDPOINTS put stock2 20
-```
-
-
-## Lease
-
-`lease` to write with TTL:
-
-<img src="https://storage.googleapis.com/etcd/demo/07_etcdctl_lease_2016050501.gif" alt="07_etcdctl_lease_2016050501"/>
-
-```
-etcdctl --endpoints=$ENDPOINTS lease grant 300
-# lease 2be7547fbc6a5afa granted with TTL(300s)
-
-etcdctl --endpoints=$ENDPOINTS put sample value --lease=2be7547fbc6a5afa
-etcdctl --endpoints=$ENDPOINTS get sample
-
-etcdctl --endpoints=$ENDPOINTS lease keep-alive 2be7547fbc6a5afa
-etcdctl --endpoints=$ENDPOINTS lease revoke 2be7547fbc6a5afa
-# or after 300 seconds
-etcdctl --endpoints=$ENDPOINTS get sample
-```
-
-
-## Distributed locks
-
-`lock` for distributed lock:
-
-<img src="https://storage.googleapis.com/etcd/demo/08_etcdctl_lock_2016050501.gif" alt="08_etcdctl_lock_2016050501"/>
-
-```
-etcdctl --endpoints=$ENDPOINTS lock mutex1
-
-# another client with the same name blocks
-etcdctl --endpoints=$ENDPOINTS lock mutex1
-```
-
-
-## Elections
-
-`elect` for leader election:
-
-<img src="https://storage.googleapis.com/etcd/demo/09_etcdctl_elect_2016050501.gif" alt="09_etcdctl_elect_2016050501"/>
-
-```
-etcdctl --endpoints=$ENDPOINTS elect one p1
-
-# another client with the same name blocks
-etcdctl --endpoints=$ENDPOINTS elect one p2
-```
-
-
-## Cluster status
-
-Specify the initial cluster configuration for each machine:
-
-<img src="https://storage.googleapis.com/etcd/demo/10_etcdctl_endpoint_2016050501.gif" alt="10_etcdctl_endpoint_2016050501"/>
-
-```
-etcdctl --write-out=table --endpoints=$ENDPOINTS endpoint status
-
-+------------------+------------------+---------+---------+-----------+-----------+------------+
-|     ENDPOINT     |        ID        | VERSION | DB SIZE | IS LEADER | RAFT TERM | RAFT INDEX |
-+------------------+------------------+---------+---------+-----------+-----------+------------+
-| 10.240.0.17:2379 | 4917a7ab173fabe7 | 3.0.0   | 45 kB   | true      |         4 |      16726 |
-| 10.240.0.18:2379 | 59796ba9cd1bcd72 | 3.0.0   | 45 kB   | false     |         4 |      16726 |
-| 10.240.0.19:2379 | 94df724b66343e6c | 3.0.0   | 45 kB   | false     |         4 |      16726 |
-+------------------+------------------+---------+---------+-----------+-----------+------------+
-```
-
-```
-etcdctl --endpoints=$ENDPOINTS endpoint health
-
-10.240.0.17:2379 is healthy: successfully committed proposal: took = 3.345431ms
-10.240.0.19:2379 is healthy: successfully committed proposal: took = 3.767967ms
-10.240.0.18:2379 is healthy: successfully committed proposal: took = 4.025451ms
-```
-
-
-## Snapshot
-
-`snapshot` to save point-in-time snapshot of etcd database:
-
-<img src="https://storage.googleapis.com/etcd/demo/11_etcdctl_snapshot_2016051001.gif" alt="11_etcdctl_snapshot_2016051001"/>
-
-```
-etcdctl --endpoints=$ENDPOINTS snapshot save my.db
-
-Snapshot saved at my.db
-```
-
-```
-etcdctl --write-out=table --endpoints=$ENDPOINTS snapshot status my.db
-
-+---------+----------+------------+------------+
-|  HASH   | REVISION | TOTAL KEYS | TOTAL SIZE |
-+---------+----------+------------+------------+
-| c55e8b8 |        9 |         13 | 25 kB      |
-+---------+----------+------------+------------+
-```
-
-
-## Migrate
-
-`migrate` to transform etcd v2 to v3 data:
-
-<img src="https://storage.googleapis.com/etcd/demo/12_etcdctl_migrate_2016061602.gif" alt="12_etcdctl_migrate_2016061602"/>
-
-```
-# write key in etcd version 2 store
-export ETCDCTL_API=2
-etcdctl --endpoints=http://$ENDPOINT set foo bar
-
-# read key in etcd v2
-etcdctl --endpoints=$ENDPOINTS --output="json" get foo
-
-# stop etcd node to migrate, one by one
-
-# migrate v2 data
-export ETCDCTL_API=3
-etcdctl --endpoints=$ENDPOINT migrate --data-dir="default.etcd" --wal-dir="default.etcd/member/wal"
-
-# restart etcd node after migrate, one by one
-
-# confirm that the key got migrated
-etcdctl --endpoints=$ENDPOINTS get /foo
-```
-
-
-## Member
-
-`member` to add,remove,update membership:
-
-<img src="https://storage.googleapis.com/etcd/demo/13_etcdctl_member_2016062301.gif" alt="13_etcdctl_member_2016062301"/>
-
-```
-# For each machine
-TOKEN=my-etcd-token-1
-CLUSTER_STATE=new
-NAME_1=etcd-node-1
-NAME_2=etcd-node-2
-NAME_3=etcd-node-3
-HOST_1=10.240.0.13
-HOST_2=10.240.0.14
-HOST_3=10.240.0.15
-CLUSTER=${NAME_1}=http://${HOST_1}:2380,${NAME_2}=http://${HOST_2}:2380,${NAME_3}=http://${HOST_3}:2380
-
-# For node 1
-THIS_NAME=${NAME_1}
-THIS_IP=${HOST_1}
-etcd --data-dir=data.etcd --name ${THIS_NAME} \
-	--initial-advertise-peer-urls http://${THIS_IP}:2380 \
-	--listen-peer-urls http://${THIS_IP}:2380 \
-	--advertise-client-urls http://${THIS_IP}:2379 \
-	--listen-client-urls http://${THIS_IP}:2379 \
-	--initial-cluster ${CLUSTER} \
-	--initial-cluster-state ${CLUSTER_STATE} \
-	--initial-cluster-token ${TOKEN}
-
-# For node 2
-THIS_NAME=${NAME_2}
-THIS_IP=${HOST_2}
-etcd --data-dir=data.etcd --name ${THIS_NAME} \
-	--initial-advertise-peer-urls http://${THIS_IP}:2380 \
-	--listen-peer-urls http://${THIS_IP}:2380 \
-	--advertise-client-urls http://${THIS_IP}:2379 \
-	--listen-client-urls http://${THIS_IP}:2379 \
-	--initial-cluster ${CLUSTER} \
-	--initial-cluster-state ${CLUSTER_STATE} \
-	--initial-cluster-token ${TOKEN}
-
-# For node 3
-THIS_NAME=${NAME_3}
-THIS_IP=${HOST_3}
-etcd --data-dir=data.etcd --name ${THIS_NAME} \
-	--initial-advertise-peer-urls http://${THIS_IP}:2380 \
-	--listen-peer-urls http://${THIS_IP}:2380 \
-	--advertise-client-urls http://${THIS_IP}:2379 \
-	--listen-client-urls http://${THIS_IP}:2379 \
-	--initial-cluster ${CLUSTER} \
-	--initial-cluster-state ${CLUSTER_STATE} \
-	--initial-cluster-token ${TOKEN}
-```
-
-Then replace a member with `member remove` and `member add` commands:
-
-```
-# get member ID
-export ETCDCTL_API=3
-HOST_1=10.240.0.13
-HOST_2=10.240.0.14
-HOST_3=10.240.0.15
-etcdctl --endpoints=${HOST_1}:2379,${HOST_2}:2379,${HOST_3}:2379 member list
-
-# remove the member
-MEMBER_ID=278c654c9a6dfd3b
-etcdctl --endpoints=${HOST_1}:2379,${HOST_2}:2379,${HOST_3}:2379 \
-	member remove ${MEMBER_ID}
-
-# add a new member (node 4)
-export ETCDCTL_API=3
-NAME_1=etcd-node-1
-NAME_2=etcd-node-2
-NAME_4=etcd-node-4
-HOST_1=10.240.0.13
-HOST_2=10.240.0.14
-HOST_4=10.240.0.16 # new member
-etcdctl --endpoints=${HOST_1}:2379,${HOST_2}:2379 \
-	member add ${NAME_4} \
-	--peer-urls=http://${HOST_4}:2380
-```
-
-Next, start the new member with `--initial-cluster-state existing` flag:
-
-```
-# [WARNING] If the new member starts from the same disk space,
-# make sure to remove the data directory of the old member
-#
-# restart with 'existing' flag
-TOKEN=my-etcd-token-1
-CLUSTER_STATE=existing
-NAME_1=etcd-node-1
-NAME_2=etcd-node-2
-NAME_4=etcd-node-4
-HOST_1=10.240.0.13
-HOST_2=10.240.0.14
-HOST_4=10.240.0.16 # new member
-CLUSTER=${NAME_1}=http://${HOST_1}:2380,${NAME_2}=http://${HOST_2}:2380,${NAME_4}=http://${HOST_4}:2380
-
-THIS_NAME=${NAME_4}
-THIS_IP=${HOST_4}
-etcd --data-dir=data.etcd --name ${THIS_NAME} \
-	--initial-advertise-peer-urls http://${THIS_IP}:2380 \
-	--listen-peer-urls http://${THIS_IP}:2380 \
-	--advertise-client-urls http://${THIS_IP}:2379 \
-	--listen-client-urls http://${THIS_IP}:2379 \
-	--initial-cluster ${CLUSTER} \
-	--initial-cluster-state ${CLUSTER_STATE} \
-	--initial-cluster-token ${TOKEN}
-```
-
-
-## Auth
-
-`auth`,`user`,`role` for authentication:
-
-<img src="https://storage.googleapis.com/etcd/demo/14_etcdctl_auth_2016062301.gif" alt="14_etcdctl_auth_2016062301"/>
-
-```
-export ETCDCTL_API=3
-ENDPOINTS=localhost:2379
-
-etcdctl --endpoints=${ENDPOINTS} role add root
-etcdctl --endpoints=${ENDPOINTS} role grant-permission root readwrite foo
-etcdctl --endpoints=${ENDPOINTS} role get root
-
-etcdctl --endpoints=${ENDPOINTS} user add root
-etcdctl --endpoints=${ENDPOINTS} user grant-role root root
-etcdctl --endpoints=${ENDPOINTS} user get root
-
-etcdctl --endpoints=${ENDPOINTS} auth enable
-# now all client requests go through auth
-
-etcdctl --endpoints=${ENDPOINTS} --user=root:123 put foo bar
-etcdctl --endpoints=${ENDPOINTS} get foo
-etcdctl --endpoints=${ENDPOINTS} --user=root:123 get foo
-etcdctl --endpoints=${ENDPOINTS} --user=root:123 get foo1
-```

+ 0 - 3
src/github.com/coreos/etcd/Documentation/dev-guide/_index.md

@@ -1,3 +0,0 @@
----
-title: Developer guide
----

+ 0 - 170
src/github.com/coreos/etcd/Documentation/dev-guide/api_concurrency_reference_v3.md

@@ -1,170 +0,0 @@
----
-title: etcd concurrency API Reference
----
-
-
-This is a generated documentation. Please read the proto files for more.
-
-
-##### service `Lock` (etcdserver/api/v3lock/v3lockpb/v3lock.proto)
-
-The lock service exposes client-side locking facilities as a gRPC interface.
-
-| Method | Request Type | Response Type | Description |
-| ------ | ------------ | ------------- | ----------- |
-| Lock | LockRequest | LockResponse | Lock acquires a distributed shared lock on a given named lock. On success, it will return a unique key that exists so long as the lock is held by the caller. This key can be used in conjunction with transactions to safely ensure updates to etcd only occur while holding lock ownership. The lock is held until Unlock is called on the key or the lease associate with the owner expires. |
-| Unlock | UnlockRequest | UnlockResponse | Unlock takes a key returned by Lock and releases the hold on lock. The next Lock caller waiting for the lock will then be woken up and given ownership of the lock. |
-
-
-
-##### message `LockRequest` (etcdserver/api/v3lock/v3lockpb/v3lock.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| name | name is the identifier for the distributed shared lock to be acquired. | bytes |
-| lease | lease is the ID of the lease that will be attached to ownership of the lock. If the lease expires or is revoked and currently holds the lock, the lock is automatically released. Calls to Lock with the same lease will be treated as a single acquisition; locking twice with the same lease is a no-op. | int64 |
-
-
-
-##### message `LockResponse` (etcdserver/api/v3lock/v3lockpb/v3lock.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | etcdserverpb.ResponseHeader |
-| key | key is a key that will exist on etcd for the duration that the Lock caller owns the lock. Users should not modify this key or the lock may exhibit undefined behavior. | bytes |
-
-
-
-##### message `UnlockRequest` (etcdserver/api/v3lock/v3lockpb/v3lock.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| key | key is the lock ownership key granted by Lock. | bytes |
-
-
-
-##### message `UnlockResponse` (etcdserver/api/v3lock/v3lockpb/v3lock.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | etcdserverpb.ResponseHeader |
-
-
-
-##### service `Election` (etcdserver/api/v3election/v3electionpb/v3election.proto)
-
-The election service exposes client-side election facilities as a gRPC interface.
-
-| Method | Request Type | Response Type | Description |
-| ------ | ------------ | ------------- | ----------- |
-| Campaign | CampaignRequest | CampaignResponse | Campaign waits to acquire leadership in an election, returning a LeaderKey representing the leadership if successful. The LeaderKey can then be used to issue new values on the election, transactionally guard API requests on leadership still being held, and resign from the election. |
-| Proclaim | ProclaimRequest | ProclaimResponse | Proclaim updates the leader's posted value with a new value. |
-| Leader | LeaderRequest | LeaderResponse | Leader returns the current election proclamation, if any. |
-| Observe | LeaderRequest | LeaderResponse | Observe streams election proclamations in-order as made by the election's elected leaders. |
-| Resign | ResignRequest | ResignResponse | Resign releases election leadership so other campaigners may acquire leadership on the election. |
-
-
-
-##### message `CampaignRequest` (etcdserver/api/v3election/v3electionpb/v3election.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| name | name is the election's identifier for the campaign. | bytes |
-| lease | lease is the ID of the lease attached to leadership of the election. If the lease expires or is revoked before resigning leadership, then the leadership is transferred to the next campaigner, if any. | int64 |
-| value | value is the initial proclaimed value set when the campaigner wins the election. | bytes |
-
-
-
-##### message `CampaignResponse` (etcdserver/api/v3election/v3electionpb/v3election.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | etcdserverpb.ResponseHeader |
-| leader | leader describes the resources used for holding leadereship of the election. | LeaderKey |
-
-
-
-##### message `LeaderKey` (etcdserver/api/v3election/v3electionpb/v3election.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| name | name is the election identifier that correponds to the leadership key. | bytes |
-| key | key is an opaque key representing the ownership of the election. If the key is deleted, then leadership is lost. | bytes |
-| rev | rev is the creation revision of the key. It can be used to test for ownership of an election during transactions by testing the key's creation revision matches rev. | int64 |
-| lease | lease is the lease ID of the election leader. | int64 |
-
-
-
-##### message `LeaderRequest` (etcdserver/api/v3election/v3electionpb/v3election.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| name | name is the election identifier for the leadership information. | bytes |
-
-
-
-##### message `LeaderResponse` (etcdserver/api/v3election/v3electionpb/v3election.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | etcdserverpb.ResponseHeader |
-| kv | kv is the key-value pair representing the latest leader update. | mvccpb.KeyValue |
-
-
-
-##### message `ProclaimRequest` (etcdserver/api/v3election/v3electionpb/v3election.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| leader | leader is the leadership hold on the election. | LeaderKey |
-| value | value is an update meant to overwrite the leader's current value. | bytes |
-
-
-
-##### message `ProclaimResponse` (etcdserver/api/v3election/v3electionpb/v3election.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | etcdserverpb.ResponseHeader |
-
-
-
-##### message `ResignRequest` (etcdserver/api/v3election/v3electionpb/v3election.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| leader | leader is the leadership to relinquish by resignation. | LeaderKey |
-
-
-
-##### message `ResignResponse` (etcdserver/api/v3election/v3electionpb/v3election.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | etcdserverpb.ResponseHeader |
-
-
-
-##### message `Event` (mvcc/mvccpb/kv.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| type | type is the kind of event. If type is a PUT, it indicates new data has been stored to the key. If type is a DELETE, it indicates the key was deleted. | EventType |
-| kv | kv holds the KeyValue for the event. A PUT event contains current kv pair. A PUT event with kv.Version=1 indicates the creation of a key. A DELETE/EXPIRE event contains the deleted key with its modification revision set to the revision of deletion. | KeyValue |
-| prev_kv | prev_kv holds the key-value pair before the event happens. | KeyValue |
-
-
-
-##### message `KeyValue` (mvcc/mvccpb/kv.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| key | key is the key in bytes. An empty key is not allowed. | bytes |
-| create_revision | create_revision is the revision of last creation on this key. | int64 |
-| mod_revision | mod_revision is the revision of last modification on this key. | int64 |
-| version | version is the version of the key. A deletion resets the version to zero and any modification of the key increases its version. | int64 |
-| value | value is the value held by the key, in bytes. | bytes |
-| lease | lease is the ID of the lease that attached to key. When the attached lease expires, the key will be deleted. If lease is 0, then no lease is attached to the key. | int64 |
-
-
-

+ 0 - 137
src/github.com/coreos/etcd/Documentation/dev-guide/api_grpc_gateway.md

@@ -1,137 +0,0 @@
----
-title: Why gRPC gateway
----
-
-etcd v3 uses [gRPC][grpc] for its messaging protocol. The etcd project includes a gRPC-based [Go client][go-client] and a command line utility, [etcdctl][etcdctl], for communicating with an etcd cluster through gRPC. For languages with no gRPC support, etcd provides a JSON [gRPC gateway][grpc-gateway]. This gateway serves a RESTful proxy that translates HTTP/JSON requests into gRPC messages.
-
-## Using gRPC gateway
-
-The gateway accepts a [JSON mapping][json-mapping] for etcd's [protocol buffer][api-ref] message definitions. Note that `key` and `value` fields are defined as byte arrays and therefore must be base64 encoded in JSON. The following examples use `curl`, but any HTTP/JSON client should work all the same.
-
-### Notes
-
-gRPC gateway endpoint has changed since etcd v3.3:
-
-- etcd v3.2 or before uses only `[CLIENT-URL]/v3alpha/*`.
-- etcd v3.3 uses `[CLIENT-URL]/v3beta/*` while keeping `[CLIENT-URL]/v3alpha/*`.
-- etcd v3.4 uses `[CLIENT-URL]/v3/*` while keeping `[CLIENT-URL]/v3beta/*`.
-  - **`[CLIENT-URL]/v3alpha/*` is deprecated**.
-- etcd v3.5 or later uses only `[CLIENT-URL]/v3/*`.
-  - **`[CLIENT-URL]/v3beta/*` is deprecated**.
-
-gRPC-gateway does not support authentication using TLS Common Name.
-
-### Put and get keys
-
-Use the `/v3/kv/range` and `/v3/kv/put` services to read and write keys:
-
-```bash
-<<COMMENT
-https://www.base64encode.org/
-foo is 'Zm9v' in Base64
-bar is 'YmFy'
-COMMENT
-
-curl -L http://localhost:2379/v3/kv/put \
-  -X POST -d '{"key": "Zm9v", "value": "YmFy"}'
-# {"header":{"cluster_id":"12585971608760269493","member_id":"13847567121247652255","revision":"2","raft_term":"3"}}
-
-curl -L http://localhost:2379/v3/kv/range \
-  -X POST -d '{"key": "Zm9v"}'
-# {"header":{"cluster_id":"12585971608760269493","member_id":"13847567121247652255","revision":"2","raft_term":"3"},"kvs":[{"key":"Zm9v","create_revision":"2","mod_revision":"2","version":"1","value":"YmFy"}],"count":"1"}
-
-# get all keys prefixed with "foo"
-curl -L http://localhost:2379/v3/kv/range \
-  -X POST -d '{"key": "Zm9v", "range_end": "Zm9w"}'
-# {"header":{"cluster_id":"12585971608760269493","member_id":"13847567121247652255","revision":"2","raft_term":"3"},"kvs":[{"key":"Zm9v","create_revision":"2","mod_revision":"2","version":"1","value":"YmFy"}],"count":"1"}
-```
-
-### Watch keys
-
-Use the `/v3/watch` service to watch keys:
-
-```bash
-curl -N http://localhost:2379/v3/watch \
-  -X POST -d '{"create_request": {"key":"Zm9v"} }' &
-# {"result":{"header":{"cluster_id":"12585971608760269493","member_id":"13847567121247652255","revision":"1","raft_term":"2"},"created":true}}
-
-curl -L http://localhost:2379/v3/kv/put \
-  -X POST -d '{"key": "Zm9v", "value": "YmFy"}' >/dev/null 2>&1
-# {"result":{"header":{"cluster_id":"12585971608760269493","member_id":"13847567121247652255","revision":"2","raft_term":"2"},"events":[{"kv":{"key":"Zm9v","create_revision":"2","mod_revision":"2","version":"1","value":"YmFy"}}]}}
-```
-
-### Transactions
-
-Issue a transaction with `/v3/kv/txn`:
-
-```bash
-# target CREATE
-curl -L http://localhost:2379/v3/kv/txn \
-  -X POST \
-  -d '{"compare":[{"target":"CREATE","key":"Zm9v","createRevision":"2"}],"success":[{"requestPut":{"key":"Zm9v","value":"YmFy"}}]}'
-# {"header":{"cluster_id":"12585971608760269493","member_id":"13847567121247652255","revision":"3","raft_term":"2"},"succeeded":true,"responses":[{"response_put":{"header":{"revision":"3"}}}]}
-```
-
-```bash
-# target VERSION
-curl -L http://localhost:2379/v3/kv/txn \
-  -X POST \
-  -d '{"compare":[{"version":"4","result":"EQUAL","target":"VERSION","key":"Zm9v"}],"success":[{"requestRange":{"key":"Zm9v"}}]}'
-# {"header":{"cluster_id":"14841639068965178418","member_id":"10276657743932975437","revision":"6","raft_term":"3"},"succeeded":true,"responses":[{"response_range":{"header":{"revision":"6"},"kvs":[{"key":"Zm9v","create_revision":"2","mod_revision":"6","version":"4","value":"YmF6"}],"count":"1"}}]}
-```
-
-### Authentication
-
-Set up authentication with the `/v3/auth` service:
-
-```bash
-# create root user
-curl -L http://localhost:2379/v3/auth/user/add \
-  -X POST -d '{"name": "root", "password": "pass"}'
-# {"header":{"cluster_id":"14841639068965178418","member_id":"10276657743932975437","revision":"1","raft_term":"2"}}
-
-# create root role
-curl -L http://localhost:2379/v3/auth/role/add \
-  -X POST -d '{"name": "root"}'
-# {"header":{"cluster_id":"14841639068965178418","member_id":"10276657743932975437","revision":"1","raft_term":"2"}}
-
-# grant root role
-curl -L http://localhost:2379/v3/auth/user/grant \
-  -X POST -d '{"user": "root", "role": "root"}'
-# {"header":{"cluster_id":"14841639068965178418","member_id":"10276657743932975437","revision":"1","raft_term":"2"}}
-
-# enable auth
-curl -L http://localhost:2379/v3/auth/enable -X POST -d '{}'
-# {"header":{"cluster_id":"14841639068965178418","member_id":"10276657743932975437","revision":"1","raft_term":"2"}}
-```
-
-Authenticate with etcd for an authentication token using `/v3/auth/authenticate`:
-
-```bash
-# get the auth token for the root user
-curl -L http://localhost:2379/v3/auth/authenticate \
-  -X POST -d '{"name": "root", "password": "pass"}'
-# {"header":{"cluster_id":"14841639068965178418","member_id":"10276657743932975437","revision":"1","raft_term":"2"},"token":"sssvIpwfnLAcWAQH.9"}
-```
-
-Set the `Authorization` header to the authentication token to fetch a key using authentication credentials:
-
-```bash
-curl -L http://localhost:2379/v3/kv/put \
-  -H 'Authorization : sssvIpwfnLAcWAQH.9' \
-  -X POST -d '{"key": "Zm9v", "value": "YmFy"}'
-# {"header":{"cluster_id":"14841639068965178418","member_id":"10276657743932975437","revision":"2","raft_term":"2"}}
-```
-
-## Swagger
-
-Generated [Swagger][swagger] API definitions can be found at [rpc.swagger.json][swagger-doc].
-
-[api-ref]: ./api_reference_v3.md
-[go-client]: https://github.com/coreos/etcd/tree/master/clientv3
-[etcdctl]: https://github.com/coreos/etcd/tree/master/etcdctl
-[grpc]: https://www.grpc.io/
-[grpc-gateway]: https://github.com/grpc-ecosystem/grpc-gateway
-[json-mapping]: https://developers.google.com/protocol-buffers/docs/proto3#json
-[swagger]: http://swagger.io/
-[swagger-doc]: apispec/swagger/rpc.swagger.json

+ 0 - 987
src/github.com/coreos/etcd/Documentation/dev-guide/api_reference_v3.md

@@ -1,987 +0,0 @@
----
-title: etcd API Reference
----
-
-
-This is a generated documentation. Please read the proto files for more.
-
-
-##### service `Auth` (etcdserver/etcdserverpb/rpc.proto)
-
-| Method | Request Type | Response Type | Description |
-| ------ | ------------ | ------------- | ----------- |
-| AuthEnable | AuthEnableRequest | AuthEnableResponse | AuthEnable enables authentication. |
-| AuthDisable | AuthDisableRequest | AuthDisableResponse | AuthDisable disables authentication. |
-| Authenticate | AuthenticateRequest | AuthenticateResponse | Authenticate processes an authenticate request. |
-| UserAdd | AuthUserAddRequest | AuthUserAddResponse | UserAdd adds a new user. |
-| UserGet | AuthUserGetRequest | AuthUserGetResponse | UserGet gets detailed user information. |
-| UserList | AuthUserListRequest | AuthUserListResponse | UserList gets a list of all users. |
-| UserDelete | AuthUserDeleteRequest | AuthUserDeleteResponse | UserDelete deletes a specified user. |
-| UserChangePassword | AuthUserChangePasswordRequest | AuthUserChangePasswordResponse | UserChangePassword changes the password of a specified user. |
-| UserGrantRole | AuthUserGrantRoleRequest | AuthUserGrantRoleResponse | UserGrant grants a role to a specified user. |
-| UserRevokeRole | AuthUserRevokeRoleRequest | AuthUserRevokeRoleResponse | UserRevokeRole revokes a role of specified user. |
-| RoleAdd | AuthRoleAddRequest | AuthRoleAddResponse | RoleAdd adds a new role. |
-| RoleGet | AuthRoleGetRequest | AuthRoleGetResponse | RoleGet gets detailed role information. |
-| RoleList | AuthRoleListRequest | AuthRoleListResponse | RoleList gets lists of all roles. |
-| RoleDelete | AuthRoleDeleteRequest | AuthRoleDeleteResponse | RoleDelete deletes a specified role. |
-| RoleGrantPermission | AuthRoleGrantPermissionRequest | AuthRoleGrantPermissionResponse | RoleGrantPermission grants a permission of a specified key or range to a specified role. |
-| RoleRevokePermission | AuthRoleRevokePermissionRequest | AuthRoleRevokePermissionResponse | RoleRevokePermission revokes a key or range permission of a specified role. |
-
-
-
-##### service `Cluster` (etcdserver/etcdserverpb/rpc.proto)
-
-| Method | Request Type | Response Type | Description |
-| ------ | ------------ | ------------- | ----------- |
-| MemberAdd | MemberAddRequest | MemberAddResponse | MemberAdd adds a member into the cluster. |
-| MemberRemove | MemberRemoveRequest | MemberRemoveResponse | MemberRemove removes an existing member from the cluster. |
-| MemberUpdate | MemberUpdateRequest | MemberUpdateResponse | MemberUpdate updates the member configuration. |
-| MemberList | MemberListRequest | MemberListResponse | MemberList lists all the members in the cluster. |
-
-
-
-##### service `KV` (etcdserver/etcdserverpb/rpc.proto)
-
-| Method | Request Type | Response Type | Description |
-| ------ | ------------ | ------------- | ----------- |
-| Range | RangeRequest | RangeResponse | Range gets the keys in the range from the key-value store. |
-| Put | PutRequest | PutResponse | Put puts the given key into the key-value store. A put request increments the revision of the key-value store and generates one event in the event history. |
-| DeleteRange | DeleteRangeRequest | DeleteRangeResponse | DeleteRange deletes the given range from the key-value store. A delete request increments the revision of the key-value store and generates a delete event in the event history for every deleted key. |
-| Txn | TxnRequest | TxnResponse | Txn processes multiple requests in a single transaction. A txn request increments the revision of the key-value store and generates events with the same revision for every completed request. It is not allowed to modify the same key several times within one txn. |
-| Compact | CompactionRequest | CompactionResponse | Compact compacts the event history in the etcd key-value store. The key-value store should be periodically compacted or the event history will continue to grow indefinitely. |
-
-
-
-##### service `Lease` (etcdserver/etcdserverpb/rpc.proto)
-
-| Method | Request Type | Response Type | Description |
-| ------ | ------------ | ------------- | ----------- |
-| LeaseGrant | LeaseGrantRequest | LeaseGrantResponse | LeaseGrant creates a lease which expires if the server does not receive a keepAlive within a given time to live period. All keys attached to the lease will be expired and deleted if the lease expires. Each expired key generates a delete event in the event history. |
-| LeaseRevoke | LeaseRevokeRequest | LeaseRevokeResponse | LeaseRevoke revokes a lease. All keys attached to the lease will expire and be deleted. |
-| LeaseKeepAlive | LeaseKeepAliveRequest | LeaseKeepAliveResponse | LeaseKeepAlive keeps the lease alive by streaming keep alive requests from the client to the server and streaming keep alive responses from the server to the client. |
-| LeaseTimeToLive | LeaseTimeToLiveRequest | LeaseTimeToLiveResponse | LeaseTimeToLive retrieves lease information. |
-| LeaseLeases | LeaseLeasesRequest | LeaseLeasesResponse | LeaseLeases lists all existing leases. |
-
-
-
-##### service `Maintenance` (etcdserver/etcdserverpb/rpc.proto)
-
-| Method | Request Type | Response Type | Description |
-| ------ | ------------ | ------------- | ----------- |
-| Alarm | AlarmRequest | AlarmResponse | Alarm activates, deactivates, and queries alarms regarding cluster health. |
-| Status | StatusRequest | StatusResponse | Status gets the status of the member. |
-| Defragment | DefragmentRequest | DefragmentResponse | Defragment defragments a member's backend database to recover storage space. |
-| Hash | HashRequest | HashResponse | Hash computes the hash of whole backend keyspace, including key, lease, and other buckets in storage. This is designed for testing ONLY! Do not rely on this in production with ongoing transactions, since Hash operation does not hold MVCC locks. Use "HashKV" API instead for "key" bucket consistency checks. |
-| HashKV | HashKVRequest | HashKVResponse | HashKV computes the hash of all MVCC keys up to a given revision. It only iterates "key" bucket in backend storage. |
-| Snapshot | SnapshotRequest | SnapshotResponse | Snapshot sends a snapshot of the entire backend from a member over a stream to a client. |
-| MoveLeader | MoveLeaderRequest | MoveLeaderResponse | MoveLeader requests current leader node to transfer its leadership to transferee. |
-
-
-
-##### service `Watch` (etcdserver/etcdserverpb/rpc.proto)
-
-| Method | Request Type | Response Type | Description |
-| ------ | ------------ | ------------- | ----------- |
-| Watch | WatchRequest | WatchResponse | Watch watches for events happening or that have happened. Both input and output are streams; the input stream is for creating and canceling watchers and the output stream sends events. One watch RPC can watch on multiple key ranges, streaming events for several watches at once. The entire event history can be watched starting from the last compaction revision. |
-
-
-
-##### message `AlarmMember` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| memberID | memberID is the ID of the member associated with the raised alarm. | uint64 |
-| alarm | alarm is the type of alarm which has been raised. | AlarmType |
-
-
-
-##### message `AlarmRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| action | action is the kind of alarm request to issue. The action may GET alarm statuses, ACTIVATE an alarm, or DEACTIVATE a raised alarm. | AlarmAction |
-| memberID | memberID is the ID of the member associated with the alarm. If memberID is 0, the alarm request covers all members. | uint64 |
-| alarm | alarm is the type of alarm to consider for this request. | AlarmType |
-
-
-
-##### message `AlarmResponse` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | ResponseHeader |
-| alarms | alarms is a list of alarms associated with the alarm request. | (slice of) AlarmMember |
-
-
-
-##### message `AuthDisableRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-Empty field.
-
-
-
-##### message `AuthDisableResponse` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | ResponseHeader |
-
-
-
-##### message `AuthEnableRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-Empty field.
-
-
-
-##### message `AuthEnableResponse` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | ResponseHeader |
-
-
-
-##### message `AuthRoleAddRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| name | name is the name of the role to add to the authentication system. | string |
-
-
-
-##### message `AuthRoleAddResponse` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | ResponseHeader |
-
-
-
-##### message `AuthRoleDeleteRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| role |  | string |
-
-
-
-##### message `AuthRoleDeleteResponse` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | ResponseHeader |
-
-
-
-##### message `AuthRoleGetRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| role |  | string |
-
-
-
-##### message `AuthRoleGetResponse` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | ResponseHeader |
-| perm |  | (slice of) authpb.Permission |
-
-
-
-##### message `AuthRoleGrantPermissionRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| name | name is the name of the role which will be granted the permission. | string |
-| perm | perm is the permission to grant to the role. | authpb.Permission |
-
-
-
-##### message `AuthRoleGrantPermissionResponse` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | ResponseHeader |
-
-
-
-##### message `AuthRoleListRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-Empty field.
-
-
-
-##### message `AuthRoleListResponse` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | ResponseHeader |
-| roles |  | (slice of) string |
-
-
-
-##### message `AuthRoleRevokePermissionRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| role |  | string |
-| key |  | bytes |
-| range_end |  | bytes |
-
-
-
-##### message `AuthRoleRevokePermissionResponse` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | ResponseHeader |
-
-
-
-##### message `AuthUserAddRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| name |  | string |
-| password |  | string |
-
-
-
-##### message `AuthUserAddResponse` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | ResponseHeader |
-
-
-
-##### message `AuthUserChangePasswordRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| name | name is the name of the user whose password is being changed. | string |
-| password | password is the new password for the user. | string |
-
-
-
-##### message `AuthUserChangePasswordResponse` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | ResponseHeader |
-
-
-
-##### message `AuthUserDeleteRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| name | name is the name of the user to delete. | string |
-
-
-
-##### message `AuthUserDeleteResponse` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | ResponseHeader |
-
-
-
-##### message `AuthUserGetRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| name |  | string |
-
-
-
-##### message `AuthUserGetResponse` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | ResponseHeader |
-| roles |  | (slice of) string |
-
-
-
-##### message `AuthUserGrantRoleRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| user | user is the name of the user which should be granted a given role. | string |
-| role | role is the name of the role to grant to the user. | string |
-
-
-
-##### message `AuthUserGrantRoleResponse` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | ResponseHeader |
-
-
-
-##### message `AuthUserListRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-Empty field.
-
-
-
-##### message `AuthUserListResponse` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | ResponseHeader |
-| users |  | (slice of) string |
-
-
-
-##### message `AuthUserRevokeRoleRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| name |  | string |
-| role |  | string |
-
-
-
-##### message `AuthUserRevokeRoleResponse` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | ResponseHeader |
-
-
-
-##### message `AuthenticateRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| name |  | string |
-| password |  | string |
-
-
-
-##### message `AuthenticateResponse` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | ResponseHeader |
-| token | token is an authorized token that can be used in succeeding RPCs | string |
-
-
-
-##### message `CompactionRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-CompactionRequest compacts the key-value store up to a given revision. All superseded keys with a revision less than the compaction revision will be removed.
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| revision | revision is the key-value store revision for the compaction operation. | int64 |
-| physical | physical is set so the RPC will wait until the compaction is physically applied to the local database such that compacted entries are totally removed from the backend database. | bool |
-
-
-
-##### message `CompactionResponse` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | ResponseHeader |
-
-
-
-##### message `Compare` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| result | result is logical comparison operation for this comparison. | CompareResult |
-| target | target is the key-value field to inspect for the comparison. | CompareTarget |
-| key | key is the subject key for the comparison operation. | bytes |
-| target_union |  | oneof |
-| version | version is the version of the given key | int64 |
-| create_revision | create_revision is the creation revision of the given key | int64 |
-| mod_revision | mod_revision is the last modified revision of the given key. | int64 |
-| value | value is the value of the given key, in bytes. | bytes |
-| lease | lease is the lease id of the given key. | int64 |
-| range_end | range_end compares the given target to all keys in the range [key, range_end). See RangeRequest for more details on key ranges. | bytes |
-
-
-
-##### message `DefragmentRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-Empty field.
-
-
-
-##### message `DefragmentResponse` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | ResponseHeader |
-
-
-
-##### message `DeleteRangeRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| key | key is the first key to delete in the range. | bytes |
-| range_end | range_end is the key following the last key to delete for the range [key, range_end). If range_end is not given, the range is defined to contain only the key argument. If range_end is one bit larger than the given key, then the range is all the keys with the prefix (the given key). If range_end is '\0', the range is all keys greater than or equal to the key argument. | bytes |
-| prev_kv | If prev_kv is set, etcd gets the previous key-value pairs before deleting it. The previous key-value pairs will be returned in the delete response. | bool |
-
-
-
-##### message `DeleteRangeResponse` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | ResponseHeader |
-| deleted | deleted is the number of keys deleted by the delete range request. | int64 |
-| prev_kvs | if prev_kv is set in the request, the previous key-value pairs will be returned. | (slice of) mvccpb.KeyValue |
-
-
-
-##### message `HashKVRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| revision | revision is the key-value store revision for the hash operation. | int64 |
-
-
-
-##### message `HashKVResponse` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | ResponseHeader |
-| hash | hash is the hash value computed from the responding member's MVCC keys up to a given revision. | uint32 |
-| compact_revision | compact_revision is the compacted revision of key-value store when hash begins. | int64 |
-
-
-
-##### message `HashRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-Empty field.
-
-
-
-##### message `HashResponse` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | ResponseHeader |
-| hash | hash is the hash value computed from the responding member's KV's backend. | uint32 |
-
-
-
-##### message `LeaseCheckpoint` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| ID | ID is the lease ID to checkpoint. | int64 |
-| remaining_TTL | Remaining_TTL is the remaining time until expiry of the lease. | int64 |
-
-
-
-##### message `LeaseCheckpointRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| checkpoints |  | (slice of) LeaseCheckpoint |
-
-
-
-##### message `LeaseCheckpointResponse` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | ResponseHeader |
-
-
-
-##### message `LeaseGrantRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| TTL | TTL is the advisory time-to-live in seconds. Expired lease will return -1. | int64 |
-| ID | ID is the requested ID for the lease. If ID is set to 0, the lessor chooses an ID. | int64 |
-
-
-
-##### message `LeaseGrantResponse` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | ResponseHeader |
-| ID | ID is the lease ID for the granted lease. | int64 |
-| TTL | TTL is the server chosen lease time-to-live in seconds. | int64 |
-| error |  | string |
-
-
-
-##### message `LeaseKeepAliveRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| ID | ID is the lease ID for the lease to keep alive. | int64 |
-
-
-
-##### message `LeaseKeepAliveResponse` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | ResponseHeader |
-| ID | ID is the lease ID from the keep alive request. | int64 |
-| TTL | TTL is the new time-to-live for the lease. | int64 |
-
-
-
-##### message `LeaseLeasesRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-Empty field.
-
-
-
-##### message `LeaseLeasesResponse` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | ResponseHeader |
-| leases |  | (slice of) LeaseStatus |
-
-
-
-##### message `LeaseRevokeRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| ID | ID is the lease ID to revoke. When the ID is revoked, all associated keys will be deleted. | int64 |
-
-
-
-##### message `LeaseRevokeResponse` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | ResponseHeader |
-
-
-
-##### message `LeaseStatus` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| ID |  | int64 |
-
-
-
-##### message `LeaseTimeToLiveRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| ID | ID is the lease ID for the lease. | int64 |
-| keys | keys is true to query all the keys attached to this lease. | bool |
-
-
-
-##### message `LeaseTimeToLiveResponse` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | ResponseHeader |
-| ID | ID is the lease ID from the keep alive request. | int64 |
-| TTL | TTL is the remaining TTL in seconds for the lease; the lease will expire in under TTL+1 seconds. | int64 |
-| grantedTTL | GrantedTTL is the initial granted time in seconds upon lease creation/renewal. | int64 |
-| keys | Keys is the list of keys attached to this lease. | (slice of) bytes |
-
-
-
-##### message `Member` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| ID | ID is the member ID for this member. | uint64 |
-| name | name is the human-readable name of the member. If the member is not started, the name will be an empty string. | string |
-| peerURLs | peerURLs is the list of URLs the member exposes to the cluster for communication. | (slice of) string |
-| clientURLs | clientURLs is the list of URLs the member exposes to clients for communication. If the member is not started, clientURLs will be empty. | (slice of) string |
-
-
-
-##### message `MemberAddRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| peerURLs | peerURLs is the list of URLs the added member will use to communicate with the cluster. | (slice of) string |
-
-
-
-##### message `MemberAddResponse` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | ResponseHeader |
-| member | member is the member information for the added member. | Member |
-| members | members is a list of all members after adding the new member. | (slice of) Member |
-
-
-
-##### message `MemberListRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-Empty field.
-
-
-
-##### message `MemberListResponse` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | ResponseHeader |
-| members | members is a list of all members associated with the cluster. | (slice of) Member |
-
-
-
-##### message `MemberRemoveRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| ID | ID is the member ID of the member to remove. | uint64 |
-
-
-
-##### message `MemberRemoveResponse` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | ResponseHeader |
-| members | members is a list of all members after removing the member. | (slice of) Member |
-
-
-
-##### message `MemberUpdateRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| ID | ID is the member ID of the member to update. | uint64 |
-| peerURLs | peerURLs is the new list of URLs the member will use to communicate with the cluster. | (slice of) string |
-
-
-
-##### message `MemberUpdateResponse` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | ResponseHeader |
-| members | members is a list of all members after updating the member. | (slice of) Member |
-
-
-
-##### message `MoveLeaderRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| targetID | targetID is the node ID for the new leader. | uint64 |
-
-
-
-##### message `MoveLeaderResponse` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | ResponseHeader |
-
-
-
-##### message `PutRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| key | key is the key, in bytes, to put into the key-value store. | bytes |
-| value | value is the value, in bytes, to associate with the key in the key-value store. | bytes |
-| lease | lease is the lease ID to associate with the key in the key-value store. A lease value of 0 indicates no lease. | int64 |
-| prev_kv | If prev_kv is set, etcd gets the previous key-value pair before changing it. The previous key-value pair will be returned in the put response. | bool |
-| ignore_value | If ignore_value is set, etcd updates the key using its current value. Returns an error if the key does not exist. | bool |
-| ignore_lease | If ignore_lease is set, etcd updates the key using its current lease. Returns an error if the key does not exist. | bool |
-
-
-
-##### message `PutResponse` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | ResponseHeader |
-| prev_kv | if prev_kv is set in the request, the previous key-value pair will be returned. | mvccpb.KeyValue |
-
-
-
-##### message `RangeRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| key | key is the first key for the range. If range_end is not given, the request only looks up key. | bytes |
-| range_end | range_end is the upper bound on the requested range [key, range_end). If range_end is '\0', the range is all keys >= key. If range_end is key plus one (e.g., "aa"+1 == "ab", "a\xff"+1 == "b"), then the range request gets all keys prefixed with key. If both key and range_end are '\0', then the range request returns all keys. | bytes |
-| limit | limit is a limit on the number of keys returned for the request. When limit is set to 0, it is treated as no limit. | int64 |
-| revision | revision is the point-in-time of the key-value store to use for the range. If revision is less or equal to zero, the range is over the newest key-value store. If the revision has been compacted, ErrCompacted is returned as a response. | int64 |
-| sort_order | sort_order is the order for returned sorted results. | SortOrder |
-| sort_target | sort_target is the key-value field to use for sorting. | SortTarget |
-| serializable | serializable sets the range request to use serializable member-local reads. Range requests are linearizable by default; linearizable requests have higher latency and lower throughput than serializable requests but reflect the current consensus of the cluster. For better performance, in exchange for possible stale reads, a serializable range request is served locally without needing to reach consensus with other nodes in the cluster. | bool |
-| keys_only | keys_only when set returns only the keys and not the values. | bool |
-| count_only | count_only when set returns only the count of the keys in the range. | bool |
-| min_mod_revision | min_mod_revision is the lower bound for returned key mod revisions; all keys with lesser mod revisions will be filtered away. | int64 |
-| max_mod_revision | max_mod_revision is the upper bound for returned key mod revisions; all keys with greater mod revisions will be filtered away. | int64 |
-| min_create_revision | min_create_revision is the lower bound for returned key create revisions; all keys with lesser create revisions will be filtered away. | int64 |
-| max_create_revision | max_create_revision is the upper bound for returned key create revisions; all keys with greater create revisions will be filtered away. | int64 |
-
-
-
-##### message `RangeResponse` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | ResponseHeader |
-| kvs | kvs is the list of key-value pairs matched by the range request. kvs is empty when count is requested. | (slice of) mvccpb.KeyValue |
-| more | more indicates if there are more keys to return in the requested range. | bool |
-| count | count is set to the number of keys within the range when requested. | int64 |
-
-
-
-##### message `RequestOp` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| request | request is a union of request types accepted by a transaction. | oneof |
-| request_range |  | RangeRequest |
-| request_put |  | PutRequest |
-| request_delete_range |  | DeleteRangeRequest |
-| request_txn |  | TxnRequest |
-
-
-
-##### message `ResponseHeader` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| cluster_id | cluster_id is the ID of the cluster which sent the response. | uint64 |
-| member_id | member_id is the ID of the member which sent the response. | uint64 |
-| revision | revision is the key-value store revision when the request was applied. For watch progress responses, the header.revision indicates progress. All future events recieved in this stream are guaranteed to have a higher revision number than the header.revision number. | int64 |
-| raft_term | raft_term is the raft term when the request was applied. | uint64 |
-
-
-
-##### message `ResponseOp` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| response | response is a union of response types returned by a transaction. | oneof |
-| response_range |  | RangeResponse |
-| response_put |  | PutResponse |
-| response_delete_range |  | DeleteRangeResponse |
-| response_txn |  | TxnResponse |
-
-
-
-##### message `SnapshotRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-Empty field.
-
-
-
-##### message `SnapshotResponse` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header | header has the current key-value store information. The first header in the snapshot stream indicates the point in time of the snapshot. | ResponseHeader |
-| remaining_bytes | remaining_bytes is the number of blob bytes to be sent after this message | uint64 |
-| blob | blob contains the next chunk of the snapshot in the snapshot stream. | bytes |
-
-
-
-##### message `StatusRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-Empty field.
-
-
-
-##### message `StatusResponse` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | ResponseHeader |
-| version | version is the cluster protocol version used by the responding member. | string |
-| dbSize | dbSize is the size of the backend database physically allocated, in bytes, of the responding member. | int64 |
-| leader | leader is the member ID which the responding member believes is the current leader. | uint64 |
-| raftIndex | raftIndex is the current raft committed index of the responding member. | uint64 |
-| raftTerm | raftTerm is the current raft term of the responding member. | uint64 |
-| raftAppliedIndex | raftAppliedIndex is the current raft applied index of the responding member. | uint64 |
-| errors | errors contains alarm/health information and status. | (slice of) string |
-| dbSizeInUse | dbSizeInUse is the size of the backend database logically in use, in bytes, of the responding member. | int64 |
-
-
-
-##### message `TxnRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-From google paxosdb paper: Our implementation hinges around a powerful primitive which we call MultiOp. All other database operations except for iteration are implemented as a single call to MultiOp. A MultiOp is applied atomically and consists of three components: 1. A list of tests called guard. Each test in guard checks a single entry in the database. It may check for the absence or presence of a value, or compare with a given value. Two different tests in the guard may apply to the same or different entries in the database. All tests in the guard are applied and MultiOp returns the results. If all tests are true, MultiOp executes t op (see item 2 below), otherwise it executes f op (see item 3 below). 2. A list of database operations called t op. Each operation in the list is either an insert, delete, or lookup operation, and applies to a single database entry. Two different operations in the list may apply to the same or different entries in the database. These operations are executed if guard evaluates to true. 3. A list of database operations called f op. Like t op, but executed if guard evaluates to false.
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| compare | compare is a list of predicates representing a conjunction of terms. If the comparisons succeed, then the success requests will be processed in order, and the response will contain their respective responses in order. If the comparisons fail, then the failure requests will be processed in order, and the response will contain their respective responses in order. | (slice of) Compare |
-| success | success is a list of requests which will be applied when compare evaluates to true. | (slice of) RequestOp |
-| failure | failure is a list of requests which will be applied when compare evaluates to false. | (slice of) RequestOp |
-
-
-
-##### message `TxnResponse` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | ResponseHeader |
-| succeeded | succeeded is set to true if the compare evaluated to true or false otherwise. | bool |
-| responses | responses is a list of responses corresponding to the results from applying success if succeeded is true or failure if succeeded is false. | (slice of) ResponseOp |
-
-
-
-##### message `WatchCancelRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| watch_id | watch_id is the watcher id to cancel so that no more events are transmitted. | int64 |
-
-
-
-##### message `WatchCreateRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| key | key is the key to register for watching. | bytes |
-| range_end | range_end is the end of the range [key, range_end) to watch. If range_end is not given, only the key argument is watched. If range_end is equal to '\0', all keys greater than or equal to the key argument are watched. If the range_end is one bit larger than the given key, then all keys with the prefix (the given key) will be watched. | bytes |
-| start_revision | start_revision is an optional revision to watch from (inclusive). No start_revision is "now". | int64 |
-| progress_notify | progress_notify is set so that the etcd server will periodically send a WatchResponse with no events to the new watcher if there are no recent events. It is useful when clients wish to recover a disconnected watcher starting from a recent known revision. The etcd server may decide how often it will send notifications based on current load. | bool |
-| filters | filters filter the events at server side before it sends back to the watcher. | (slice of) FilterType |
-| prev_kv | If prev_kv is set, created watcher gets the previous KV before the event happens. If the previous KV is already compacted, nothing will be returned. | bool |
-| watch_id | If watch_id is provided and non-zero, it will be assigned to this watcher. Since creating a watcher in etcd is not a synchronous operation, this can be used ensure that ordering is correct when creating multiple watchers on the same stream. Creating a watcher with an ID already in use on the stream will cause an error to be returned. | int64 |
-| fragment | fragment enables splitting large revisions into multiple watch responses. | bool |
-
-
-
-##### message `WatchProgressRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-Requests the a watch stream progress status be sent in the watch response stream as soon as possible.
-
-Empty field.
-
-
-
-##### message `WatchRequest` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| request_union | request_union is a request to either create a new watcher or cancel an existing watcher. | oneof |
-| create_request |  | WatchCreateRequest |
-| cancel_request |  | WatchCancelRequest |
-| progress_request |  | WatchProgressRequest |
-
-
-
-##### message `WatchResponse` (etcdserver/etcdserverpb/rpc.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| header |  | ResponseHeader |
-| watch_id | watch_id is the ID of the watcher that corresponds to the response. | int64 |
-| created | created is set to true if the response is for a create watch request. The client should record the watch_id and expect to receive events for the created watcher from the same stream. All events sent to the created watcher will attach with the same watch_id. | bool |
-| canceled | canceled is set to true if the response is for a cancel watch request. No further events will be sent to the canceled watcher. | bool |
-| compact_revision | compact_revision is set to the minimum index if a watcher tries to watch at a compacted index.  This happens when creating a watcher at a compacted revision or the watcher cannot catch up with the progress of the key-value store.  The client should treat the watcher as canceled and should not try to create any watcher with the same start_revision again. | int64 |
-| cancel_reason | cancel_reason indicates the reason for canceling the watcher. | string |
-| fragment | framgment is true if large watch response was split over multiple responses. | bool |
-| events |  | (slice of) mvccpb.Event |
-
-
-
-##### message `Event` (mvcc/mvccpb/kv.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| type | type is the kind of event. If type is a PUT, it indicates new data has been stored to the key. If type is a DELETE, it indicates the key was deleted. | EventType |
-| kv | kv holds the KeyValue for the event. A PUT event contains current kv pair. A PUT event with kv.Version=1 indicates the creation of a key. A DELETE/EXPIRE event contains the deleted key with its modification revision set to the revision of deletion. | KeyValue |
-| prev_kv | prev_kv holds the key-value pair before the event happens. | KeyValue |
-
-
-
-##### message `KeyValue` (mvcc/mvccpb/kv.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| key | key is the key in bytes. An empty key is not allowed. | bytes |
-| create_revision | create_revision is the revision of last creation on this key. | int64 |
-| mod_revision | mod_revision is the revision of last modification on this key. | int64 |
-| version | version is the version of the key. A deletion resets the version to zero and any modification of the key increases its version. | int64 |
-| value | value is the value held by the key, in bytes. | bytes |
-| lease | lease is the ID of the lease that attached to key. When the attached lease expires, the key will be deleted. If lease is 0, then no lease is attached to the key. | int64 |
-
-
-
-##### message `Lease` (lease/leasepb/lease.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| ID |  | int64 |
-| TTL |  | int64 |
-| RemainingTTL |  | int64 |
-
-
-
-##### message `LeaseInternalRequest` (lease/leasepb/lease.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| LeaseTimeToLiveRequest |  | etcdserverpb.LeaseTimeToLiveRequest |
-
-
-
-##### message `LeaseInternalResponse` (lease/leasepb/lease.proto)
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| LeaseTimeToLiveResponse |  | etcdserverpb.LeaseTimeToLiveResponse |
-
-
-
-##### message `Permission` (auth/authpb/auth.proto)
-
-Permission is a single entity
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| permType |  | Type |
-| key |  | bytes |
-| range_end |  | bytes |
-
-
-
-##### message `Role` (auth/authpb/auth.proto)
-
-Role is a single entry in the bucket authRoles
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| name |  | bytes |
-| keyPermission |  | (slice of) Permission |
-
-
-
-##### message `User` (auth/authpb/auth.proto)
-
-User is a single entry in the bucket authUsers
-
-| Field | Description | Type |
-| ----- | ----------- | ---- |
-| name |  | bytes |
-| password |  | bytes |
-| roles |  | (slice of) string |
-
-
-

+ 0 - 2525
src/github.com/coreos/etcd/Documentation/dev-guide/apispec/swagger/rpc.swagger.json

@@ -1,2525 +0,0 @@
-{
-  "consumes": [
-    "application/json"
-  ],
-  "produces": [
-    "application/json"
-  ],
-  "schemes": [
-    "http",
-    "https"
-  ],
-  "swagger": "2.0",
-  "info": {
-    "title": "etcdserver/etcdserverpb/rpc.proto",
-    "version": "version not set"
-  },
-  "paths": {
-    "/v3/auth/authenticate": {
-      "post": {
-        "tags": [
-          "Auth"
-        ],
-        "summary": "Authenticate processes an authenticate request.",
-        "operationId": "Authenticate",
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbAuthenticateRequest"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbAuthenticateResponse"
-            }
-          }
-        }
-      }
-    },
-    "/v3/auth/disable": {
-      "post": {
-        "tags": [
-          "Auth"
-        ],
-        "summary": "AuthDisable disables authentication.",
-        "operationId": "AuthDisable",
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbAuthDisableRequest"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbAuthDisableResponse"
-            }
-          }
-        }
-      }
-    },
-    "/v3/auth/enable": {
-      "post": {
-        "tags": [
-          "Auth"
-        ],
-        "summary": "AuthEnable enables authentication.",
-        "operationId": "AuthEnable",
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbAuthEnableRequest"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbAuthEnableResponse"
-            }
-          }
-        }
-      }
-    },
-    "/v3/auth/role/add": {
-      "post": {
-        "tags": [
-          "Auth"
-        ],
-        "summary": "RoleAdd adds a new role.",
-        "operationId": "RoleAdd",
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbAuthRoleAddRequest"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbAuthRoleAddResponse"
-            }
-          }
-        }
-      }
-    },
-    "/v3/auth/role/delete": {
-      "post": {
-        "tags": [
-          "Auth"
-        ],
-        "summary": "RoleDelete deletes a specified role.",
-        "operationId": "RoleDelete",
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbAuthRoleDeleteRequest"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbAuthRoleDeleteResponse"
-            }
-          }
-        }
-      }
-    },
-    "/v3/auth/role/get": {
-      "post": {
-        "tags": [
-          "Auth"
-        ],
-        "summary": "RoleGet gets detailed role information.",
-        "operationId": "RoleGet",
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbAuthRoleGetRequest"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbAuthRoleGetResponse"
-            }
-          }
-        }
-      }
-    },
-    "/v3/auth/role/grant": {
-      "post": {
-        "tags": [
-          "Auth"
-        ],
-        "summary": "RoleGrantPermission grants a permission of a specified key or range to a specified role.",
-        "operationId": "RoleGrantPermission",
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbAuthRoleGrantPermissionRequest"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbAuthRoleGrantPermissionResponse"
-            }
-          }
-        }
-      }
-    },
-    "/v3/auth/role/list": {
-      "post": {
-        "tags": [
-          "Auth"
-        ],
-        "summary": "RoleList gets lists of all roles.",
-        "operationId": "RoleList",
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbAuthRoleListRequest"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbAuthRoleListResponse"
-            }
-          }
-        }
-      }
-    },
-    "/v3/auth/role/revoke": {
-      "post": {
-        "tags": [
-          "Auth"
-        ],
-        "summary": "RoleRevokePermission revokes a key or range permission of a specified role.",
-        "operationId": "RoleRevokePermission",
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbAuthRoleRevokePermissionRequest"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbAuthRoleRevokePermissionResponse"
-            }
-          }
-        }
-      }
-    },
-    "/v3/auth/user/add": {
-      "post": {
-        "tags": [
-          "Auth"
-        ],
-        "summary": "UserAdd adds a new user.",
-        "operationId": "UserAdd",
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbAuthUserAddRequest"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbAuthUserAddResponse"
-            }
-          }
-        }
-      }
-    },
-    "/v3/auth/user/changepw": {
-      "post": {
-        "tags": [
-          "Auth"
-        ],
-        "summary": "UserChangePassword changes the password of a specified user.",
-        "operationId": "UserChangePassword",
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbAuthUserChangePasswordRequest"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbAuthUserChangePasswordResponse"
-            }
-          }
-        }
-      }
-    },
-    "/v3/auth/user/delete": {
-      "post": {
-        "tags": [
-          "Auth"
-        ],
-        "summary": "UserDelete deletes a specified user.",
-        "operationId": "UserDelete",
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbAuthUserDeleteRequest"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbAuthUserDeleteResponse"
-            }
-          }
-        }
-      }
-    },
-    "/v3/auth/user/get": {
-      "post": {
-        "tags": [
-          "Auth"
-        ],
-        "summary": "UserGet gets detailed user information.",
-        "operationId": "UserGet",
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbAuthUserGetRequest"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbAuthUserGetResponse"
-            }
-          }
-        }
-      }
-    },
-    "/v3/auth/user/grant": {
-      "post": {
-        "tags": [
-          "Auth"
-        ],
-        "summary": "UserGrant grants a role to a specified user.",
-        "operationId": "UserGrantRole",
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbAuthUserGrantRoleRequest"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbAuthUserGrantRoleResponse"
-            }
-          }
-        }
-      }
-    },
-    "/v3/auth/user/list": {
-      "post": {
-        "tags": [
-          "Auth"
-        ],
-        "summary": "UserList gets a list of all users.",
-        "operationId": "UserList",
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbAuthUserListRequest"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbAuthUserListResponse"
-            }
-          }
-        }
-      }
-    },
-    "/v3/auth/user/revoke": {
-      "post": {
-        "tags": [
-          "Auth"
-        ],
-        "summary": "UserRevokeRole revokes a role of specified user.",
-        "operationId": "UserRevokeRole",
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbAuthUserRevokeRoleRequest"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbAuthUserRevokeRoleResponse"
-            }
-          }
-        }
-      }
-    },
-    "/v3/cluster/member/add": {
-      "post": {
-        "tags": [
-          "Cluster"
-        ],
-        "summary": "MemberAdd adds a member into the cluster.",
-        "operationId": "MemberAdd",
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbMemberAddRequest"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbMemberAddResponse"
-            }
-          }
-        }
-      }
-    },
-    "/v3/cluster/member/list": {
-      "post": {
-        "tags": [
-          "Cluster"
-        ],
-        "summary": "MemberList lists all the members in the cluster.",
-        "operationId": "MemberList",
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbMemberListRequest"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbMemberListResponse"
-            }
-          }
-        }
-      }
-    },
-    "/v3/cluster/member/remove": {
-      "post": {
-        "tags": [
-          "Cluster"
-        ],
-        "summary": "MemberRemove removes an existing member from the cluster.",
-        "operationId": "MemberRemove",
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbMemberRemoveRequest"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbMemberRemoveResponse"
-            }
-          }
-        }
-      }
-    },
-    "/v3/cluster/member/update": {
-      "post": {
-        "tags": [
-          "Cluster"
-        ],
-        "summary": "MemberUpdate updates the member configuration.",
-        "operationId": "MemberUpdate",
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbMemberUpdateRequest"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbMemberUpdateResponse"
-            }
-          }
-        }
-      }
-    },
-    "/v3/kv/compaction": {
-      "post": {
-        "tags": [
-          "KV"
-        ],
-        "summary": "Compact compacts the event history in the etcd key-value store. The key-value\nstore should be periodically compacted or the event history will continue to grow\nindefinitely.",
-        "operationId": "Compact",
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbCompactionRequest"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbCompactionResponse"
-            }
-          }
-        }
-      }
-    },
-    "/v3/kv/deleterange": {
-      "post": {
-        "tags": [
-          "KV"
-        ],
-        "summary": "DeleteRange deletes the given range from the key-value store.\nA delete request increments the revision of the key-value store\nand generates a delete event in the event history for every deleted key.",
-        "operationId": "DeleteRange",
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbDeleteRangeRequest"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbDeleteRangeResponse"
-            }
-          }
-        }
-      }
-    },
-    "/v3/kv/lease/leases": {
-      "post": {
-        "tags": [
-          "Lease"
-        ],
-        "summary": "LeaseLeases lists all existing leases.",
-        "operationId": "LeaseLeases2",
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbLeaseLeasesRequest"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbLeaseLeasesResponse"
-            }
-          }
-        }
-      }
-    },
-    "/v3/kv/lease/revoke": {
-      "post": {
-        "tags": [
-          "Lease"
-        ],
-        "summary": "LeaseRevoke revokes a lease. All keys attached to the lease will expire and be deleted.",
-        "operationId": "LeaseRevoke2",
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbLeaseRevokeRequest"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbLeaseRevokeResponse"
-            }
-          }
-        }
-      }
-    },
-    "/v3/kv/lease/timetolive": {
-      "post": {
-        "tags": [
-          "Lease"
-        ],
-        "summary": "LeaseTimeToLive retrieves lease information.",
-        "operationId": "LeaseTimeToLive2",
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbLeaseTimeToLiveRequest"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbLeaseTimeToLiveResponse"
-            }
-          }
-        }
-      }
-    },
-    "/v3/kv/put": {
-      "post": {
-        "tags": [
-          "KV"
-        ],
-        "summary": "Put puts the given key into the key-value store.\nA put request increments the revision of the key-value store\nand generates one event in the event history.",
-        "operationId": "Put",
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbPutRequest"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbPutResponse"
-            }
-          }
-        }
-      }
-    },
-    "/v3/kv/range": {
-      "post": {
-        "tags": [
-          "KV"
-        ],
-        "summary": "Range gets the keys in the range from the key-value store.",
-        "operationId": "Range",
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbRangeRequest"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbRangeResponse"
-            }
-          }
-        }
-      }
-    },
-    "/v3/kv/txn": {
-      "post": {
-        "tags": [
-          "KV"
-        ],
-        "summary": "Txn processes multiple requests in a single transaction.\nA txn request increments the revision of the key-value store\nand generates events with the same revision for every completed request.\nIt is not allowed to modify the same key several times within one txn.",
-        "operationId": "Txn",
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbTxnRequest"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbTxnResponse"
-            }
-          }
-        }
-      }
-    },
-    "/v3/lease/grant": {
-      "post": {
-        "tags": [
-          "Lease"
-        ],
-        "summary": "LeaseGrant creates a lease which expires if the server does not receive a keepAlive\nwithin a given time to live period. All keys attached to the lease will be expired and\ndeleted if the lease expires. Each expired key generates a delete event in the event history.",
-        "operationId": "LeaseGrant",
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbLeaseGrantRequest"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbLeaseGrantResponse"
-            }
-          }
-        }
-      }
-    },
-    "/v3/lease/keepalive": {
-      "post": {
-        "tags": [
-          "Lease"
-        ],
-        "summary": "LeaseKeepAlive keeps the lease alive by streaming keep alive requests from the client\nto the server and streaming keep alive responses from the server to the client.",
-        "operationId": "LeaseKeepAlive",
-        "parameters": [
-          {
-            "description": " (streaming inputs)",
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbLeaseKeepAliveRequest"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "A successful response.(streaming responses)",
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbLeaseKeepAliveResponse"
-            }
-          }
-        }
-      }
-    },
-    "/v3/lease/leases": {
-      "post": {
-        "tags": [
-          "Lease"
-        ],
-        "summary": "LeaseLeases lists all existing leases.",
-        "operationId": "LeaseLeases",
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbLeaseLeasesRequest"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbLeaseLeasesResponse"
-            }
-          }
-        }
-      }
-    },
-    "/v3/lease/revoke": {
-      "post": {
-        "tags": [
-          "Lease"
-        ],
-        "summary": "LeaseRevoke revokes a lease. All keys attached to the lease will expire and be deleted.",
-        "operationId": "LeaseRevoke",
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbLeaseRevokeRequest"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbLeaseRevokeResponse"
-            }
-          }
-        }
-      }
-    },
-    "/v3/lease/timetolive": {
-      "post": {
-        "tags": [
-          "Lease"
-        ],
-        "summary": "LeaseTimeToLive retrieves lease information.",
-        "operationId": "LeaseTimeToLive",
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbLeaseTimeToLiveRequest"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbLeaseTimeToLiveResponse"
-            }
-          }
-        }
-      }
-    },
-    "/v3/maintenance/alarm": {
-      "post": {
-        "tags": [
-          "Maintenance"
-        ],
-        "summary": "Alarm activates, deactivates, and queries alarms regarding cluster health.",
-        "operationId": "Alarm",
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbAlarmRequest"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbAlarmResponse"
-            }
-          }
-        }
-      }
-    },
-    "/v3/maintenance/defragment": {
-      "post": {
-        "tags": [
-          "Maintenance"
-        ],
-        "summary": "Defragment defragments a member's backend database to recover storage space.",
-        "operationId": "Defragment",
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbDefragmentRequest"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbDefragmentResponse"
-            }
-          }
-        }
-      }
-    },
-    "/v3/maintenance/hash": {
-      "post": {
-        "tags": [
-          "Maintenance"
-        ],
-        "summary": "HashKV computes the hash of all MVCC keys up to a given revision.\nIt only iterates \"key\" bucket in backend storage.",
-        "operationId": "HashKV",
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbHashKVRequest"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbHashKVResponse"
-            }
-          }
-        }
-      }
-    },
-    "/v3/maintenance/snapshot": {
-      "post": {
-        "tags": [
-          "Maintenance"
-        ],
-        "summary": "Snapshot sends a snapshot of the entire backend from a member over a stream to a client.",
-        "operationId": "Snapshot",
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbSnapshotRequest"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "A successful response.(streaming responses)",
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbSnapshotResponse"
-            }
-          }
-        }
-      }
-    },
-    "/v3/maintenance/status": {
-      "post": {
-        "tags": [
-          "Maintenance"
-        ],
-        "summary": "Status gets the status of the member.",
-        "operationId": "Status",
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbStatusRequest"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbStatusResponse"
-            }
-          }
-        }
-      }
-    },
-    "/v3/maintenance/transfer-leadership": {
-      "post": {
-        "tags": [
-          "Maintenance"
-        ],
-        "summary": "MoveLeader requests current leader node to transfer its leadership to transferee.",
-        "operationId": "MoveLeader",
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbMoveLeaderRequest"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbMoveLeaderResponse"
-            }
-          }
-        }
-      }
-    },
-    "/v3/watch": {
-      "post": {
-        "tags": [
-          "Watch"
-        ],
-        "summary": "Watch watches for events happening or that have happened. Both input and output\nare streams; the input stream is for creating and canceling watchers and the output\nstream sends events. One watch RPC can watch on multiple key ranges, streaming events\nfor several watches at once. The entire event history can be watched starting from the\nlast compaction revision.",
-        "operationId": "Watch",
-        "parameters": [
-          {
-            "description": " (streaming inputs)",
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbWatchRequest"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "A successful response.(streaming responses)",
-            "schema": {
-              "$ref": "#/definitions/etcdserverpbWatchResponse"
-            }
-          }
-        }
-      }
-    }
-  },
-  "definitions": {
-    "AlarmRequestAlarmAction": {
-      "type": "string",
-      "default": "GET",
-      "enum": [
-        "GET",
-        "ACTIVATE",
-        "DEACTIVATE"
-      ]
-    },
-    "CompareCompareResult": {
-      "type": "string",
-      "default": "EQUAL",
-      "enum": [
-        "EQUAL",
-        "GREATER",
-        "LESS",
-        "NOT_EQUAL"
-      ]
-    },
-    "CompareCompareTarget": {
-      "type": "string",
-      "default": "VERSION",
-      "enum": [
-        "VERSION",
-        "CREATE",
-        "MOD",
-        "VALUE",
-        "LEASE"
-      ]
-    },
-    "EventEventType": {
-      "type": "string",
-      "default": "PUT",
-      "enum": [
-        "PUT",
-        "DELETE"
-      ]
-    },
-    "RangeRequestSortOrder": {
-      "type": "string",
-      "default": "NONE",
-      "enum": [
-        "NONE",
-        "ASCEND",
-        "DESCEND"
-      ]
-    },
-    "RangeRequestSortTarget": {
-      "type": "string",
-      "default": "KEY",
-      "enum": [
-        "KEY",
-        "VERSION",
-        "CREATE",
-        "MOD",
-        "VALUE"
-      ]
-    },
-    "WatchCreateRequestFilterType": {
-      "description": " - NOPUT: filter out put event.\n - NODELETE: filter out delete event.",
-      "type": "string",
-      "default": "NOPUT",
-      "enum": [
-        "NOPUT",
-        "NODELETE"
-      ]
-    },
-    "authpbPermission": {
-      "type": "object",
-      "title": "Permission is a single entity",
-      "properties": {
-        "key": {
-          "type": "string",
-          "format": "byte"
-        },
-        "permType": {
-          "$ref": "#/definitions/authpbPermissionType"
-        },
-        "range_end": {
-          "type": "string",
-          "format": "byte"
-        }
-      }
-    },
-    "authpbPermissionType": {
-      "type": "string",
-      "default": "READ",
-      "enum": [
-        "READ",
-        "WRITE",
-        "READWRITE"
-      ]
-    },
-    "etcdserverpbAlarmMember": {
-      "type": "object",
-      "properties": {
-        "alarm": {
-          "description": "alarm is the type of alarm which has been raised.",
-          "$ref": "#/definitions/etcdserverpbAlarmType"
-        },
-        "memberID": {
-          "description": "memberID is the ID of the member associated with the raised alarm.",
-          "type": "string",
-          "format": "uint64"
-        }
-      }
-    },
-    "etcdserverpbAlarmRequest": {
-      "type": "object",
-      "properties": {
-        "action": {
-          "description": "action is the kind of alarm request to issue. The action\nmay GET alarm statuses, ACTIVATE an alarm, or DEACTIVATE a\nraised alarm.",
-          "$ref": "#/definitions/AlarmRequestAlarmAction"
-        },
-        "alarm": {
-          "description": "alarm is the type of alarm to consider for this request.",
-          "$ref": "#/definitions/etcdserverpbAlarmType"
-        },
-        "memberID": {
-          "description": "memberID is the ID of the member associated with the alarm. If memberID is 0, the\nalarm request covers all members.",
-          "type": "string",
-          "format": "uint64"
-        }
-      }
-    },
-    "etcdserverpbAlarmResponse": {
-      "type": "object",
-      "properties": {
-        "alarms": {
-          "description": "alarms is a list of alarms associated with the alarm request.",
-          "type": "array",
-          "items": {
-            "$ref": "#/definitions/etcdserverpbAlarmMember"
-          }
-        },
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        }
-      }
-    },
-    "etcdserverpbAlarmType": {
-      "type": "string",
-      "default": "NONE",
-      "enum": [
-        "NONE",
-        "NOSPACE",
-        "CORRUPT"
-      ]
-    },
-    "etcdserverpbAuthDisableRequest": {
-      "type": "object"
-    },
-    "etcdserverpbAuthDisableResponse": {
-      "type": "object",
-      "properties": {
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        }
-      }
-    },
-    "etcdserverpbAuthEnableRequest": {
-      "type": "object"
-    },
-    "etcdserverpbAuthEnableResponse": {
-      "type": "object",
-      "properties": {
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        }
-      }
-    },
-    "etcdserverpbAuthRoleAddRequest": {
-      "type": "object",
-      "properties": {
-        "name": {
-          "description": "name is the name of the role to add to the authentication system.",
-          "type": "string"
-        }
-      }
-    },
-    "etcdserverpbAuthRoleAddResponse": {
-      "type": "object",
-      "properties": {
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        }
-      }
-    },
-    "etcdserverpbAuthRoleDeleteRequest": {
-      "type": "object",
-      "properties": {
-        "role": {
-          "type": "string"
-        }
-      }
-    },
-    "etcdserverpbAuthRoleDeleteResponse": {
-      "type": "object",
-      "properties": {
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        }
-      }
-    },
-    "etcdserverpbAuthRoleGetRequest": {
-      "type": "object",
-      "properties": {
-        "role": {
-          "type": "string"
-        }
-      }
-    },
-    "etcdserverpbAuthRoleGetResponse": {
-      "type": "object",
-      "properties": {
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        },
-        "perm": {
-          "type": "array",
-          "items": {
-            "$ref": "#/definitions/authpbPermission"
-          }
-        }
-      }
-    },
-    "etcdserverpbAuthRoleGrantPermissionRequest": {
-      "type": "object",
-      "properties": {
-        "name": {
-          "description": "name is the name of the role which will be granted the permission.",
-          "type": "string"
-        },
-        "perm": {
-          "description": "perm is the permission to grant to the role.",
-          "$ref": "#/definitions/authpbPermission"
-        }
-      }
-    },
-    "etcdserverpbAuthRoleGrantPermissionResponse": {
-      "type": "object",
-      "properties": {
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        }
-      }
-    },
-    "etcdserverpbAuthRoleListRequest": {
-      "type": "object"
-    },
-    "etcdserverpbAuthRoleListResponse": {
-      "type": "object",
-      "properties": {
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        },
-        "roles": {
-          "type": "array",
-          "items": {
-            "type": "string"
-          }
-        }
-      }
-    },
-    "etcdserverpbAuthRoleRevokePermissionRequest": {
-      "type": "object",
-      "properties": {
-        "key": {
-          "type": "string",
-          "format": "byte"
-        },
-        "range_end": {
-          "type": "string",
-          "format": "byte"
-        },
-        "role": {
-          "type": "string"
-        }
-      }
-    },
-    "etcdserverpbAuthRoleRevokePermissionResponse": {
-      "type": "object",
-      "properties": {
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        }
-      }
-    },
-    "etcdserverpbAuthUserAddRequest": {
-      "type": "object",
-      "properties": {
-        "name": {
-          "type": "string"
-        },
-        "password": {
-          "type": "string"
-        }
-      }
-    },
-    "etcdserverpbAuthUserAddResponse": {
-      "type": "object",
-      "properties": {
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        }
-      }
-    },
-    "etcdserverpbAuthUserChangePasswordRequest": {
-      "type": "object",
-      "properties": {
-        "name": {
-          "description": "name is the name of the user whose password is being changed.",
-          "type": "string"
-        },
-        "password": {
-          "description": "password is the new password for the user.",
-          "type": "string"
-        }
-      }
-    },
-    "etcdserverpbAuthUserChangePasswordResponse": {
-      "type": "object",
-      "properties": {
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        }
-      }
-    },
-    "etcdserverpbAuthUserDeleteRequest": {
-      "type": "object",
-      "properties": {
-        "name": {
-          "description": "name is the name of the user to delete.",
-          "type": "string"
-        }
-      }
-    },
-    "etcdserverpbAuthUserDeleteResponse": {
-      "type": "object",
-      "properties": {
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        }
-      }
-    },
-    "etcdserverpbAuthUserGetRequest": {
-      "type": "object",
-      "properties": {
-        "name": {
-          "type": "string"
-        }
-      }
-    },
-    "etcdserverpbAuthUserGetResponse": {
-      "type": "object",
-      "properties": {
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        },
-        "roles": {
-          "type": "array",
-          "items": {
-            "type": "string"
-          }
-        }
-      }
-    },
-    "etcdserverpbAuthUserGrantRoleRequest": {
-      "type": "object",
-      "properties": {
-        "role": {
-          "description": "role is the name of the role to grant to the user.",
-          "type": "string"
-        },
-        "user": {
-          "description": "user is the name of the user which should be granted a given role.",
-          "type": "string"
-        }
-      }
-    },
-    "etcdserverpbAuthUserGrantRoleResponse": {
-      "type": "object",
-      "properties": {
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        }
-      }
-    },
-    "etcdserverpbAuthUserListRequest": {
-      "type": "object"
-    },
-    "etcdserverpbAuthUserListResponse": {
-      "type": "object",
-      "properties": {
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        },
-        "users": {
-          "type": "array",
-          "items": {
-            "type": "string"
-          }
-        }
-      }
-    },
-    "etcdserverpbAuthUserRevokeRoleRequest": {
-      "type": "object",
-      "properties": {
-        "name": {
-          "type": "string"
-        },
-        "role": {
-          "type": "string"
-        }
-      }
-    },
-    "etcdserverpbAuthUserRevokeRoleResponse": {
-      "type": "object",
-      "properties": {
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        }
-      }
-    },
-    "etcdserverpbAuthenticateRequest": {
-      "type": "object",
-      "properties": {
-        "name": {
-          "type": "string"
-        },
-        "password": {
-          "type": "string"
-        }
-      }
-    },
-    "etcdserverpbAuthenticateResponse": {
-      "type": "object",
-      "properties": {
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        },
-        "token": {
-          "type": "string",
-          "title": "token is an authorized token that can be used in succeeding RPCs"
-        }
-      }
-    },
-    "etcdserverpbCompactionRequest": {
-      "description": "CompactionRequest compacts the key-value store up to a given revision. All superseded keys\nwith a revision less than the compaction revision will be removed.",
-      "type": "object",
-      "properties": {
-        "physical": {
-          "description": "physical is set so the RPC will wait until the compaction is physically\napplied to the local database such that compacted entries are totally\nremoved from the backend database.",
-          "type": "boolean",
-          "format": "boolean"
-        },
-        "revision": {
-          "description": "revision is the key-value store revision for the compaction operation.",
-          "type": "string",
-          "format": "int64"
-        }
-      }
-    },
-    "etcdserverpbCompactionResponse": {
-      "type": "object",
-      "properties": {
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        }
-      }
-    },
-    "etcdserverpbCompare": {
-      "type": "object",
-      "properties": {
-        "create_revision": {
-          "type": "string",
-          "format": "int64",
-          "title": "create_revision is the creation revision of the given key"
-        },
-        "key": {
-          "description": "key is the subject key for the comparison operation.",
-          "type": "string",
-          "format": "byte"
-        },
-        "lease": {
-          "description": "lease is the lease id of the given key.",
-          "type": "string",
-          "format": "int64"
-        },
-        "mod_revision": {
-          "description": "mod_revision is the last modified revision of the given key.",
-          "type": "string",
-          "format": "int64"
-        },
-        "range_end": {
-          "description": "range_end compares the given target to all keys in the range [key, range_end).\nSee RangeRequest for more details on key ranges.",
-          "type": "string",
-          "format": "byte"
-        },
-        "result": {
-          "description": "result is logical comparison operation for this comparison.",
-          "$ref": "#/definitions/CompareCompareResult"
-        },
-        "target": {
-          "description": "target is the key-value field to inspect for the comparison.",
-          "$ref": "#/definitions/CompareCompareTarget"
-        },
-        "value": {
-          "description": "value is the value of the given key, in bytes.",
-          "type": "string",
-          "format": "byte"
-        },
-        "version": {
-          "type": "string",
-          "format": "int64",
-          "title": "version is the version of the given key"
-        }
-      }
-    },
-    "etcdserverpbDefragmentRequest": {
-      "type": "object"
-    },
-    "etcdserverpbDefragmentResponse": {
-      "type": "object",
-      "properties": {
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        }
-      }
-    },
-    "etcdserverpbDeleteRangeRequest": {
-      "type": "object",
-      "properties": {
-        "key": {
-          "description": "key is the first key to delete in the range.",
-          "type": "string",
-          "format": "byte"
-        },
-        "prev_kv": {
-          "description": "If prev_kv is set, etcd gets the previous key-value pairs before deleting it.\nThe previous key-value pairs will be returned in the delete response.",
-          "type": "boolean",
-          "format": "boolean"
-        },
-        "range_end": {
-          "description": "range_end is the key following the last key to delete for the range [key, range_end).\nIf range_end is not given, the range is defined to contain only the key argument.\nIf range_end is one bit larger than the given key, then the range is all the keys\nwith the prefix (the given key).\nIf range_end is '\\0', the range is all keys greater than or equal to the key argument.",
-          "type": "string",
-          "format": "byte"
-        }
-      }
-    },
-    "etcdserverpbDeleteRangeResponse": {
-      "type": "object",
-      "properties": {
-        "deleted": {
-          "description": "deleted is the number of keys deleted by the delete range request.",
-          "type": "string",
-          "format": "int64"
-        },
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        },
-        "prev_kvs": {
-          "description": "if prev_kv is set in the request, the previous key-value pairs will be returned.",
-          "type": "array",
-          "items": {
-            "$ref": "#/definitions/mvccpbKeyValue"
-          }
-        }
-      }
-    },
-    "etcdserverpbHashKVRequest": {
-      "type": "object",
-      "properties": {
-        "revision": {
-          "description": "revision is the key-value store revision for the hash operation.",
-          "type": "string",
-          "format": "int64"
-        }
-      }
-    },
-    "etcdserverpbHashKVResponse": {
-      "type": "object",
-      "properties": {
-        "compact_revision": {
-          "description": "compact_revision is the compacted revision of key-value store when hash begins.",
-          "type": "string",
-          "format": "int64"
-        },
-        "hash": {
-          "description": "hash is the hash value computed from the responding member's MVCC keys up to a given revision.",
-          "type": "integer",
-          "format": "int64"
-        },
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        }
-      }
-    },
-    "etcdserverpbHashRequest": {
-      "type": "object"
-    },
-    "etcdserverpbHashResponse": {
-      "type": "object",
-      "properties": {
-        "hash": {
-          "description": "hash is the hash value computed from the responding member's KV's backend.",
-          "type": "integer",
-          "format": "int64"
-        },
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        }
-      }
-    },
-    "etcdserverpbLeaseGrantRequest": {
-      "type": "object",
-      "properties": {
-        "ID": {
-          "description": "ID is the requested ID for the lease. If ID is set to 0, the lessor chooses an ID.",
-          "type": "string",
-          "format": "int64"
-        },
-        "TTL": {
-          "description": "TTL is the advisory time-to-live in seconds. Expired lease will return -1.",
-          "type": "string",
-          "format": "int64"
-        }
-      }
-    },
-    "etcdserverpbLeaseGrantResponse": {
-      "type": "object",
-      "properties": {
-        "ID": {
-          "description": "ID is the lease ID for the granted lease.",
-          "type": "string",
-          "format": "int64"
-        },
-        "TTL": {
-          "description": "TTL is the server chosen lease time-to-live in seconds.",
-          "type": "string",
-          "format": "int64"
-        },
-        "error": {
-          "type": "string"
-        },
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        }
-      }
-    },
-    "etcdserverpbLeaseKeepAliveRequest": {
-      "type": "object",
-      "properties": {
-        "ID": {
-          "description": "ID is the lease ID for the lease to keep alive.",
-          "type": "string",
-          "format": "int64"
-        }
-      }
-    },
-    "etcdserverpbLeaseKeepAliveResponse": {
-      "type": "object",
-      "properties": {
-        "ID": {
-          "description": "ID is the lease ID from the keep alive request.",
-          "type": "string",
-          "format": "int64"
-        },
-        "TTL": {
-          "description": "TTL is the new time-to-live for the lease.",
-          "type": "string",
-          "format": "int64"
-        },
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        }
-      }
-    },
-    "etcdserverpbLeaseLeasesRequest": {
-      "type": "object"
-    },
-    "etcdserverpbLeaseLeasesResponse": {
-      "type": "object",
-      "properties": {
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        },
-        "leases": {
-          "type": "array",
-          "items": {
-            "$ref": "#/definitions/etcdserverpbLeaseStatus"
-          }
-        }
-      }
-    },
-    "etcdserverpbLeaseRevokeRequest": {
-      "type": "object",
-      "properties": {
-        "ID": {
-          "description": "ID is the lease ID to revoke. When the ID is revoked, all associated keys will be deleted.",
-          "type": "string",
-          "format": "int64"
-        }
-      }
-    },
-    "etcdserverpbLeaseRevokeResponse": {
-      "type": "object",
-      "properties": {
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        }
-      }
-    },
-    "etcdserverpbLeaseStatus": {
-      "type": "object",
-      "properties": {
-        "ID": {
-          "type": "string",
-          "format": "int64"
-        }
-      }
-    },
-    "etcdserverpbLeaseTimeToLiveRequest": {
-      "type": "object",
-      "properties": {
-        "ID": {
-          "description": "ID is the lease ID for the lease.",
-          "type": "string",
-          "format": "int64"
-        },
-        "keys": {
-          "description": "keys is true to query all the keys attached to this lease.",
-          "type": "boolean",
-          "format": "boolean"
-        }
-      }
-    },
-    "etcdserverpbLeaseTimeToLiveResponse": {
-      "type": "object",
-      "properties": {
-        "ID": {
-          "description": "ID is the lease ID from the keep alive request.",
-          "type": "string",
-          "format": "int64"
-        },
-        "TTL": {
-          "description": "TTL is the remaining TTL in seconds for the lease; the lease will expire in under TTL+1 seconds.",
-          "type": "string",
-          "format": "int64"
-        },
-        "grantedTTL": {
-          "description": "GrantedTTL is the initial granted time in seconds upon lease creation/renewal.",
-          "type": "string",
-          "format": "int64"
-        },
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        },
-        "keys": {
-          "description": "Keys is the list of keys attached to this lease.",
-          "type": "array",
-          "items": {
-            "type": "string",
-            "format": "byte"
-          }
-        }
-      }
-    },
-    "etcdserverpbMember": {
-      "type": "object",
-      "properties": {
-        "ID": {
-          "description": "ID is the member ID for this member.",
-          "type": "string",
-          "format": "uint64"
-        },
-        "clientURLs": {
-          "description": "clientURLs is the list of URLs the member exposes to clients for communication. If the member is not started, clientURLs will be empty.",
-          "type": "array",
-          "items": {
-            "type": "string"
-          }
-        },
-        "name": {
-          "description": "name is the human-readable name of the member. If the member is not started, the name will be an empty string.",
-          "type": "string"
-        },
-        "peerURLs": {
-          "description": "peerURLs is the list of URLs the member exposes to the cluster for communication.",
-          "type": "array",
-          "items": {
-            "type": "string"
-          }
-        }
-      }
-    },
-    "etcdserverpbMemberAddRequest": {
-      "type": "object",
-      "properties": {
-        "peerURLs": {
-          "description": "peerURLs is the list of URLs the added member will use to communicate with the cluster.",
-          "type": "array",
-          "items": {
-            "type": "string"
-          }
-        }
-      }
-    },
-    "etcdserverpbMemberAddResponse": {
-      "type": "object",
-      "properties": {
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        },
-        "member": {
-          "description": "member is the member information for the added member.",
-          "$ref": "#/definitions/etcdserverpbMember"
-        },
-        "members": {
-          "description": "members is a list of all members after adding the new member.",
-          "type": "array",
-          "items": {
-            "$ref": "#/definitions/etcdserverpbMember"
-          }
-        }
-      }
-    },
-    "etcdserverpbMemberListRequest": {
-      "type": "object"
-    },
-    "etcdserverpbMemberListResponse": {
-      "type": "object",
-      "properties": {
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        },
-        "members": {
-          "description": "members is a list of all members associated with the cluster.",
-          "type": "array",
-          "items": {
-            "$ref": "#/definitions/etcdserverpbMember"
-          }
-        }
-      }
-    },
-    "etcdserverpbMemberRemoveRequest": {
-      "type": "object",
-      "properties": {
-        "ID": {
-          "description": "ID is the member ID of the member to remove.",
-          "type": "string",
-          "format": "uint64"
-        }
-      }
-    },
-    "etcdserverpbMemberRemoveResponse": {
-      "type": "object",
-      "properties": {
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        },
-        "members": {
-          "description": "members is a list of all members after removing the member.",
-          "type": "array",
-          "items": {
-            "$ref": "#/definitions/etcdserverpbMember"
-          }
-        }
-      }
-    },
-    "etcdserverpbMemberUpdateRequest": {
-      "type": "object",
-      "properties": {
-        "ID": {
-          "description": "ID is the member ID of the member to update.",
-          "type": "string",
-          "format": "uint64"
-        },
-        "peerURLs": {
-          "description": "peerURLs is the new list of URLs the member will use to communicate with the cluster.",
-          "type": "array",
-          "items": {
-            "type": "string"
-          }
-        }
-      }
-    },
-    "etcdserverpbMemberUpdateResponse": {
-      "type": "object",
-      "properties": {
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        },
-        "members": {
-          "description": "members is a list of all members after updating the member.",
-          "type": "array",
-          "items": {
-            "$ref": "#/definitions/etcdserverpbMember"
-          }
-        }
-      }
-    },
-    "etcdserverpbMoveLeaderRequest": {
-      "type": "object",
-      "properties": {
-        "targetID": {
-          "description": "targetID is the node ID for the new leader.",
-          "type": "string",
-          "format": "uint64"
-        }
-      }
-    },
-    "etcdserverpbMoveLeaderResponse": {
-      "type": "object",
-      "properties": {
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        }
-      }
-    },
-    "etcdserverpbPutRequest": {
-      "type": "object",
-      "properties": {
-        "ignore_lease": {
-          "description": "If ignore_lease is set, etcd updates the key using its current lease.\nReturns an error if the key does not exist.",
-          "type": "boolean",
-          "format": "boolean"
-        },
-        "ignore_value": {
-          "description": "If ignore_value is set, etcd updates the key using its current value.\nReturns an error if the key does not exist.",
-          "type": "boolean",
-          "format": "boolean"
-        },
-        "key": {
-          "description": "key is the key, in bytes, to put into the key-value store.",
-          "type": "string",
-          "format": "byte"
-        },
-        "lease": {
-          "description": "lease is the lease ID to associate with the key in the key-value store. A lease\nvalue of 0 indicates no lease.",
-          "type": "string",
-          "format": "int64"
-        },
-        "prev_kv": {
-          "description": "If prev_kv is set, etcd gets the previous key-value pair before changing it.\nThe previous key-value pair will be returned in the put response.",
-          "type": "boolean",
-          "format": "boolean"
-        },
-        "value": {
-          "description": "value is the value, in bytes, to associate with the key in the key-value store.",
-          "type": "string",
-          "format": "byte"
-        }
-      }
-    },
-    "etcdserverpbPutResponse": {
-      "type": "object",
-      "properties": {
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        },
-        "prev_kv": {
-          "description": "if prev_kv is set in the request, the previous key-value pair will be returned.",
-          "$ref": "#/definitions/mvccpbKeyValue"
-        }
-      }
-    },
-    "etcdserverpbRangeRequest": {
-      "type": "object",
-      "properties": {
-        "count_only": {
-          "description": "count_only when set returns only the count of the keys in the range.",
-          "type": "boolean",
-          "format": "boolean"
-        },
-        "key": {
-          "description": "key is the first key for the range. If range_end is not given, the request only looks up key.",
-          "type": "string",
-          "format": "byte"
-        },
-        "keys_only": {
-          "description": "keys_only when set returns only the keys and not the values.",
-          "type": "boolean",
-          "format": "boolean"
-        },
-        "limit": {
-          "description": "limit is a limit on the number of keys returned for the request. When limit is set to 0,\nit is treated as no limit.",
-          "type": "string",
-          "format": "int64"
-        },
-        "max_create_revision": {
-          "description": "max_create_revision is the upper bound for returned key create revisions; all keys with\ngreater create revisions will be filtered away.",
-          "type": "string",
-          "format": "int64"
-        },
-        "max_mod_revision": {
-          "description": "max_mod_revision is the upper bound for returned key mod revisions; all keys with\ngreater mod revisions will be filtered away.",
-          "type": "string",
-          "format": "int64"
-        },
-        "min_create_revision": {
-          "description": "min_create_revision is the lower bound for returned key create revisions; all keys with\nlesser create revisions will be filtered away.",
-          "type": "string",
-          "format": "int64"
-        },
-        "min_mod_revision": {
-          "description": "min_mod_revision is the lower bound for returned key mod revisions; all keys with\nlesser mod revisions will be filtered away.",
-          "type": "string",
-          "format": "int64"
-        },
-        "range_end": {
-          "description": "range_end is the upper bound on the requested range [key, range_end).\nIf range_end is '\\0', the range is all keys \u003e= key.\nIf range_end is key plus one (e.g., \"aa\"+1 == \"ab\", \"a\\xff\"+1 == \"b\"),\nthen the range request gets all keys prefixed with key.\nIf both key and range_end are '\\0', then the range request returns all keys.",
-          "type": "string",
-          "format": "byte"
-        },
-        "revision": {
-          "description": "revision is the point-in-time of the key-value store to use for the range.\nIf revision is less or equal to zero, the range is over the newest key-value store.\nIf the revision has been compacted, ErrCompacted is returned as a response.",
-          "type": "string",
-          "format": "int64"
-        },
-        "serializable": {
-          "description": "serializable sets the range request to use serializable member-local reads.\nRange requests are linearizable by default; linearizable requests have higher\nlatency and lower throughput than serializable requests but reflect the current\nconsensus of the cluster. For better performance, in exchange for possible stale reads,\na serializable range request is served locally without needing to reach consensus\nwith other nodes in the cluster.",
-          "type": "boolean",
-          "format": "boolean"
-        },
-        "sort_order": {
-          "description": "sort_order is the order for returned sorted results.",
-          "$ref": "#/definitions/RangeRequestSortOrder"
-        },
-        "sort_target": {
-          "description": "sort_target is the key-value field to use for sorting.",
-          "$ref": "#/definitions/RangeRequestSortTarget"
-        }
-      }
-    },
-    "etcdserverpbRangeResponse": {
-      "type": "object",
-      "properties": {
-        "count": {
-          "description": "count is set to the number of keys within the range when requested.",
-          "type": "string",
-          "format": "int64"
-        },
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        },
-        "kvs": {
-          "description": "kvs is the list of key-value pairs matched by the range request.\nkvs is empty when count is requested.",
-          "type": "array",
-          "items": {
-            "$ref": "#/definitions/mvccpbKeyValue"
-          }
-        },
-        "more": {
-          "description": "more indicates if there are more keys to return in the requested range.",
-          "type": "boolean",
-          "format": "boolean"
-        }
-      }
-    },
-    "etcdserverpbRequestOp": {
-      "type": "object",
-      "properties": {
-        "request_delete_range": {
-          "$ref": "#/definitions/etcdserverpbDeleteRangeRequest"
-        },
-        "request_put": {
-          "$ref": "#/definitions/etcdserverpbPutRequest"
-        },
-        "request_range": {
-          "$ref": "#/definitions/etcdserverpbRangeRequest"
-        },
-        "request_txn": {
-          "$ref": "#/definitions/etcdserverpbTxnRequest"
-        }
-      }
-    },
-    "etcdserverpbResponseHeader": {
-      "type": "object",
-      "properties": {
-        "cluster_id": {
-          "description": "cluster_id is the ID of the cluster which sent the response.",
-          "type": "string",
-          "format": "uint64"
-        },
-        "member_id": {
-          "description": "member_id is the ID of the member which sent the response.",
-          "type": "string",
-          "format": "uint64"
-        },
-        "raft_term": {
-          "description": "raft_term is the raft term when the request was applied.",
-          "type": "string",
-          "format": "uint64"
-        },
-        "revision": {
-          "description": "revision is the key-value store revision when the request was applied.\nFor watch progress responses, the header.revision indicates progress. All future events\nrecieved in this stream are guaranteed to have a higher revision number than the\nheader.revision number.",
-          "type": "string",
-          "format": "int64"
-        }
-      }
-    },
-    "etcdserverpbResponseOp": {
-      "type": "object",
-      "properties": {
-        "response_delete_range": {
-          "$ref": "#/definitions/etcdserverpbDeleteRangeResponse"
-        },
-        "response_put": {
-          "$ref": "#/definitions/etcdserverpbPutResponse"
-        },
-        "response_range": {
-          "$ref": "#/definitions/etcdserverpbRangeResponse"
-        },
-        "response_txn": {
-          "$ref": "#/definitions/etcdserverpbTxnResponse"
-        }
-      }
-    },
-    "etcdserverpbSnapshotRequest": {
-      "type": "object"
-    },
-    "etcdserverpbSnapshotResponse": {
-      "type": "object",
-      "properties": {
-        "blob": {
-          "description": "blob contains the next chunk of the snapshot in the snapshot stream.",
-          "type": "string",
-          "format": "byte"
-        },
-        "header": {
-          "description": "header has the current key-value store information. The first header in the snapshot\nstream indicates the point in time of the snapshot.",
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        },
-        "remaining_bytes": {
-          "type": "string",
-          "format": "uint64",
-          "title": "remaining_bytes is the number of blob bytes to be sent after this message"
-        }
-      }
-    },
-    "etcdserverpbStatusRequest": {
-      "type": "object"
-    },
-    "etcdserverpbStatusResponse": {
-      "type": "object",
-      "properties": {
-        "dbSize": {
-          "description": "dbSize is the size of the backend database physically allocated, in bytes, of the responding member.",
-          "type": "string",
-          "format": "int64"
-        },
-        "dbSizeInUse": {
-          "description": "dbSizeInUse is the size of the backend database logically in use, in bytes, of the responding member.",
-          "type": "string",
-          "format": "int64"
-        },
-        "errors": {
-          "description": "errors contains alarm/health information and status.",
-          "type": "array",
-          "items": {
-            "type": "string"
-          }
-        },
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        },
-        "leader": {
-          "description": "leader is the member ID which the responding member believes is the current leader.",
-          "type": "string",
-          "format": "uint64"
-        },
-        "raftAppliedIndex": {
-          "description": "raftAppliedIndex is the current raft applied index of the responding member.",
-          "type": "string",
-          "format": "uint64"
-        },
-        "raftIndex": {
-          "description": "raftIndex is the current raft committed index of the responding member.",
-          "type": "string",
-          "format": "uint64"
-        },
-        "raftTerm": {
-          "description": "raftTerm is the current raft term of the responding member.",
-          "type": "string",
-          "format": "uint64"
-        },
-        "version": {
-          "description": "version is the cluster protocol version used by the responding member.",
-          "type": "string"
-        }
-      }
-    },
-    "etcdserverpbTxnRequest": {
-      "description": "From google paxosdb paper:\nOur implementation hinges around a powerful primitive which we call MultiOp. All other database\noperations except for iteration are implemented as a single call to MultiOp. A MultiOp is applied atomically\nand consists of three components:\n1. A list of tests called guard. Each test in guard checks a single entry in the database. It may check\nfor the absence or presence of a value, or compare with a given value. Two different tests in the guard\nmay apply to the same or different entries in the database. All tests in the guard are applied and\nMultiOp returns the results. If all tests are true, MultiOp executes t op (see item 2 below), otherwise\nit executes f op (see item 3 below).\n2. A list of database operations called t op. Each operation in the list is either an insert, delete, or\nlookup operation, and applies to a single database entry. Two different operations in the list may apply\nto the same or different entries in the database. These operations are executed\nif guard evaluates to\ntrue.\n3. A list of database operations called f op. Like t op, but executed if guard evaluates to false.",
-      "type": "object",
-      "properties": {
-        "compare": {
-          "description": "compare is a list of predicates representing a conjunction of terms.\nIf the comparisons succeed, then the success requests will be processed in order,\nand the response will contain their respective responses in order.\nIf the comparisons fail, then the failure requests will be processed in order,\nand the response will contain their respective responses in order.",
-          "type": "array",
-          "items": {
-            "$ref": "#/definitions/etcdserverpbCompare"
-          }
-        },
-        "failure": {
-          "description": "failure is a list of requests which will be applied when compare evaluates to false.",
-          "type": "array",
-          "items": {
-            "$ref": "#/definitions/etcdserverpbRequestOp"
-          }
-        },
-        "success": {
-          "description": "success is a list of requests which will be applied when compare evaluates to true.",
-          "type": "array",
-          "items": {
-            "$ref": "#/definitions/etcdserverpbRequestOp"
-          }
-        }
-      }
-    },
-    "etcdserverpbTxnResponse": {
-      "type": "object",
-      "properties": {
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        },
-        "responses": {
-          "description": "responses is a list of responses corresponding to the results from applying\nsuccess if succeeded is true or failure if succeeded is false.",
-          "type": "array",
-          "items": {
-            "$ref": "#/definitions/etcdserverpbResponseOp"
-          }
-        },
-        "succeeded": {
-          "description": "succeeded is set to true if the compare evaluated to true or false otherwise.",
-          "type": "boolean",
-          "format": "boolean"
-        }
-      }
-    },
-    "etcdserverpbWatchCancelRequest": {
-      "type": "object",
-      "properties": {
-        "watch_id": {
-          "description": "watch_id is the watcher id to cancel so that no more events are transmitted.",
-          "type": "string",
-          "format": "int64"
-        }
-      }
-    },
-    "etcdserverpbWatchCreateRequest": {
-      "type": "object",
-      "properties": {
-        "filters": {
-          "description": "filters filter the events at server side before it sends back to the watcher.",
-          "type": "array",
-          "items": {
-            "$ref": "#/definitions/WatchCreateRequestFilterType"
-          }
-        },
-        "fragment": {
-          "description": "fragment enables splitting large revisions into multiple watch responses.",
-          "type": "boolean",
-          "format": "boolean"
-        },
-        "key": {
-          "description": "key is the key to register for watching.",
-          "type": "string",
-          "format": "byte"
-        },
-        "prev_kv": {
-          "description": "If prev_kv is set, created watcher gets the previous KV before the event happens.\nIf the previous KV is already compacted, nothing will be returned.",
-          "type": "boolean",
-          "format": "boolean"
-        },
-        "progress_notify": {
-          "description": "progress_notify is set so that the etcd server will periodically send a WatchResponse with\nno events to the new watcher if there are no recent events. It is useful when clients\nwish to recover a disconnected watcher starting from a recent known revision.\nThe etcd server may decide how often it will send notifications based on current load.",
-          "type": "boolean",
-          "format": "boolean"
-        },
-        "range_end": {
-          "description": "range_end is the end of the range [key, range_end) to watch. If range_end is not given,\nonly the key argument is watched. If range_end is equal to '\\0', all keys greater than\nor equal to the key argument are watched.\nIf the range_end is one bit larger than the given key,\nthen all keys with the prefix (the given key) will be watched.",
-          "type": "string",
-          "format": "byte"
-        },
-        "start_revision": {
-          "description": "start_revision is an optional revision to watch from (inclusive). No start_revision is \"now\".",
-          "type": "string",
-          "format": "int64"
-        },
-        "watch_id": {
-          "description": "If watch_id is provided and non-zero, it will be assigned to this watcher.\nSince creating a watcher in etcd is not a synchronous operation,\nthis can be used ensure that ordering is correct when creating multiple\nwatchers on the same stream. Creating a watcher with an ID already in\nuse on the stream will cause an error to be returned.",
-          "type": "string",
-          "format": "int64"
-        }
-      }
-    },
-    "etcdserverpbWatchProgressRequest": {
-      "description": "Requests the a watch stream progress status be sent in the watch response stream as soon as\npossible.",
-      "type": "object"
-    },
-    "etcdserverpbWatchRequest": {
-      "type": "object",
-      "properties": {
-        "cancel_request": {
-          "$ref": "#/definitions/etcdserverpbWatchCancelRequest"
-        },
-        "create_request": {
-          "$ref": "#/definitions/etcdserverpbWatchCreateRequest"
-        },
-        "progress_request": {
-          "$ref": "#/definitions/etcdserverpbWatchProgressRequest"
-        }
-      }
-    },
-    "etcdserverpbWatchResponse": {
-      "type": "object",
-      "properties": {
-        "cancel_reason": {
-          "description": "cancel_reason indicates the reason for canceling the watcher.",
-          "type": "string"
-        },
-        "canceled": {
-          "description": "canceled is set to true if the response is for a cancel watch request.\nNo further events will be sent to the canceled watcher.",
-          "type": "boolean",
-          "format": "boolean"
-        },
-        "compact_revision": {
-          "description": "compact_revision is set to the minimum index if a watcher tries to watch\nat a compacted index.\n\nThis happens when creating a watcher at a compacted revision or the watcher cannot\ncatch up with the progress of the key-value store.\n\nThe client should treat the watcher as canceled and should not try to create any\nwatcher with the same start_revision again.",
-          "type": "string",
-          "format": "int64"
-        },
-        "created": {
-          "description": "created is set to true if the response is for a create watch request.\nThe client should record the watch_id and expect to receive events for\nthe created watcher from the same stream.\nAll events sent to the created watcher will attach with the same watch_id.",
-          "type": "boolean",
-          "format": "boolean"
-        },
-        "events": {
-          "type": "array",
-          "items": {
-            "$ref": "#/definitions/mvccpbEvent"
-          }
-        },
-        "fragment": {
-          "description": "framgment is true if large watch response was split over multiple responses.",
-          "type": "boolean",
-          "format": "boolean"
-        },
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        },
-        "watch_id": {
-          "description": "watch_id is the ID of the watcher that corresponds to the response.",
-          "type": "string",
-          "format": "int64"
-        }
-      }
-    },
-    "mvccpbEvent": {
-      "type": "object",
-      "properties": {
-        "kv": {
-          "description": "kv holds the KeyValue for the event.\nA PUT event contains current kv pair.\nA PUT event with kv.Version=1 indicates the creation of a key.\nA DELETE/EXPIRE event contains the deleted key with\nits modification revision set to the revision of deletion.",
-          "$ref": "#/definitions/mvccpbKeyValue"
-        },
-        "prev_kv": {
-          "description": "prev_kv holds the key-value pair before the event happens.",
-          "$ref": "#/definitions/mvccpbKeyValue"
-        },
-        "type": {
-          "description": "type is the kind of event. If type is a PUT, it indicates\nnew data has been stored to the key. If type is a DELETE,\nit indicates the key was deleted.",
-          "$ref": "#/definitions/EventEventType"
-        }
-      }
-    },
-    "mvccpbKeyValue": {
-      "type": "object",
-      "properties": {
-        "create_revision": {
-          "description": "create_revision is the revision of last creation on this key.",
-          "type": "string",
-          "format": "int64"
-        },
-        "key": {
-          "description": "key is the key in bytes. An empty key is not allowed.",
-          "type": "string",
-          "format": "byte"
-        },
-        "lease": {
-          "description": "lease is the ID of the lease that attached to key.\nWhen the attached lease expires, the key will be deleted.\nIf lease is 0, then no lease is attached to the key.",
-          "type": "string",
-          "format": "int64"
-        },
-        "mod_revision": {
-          "description": "mod_revision is the revision of last modification on this key.",
-          "type": "string",
-          "format": "int64"
-        },
-        "value": {
-          "description": "value is the value held by the key, in bytes.",
-          "type": "string",
-          "format": "byte"
-        },
-        "version": {
-          "description": "version is the version of the key. A deletion resets\nthe version to zero and any modification of the key\nincreases its version.",
-          "type": "string",
-          "format": "int64"
-        }
-      }
-    }
-  },
-  "securityDefinitions": {
-    "ApiKey": {
-      "type": "apiKey",
-      "name": "Authorization",
-      "in": "header"
-    }
-  },
-  "security": [
-    {
-      "ApiKey": []
-    }
-  ]
-}

+ 0 - 334
src/github.com/coreos/etcd/Documentation/dev-guide/apispec/swagger/v3election.swagger.json

@@ -1,334 +0,0 @@
-{
-  "swagger": "2.0",
-  "info": {
-    "title": "etcdserver/api/v3election/v3electionpb/v3election.proto",
-    "version": "version not set"
-  },
-  "schemes": [
-    "http",
-    "https"
-  ],
-  "consumes": [
-    "application/json"
-  ],
-  "produces": [
-    "application/json"
-  ],
-  "paths": {
-    "/v3/election/campaign": {
-      "post": {
-        "summary": "Campaign waits to acquire leadership in an election, returning a LeaderKey\nrepresenting the leadership if successful. The LeaderKey can then be used\nto issue new values on the election, transactionally guard API requests on\nleadership still being held, and resign from the election.",
-        "operationId": "Campaign",
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/v3electionpbCampaignResponse"
-            }
-          }
-        },
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/v3electionpbCampaignRequest"
-            }
-          }
-        ],
-        "tags": [
-          "Election"
-        ]
-      }
-    },
-    "/v3/election/leader": {
-      "post": {
-        "summary": "Leader returns the current election proclamation, if any.",
-        "operationId": "Leader",
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/v3electionpbLeaderResponse"
-            }
-          }
-        },
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/v3electionpbLeaderRequest"
-            }
-          }
-        ],
-        "tags": [
-          "Election"
-        ]
-      }
-    },
-    "/v3/election/observe": {
-      "post": {
-        "summary": "Observe streams election proclamations in-order as made by the election's\nelected leaders.",
-        "operationId": "Observe",
-        "responses": {
-          "200": {
-            "description": "A successful response.(streaming responses)",
-            "schema": {
-              "$ref": "#/definitions/v3electionpbLeaderResponse"
-            }
-          }
-        },
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/v3electionpbLeaderRequest"
-            }
-          }
-        ],
-        "tags": [
-          "Election"
-        ]
-      }
-    },
-    "/v3/election/proclaim": {
-      "post": {
-        "summary": "Proclaim updates the leader's posted value with a new value.",
-        "operationId": "Proclaim",
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/v3electionpbProclaimResponse"
-            }
-          }
-        },
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/v3electionpbProclaimRequest"
-            }
-          }
-        ],
-        "tags": [
-          "Election"
-        ]
-      }
-    },
-    "/v3/election/resign": {
-      "post": {
-        "summary": "Resign releases election leadership so other campaigners may acquire\nleadership on the election.",
-        "operationId": "Resign",
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/v3electionpbResignResponse"
-            }
-          }
-        },
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/v3electionpbResignRequest"
-            }
-          }
-        ],
-        "tags": [
-          "Election"
-        ]
-      }
-    }
-  },
-  "definitions": {
-    "etcdserverpbResponseHeader": {
-      "type": "object",
-      "properties": {
-        "cluster_id": {
-          "type": "string",
-          "format": "uint64",
-          "description": "cluster_id is the ID of the cluster which sent the response."
-        },
-        "member_id": {
-          "type": "string",
-          "format": "uint64",
-          "description": "member_id is the ID of the member which sent the response."
-        },
-        "revision": {
-          "type": "string",
-          "format": "int64",
-          "description": "revision is the key-value store revision when the request was applied.\nFor watch progress responses, the header.revision indicates progress. All future events\nrecieved in this stream are guaranteed to have a higher revision number than the\nheader.revision number."
-        },
-        "raft_term": {
-          "type": "string",
-          "format": "uint64",
-          "description": "raft_term is the raft term when the request was applied."
-        }
-      }
-    },
-    "mvccpbKeyValue": {
-      "type": "object",
-      "properties": {
-        "key": {
-          "type": "string",
-          "format": "byte",
-          "description": "key is the key in bytes. An empty key is not allowed."
-        },
-        "create_revision": {
-          "type": "string",
-          "format": "int64",
-          "description": "create_revision is the revision of last creation on this key."
-        },
-        "mod_revision": {
-          "type": "string",
-          "format": "int64",
-          "description": "mod_revision is the revision of last modification on this key."
-        },
-        "version": {
-          "type": "string",
-          "format": "int64",
-          "description": "version is the version of the key. A deletion resets\nthe version to zero and any modification of the key\nincreases its version."
-        },
-        "value": {
-          "type": "string",
-          "format": "byte",
-          "description": "value is the value held by the key, in bytes."
-        },
-        "lease": {
-          "type": "string",
-          "format": "int64",
-          "description": "lease is the ID of the lease that attached to key.\nWhen the attached lease expires, the key will be deleted.\nIf lease is 0, then no lease is attached to the key."
-        }
-      }
-    },
-    "v3electionpbCampaignRequest": {
-      "type": "object",
-      "properties": {
-        "name": {
-          "type": "string",
-          "format": "byte",
-          "description": "name is the election's identifier for the campaign."
-        },
-        "lease": {
-          "type": "string",
-          "format": "int64",
-          "description": "lease is the ID of the lease attached to leadership of the election. If the\nlease expires or is revoked before resigning leadership, then the\nleadership is transferred to the next campaigner, if any."
-        },
-        "value": {
-          "type": "string",
-          "format": "byte",
-          "description": "value is the initial proclaimed value set when the campaigner wins the\nelection."
-        }
-      }
-    },
-    "v3electionpbCampaignResponse": {
-      "type": "object",
-      "properties": {
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        },
-        "leader": {
-          "$ref": "#/definitions/v3electionpbLeaderKey",
-          "description": "leader describes the resources used for holding leadereship of the election."
-        }
-      }
-    },
-    "v3electionpbLeaderKey": {
-      "type": "object",
-      "properties": {
-        "name": {
-          "type": "string",
-          "format": "byte",
-          "description": "name is the election identifier that correponds to the leadership key."
-        },
-        "key": {
-          "type": "string",
-          "format": "byte",
-          "description": "key is an opaque key representing the ownership of the election. If the key\nis deleted, then leadership is lost."
-        },
-        "rev": {
-          "type": "string",
-          "format": "int64",
-          "description": "rev is the creation revision of the key. It can be used to test for ownership\nof an election during transactions by testing the key's creation revision\nmatches rev."
-        },
-        "lease": {
-          "type": "string",
-          "format": "int64",
-          "description": "lease is the lease ID of the election leader."
-        }
-      }
-    },
-    "v3electionpbLeaderRequest": {
-      "type": "object",
-      "properties": {
-        "name": {
-          "type": "string",
-          "format": "byte",
-          "description": "name is the election identifier for the leadership information."
-        }
-      }
-    },
-    "v3electionpbLeaderResponse": {
-      "type": "object",
-      "properties": {
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        },
-        "kv": {
-          "$ref": "#/definitions/mvccpbKeyValue",
-          "description": "kv is the key-value pair representing the latest leader update."
-        }
-      }
-    },
-    "v3electionpbProclaimRequest": {
-      "type": "object",
-      "properties": {
-        "leader": {
-          "$ref": "#/definitions/v3electionpbLeaderKey",
-          "description": "leader is the leadership hold on the election."
-        },
-        "value": {
-          "type": "string",
-          "format": "byte",
-          "description": "value is an update meant to overwrite the leader's current value."
-        }
-      }
-    },
-    "v3electionpbProclaimResponse": {
-      "type": "object",
-      "properties": {
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        }
-      }
-    },
-    "v3electionpbResignRequest": {
-      "type": "object",
-      "properties": {
-        "leader": {
-          "$ref": "#/definitions/v3electionpbLeaderKey",
-          "description": "leader is the leadership to relinquish by resignation."
-        }
-      }
-    },
-    "v3electionpbResignResponse": {
-      "type": "object",
-      "properties": {
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        }
-      }
-    }
-  }
-}

+ 0 - 146
src/github.com/coreos/etcd/Documentation/dev-guide/apispec/swagger/v3lock.swagger.json

@@ -1,146 +0,0 @@
-{
-  "swagger": "2.0",
-  "info": {
-    "title": "etcdserver/api/v3lock/v3lockpb/v3lock.proto",
-    "version": "version not set"
-  },
-  "schemes": [
-    "http",
-    "https"
-  ],
-  "consumes": [
-    "application/json"
-  ],
-  "produces": [
-    "application/json"
-  ],
-  "paths": {
-    "/v3/lock/lock": {
-      "post": {
-        "summary": "Lock acquires a distributed shared lock on a given named lock.\nOn success, it will return a unique key that exists so long as the\nlock is held by the caller. This key can be used in conjunction with\ntransactions to safely ensure updates to etcd only occur while holding\nlock ownership. The lock is held until Unlock is called on the key or the\nlease associate with the owner expires.",
-        "operationId": "Lock",
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/v3lockpbLockResponse"
-            }
-          }
-        },
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/v3lockpbLockRequest"
-            }
-          }
-        ],
-        "tags": [
-          "Lock"
-        ]
-      }
-    },
-    "/v3/lock/unlock": {
-      "post": {
-        "summary": "Unlock takes a key returned by Lock and releases the hold on lock. The\nnext Lock caller waiting for the lock will then be woken up and given\nownership of the lock.",
-        "operationId": "Unlock",
-        "responses": {
-          "200": {
-            "description": "A successful response.",
-            "schema": {
-              "$ref": "#/definitions/v3lockpbUnlockResponse"
-            }
-          }
-        },
-        "parameters": [
-          {
-            "name": "body",
-            "in": "body",
-            "required": true,
-            "schema": {
-              "$ref": "#/definitions/v3lockpbUnlockRequest"
-            }
-          }
-        ],
-        "tags": [
-          "Lock"
-        ]
-      }
-    }
-  },
-  "definitions": {
-    "etcdserverpbResponseHeader": {
-      "type": "object",
-      "properties": {
-        "cluster_id": {
-          "type": "string",
-          "format": "uint64",
-          "description": "cluster_id is the ID of the cluster which sent the response."
-        },
-        "member_id": {
-          "type": "string",
-          "format": "uint64",
-          "description": "member_id is the ID of the member which sent the response."
-        },
-        "revision": {
-          "type": "string",
-          "format": "int64",
-          "description": "revision is the key-value store revision when the request was applied.\nFor watch progress responses, the header.revision indicates progress. All future events\nrecieved in this stream are guaranteed to have a higher revision number than the\nheader.revision number."
-        },
-        "raft_term": {
-          "type": "string",
-          "format": "uint64",
-          "description": "raft_term is the raft term when the request was applied."
-        }
-      }
-    },
-    "v3lockpbLockRequest": {
-      "type": "object",
-      "properties": {
-        "name": {
-          "type": "string",
-          "format": "byte",
-          "description": "name is the identifier for the distributed shared lock to be acquired."
-        },
-        "lease": {
-          "type": "string",
-          "format": "int64",
-          "description": "lease is the ID of the lease that will be attached to ownership of the\nlock. If the lease expires or is revoked and currently holds the lock,\nthe lock is automatically released. Calls to Lock with the same lease will\nbe treated as a single acquisition; locking twice with the same lease is a\nno-op."
-        }
-      }
-    },
-    "v3lockpbLockResponse": {
-      "type": "object",
-      "properties": {
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        },
-        "key": {
-          "type": "string",
-          "format": "byte",
-          "description": "key is a key that will exist on etcd for the duration that the Lock caller\nowns the lock. Users should not modify this key or the lock may exhibit\nundefined behavior."
-        }
-      }
-    },
-    "v3lockpbUnlockRequest": {
-      "type": "object",
-      "properties": {
-        "key": {
-          "type": "string",
-          "format": "byte",
-          "description": "key is the lock ownership key granted by Lock."
-        }
-      }
-    },
-    "v3lockpbUnlockResponse": {
-      "type": "object",
-      "properties": {
-        "header": {
-          "$ref": "#/definitions/etcdserverpbResponseHeader"
-        }
-      }
-    }
-  }
-}

+ 0 - 9
src/github.com/coreos/etcd/Documentation/dev-guide/experimental_apis.md

@@ -1,9 +0,0 @@
----
-title: Experimental APIs and features
----
-
-For the most part, the etcd project is stable, but we are still moving fast! We believe in the release fast philosophy. We want to get early feedback on features still in development and stabilizing. Thus, there are, and will be more, experimental features and APIs. We plan to improve these features based on the early feedback from the community, or abandon them if there is little interest, in the next few releases. Please do not rely on any experimental features or APIs in production environment.
-
-## The current experimental API/features are:
-
-- [KV ordering](https://godoc.org/github.com/etcd-io/etcd/clientv3/ordering) wrapper. When an etcd client switches endpoints, responses to serializable reads may go backward in time if the new endpoint is lagging behind the rest of the cluster. The ordering wrapper caches the current cluster revision from response headers. If a response revision is less than the cached revision, the client selects another endpoint and reissues the read. Enable in grpcproxy with `--experimental-serializable-ordering`.

+ 0 - 67
src/github.com/coreos/etcd/Documentation/dev-guide/grpc_naming.md

@@ -1,67 +0,0 @@
----
-title: gRPC naming and discovery
----
-
-etcd provides a gRPC resolver to support an alternative name system that fetches endpoints from etcd for discovering gRPC services. The underlying mechanism is based on watching updates to keys prefixed with the service name.
-
-## Using etcd discovery with go-grpc
-
-The etcd client provides a gRPC resolver for resolving gRPC endpoints with an etcd backend. The resolver is initialized with an etcd client and given a target for resolution:
-
-```go
-import (
-	"go.etcd.io/etcd/clientv3"
-	etcdnaming "go.etcd.io/etcd/clientv3/naming"
-
-	"google.golang.org/grpc"
-)
-
-...
-
-cli, cerr := clientv3.NewFromURL("http://localhost:2379")
-r := &etcdnaming.GRPCResolver{Client: cli}
-b := grpc.RoundRobin(r)
-conn, gerr := grpc.Dial("my-service", grpc.WithBalancer(b), grpc.WithBlock(), ...)
-```
-
-## Managing service endpoints
-
-The etcd resolver treats all keys under the prefix of the resolution target following a "/" (e.g., "my-service/") with JSON-encoded go-grpc `naming.Update` values as potential service endpoints. Endpoints are added to the service by creating new keys and removed from the service by deleting keys.
-
-### Adding an endpoint
-
-New endpoints can be added to the service through `etcdctl`:
-
-```sh
-ETCDCTL_API=3 etcdctl put my-service/1.2.3.4 '{"Addr":"1.2.3.4","Metadata":"..."}'
-```
-
-The etcd client's `GRPCResolver.Update` method can also register new endpoints with a key matching the `Addr`:
-
-```go
-r.Update(context.TODO(), "my-service", naming.Update{Op: naming.Add, Addr: "1.2.3.4", Metadata: "..."})
-```
-
-### Deleting an endpoint
-
-Hosts can be deleted from the service through `etcdctl`:
-
-```sh
-ETCDCTL_API=3 etcdctl del my-service/1.2.3.4
-```
-
-The etcd client's `GRPCResolver.Update` method also supports deleting endpoints:
-
-```go
-r.Update(context.TODO(), "my-service", naming.Update{Op: naming.Delete, Addr: "1.2.3.4"})
-```
-
-### Registering an endpoint with a lease
-
-Registering an endpoint with a lease ensures that if the host can't maintain a keepalive heartbeat (e.g., its machine fails), it will be removed from the service:
-
-```sh
-lease=`ETCDCTL_API=3 etcdctl lease grant 5 | cut -f2 -d' '`
-ETCDCTL_API=3 etcdctl put --lease=$lease my-service/1.2.3.4 '{"Addr":"1.2.3.4","Metadata":"..."}'
-ETCDCTL_API=3 etcdctl lease keep-alive $lease
-```

+ 0 - 499
src/github.com/coreos/etcd/Documentation/dev-guide/interacting_v3.md

@@ -1,499 +0,0 @@
----
-title: Interacting with etcd
----
-
-Users mostly interact with etcd by putting or getting the value of a key. This section describes how to do that by using etcdctl, a command line tool for interacting with etcd server. The concepts described here should apply to the gRPC APIs or client library APIs.
-
-The API version used by etcdctl to speak to etcd may be set to version `2` or `3` via the `ETCDCTL_API` environment variable. By default, etcdctl on master (3.4) uses the v3 API and earlier versions (3.3 and earlier) default to the v2 API.
-
-Note that any key that was created using the v2 API will not be able to be queried via the v2 API.  A v3 API ```etcdctl get``` of a v2 key will exit with 0 and no key data, this is the expected behaviour.
-
-
-```bash
-export ETCDCTL_API=3
-```
-
-## Find versions
-
-etcdctl version and Server API version can be useful in finding the appropriate commands to be used for performing various operations on etcd.
-
-Here is the command to find the versions:
-
-```bash
-$ etcdctl version
-etcdctl version: 3.1.0-alpha.0+git
-API version: 3.1
-```
-
-## Write a key
-
-Applications store keys into the etcd cluster by writing to keys. Every stored key is replicated to all etcd cluster members through the Raft protocol to achieve consistency and reliability.
-
-Here is the command to set the value of key `foo` to `bar`:
-
-```bash
-$ etcdctl put foo bar
-OK
-```
-
-Also a key can be set for a specified interval of time by attaching lease to it.
-
-Here is the command to set the value of key `foo1` to `bar1` for 10s.
-
-```bash
-$ etcdctl put foo1 bar1 --lease=1234abcd
-OK
-```
-
-Note: The lease id `1234abcd` in the above command refers to id returned on creating the lease of 10s. This id can then be attached to the key.
-
-## Read keys
-
-Applications can read values of keys from an etcd cluster. Queries may read a single key, or a range of keys.
-
-Suppose the etcd cluster has stored the following keys:
-
-```bash
-foo = bar
-foo1 = bar1
-foo2 = bar2
-foo3 = bar3
-```
-
-Here is the command to read the value of key `foo`:
-
-```bash
-$ etcdctl get foo
-foo
-bar
-```
-
-Here is the command to read the value of key `foo` in hex format:
-
-```bash
-$ etcdctl get foo --hex
-\x66\x6f\x6f          # Key
-\x62\x61\x72          # Value
-```
-
-Here is the command to read only the value of key `foo`:
-
-```bash
-$ etcdctl get foo --print-value-only
-bar
-```
-
-Here is the command to range over the keys from `foo` to `foo3`:
-
-```bash
-$ etcdctl get foo foo3
-foo
-bar
-foo1
-bar1
-foo2
-bar2
-```
-
-Note that `foo3` is excluded since the range is over the half-open interval `[foo, foo3)`, excluding `foo3`.
-
-Here is the command to range over all keys prefixed with `foo`:
-
-```bash
-$ etcdctl get --prefix foo
-foo
-bar
-foo1
-bar1
-foo2
-bar2
-foo3
-bar3
-```
-
-Here is the command to range over all keys prefixed with `foo`, limiting the number of results to 2:
-
-```bash
-$ etcdctl get --prefix --limit=2 foo
-foo
-bar
-foo1
-bar1
-```
-
-## Read past version of keys
-
-Applications may want to read superseded versions of a key. For example, an application may wish to roll back to an old configuration by accessing an earlier version of a key. Alternatively, an application may want a consistent view over multiple keys through multiple requests by accessing key history.
-Since every modification to the etcd cluster key-value store increments the global revision of an etcd cluster, an application can read superseded keys by providing an older etcd revision.
-
-Suppose an etcd cluster already has the following keys:
-
-```bash
-foo = bar         # revision = 2
-foo1 = bar1       # revision = 3
-foo = bar_new     # revision = 4
-foo1 = bar1_new   # revision = 5
-```
-
-Here are an example to access the past versions of keys:
-
-```bash
-$ etcdctl get --prefix foo # access the most recent versions of keys
-foo
-bar_new
-foo1
-bar1_new
-
-$ etcdctl get --prefix --rev=4 foo # access the versions of keys at revision 4
-foo
-bar_new
-foo1
-bar1
-
-$ etcdctl get --prefix --rev=3 foo # access the versions of keys at revision 3
-foo
-bar
-foo1
-bar1
-
-$ etcdctl get --prefix --rev=2 foo # access the versions of keys at revision 2
-foo
-bar
-
-$ etcdctl get --prefix --rev=1 foo # access the versions of keys at revision 1
-```
-
-## Read keys which are greater than or equal to the byte value of the specified key
-
-Applications may want to read keys which are greater than or equal to the byte value of the specified key.
-
-Suppose an etcd cluster already has the following keys:
-
-```bash
-a = 123
-b = 456
-z = 789
-```
-
-Here is the command to read keys which are greater than or equal to the byte value of key `b` :
-
-```bash
-$ etcdctl get --from-key b
-b
-456
-z
-789
-```
-
-## Delete keys
-
-Applications can delete a key or a range of keys from an etcd cluster.
-
-Suppose an etcd cluster already has the following keys:
-
-```bash
-foo = bar
-foo1 = bar1
-foo3 = bar3
-zoo = val
-zoo1 = val1
-zoo2 = val2
-a = 123
-b = 456
-z = 789
-```
-
-Here is the command to delete key `foo`:
-
-```bash
-$ etcdctl del foo
-1 # one key is deleted
-```
-
-Here is the command to delete keys ranging from `foo` to `foo9`:
-
-```bash
-$ etcdctl del foo foo9
-2 # two keys are deleted
-```
-
-Here is the command to delete key `zoo` with the deleted key value pair returned:
-
-```bash
-$ etcdctl del --prev-kv zoo
-1   # one key is deleted
-zoo # deleted key
-val # the value of the deleted key
-```
-
-Here is the command to delete keys having prefix as `zoo`:
-
-```bash
-$ etcdctl del --prefix zoo
-2 # two keys are deleted
-```
-
-Here is the command to delete keys which are greater than or equal to the byte value of key `b` :
-
-```bash
-$ etcdctl del --from-key b
-2 # two keys are deleted
-```
-
-## Watch key changes
-
-Applications can watch on a key or a range of keys to monitor for any updates.
-
-Here is the command to watch on key `foo`:
-
-```bash
-$ etcdctl watch foo
-# in another terminal: etcdctl put foo bar
-PUT
-foo
-bar
-```
-
-Here is the command to watch on key `foo` in hex format:
-
-```bash
-$ etcdctl watch foo --hex
-# in another terminal: etcdctl put foo bar
-PUT
-\x66\x6f\x6f          # Key
-\x62\x61\x72          # Value
-```
-
-Here is the command to watch on a range key from `foo` to `foo9`:
-
-```bash
-$ etcdctl watch foo foo9
-# in another terminal: etcdctl put foo bar
-PUT
-foo
-bar
-# in another terminal: etcdctl put foo1 bar1
-PUT
-foo1
-bar1
-```
-
-Here is the command to watch on keys having prefix `foo`:
-
-```bash
-$ etcdctl watch --prefix foo
-# in another terminal: etcdctl put foo bar
-PUT
-foo
-bar
-# in another terminal: etcdctl put fooz1 barz1
-PUT
-fooz1
-barz1
-```
-
-Here is the command to watch on multiple keys `foo` and `zoo`:
-
-```bash
-$ etcdctl watch -i
-$ watch foo
-$ watch zoo
-# in another terminal: etcdctl put foo bar
-PUT
-foo
-bar
-# in another terminal: etcdctl put zoo val
-PUT
-zoo
-val
-```
-
-## Watch historical changes of keys
-
-Applications may want to watch for historical changes of keys in etcd. For example, an application may wish to receive all the modifications of a key; if the application stays connected to etcd, then `watch` is good enough. However, if the application or etcd fails, a change may happen during the failure, and the application will not receive the update in real time. To guarantee the update is delivered, the application must be able to watch for historical changes to keys. To do this, an application can specify a historical revision on a watch, just like reading past version of keys.
-
-Suppose we finished the following sequence of operations:
-
-```bash
-$ etcdctl put foo bar         # revision = 2
-OK
-$ etcdctl put foo1 bar1       # revision = 3
-OK
-$ etcdctl put foo bar_new     # revision = 4
-OK
-$ etcdctl put foo1 bar1_new   # revision = 5
-OK
-```
-
-Here is an example to watch the historical changes:
-
-```bash
-# watch for changes on key `foo` since revision 2
-$ etcdctl watch --rev=2 foo
-PUT
-foo
-bar
-PUT
-foo
-bar_new
-```
-
-```bash
-# watch for changes on key `foo` since revision 3
-$ etcdctl watch --rev=3 foo
-PUT
-foo
-bar_new
-```
-
-Here is an example to watch only from the last historical change:
-
-```bash
-# watch for changes on key `foo` and return last revision value along with modified value
-$ etcdctl watch --prev-kv foo
-# in another terminal: etcdctl put foo bar_latest
-PUT
-foo         # key
-bar_new     # last value of foo key before modification
-foo         # key
-bar_latest  # value of foo key after modification
-```
-
-## Watch progress
-
-Applications may want to check the progress of a watch to determine how up-to-date the watch stream is. For example, if a watch is used to update a cache, it can be useful to know if the cache is stale compared to the revision from a quorum read. 
-
-Progress requests can be issued using the "progress" command in interactive watch session to ask the etcd server to send a progress notify update in the watch stream:
-
-```bash
-$ etcdctl watch -i
-$ watch a
-$ progress
-progress notify: 1
-# in another terminal: etcdctl put x 0
-# in another terminal: etcdctl put y 1
-$ progress
-progress notify: 3
-```
-
-Note: The revision number in the progress notify response is the revision from the local etcd server node that the watch stream is connected to. If this node is partitioned and not part of quorum, this progress notify revision might be lower than 
-than the revision returned by a quorum read against a non-partitioned etcd server node.
-
-## Compacted revisions
-
-As we mentioned, etcd keeps revisions so that applications can read past versions of keys. However, to avoid accumulating an unbounded amount of history, it is important to compact past revisions. After compacting, etcd removes historical revisions, releasing resources for future use. All superseded data with revisions before the compacted revision will be unavailable.
-
-Here is the command to compact the revisions:
-
-```bash
-$ etcdctl compact 5
-compacted revision 5
-
-# any revisions before the compacted one are not accessible
-$ etcdctl get --rev=4 foo
-Error:  rpc error: code = 11 desc = etcdserver: mvcc: required revision has been compacted
-```
-
-Note: The current revision of etcd server can be found using get command on any key (existent or non-existent) in json format. Example is shown below for mykey which does not exist in etcd server:
-
-```bash
-$ etcdctl get mykey -w=json
-{"header":{"cluster_id":14841639068965178418,"member_id":10276657743932975437,"revision":15,"raft_term":4}}
-```
-
-## Grant leases
-
-Applications can grant leases for keys from an etcd cluster. When a key is attached to a lease, its lifetime is bound to the lease's lifetime which in turn is governed by a time-to-live (TTL). Each lease has a minimum time-to-live (TTL) value specified by the application at grant time. The lease's actual TTL value is at least the minimum TTL and is chosen by the etcd cluster. Once a lease's TTL elapses, the lease expires and all attached keys are deleted.
-
-Here is the command to grant a lease:
-
-```bash
-# grant a lease with 10 second TTL
-$ etcdctl lease grant 10
-lease 32695410dcc0ca06 granted with TTL(10s)
-
-# attach key foo to lease 32695410dcc0ca06
-$ etcdctl put --lease=32695410dcc0ca06 foo bar
-OK
-```
-
-## Revoke leases
-
-Applications revoke leases by lease ID. Revoking a lease deletes all of its attached keys.
-
-Suppose we finished the following sequence of operations:
-
-```bash
-$ etcdctl lease grant 10
-lease 32695410dcc0ca06 granted with TTL(10s)
-$ etcdctl put --lease=32695410dcc0ca06 foo bar
-OK
-```
-
-Here is the command to revoke the same lease:
-
-```bash
-$ etcdctl lease revoke 32695410dcc0ca06
-lease 32695410dcc0ca06 revoked
-
-$ etcdctl get foo
-# empty response since foo is deleted due to lease revocation
-```
-
-## Keep leases alive
-
-Applications can keep a lease alive by refreshing its TTL so it does not expire.
-
-Suppose we finished the following sequence of operations:
-
-```bash
-$ etcdctl lease grant 10
-lease 32695410dcc0ca06 granted with TTL(10s)
-```
-
-Here is the command to keep the same lease alive:
-
-```bash
-$ etcdctl lease keep-alive 32695410dcc0ca06
-lease 32695410dcc0ca06 keepalived with TTL(10)
-lease 32695410dcc0ca06 keepalived with TTL(10)
-lease 32695410dcc0ca06 keepalived with TTL(10)
-...
-```
-
-## Get lease information
-
-Applications may want to know about lease information, so that they can be renewed or to check if the lease still exists or it has expired. Applications may also want to know the keys to which a particular lease is attached.
-
-Suppose we finished the following sequence of operations:
-
-```bash
-# grant a lease with 500 second TTL
-$ etcdctl lease grant 500
-lease 694d5765fc71500b granted with TTL(500s)
-
-# attach key zoo1 to lease 694d5765fc71500b
-$ etcdctl put zoo1 val1 --lease=694d5765fc71500b
-OK
-
-# attach key zoo2 to lease 694d5765fc71500b
-$ etcdctl put zoo2 val2 --lease=694d5765fc71500b
-OK
-```
-
-Here is the command to get information about the lease:
-
-```bash
-$ etcdctl lease timetolive 694d5765fc71500b
-lease 694d5765fc71500b granted with TTL(500s), remaining(258s)
-```
-
-Here is the command to get information about the lease along with the keys attached with the lease:
-
-```bash
-$ etcdctl lease timetolive --keys 694d5765fc71500b
-lease 694d5765fc71500b granted with TTL(500s), remaining(132s), attached keys([zoo2 zoo1])
-
-# if the lease has expired or does not exist it will give the below response:
-Error:  etcdserver: requested lease not found
-```

+ 0 - 11
src/github.com/coreos/etcd/Documentation/dev-guide/limit.md

@@ -1,11 +0,0 @@
----
-title: System limits
----
-
-## Request size limit
-
-etcd is designed to handle small key value pairs typical for metadata. Larger requests will work, but may increase the latency of other requests. By default, the maximum size of any request is 1.5 MiB. This limit is configurable through `--max-request-bytes` flag for etcd server.
-
-## Storage size limit
-
-The default storage size limit is 2GB, configurable with `--quota-backend-bytes` flag. 8GB is a suggested maximum size for normal environments and etcd warns at startup if the configured value exceeds it.

+ 0 - 151
src/github.com/coreos/etcd/Documentation/dev-guide/local_cluster.md

@@ -1,151 +0,0 @@
----
-title: Set up a local cluster
----
-
-For testing and development deployments, the quickest and easiest way is to configure a local cluster. For a production deployment, refer to the [clustering][clustering] section.
-
-## Local standalone cluster
-
-### Starting a cluster
-
-Run the following to deploy an etcd cluster as a standalone cluster:
-
-```
-$ ./etcd
-...
-```
-
-If the `etcd` binary is not present in the current working directory, it might be located either at `$GOPATH/bin/etcd` or at `/usr/local/bin/etcd`. Run the command appropriately.
-
-The running etcd member listens on `localhost:2379` for client requests.
-
-### Interacting with the cluster
-
-Use `etcdctl` to interact with the running cluster:
-
-1. Store an example key-value pair in the cluster:
-
-    ```
-      $ ./etcdctl put foo bar
-      OK
-    ```
-
-    If OK is printed, storing key-value pair is successful.
-
-2. Retrieve the value of `foo`:
-
-    ```
-    $ ./etcdctl get foo
-    bar
-    ```
-
-    If `bar` is returned, interaction with the etcd cluster is working as expected.
-
-## Local multi-member cluster
-
-### Starting a cluster
-
-A `Procfile` at the base of the etcd git repository is provided to easily configure a local multi-member cluster. To start a multi-member cluster, navigate to the root of the etcd source tree and perform the following:
-
-1. Install `goreman` to control Procfile-based applications:
-
-    ```
-    $ go get github.com/mattn/goreman
-    ```
-
-2. Start a cluster with `goreman` using etcd's stock Procfile:
-
-    ```
-    $ goreman -f Procfile start
-    ```
-
-    The members start running. They listen on `localhost:2379`, `localhost:22379`, and `localhost:32379` respectively for client requests.
-
-### Interacting with the cluster
-
-Use `etcdctl` to interact with the running cluster:
-
-1. Print the list of members:
-
-    ```
-    $ etcdctl --write-out=table --endpoints=localhost:2379 member list
-    ```
-    The list of etcd members are displayed as follows:
-
-    ```
-    +------------------+---------+--------+------------------------+------------------------+
-    |        ID        | STATUS  |  NAME  |       PEER ADDRS       |      CLIENT ADDRS      |
-    +------------------+---------+--------+------------------------+------------------------+
-    | 8211f1d0f64f3269 | started | infra1 | http://127.0.0.1:2380  | http://127.0.0.1:2379  |
-    | 91bc3c398fb3c146 | started | infra2 | http://127.0.0.1:22380 | http://127.0.0.1:22379 |
-    | fd422379fda50e48 | started | infra3 | http://127.0.0.1:32380 | http://127.0.0.1:32379 |
-    +------------------+---------+--------+------------------------+------------------------+
-    ```
-
-2. Store an example key-value pair in the cluster:
-
-    ```
-    $ etcdctl put foo bar
-    OK
-    ```
-
-    If OK is printed, storing key-value pair is successful.
-
-### Testing fault tolerance  
-
-To exercise etcd's fault tolerance, kill a member and attempt to retrieve the key.
-
-1. Identify the process name of the member to be stopped.
-
-    The `Procfile` lists the properties of the multi-member cluster. For example, consider the member with the process name, `etcd2`.
-
-2. Stop the member:
-
-    ```
-    # kill etcd2
-    $ goreman run stop etcd2
-    ```
-
-3. Store a key:
-
-    ```
-    $ etcdctl put key hello
-    OK
-    ```
-
-4.  Retrieve the key that is stored in the previous step:
-
-    ```
-    $ etcdctl get key
-    hello
-    ```
-
-5. Retrieve a key from the stopped member:
-
-    ```
-    $ etcdctl --endpoints=localhost:22379 get key
-    ```
-
-    The command should display an error caused by connection failure:
-
-    ```
-    2017/06/18 23:07:35 grpc: Conn.resetTransport failed to create client transport: connection error: desc = "transport: dial tcp 127.0.0.1:22379: getsockopt: connection refused"; Reconnecting to "localhost:22379"
-    Error:  grpc: timed out trying to connect
-    ```
-6. Restart the stopped member:
-
-    ```
-    $ goreman run restart etcd2
-    ```
-
-7. Get the key from the restarted member:
-
-    ```
-    $ etcdctl --endpoints=localhost:22379 get key
-    hello
-    ```
-
-    Restarting the member re-establish the connection. `etcdctl` will now be able to retrieve the key successfully. To learn more about interacting with etcd, read [interacting with etcd section][interacting].
-
-[interacting]: ./interacting_v3.md
-[clustering]: ../op-guide/clustering.md

Некоторые файлы не были показаны из-за большого количества измененных файлов