Skip to content

Commit ee8c3bf

Browse files
committed
Merge branch 'main' into acmestack#80
# Conflicts: # internal/core/openapi/user.go # internal/core/storage/dao/dictionary.go # internal/core/storage/xml/dictionary_mapper.xml
2 parents dedd681 + 4773dd0 commit ee8c3bf

19 files changed

+664
-177
lines changed

db/envcd.sql

+2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ SET FOREIGN_KEY_CHECKS = 0;
2424
DROP TABLE IF EXISTS `scopespace`;
2525
CREATE TABLE `scopespace` (
2626
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
27+
`user_id` int(10) unsigned NOT NULL,
2728
`name` varchar(100) NOT NULL,
2829
`note` varchar(150) NOT NULL,
2930
`state` varchar(12) NOT NULL DEFAULT 'enabled' COMMENT 'enabled; disabled; deleted',
@@ -42,6 +43,7 @@ CREATE TABLE `dictionary` (
4243
`scopespace_id` int(10) unsigned NOT NULL,
4344
`dict_key` varchar(200) NOT NULL,
4445
`dict_value` text NOT NULL,
46+
`version` varchar(20) NOT NULL,
4547
`state` varchar(12) NOT NULL DEFAULT 'enabled' COMMENT 'enabled; disabled; deleted',
4648
`created_at` datetime NOT NULL DEFAULT current_timestamp(),
4749
`updated_at` datetime NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),

go.mod

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ module github.com/acmestack/envcd
22

33
go 1.18
44

5-
require github.com/acmestack/godkits v0.0.8
5+
require github.com/acmestack/godkits v0.0.10
66

77
require (
88
github.com/acmestack/gobatis v0.2.8
9+
github.com/acmestack/pagehelper v1.0.0
910
github.com/gin-gonic/gin v1.8.1
1011
github.com/go-sql-driver/mysql v1.6.0
1112
github.com/golang-jwt/jwt/v4 v4.4.2

go.sum

+4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ github.com/acmestack/gobatis v0.2.8 h1:dYA3AUVXLQvHcuGA9bscqq4xw6tEC1E9dlyx4ebCH
1111
github.com/acmestack/gobatis v0.2.8/go.mod h1:vEEXPWzVzeDoFpYD2FoOfGfCyEuLtSiMIbP6jqO44Xg=
1212
github.com/acmestack/godkits v0.0.8 h1:On9Dv71MBnZXioP7p9PfpvdDPYIKYyfM/GoZJ4N62P8=
1313
github.com/acmestack/godkits v0.0.8/go.mod h1:d5kiqEvQl/LpXd8VTy7PZvQ5DDiasCX+QKA3+q8fWos=
14+
github.com/acmestack/godkits v0.0.10 h1:gIVwtJ/ZVSUr4u5NsKq35Hvp+lecTImA9EYkVACUpss=
15+
github.com/acmestack/godkits v0.0.10/go.mod h1:d5kiqEvQl/LpXd8VTy7PZvQ5DDiasCX+QKA3+q8fWos=
16+
github.com/acmestack/pagehelper v1.0.0 h1:xRTAb+3ZHuGuaCeDTNNy2PVzjR6rfSpIuZrdnboTCFY=
17+
github.com/acmestack/pagehelper v1.0.0/go.mod h1:sncmjrPfLMpX+2SpgotZk/dgCjss0yM7dHHn/8aoz/A=
1418
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
1519
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
1620
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=

internal/core/openapi/dictionary.go

+215-63
Original file line numberDiff line numberDiff line change
@@ -18,123 +18,275 @@
1818
package openapi
1919

2020
import (
21+
"context"
22+
"errors"
2123
"fmt"
2224
"time"
2325

26+
"github.com/acmestack/envcd/internal/core/storage"
2427
"github.com/acmestack/envcd/internal/core/storage/dao"
28+
"github.com/acmestack/envcd/internal/pkg/constant"
2529
"github.com/acmestack/envcd/internal/pkg/entity"
2630
"github.com/acmestack/envcd/pkg/entity/result"
31+
"github.com/acmestack/godkits/array"
2732
"github.com/acmestack/godkits/gox/stringsx"
33+
"github.com/acmestack/pagehelper"
2834
"github.com/gin-gonic/gin"
2935
)
3036

31-
type dictParams struct {
32-
DictKey string `json:"dictKey"`
37+
type DictionaryDTO struct {
38+
UserId int `json:"userId" binding:"required"`
39+
ScopeSpaceId int `json:"scopeSpaceId" binding:"required"`
40+
DictKey string `json:"dictKey" binding:"required"`
41+
DictValue string `json:"dictValue" binding:"required"`
42+
Version string `json:"version" binding:"required"`
43+
State string `json:"state" binding:"required"`
44+
}
45+
46+
type dictionUpdateDTO struct {
47+
DictId int `json:"dictId" binding:"required"`
3348
DictValue string `json:"dictValue"`
34-
Version string `json:"version"`
3549
State string `json:"state"`
3650
}
3751

52+
func dictionary(storage *storage.Storage, dictionaryId *int, ginCtx *gin.Context) (*entity.Dictionary, error) {
53+
// get user id from gin context
54+
dictId := stringsx.ToInt(ginCtx.Param("dictionaryId"))
55+
if dictionaryId != nil {
56+
dictId = *dictionaryId
57+
}
58+
dict := entity.Dictionary{Id: dictId}
59+
dictionaries, err := dao.New(storage).SelectDictionary(dict, nil)
60+
if err != nil {
61+
return nil, err
62+
}
63+
if array.Empty(dictionaries) {
64+
return nil, nil
65+
}
66+
return &dictionaries[0], nil
67+
}
68+
69+
// dictionary query single dictionary mapping
70+
// @receiver openapi common openapi
71+
// @param ginCtx gin context
3872
func (openapi *Openapi) dictionary(ginCtx *gin.Context) {
3973
openapi.response(ginCtx, nil, func() *result.EnvcdResult {
40-
// get user id from gin context
41-
userId := stringsx.ToInt(ginCtx.Param("userId"))
42-
scopeSpaceId := stringsx.ToInt(ginCtx.Param("scopeSpaceId"))
43-
dictId := stringsx.ToInt(ginCtx.Param("dictId"))
44-
dict := entity.Dictionary{Id: dictId, UserId: userId, ScopeSpaceId: scopeSpaceId}
45-
dictionary, err := dao.New(openapi.storage).SelectDictionary(dict)
74+
dict, err := dictionary(openapi.storage, nil, ginCtx)
4675
if err != nil {
4776
return result.InternalFailure(err)
4877
}
49-
return result.Success(dictionary)
78+
return result.Success(dict)
5079
})
5180
}
5281

82+
// createDictionary create dictionary
83+
// @receiver openapi openapi
84+
// @param ginCtx gin context
5385
func (openapi *Openapi) createDictionary(ginCtx *gin.Context) {
5486
openapi.response(ginCtx, nil, func() *result.EnvcdResult {
55-
param := dictParams{}
56-
if err := ginCtx.ShouldBindJSON(&param); err != nil {
87+
dictParams := &DictionaryDTO{}
88+
if err := ginCtx.ShouldBindJSON(dictParams); err != nil {
5789
fmt.Printf("Bind error, %v\n", err)
5890
return result.InternalFailure(err)
5991
}
60-
// get userId and appId from gin context
61-
userId := stringsx.ToInt(ginCtx.Param("userId"))
62-
scopeSpaceId := stringsx.ToInt(ginCtx.Param("scopeSpaceId"))
63-
92+
daoAction := dao.New(openapi.storage)
93+
// build dictionary with parameters
6494
dictionary := entity.Dictionary{
65-
UserId: userId,
66-
ScopeSpaceId: scopeSpaceId,
67-
DictKey: param.DictKey,
68-
DictValue: param.DictValue,
69-
State: param.State,
95+
UserId: dictParams.UserId,
96+
ScopeSpaceId: dictParams.ScopeSpaceId,
97+
DictKey: dictParams.DictKey + "@" + dictParams.Version,
98+
DictValue: dictParams.DictValue,
99+
State: dictParams.State,
70100
CreatedAt: time.Now(),
71101
UpdatedAt: time.Now(),
72102
}
73-
// Strategy
74-
// scopespace + username + dictKey + version
75-
// insertDictionary, i, err := dao.New(openapi.storage).InsertDictionary(dictionary)
76-
// openapi.exchange.Put(dictionary.DictKey, dictionary.DictValue)
77-
// if err != nil {
78-
// return nil
79-
//}
80-
fmt.Println(dictionary)
81-
// create config
82-
// ConfigDao.save();
83-
// go LogDao.save()
84-
// openapi.exchange.Put("key", "value")
85-
return nil
103+
_, id, err := daoAction.InsertDictionary(dictionary)
104+
if err != nil {
105+
return result.InternalFailure(err)
106+
}
107+
path, PathErr := buildEtcdPath(daoAction, dictionary)
108+
if PathErr != nil {
109+
return result.Failure0(result.ErrorEtcdPath)
110+
}
111+
if stringsx.Empty(path) {
112+
return result.Failure0(result.NilExchangePath)
113+
}
114+
exchangeErr := openapi.exchange.Put(path, dictParams.DictValue)
115+
if exchangeErr != nil {
116+
return result.InternalFailure(exchangeErr)
117+
}
118+
openapi.doOperationLogging(dictParams.UserId, "create dictionary and insert into mysql and etcd")
119+
return result.Success(id)
86120
})
87121
}
88122

123+
// updateDictionary update dictionary
124+
// @receiver openapi openapi
125+
// @param ginCtx gin context
89126
func (openapi *Openapi) updateDictionary(ginCtx *gin.Context) {
90127
openapi.response(ginCtx, nil, func() *result.EnvcdResult {
91-
fmt.Println("hello world")
92-
// create config
93-
// ConfigDao.save();
94-
// go LogDao.save()
95-
// openapi.exchange.Put("key", "value")
96-
return nil
128+
dictParams := &dictionUpdateDTO{}
129+
if err := ginCtx.ShouldBindJSON(dictParams); err != nil {
130+
fmt.Printf("Bind error, %v\n", err)
131+
return result.InternalFailure(err)
132+
}
133+
daoAction := dao.New(openapi.storage)
134+
135+
dictionary := entity.Dictionary{
136+
Id: dictParams.DictId,
137+
DictValue: dictParams.DictValue,
138+
UpdatedAt: time.Now(),
139+
}
140+
// update dictionary
141+
_, updateDictErr := daoAction.UpdateDictionary(dictionary)
142+
if updateDictErr != nil {
143+
return result.InternalFailure(updateDictErr)
144+
}
145+
// update state
146+
ret := openapi.updateDictionaryState(dictParams.DictId, dictParams.State)
147+
if ret != nil {
148+
return ret
149+
}
150+
return result.Success(nil)
97151
})
98152
}
99153

154+
// removeDictionary remove dictionary
155+
// @receiver openapi
156+
// @param ginCtx gin context
100157
func (openapi *Openapi) removeDictionary(ginCtx *gin.Context) {
101158
openapi.response(ginCtx, nil, func() *result.EnvcdResult {
102-
userId := stringsx.ToInt(ginCtx.Param("userId"))
103-
appId := stringsx.ToInt(ginCtx.Param("appId"))
104-
dictId := stringsx.ToInt(ginCtx.Param("dictId"))
105-
dict := entity.Dictionary{Id: dictId, UserId: userId, ScopeSpaceId: appId}
106-
// query dictionary exist
107-
daoAction := dao.New(openapi.storage)
108-
dictionary, err := daoAction.SelectDictionary(dict)
159+
dict, err := dictionary(openapi.storage, nil, ginCtx)
109160
if err != nil {
110161
return result.InternalFailure(err)
111162
}
112-
if len(dictionary) == 0 {
163+
if dict == nil {
113164
return result.Failure0(result.ErrorDictionaryNotExist)
114165
}
115-
exchangeErr := openapi.exchange.Remove(getFirstDictionary(dictionary).DictKey)
116-
if exchangeErr != nil {
117-
return result.InternalFailure(exchangeErr)
118-
}
119-
retId, delErr := daoAction.DeleteDictionary(getFirstDictionary(dictionary))
166+
daoAction := dao.New(openapi.storage)
167+
// set dictionaries state: deleted
168+
retId, delErr := daoAction.DeleteDictionary(*dict)
120169
if delErr != nil {
121170
return result.InternalFailure(delErr)
122171
}
172+
// delete etcd path
173+
path, etcdPathError := buildEtcdPath(daoAction, *dict)
174+
if etcdPathError != nil {
175+
return result.Failure0(result.ErrorEtcdPath)
176+
}
177+
if stringsx.Empty(path) {
178+
return result.Failure0(result.NilExchangePath)
179+
}
180+
if stringsx.NotEmpty(path) {
181+
exchangeErr := openapi.exchange.Remove(path)
182+
if exchangeErr != nil {
183+
return result.InternalFailure(exchangeErr)
184+
}
185+
}
186+
openapi.doOperationLogging(dict.UserId, "remove dictionaries from mysql and etcd")
123187
return result.Success(retId)
124188
})
125189
}
126190

127-
func getFirstDictionary(dictionaryList []entity.Dictionary) entity.Dictionary {
128-
return dictionaryList[0]
129-
}
130-
131191
func (openapi *Openapi) dictionaries(ginCtx *gin.Context) {
132192
openapi.response(ginCtx, nil, func() *result.EnvcdResult {
133-
fmt.Println("hello world")
134-
// create config
135-
// ConfigDao.save();
136-
// go LogDao.save()
137-
// openapi.exchange.Put("key", "value")
138-
return nil
193+
pageNum := stringsx.ToInt(ginCtx.DefaultQuery("page", "1"))
194+
pageSize := stringsx.ToInt(ginCtx.DefaultQuery("pageSize", "20"))
195+
daoAction := dao.New(openapi.storage)
196+
ctx := pagehelper.C(context.Background()).PageWithCount(int64(pageNum-1), int64(pageSize), "").Build()
197+
dictionary, err := daoAction.SelectDictionary(entity.Dictionary{}, ctx)
198+
if err != nil {
199+
return result.InternalFailure(err)
200+
}
201+
pageInfo := pagehelper.GetPageInfo(ctx)
202+
return result.Success(PageListVO{
203+
Page: pageInfo.Page + 1,
204+
PageSize: pageInfo.PageSize,
205+
Total: pageInfo.GetTotal(),
206+
TotalPage: pageInfo.GetTotalPage(),
207+
List: dictionary,
208+
})
139209
})
140210
}
211+
212+
// buildEtcdPath build etcd path
213+
// @param daoAction dao
214+
// @param dictionary
215+
// @return string path
216+
// @return error message
217+
func buildEtcdPath(daoAction *dao.Dao, dictionary entity.Dictionary) (string, error) {
218+
// todo user name from jwt
219+
user, userErr := daoAction.SelectUser(entity.User{Id: dictionary.UserId})
220+
if userErr != nil {
221+
return "", userErr
222+
}
223+
scopeSpace, scopeSpaceErr := daoAction.SelectScopeSpace(entity.ScopeSpace{Id: dictionary.ScopeSpaceId})
224+
if scopeSpaceErr != nil {
225+
return "", scopeSpaceErr
226+
}
227+
// user and scopeSpace not exist
228+
if len(user) == 0 || len(scopeSpace) == 0 {
229+
return "", errors.New("user or spaceSpace not exist")
230+
}
231+
// build path
232+
build := stringsx.Builder{}
233+
// /scopeSpaceName/userName/dictKey, etc. /spring/moremind/userKey@version
234+
_, err := build.JoinString("/", scopeSpace[0].Name, "/", user[0].Name, "/", dictionary.DictKey)
235+
if err != nil {
236+
return "", err
237+
}
238+
return build.String(), nil
239+
}
240+
241+
// updateDictionaryState update dictionary state
242+
// @receiver openapi openapi
243+
// @param dictId dict id
244+
// @param state updated state
245+
// @return *result.EnvcdResult
246+
func (openapi *Openapi) updateDictionaryState(dictId int, state string) *result.EnvcdResult {
247+
daoAction := dao.New(openapi.storage)
248+
dictionaries, dictErr := daoAction.SelectDictionary(entity.Dictionary{Id: dictId}, nil)
249+
if dictErr != nil {
250+
return result.InternalFailure(dictErr)
251+
}
252+
if array.Empty(dictionaries) {
253+
return result.Failure0(result.ErrorDictionaryNotExist)
254+
}
255+
defaultDictionary := dictionaries[0]
256+
path, err := buildEtcdPath(daoAction, defaultDictionary)
257+
if stringsx.Empty(path) {
258+
return result.Failure0(result.NilExchangePath)
259+
}
260+
if err != nil {
261+
return result.Failure0(result.ErrorEtcdPath)
262+
}
263+
switch state {
264+
case constant.EnabledState:
265+
// case enabled, should generate path and put key and value
266+
if defaultDictionary.State != constant.EnabledState {
267+
exchangeErr := openapi.exchange.Put(path, defaultDictionary.DictValue)
268+
if exchangeErr != nil {
269+
return result.InternalFailure(exchangeErr)
270+
}
271+
}
272+
break
273+
case constant.DisabledState:
274+
// case disabled, should set state in mysql and delete dictionaries in etcd
275+
case constant.DeletedState:
276+
// case deleted, should set state in mysql and delete dictionaries in etcd
277+
if defaultDictionary.State == constant.DisabledState || defaultDictionary.State == constant.DeletedState {
278+
_, updateErr := daoAction.UpdateDictionary(entity.Dictionary{State: state})
279+
if updateErr != nil {
280+
return result.InternalFailure(updateErr)
281+
}
282+
exchangeErr := openapi.exchange.Remove(path)
283+
if exchangeErr != nil {
284+
return result.InternalFailure(exchangeErr)
285+
}
286+
}
287+
break
288+
default:
289+
return result.Failure0(result.ErrorNotExistState)
290+
}
291+
return nil
292+
}

0 commit comments

Comments
 (0)