Skip to content

Commit

Permalink
Merge branch 'main' into acmestack#80
Browse files Browse the repository at this point in the history
# Conflicts:
#	internal/core/openapi/user.go
#	internal/core/storage/dao/dictionary.go
#	internal/core/storage/xml/dictionary_mapper.xml
  • Loading branch information
liuzwei committed Aug 25, 2022
2 parents dedd681 + 4773dd0 commit ee8c3bf
Show file tree
Hide file tree
Showing 19 changed files with 664 additions and 177 deletions.
2 changes: 2 additions & 0 deletions db/envcd.sql
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ SET FOREIGN_KEY_CHECKS = 0;
DROP TABLE IF EXISTS `scopespace`;
CREATE TABLE `scopespace` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(10) unsigned NOT NULL,
`name` varchar(100) NOT NULL,
`note` varchar(150) NOT NULL,
`state` varchar(12) NOT NULL DEFAULT 'enabled' COMMENT 'enabled; disabled; deleted',
Expand All @@ -42,6 +43,7 @@ CREATE TABLE `dictionary` (
`scopespace_id` int(10) unsigned NOT NULL,
`dict_key` varchar(200) NOT NULL,
`dict_value` text NOT NULL,
`version` varchar(20) NOT NULL,
`state` varchar(12) NOT NULL DEFAULT 'enabled' COMMENT 'enabled; disabled; deleted',
`created_at` datetime NOT NULL DEFAULT current_timestamp(),
`updated_at` datetime NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ module github.com/acmestack/envcd

go 1.18

require github.com/acmestack/godkits v0.0.8
require github.com/acmestack/godkits v0.0.10

require (
github.com/acmestack/gobatis v0.2.8
github.com/acmestack/pagehelper v1.0.0
github.com/gin-gonic/gin v1.8.1
github.com/go-sql-driver/mysql v1.6.0
github.com/golang-jwt/jwt/v4 v4.4.2
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ github.com/acmestack/gobatis v0.2.8 h1:dYA3AUVXLQvHcuGA9bscqq4xw6tEC1E9dlyx4ebCH
github.com/acmestack/gobatis v0.2.8/go.mod h1:vEEXPWzVzeDoFpYD2FoOfGfCyEuLtSiMIbP6jqO44Xg=
github.com/acmestack/godkits v0.0.8 h1:On9Dv71MBnZXioP7p9PfpvdDPYIKYyfM/GoZJ4N62P8=
github.com/acmestack/godkits v0.0.8/go.mod h1:d5kiqEvQl/LpXd8VTy7PZvQ5DDiasCX+QKA3+q8fWos=
github.com/acmestack/godkits v0.0.10 h1:gIVwtJ/ZVSUr4u5NsKq35Hvp+lecTImA9EYkVACUpss=
github.com/acmestack/godkits v0.0.10/go.mod h1:d5kiqEvQl/LpXd8VTy7PZvQ5DDiasCX+QKA3+q8fWos=
github.com/acmestack/pagehelper v1.0.0 h1:xRTAb+3ZHuGuaCeDTNNy2PVzjR6rfSpIuZrdnboTCFY=
github.com/acmestack/pagehelper v1.0.0/go.mod h1:sncmjrPfLMpX+2SpgotZk/dgCjss0yM7dHHn/8aoz/A=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
Expand Down
278 changes: 215 additions & 63 deletions internal/core/openapi/dictionary.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,123 +18,275 @@
package openapi

import (
"context"
"errors"
"fmt"
"time"

"github.com/acmestack/envcd/internal/core/storage"
"github.com/acmestack/envcd/internal/core/storage/dao"
"github.com/acmestack/envcd/internal/pkg/constant"
"github.com/acmestack/envcd/internal/pkg/entity"
"github.com/acmestack/envcd/pkg/entity/result"
"github.com/acmestack/godkits/array"
"github.com/acmestack/godkits/gox/stringsx"
"github.com/acmestack/pagehelper"
"github.com/gin-gonic/gin"
)

type dictParams struct {
DictKey string `json:"dictKey"`
type DictionaryDTO struct {
UserId int `json:"userId" binding:"required"`
ScopeSpaceId int `json:"scopeSpaceId" binding:"required"`
DictKey string `json:"dictKey" binding:"required"`
DictValue string `json:"dictValue" binding:"required"`
Version string `json:"version" binding:"required"`
State string `json:"state" binding:"required"`
}

type dictionUpdateDTO struct {
DictId int `json:"dictId" binding:"required"`
DictValue string `json:"dictValue"`
Version string `json:"version"`
State string `json:"state"`
}

func dictionary(storage *storage.Storage, dictionaryId *int, ginCtx *gin.Context) (*entity.Dictionary, error) {
// get user id from gin context
dictId := stringsx.ToInt(ginCtx.Param("dictionaryId"))
if dictionaryId != nil {
dictId = *dictionaryId
}
dict := entity.Dictionary{Id: dictId}
dictionaries, err := dao.New(storage).SelectDictionary(dict, nil)
if err != nil {
return nil, err
}
if array.Empty(dictionaries) {
return nil, nil
}
return &dictionaries[0], nil
}

// dictionary query single dictionary mapping
// @receiver openapi common openapi
// @param ginCtx gin context
func (openapi *Openapi) dictionary(ginCtx *gin.Context) {
openapi.response(ginCtx, nil, func() *result.EnvcdResult {
// get user id from gin context
userId := stringsx.ToInt(ginCtx.Param("userId"))
scopeSpaceId := stringsx.ToInt(ginCtx.Param("scopeSpaceId"))
dictId := stringsx.ToInt(ginCtx.Param("dictId"))
dict := entity.Dictionary{Id: dictId, UserId: userId, ScopeSpaceId: scopeSpaceId}
dictionary, err := dao.New(openapi.storage).SelectDictionary(dict)
dict, err := dictionary(openapi.storage, nil, ginCtx)
if err != nil {
return result.InternalFailure(err)
}
return result.Success(dictionary)
return result.Success(dict)
})
}

// createDictionary create dictionary
// @receiver openapi openapi
// @param ginCtx gin context
func (openapi *Openapi) createDictionary(ginCtx *gin.Context) {
openapi.response(ginCtx, nil, func() *result.EnvcdResult {
param := dictParams{}
if err := ginCtx.ShouldBindJSON(&param); err != nil {
dictParams := &DictionaryDTO{}
if err := ginCtx.ShouldBindJSON(dictParams); err != nil {
fmt.Printf("Bind error, %v\n", err)
return result.InternalFailure(err)
}
// get userId and appId from gin context
userId := stringsx.ToInt(ginCtx.Param("userId"))
scopeSpaceId := stringsx.ToInt(ginCtx.Param("scopeSpaceId"))

daoAction := dao.New(openapi.storage)
// build dictionary with parameters
dictionary := entity.Dictionary{
UserId: userId,
ScopeSpaceId: scopeSpaceId,
DictKey: param.DictKey,
DictValue: param.DictValue,
State: param.State,
UserId: dictParams.UserId,
ScopeSpaceId: dictParams.ScopeSpaceId,
DictKey: dictParams.DictKey + "@" + dictParams.Version,
DictValue: dictParams.DictValue,
State: dictParams.State,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
// Strategy
// scopespace + username + dictKey + version
// insertDictionary, i, err := dao.New(openapi.storage).InsertDictionary(dictionary)
// openapi.exchange.Put(dictionary.DictKey, dictionary.DictValue)
// if err != nil {
// return nil
//}
fmt.Println(dictionary)
// create config
// ConfigDao.save();
// go LogDao.save()
// openapi.exchange.Put("key", "value")
return nil
_, id, err := daoAction.InsertDictionary(dictionary)
if err != nil {
return result.InternalFailure(err)
}
path, PathErr := buildEtcdPath(daoAction, dictionary)
if PathErr != nil {
return result.Failure0(result.ErrorEtcdPath)
}
if stringsx.Empty(path) {
return result.Failure0(result.NilExchangePath)
}
exchangeErr := openapi.exchange.Put(path, dictParams.DictValue)
if exchangeErr != nil {
return result.InternalFailure(exchangeErr)
}
openapi.doOperationLogging(dictParams.UserId, "create dictionary and insert into mysql and etcd")
return result.Success(id)
})
}

// updateDictionary update dictionary
// @receiver openapi openapi
// @param ginCtx gin context
func (openapi *Openapi) updateDictionary(ginCtx *gin.Context) {
openapi.response(ginCtx, nil, func() *result.EnvcdResult {
fmt.Println("hello world")
// create config
// ConfigDao.save();
// go LogDao.save()
// openapi.exchange.Put("key", "value")
return nil
dictParams := &dictionUpdateDTO{}
if err := ginCtx.ShouldBindJSON(dictParams); err != nil {
fmt.Printf("Bind error, %v\n", err)
return result.InternalFailure(err)
}
daoAction := dao.New(openapi.storage)

dictionary := entity.Dictionary{
Id: dictParams.DictId,
DictValue: dictParams.DictValue,
UpdatedAt: time.Now(),
}
// update dictionary
_, updateDictErr := daoAction.UpdateDictionary(dictionary)
if updateDictErr != nil {
return result.InternalFailure(updateDictErr)
}
// update state
ret := openapi.updateDictionaryState(dictParams.DictId, dictParams.State)
if ret != nil {
return ret
}
return result.Success(nil)
})
}

// removeDictionary remove dictionary
// @receiver openapi
// @param ginCtx gin context
func (openapi *Openapi) removeDictionary(ginCtx *gin.Context) {
openapi.response(ginCtx, nil, func() *result.EnvcdResult {
userId := stringsx.ToInt(ginCtx.Param("userId"))
appId := stringsx.ToInt(ginCtx.Param("appId"))
dictId := stringsx.ToInt(ginCtx.Param("dictId"))
dict := entity.Dictionary{Id: dictId, UserId: userId, ScopeSpaceId: appId}
// query dictionary exist
daoAction := dao.New(openapi.storage)
dictionary, err := daoAction.SelectDictionary(dict)
dict, err := dictionary(openapi.storage, nil, ginCtx)
if err != nil {
return result.InternalFailure(err)
}
if len(dictionary) == 0 {
if dict == nil {
return result.Failure0(result.ErrorDictionaryNotExist)
}
exchangeErr := openapi.exchange.Remove(getFirstDictionary(dictionary).DictKey)
if exchangeErr != nil {
return result.InternalFailure(exchangeErr)
}
retId, delErr := daoAction.DeleteDictionary(getFirstDictionary(dictionary))
daoAction := dao.New(openapi.storage)
// set dictionaries state: deleted
retId, delErr := daoAction.DeleteDictionary(*dict)
if delErr != nil {
return result.InternalFailure(delErr)
}
// delete etcd path
path, etcdPathError := buildEtcdPath(daoAction, *dict)
if etcdPathError != nil {
return result.Failure0(result.ErrorEtcdPath)
}
if stringsx.Empty(path) {
return result.Failure0(result.NilExchangePath)
}
if stringsx.NotEmpty(path) {
exchangeErr := openapi.exchange.Remove(path)
if exchangeErr != nil {
return result.InternalFailure(exchangeErr)
}
}
openapi.doOperationLogging(dict.UserId, "remove dictionaries from mysql and etcd")
return result.Success(retId)
})
}

func getFirstDictionary(dictionaryList []entity.Dictionary) entity.Dictionary {
return dictionaryList[0]
}

func (openapi *Openapi) dictionaries(ginCtx *gin.Context) {
openapi.response(ginCtx, nil, func() *result.EnvcdResult {
fmt.Println("hello world")
// create config
// ConfigDao.save();
// go LogDao.save()
// openapi.exchange.Put("key", "value")
return nil
pageNum := stringsx.ToInt(ginCtx.DefaultQuery("page", "1"))
pageSize := stringsx.ToInt(ginCtx.DefaultQuery("pageSize", "20"))
daoAction := dao.New(openapi.storage)
ctx := pagehelper.C(context.Background()).PageWithCount(int64(pageNum-1), int64(pageSize), "").Build()
dictionary, err := daoAction.SelectDictionary(entity.Dictionary{}, ctx)
if err != nil {
return result.InternalFailure(err)
}
pageInfo := pagehelper.GetPageInfo(ctx)
return result.Success(PageListVO{
Page: pageInfo.Page + 1,
PageSize: pageInfo.PageSize,
Total: pageInfo.GetTotal(),
TotalPage: pageInfo.GetTotalPage(),
List: dictionary,
})
})
}

// buildEtcdPath build etcd path
// @param daoAction dao
// @param dictionary
// @return string path
// @return error message
func buildEtcdPath(daoAction *dao.Dao, dictionary entity.Dictionary) (string, error) {
// todo user name from jwt
user, userErr := daoAction.SelectUser(entity.User{Id: dictionary.UserId})
if userErr != nil {
return "", userErr
}
scopeSpace, scopeSpaceErr := daoAction.SelectScopeSpace(entity.ScopeSpace{Id: dictionary.ScopeSpaceId})
if scopeSpaceErr != nil {
return "", scopeSpaceErr
}
// user and scopeSpace not exist
if len(user) == 0 || len(scopeSpace) == 0 {
return "", errors.New("user or spaceSpace not exist")
}
// build path
build := stringsx.Builder{}
// /scopeSpaceName/userName/dictKey, etc. /spring/moremind/userKey@version
_, err := build.JoinString("/", scopeSpace[0].Name, "/", user[0].Name, "/", dictionary.DictKey)
if err != nil {
return "", err
}
return build.String(), nil
}

// updateDictionaryState update dictionary state
// @receiver openapi openapi
// @param dictId dict id
// @param state updated state
// @return *result.EnvcdResult
func (openapi *Openapi) updateDictionaryState(dictId int, state string) *result.EnvcdResult {
daoAction := dao.New(openapi.storage)
dictionaries, dictErr := daoAction.SelectDictionary(entity.Dictionary{Id: dictId}, nil)
if dictErr != nil {
return result.InternalFailure(dictErr)
}
if array.Empty(dictionaries) {
return result.Failure0(result.ErrorDictionaryNotExist)
}
defaultDictionary := dictionaries[0]
path, err := buildEtcdPath(daoAction, defaultDictionary)
if stringsx.Empty(path) {
return result.Failure0(result.NilExchangePath)
}
if err != nil {
return result.Failure0(result.ErrorEtcdPath)
}
switch state {
case constant.EnabledState:
// case enabled, should generate path and put key and value
if defaultDictionary.State != constant.EnabledState {
exchangeErr := openapi.exchange.Put(path, defaultDictionary.DictValue)
if exchangeErr != nil {
return result.InternalFailure(exchangeErr)
}
}
break
case constant.DisabledState:
// case disabled, should set state in mysql and delete dictionaries in etcd
case constant.DeletedState:
// case deleted, should set state in mysql and delete dictionaries in etcd
if defaultDictionary.State == constant.DisabledState || defaultDictionary.State == constant.DeletedState {
_, updateErr := daoAction.UpdateDictionary(entity.Dictionary{State: state})
if updateErr != nil {
return result.InternalFailure(updateErr)
}
exchangeErr := openapi.exchange.Remove(path)
if exchangeErr != nil {
return result.InternalFailure(exchangeErr)
}
}
break
default:
return result.Failure0(result.ErrorNotExistState)
}
return nil
}
Loading

0 comments on commit ee8c3bf

Please sign in to comment.