diff --git a/.gitignore b/.gitignore index cb78238..e8465a6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,15 @@ works-api/works-api works-shell/works-shell.exe works-shell/works-shell -.idea/ +works-api/docs/docs.go +works-api/docs/swagger.json +works-api/docs/swagger.yaml +works-api/docs/* +Works-ui/node_modules/* +works-api/.idea/*.xml +works-api/.idea/**/*.xml samba-ad.zip *.exe *.log *.msi *.zip -works-api/docs/docs.go \ No newline at end of file diff --git a/works-api/authController.go b/works-api/authController.go index fd9fde0..675c6b2 100644 --- a/works-api/authController.go +++ b/works-api/authController.go @@ -500,3 +500,78 @@ func delDeleteUserToGroup(c *gin.Context) { "result": result, }) } + +// patchPasswordUser godoc +// @Summary 사용자 비밀번호를 변경 하는 API +// @Description 사용자 비밀번호를 변경하는 API 입니다. +// @Accept json +// @Tags User +// @Produce json +// @Param userName path string true "사용자 계정" +// @Param oldPassword path string true "기존 비밀번호" +// @Param userName path string true "새로운 비밀번호" +// @Router /api/v1/passwordUser/:userName [patch] +// @Success 200 {object} map[string]interface{} +func patchPasswordUser(c *gin.Context) { + userName := c.Param("userName") + oldPassword := c.PostForm("oldPassword") + newPassword := c.PostForm("newPassword") + //log.Infof("deleteDCUserResult [%v], err [%v]", deleteDCUserResult, err) + //result["status"] = http.StatusOK + resultLogin, err := postLogin(userName, oldPassword) + result := map[string]interface{}{} + if err != nil { + log.Errorf("result [%v], error [%v]", result, err) + result["message"] = "Communication with the DC server failed." + c.JSON(http.StatusBadRequest, gin.H{ + "result": result, + }) + return + } else { + + var res map[string]interface{} + json.NewDecoder(resultLogin.Body).Decode(&res) + + user := User{} + userInfo, _ := json.Marshal(res) + json.Unmarshal(userInfo, &user) + loginBool := user.Login + if loginBool == false { + result["message"] = " " + c.JSON(http.StatusNotFound, gin.H{ + "result": result, + }) + return + } else if loginBool == true { + userPasswordChange(userName, newPassword) + user.ClusterName = os.Getenv("ClusterName") + user.DomainName = os.Getenv("SambaDomain") + c.JSON(http.StatusOK, gin.H{ + "result": user, + }) + return + } + } + c.JSON(http.StatusNoContent, gin.H{ + "result": "user password change failure", + }) +} + +// patchPasswordAdmin godoc +// @Summary 사용자 비밀번호를 변경 하는 API +// @Description 사용자 비밀번호를 변경하는 API 입니다. +// @Accept json +// @Tags User +// @Produce json +// @Param userName path string true "사용자 계정" +// @Param userName path string true "새로운 비밀번호" +// @Router /api/v1/passwordAdmin/:userName [patch] +// @Success 200 {object} map[string]interface{} +func patchPasswordAdmin(c *gin.Context) { + userName := c.Param("userName") + newPassword := c.PostForm("newPassword") + userPasswordChange(userName, newPassword) + c.JSON(http.StatusOK, gin.H{ + "result": "password change result", + }) +} diff --git a/works-api/authDao.go b/works-api/authDao.go new file mode 100644 index 0000000..88e1472 --- /dev/null +++ b/works-api/authDao.go @@ -0,0 +1,135 @@ +package main + +import ( + "database/sql" + "net/http" + "os" +) + +type User struct { + Id string `json:"id"` + Uuid string `json:"uuid"` + UserName string `json:"user_name"` + CreateDate string `json:"create_date"` + Password string `json:"password"` + Removed string `json:"removed"` + C string `json:"c"` // 국가코드 영문 + Cn string `json:"cn"` // 유저아이디 + Co string `json:"co"` // 국가코드 영문 + CountryCode string `json:"countryCode"` // 국가코드 숫자 + DistinguishedName string `json:"distinguishedName"` // 고유이름 + GivenName string `json:"givenName"` // 사용자 이름 + Mail string `json:"mail"` // e-mail + MemberOf string `json:"memberOf"` // 소속 그룹 + Name string `json:"name"` // 사용자 계정 + SAMAccountName string `json:"sAMAccountName"` // 사용자 계정 + Sn string `json:"sn"` // 사용자 성 + TelephoneNumber string `json:"telephoneNumber"` // 전화번호 + Title string `json:"title"` // 직책 + UserPrincipalName string `json:"userPrincipalName"` // 사용자 도메인 계정정보 + Department string `json:"department"` // 사용자 부서 + ClusterName string `json:"clusterName"` + DomainName string `json:"domainName"` + Login bool `json:"login"` + UserNameDc string `json:"username"` + Groups []string `json:"groups"` + IsAdmin bool `json:"isAdmin"` + Token string `json:"token"` +} + +func insertUserDB(user User) map[string]interface{} { + db, err := sql.Open(os.Getenv("MysqlType"), os.Getenv("DbInfo")) + resultReturn := map[string]interface{}{} + if err != nil { + log.Error("DB connect error") + log.Error(err) + resultReturn["message"] = "DB connect error" + } + defer db.Close() + result, err := db.Exec("INSERT INTO users(uuid, user_name, password, create_date) VALUES (?, ?, ?, now())", getUuid(), user.Cn, user.Password) + if err != nil { + log.Errorf("유저를 DB 등록중에러가 발생했습니다. [%v]", err) + resultReturn["message"] = "An error occurred while registering Async Job." + resultReturn["status"] = SQLQueryError + } + n, _ := result.RowsAffected() + if n == 1 { + log.Info("유저가 정상적으로 등록되었습니다.") + resultReturn["status"] = http.StatusOK + resultReturn["message"] = "The async job has been successfully registered." + } + return resultReturn +} + +func selectUserDBDetail(userName string) User { + db, err := sql.Open(os.Getenv("MysqlType"), os.Getenv("DbInfo")) + if err != nil { + log.Error("DB connect error") + log.Error(err) + } + defer db.Close() + log.Info("DB connect success") + user := User{} + err = db.QueryRow("SELECT uuid, user_name, create_date, password FROM users WHERE removed IS NULL AND user_name = ? ORDER BY id DESC ", userName).Scan( + &user.Uuid, &user.UserName, &user.CreateDate, &user.Password) + if err != nil { + log.Error("user select query FAILED") + log.Error(err.Error()) + } + + return user +} + +func deleteUserDB(userName string) map[string]interface{} { + db, err := sql.Open(os.Getenv("MysqlType"), os.Getenv("DbInfo")) + if err != nil { + log.Error("DB connect error") + log.Error(err) + } + defer db.Close() + log.Info("DB connect success") + returnValue := map[string]interface{}{} + result, err := db.Exec("UPDATE users SET removed=NOW() WHERE user_name=? ", userName) + if err != nil { + log.Errorf("유저 삭제중 에러가 발생했습니다.\n") + log.Errorf("%v\n", err) + returnValue["status"] = BaseErrorCode + returnValue["message"] = "An error occurred while registering Async Job." + } + n, _ := result.RowsAffected() + if n == 1 { + log.Infof("%v\n", result) + log.Infof("유저가 정상적으로 삭제 되였습니다.\n") + returnValue["status"] = http.StatusOK + returnValue["message"] = "async job has been updated normally." + } + + return returnValue +} + +func updateUserPassword(userName string, newPassword string) DatabaseReturnValue { + db, err := sql.Open(os.Getenv("MysqlType"), os.Getenv("DbInfo")) + if err != nil { + log.Error("DB connect error") + log.Error(err) + } + defer db.Close() + log.Info("DB connect success") + databaseReturnValue := DatabaseReturnValue{} + result, err := db.Exec("UPDATE users SET password=? WHERE user_name=? ", newPassword, userName) + if err != nil { + log.Errorf("유저 비밀번호 업데이트 중 에러가 발생했습니다.\n") + log.Errorf("%v\n", err) + databaseReturnValue.status = BaseErrorCode + databaseReturnValue.message = "An error occurred while registering Async Job." + } + n, _ := result.RowsAffected() + if n == 1 { + log.Infof("%v\n", result) + log.Infof("유저 비밀번호 업데이트가 정상적으로 되였습니다.\n") + databaseReturnValue.status = http.StatusOK + databaseReturnValue.message = "async job has been updated normally." + } + + return databaseReturnValue +} diff --git a/works-api/authService.go b/works-api/authService.go index 1dc757b..1367b44 100644 --- a/works-api/authService.go +++ b/works-api/authService.go @@ -1,84 +1,10 @@ package main -import ( - "database/sql" - "net/http" - "os" -) +import "net/http" -type User struct { - Id string `json:"id"` - Uuid string `json:"uuid"` - UserName string `json:"user_name"` - CreateDate string `json:"create_date"` - Password string `json:"password"` - Removed string `json:"removed"` - C string `json:"c"` // 국가코드 영문 - Cn string `json:"cn"` // 유저아이디 - Co string `json:"co"` // 국가코드 영문 - CountryCode string `json:"countryCode"` // 국가코드 숫자 - DistinguishedName string `json:"distinguishedName"` // 고유이름 - GivenName string `json:"givenName"` // 사용자 이름 - Mail string `json:"mail"` // e-mail - MemberOf string `json:"memberOf"` // 소속 그룹 - Name string `json:"name"` // 사용자 계정 - SAMAccountName string `json:"sAMAccountName"` // 사용자 계정 - Sn string `json:"sn"` // 사용자 성 - TelephoneNumber string `json:"telephoneNumber"` // 전화번호 - Title string `json:"title"` // 직책 - UserPrincipalName string `json:"userPrincipalName"` // 사용자 도메인 계정정보 - Department string `json:"department"` // 사용자 부서 - ClusterName string `json:"clusterName"` - DomainName string `json:"domainName"` - Login bool `json:"login"` - UserNameDc string `json:"username"` - Groups []string `json:"groups"` - IsAdmin bool `json:"isAdmin"` - Token string `json:"token"` -} - -func selectUserDBDetail(userName string) User { - db, err := sql.Open(os.Getenv("MysqlType"), os.Getenv("DbInfo")) - if err != nil { - log.Error("DB connect error") - log.Error(err) - } - defer db.Close() - log.Info("DB connect success") - user := User{} - err = db.QueryRow("SELECT uuid, user_name, create_date, password FROM users WHERE removed IS NULL AND user_name = ? ORDER BY id DESC ", userName).Scan( - &user.Uuid, &user.UserName, &user.CreateDate, &user.Password) - if err != nil { - log.Error("user select query FAILED") - log.Error(err.Error()) - } - - return user -} - -func deleteUserDB(userName string) map[string]interface{} { - db, err := sql.Open(os.Getenv("MysqlType"), os.Getenv("DbInfo")) - if err != nil { - log.Error("DB connect error") - log.Error(err) - } - defer db.Close() - log.Info("DB connect success") - returnValue := map[string]interface{}{} - result, err := db.Exec("UPDATE users SET removed=NOW() WHERE user_name=? ", userName) - if err != nil { - log.Errorf("유저 삭제중 에러가 발생했습니다.\n") - log.Errorf("%v\n", err) - returnValue["status"] = BaseErrorCode - returnValue["message"] = "An error occurred while registering Async Job." +func userPasswordChange(userName string, newPassword string) { + databaseReturnValue := updateUserPassword(userName, newPassword) + if databaseReturnValue.status == http.StatusOK { + patchUserPassword(userName, newPassword) } - n, _ := result.RowsAffected() - if n == 1 { - log.Infof("%v\n", result) - log.Infof("유저가 정상적으로 삭제 되였습니다.\n") - returnValue["status"] = http.StatusOK - returnValue["message"] = "async job has been updated normally." - } - - return returnValue } diff --git a/works-api/communicationDC.go b/works-api/communicationDC.go index 4fdf259..1d1b2e8 100644 --- a/works-api/communicationDC.go +++ b/works-api/communicationDC.go @@ -1,13 +1,14 @@ package main import ( - "database/sql" "encoding/json" "fmt" "github.com/sirupsen/logrus" "net/http" "net/url" "os" + "strconv" + "strings" "time" ) @@ -69,7 +70,11 @@ func getUserList() ([]User, error) { "authDAO": "getUserList", }).Errorf("DC communication failed. [%v], error [%v]", resp, err) } else { - json.NewDecoder(resp.Body).Decode(&res) + err := json.NewDecoder(resp.Body).Decode(&res) + if err != nil { + return nil, err + } + jsonMarshal, _ := json.Marshal(res) json.Unmarshal([]byte(jsonMarshal), &userInfoList) log.WithFields(logrus.Fields{ @@ -145,6 +150,46 @@ func insertPolicyRemotefx(groupName string) (*http.Response, error) { return resp, err } +func insertPolicyDC(groupName string, policy Policy) (*http.Response, error) { + var DCInfo = os.Getenv("DCUrl") + client := http.Client{ + Timeout: 20 * time.Second, + } + params := url.Values{ + "groupname": {groupName}, + } + log.Infof("paramsInfo = [%v]", params) + + req, err := http.NewRequest(http.MethodPut, fmt.Sprintf("%v/v1/policy/%v/%v", DCInfo, policy.AdGroupName, groupName), nil) + + req.Header.Add("Content-Type", "application/x-www-form-urlencoded") + resp, err := client.Do(req) + log.WithFields(logrus.Fields{ + "dcDAO": "insertPolicyRemotefx", + }).Infof("workspace group add remotrfx status. resp [%v], err [%v]", resp, err) + return resp, err +} + +func deletePolicyDC(groupName string, policy Policy) (*http.Response, error) { + var DCInfo = os.Getenv("DCUrl") + client := http.Client{ + Timeout: 20 * time.Second, + } + params := url.Values{ + "groupname": {groupName}, + } + log.Infof("paramsInfo = [%v]", params) + + req, err := http.NewRequest(http.MethodDelete, fmt.Sprintf("%v/v1/policy/%v/%v", DCInfo, policy.AdGroupName, groupName), nil) + + req.Header.Add("Content-Type", "application/x-www-form-urlencoded") + resp, err := client.Do(req) + log.WithFields(logrus.Fields{ + "dcDAO": "insertPolicyRemotefx", + }).Infof("workspace group add remotrfx status. resp [%v], err [%v]", resp, err) + return resp, err +} + func selectDCWorkspacePolicyList(workspace Workspace) (*http.Response, error) { var DCInfo = os.Getenv("DCUrl") @@ -240,30 +285,6 @@ func deleteAddUserToGroup(groupName string, userName string) (*http.Response, er return resp, err1 } -func insertUserDB(user User) map[string]interface{} { - db, err := sql.Open(os.Getenv("MysqlType"), os.Getenv("DbInfo")) - resultReturn := map[string]interface{}{} - if err != nil { - log.Error("DB connect error") - log.Error(err) - resultReturn["message"] = "DB connect error" - } - defer db.Close() - result, err := db.Exec("INSERT INTO users(uuid, user_name, password, create_date) VALUES (?, ?, ?, now())", getUuid(), user.Cn, user.Password) - if err != nil { - log.Errorf("유저를 DB 등록중에러가 발생했습니다. [%v]", err) - resultReturn["message"] = "An error occurred while registering Async Job." - resultReturn["status"] = SQLQueryError - } - n, _ := result.RowsAffected() - if n == 1 { - log.Info("유저가 정상적으로 등록되었습니다.") - resultReturn["status"] = http.StatusOK - resultReturn["message"] = "The async job has been successfully registered." - } - return resultReturn -} - func insertUserAllocatedInstance1(username string, instanceUuid string) *http.Response { var DCInfo = os.Getenv("DCUrl") client := http.Client{ @@ -346,3 +367,25 @@ func selectPasswordConvert(password string) (*http.Response, error) { return resp, err } + +func patchUserPassword(userName string, newPassword string) (*http.Response, error) { + var DCInfo = os.Getenv("DCUrl") + client := http.Client{ + Timeout: 30 * time.Second, + } + params := url.Values{ + "password": {newPassword}, + } + req, _ := http.NewRequest(http.MethodPatch, fmt.Sprintf("%v/v1/user/%v", DCInfo, userName), strings.NewReader(params.Encode())) + + req.Header.Add("Content-Type", "application/x-www-form-urlencoded") + req.Header.Add("Content-Length", strconv.Itoa(len(params.Encode()))) + resp, err := client.Do(req) + if err != nil { + log.WithFields(logrus.Fields{ + "communicationMold.go": "patchUserPassword", + }).Errorf("An error occurred while deleting the connection. resp [%v], err [%v]", resp, err) + } + + return resp, err +} diff --git a/works-api/container/Dockerfile b/works-api/container/Dockerfile new file mode 100644 index 0000000..8ab79de --- /dev/null +++ b/works-api/container/Dockerfile @@ -0,0 +1,9 @@ +FROM alpine:3.14 + +LABEL MAINTAINER="Lee SeockMin " + +WORKDIR /go/src/app + +COPY . . + +CMD ["./works-api"] diff --git a/works-api/container/properties.json b/works-api/container/properties.json new file mode 100644 index 0000000..d673fe9 --- /dev/null +++ b/works-api/container/properties.json @@ -0,0 +1,15 @@ +{ + "database": { + "type": "mysql", + "user":{ + "id":"works", + "password":"Ablecloud1!" + }, + "host":{ + "address": "10.88.2.12", + "port": "3306", + "protocol": "tcp" + }, + "db": "works" + } +} diff --git a/works-api/dist/README.md b/works-api/dist/README.md deleted file mode 100644 index d3d4390..0000000 --- a/works-api/dist/README.md +++ /dev/null @@ -1 +0,0 @@ -works-api build diff --git a/works-api/docs/docs.go b/works-api/docs/docs.go index 4f693bb..f9d6994 100644 --- a/works-api/docs/docs.go +++ b/works-api/docs/docs.go @@ -124,167 +124,6 @@ var doc = `{ } } }, - "/api/v1/application": { - "post": { - "description": "워크스페이스 수, 데스크톱 수, 데스크톱 연결 수, APP 연결 수 정보를 제공하는 API 입니다.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Application" - ], - "summary": "Application 가상화를 등록하는 API", - "parameters": [ - { - "type": "string", - "description": "Workspace 의 Uuid", - "name": "workspaceUuid", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Application 이름", - "name": "name", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Application 경로", - "name": "path", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Application workingDirectory", - "name": "workingDirectory", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Application RegApplicationServer", - "name": "RegApplicationServer", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "object", - "additionalProperties": true - } - } - } - }, - "delete": { - "description": "워크스페이스 수, 데스크톱 수, 데스크톱 연결 수, APP 연결 수 정보를 제공하는 API 입니다.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Application" - ], - "summary": "Application 가상화를 등록하는 API", - "parameters": [ - { - "type": "string", - "description": "Application 이름", - "name": "name", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Application 경로", - "name": "path", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Application workingDirectory", - "name": "workingDirectory", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Application RegApplicationServer", - "name": "RegApplicationServer", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "object", - "additionalProperties": true - } - } - } - } - }, - "/api/v1/application/:workspaceUuid": { - "get": { - "description": "Application List 를 조회하는 API 입니다.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Application" - ], - "summary": "Application List 조회하는 API", - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "object", - "additionalProperties": true - } - } - } - } - }, - "/api/v1/applicationServer/:workspaceUuid": { - "get": { - "description": "Application List 를 조회하는 API 입니다.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Application" - ], - "summary": "Application List 조회하는 API", - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "object", - "additionalProperties": true - } - } - } - } - }, "/api/v1/configuration": { "get": { "description": "Works 의 환경 설정을 조회하는 API 입니다.", @@ -708,7 +547,7 @@ var doc = `{ "parameters": [ { "type": "string", - "description": "action 해당 값은 [VMStart, VMStop, VMDestroy] 으로 보내야 합니다.", + "description": "action 해당 값은 [VMStart, VMStop, VMDestroy, VMReboot] 으로 보내야 합니다.", "name": "action", "in": "path", "required": true @@ -1035,6 +874,30 @@ var doc = `{ } } }, + "/api/v1/userdesktop/:userName": { + "get": { + "description": "유저에게 할당된 Desktop 목록을 조회하는 API", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "userDesktop" + ], + "summary": "유저 Desktop 목록을 조회하는 API", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + } + }, "/api/v1/workspace": { "get": { "description": "워크 스페이스 리스트를 조회하는 API 입니다.", diff --git a/works-api/docs/swagger.json b/works-api/docs/swagger.json index 816d34c..9af58aa 100644 --- a/works-api/docs/swagger.json +++ b/works-api/docs/swagger.json @@ -105,167 +105,6 @@ } } }, - "/api/v1/application": { - "post": { - "description": "워크스페이스 수, 데스크톱 수, 데스크톱 연결 수, APP 연결 수 정보를 제공하는 API 입니다.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Application" - ], - "summary": "Application 가상화를 등록하는 API", - "parameters": [ - { - "type": "string", - "description": "Workspace 의 Uuid", - "name": "workspaceUuid", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Application 이름", - "name": "name", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Application 경로", - "name": "path", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Application workingDirectory", - "name": "workingDirectory", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Application RegApplicationServer", - "name": "RegApplicationServer", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "object", - "additionalProperties": true - } - } - } - }, - "delete": { - "description": "워크스페이스 수, 데스크톱 수, 데스크톱 연결 수, APP 연결 수 정보를 제공하는 API 입니다.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Application" - ], - "summary": "Application 가상화를 등록하는 API", - "parameters": [ - { - "type": "string", - "description": "Application 이름", - "name": "name", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Application 경로", - "name": "path", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Application workingDirectory", - "name": "workingDirectory", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Application RegApplicationServer", - "name": "RegApplicationServer", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "object", - "additionalProperties": true - } - } - } - } - }, - "/api/v1/application/:workspaceUuid": { - "get": { - "description": "Application List 를 조회하는 API 입니다.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Application" - ], - "summary": "Application List 조회하는 API", - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "object", - "additionalProperties": true - } - } - } - } - }, - "/api/v1/applicationServer/:workspaceUuid": { - "get": { - "description": "Application List 를 조회하는 API 입니다.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Application" - ], - "summary": "Application List 조회하는 API", - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "object", - "additionalProperties": true - } - } - } - } - }, "/api/v1/configuration": { "get": { "description": "Works 의 환경 설정을 조회하는 API 입니다.", @@ -689,7 +528,7 @@ "parameters": [ { "type": "string", - "description": "action 해당 값은 [VMStart, VMStop, VMDestroy] 으로 보내야 합니다.", + "description": "action 해당 값은 [VMStart, VMStop, VMDestroy, VMReboot] 으로 보내야 합니다.", "name": "action", "in": "path", "required": true @@ -1016,6 +855,30 @@ } } }, + "/api/v1/userdesktop/:userName": { + "get": { + "description": "유저에게 할당된 Desktop 목록을 조회하는 API", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "userDesktop" + ], + "summary": "유저 Desktop 목록을 조회하는 API", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + } + }, "/api/v1/workspace": { "get": { "description": "워크 스페이스 리스트를 조회하는 API 입니다.", diff --git a/works-api/docs/swagger.yaml b/works-api/docs/swagger.yaml index 9197666..64d5b17 100644 --- a/works-api/docs/swagger.yaml +++ b/works-api/docs/swagger.yaml @@ -70,116 +70,6 @@ paths: summary: instance 에 사용자를 할당하는 API tags: - Connection - /api/v1/application: - delete: - consumes: - - application/json - description: 워크스페이스 수, 데스크톱 수, 데스크톱 연결 수, APP 연결 수 정보를 제공하는 API 입니다. - parameters: - - description: Application 이름 - in: path - name: name - required: true - type: string - - description: Application 경로 - in: path - name: path - required: true - type: string - - description: Application workingDirectory - in: path - name: workingDirectory - required: true - type: string - - description: Application RegApplicationServer - in: path - name: RegApplicationServer - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - additionalProperties: true - type: object - summary: Application 가상화를 등록하는 API - tags: - - Application - post: - consumes: - - application/json - description: 워크스페이스 수, 데스크톱 수, 데스크톱 연결 수, APP 연결 수 정보를 제공하는 API 입니다. - parameters: - - description: Workspace 의 Uuid - in: path - name: workspaceUuid - required: true - type: string - - description: Application 이름 - in: path - name: name - required: true - type: string - - description: Application 경로 - in: path - name: path - required: true - type: string - - description: Application workingDirectory - in: path - name: workingDirectory - required: true - type: string - - description: Application RegApplicationServer - in: path - name: RegApplicationServer - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - additionalProperties: true - type: object - summary: Application 가상화를 등록하는 API - tags: - - Application - /api/v1/application/:workspaceUuid: - get: - consumes: - - application/json - description: Application List 를 조회하는 API 입니다. - produces: - - application/json - responses: - "200": - description: OK - schema: - additionalProperties: true - type: object - summary: Application List 조회하는 API - tags: - - Application - /api/v1/applicationServer/:workspaceUuid: - get: - consumes: - - application/json - description: Application List 를 조회하는 API 입니다. - produces: - - application/json - responses: - "200": - description: OK - schema: - additionalProperties: true - type: object - summary: Application List 조회하는 API - tags: - - Application /api/v1/configuration: get: consumes: @@ -460,7 +350,7 @@ paths: - application/json description: instance 의 상태를 변경하는 API 입니다. parameters: - - description: action 해당 값은 [VMStart, VMStop, VMDestroy] 으로 보내야 합니다. + - description: action 해당 값은 [VMStart, VMStop, VMDestroy, VMReboot] 으로 보내야 합니다. in: path name: action required: true @@ -689,6 +579,22 @@ paths: summary: 사용자 상세조회 하는 API tags: - User + /api/v1/userdesktop/:userName: + get: + consumes: + - application/json + description: 유저에게 할당된 Desktop 목록을 조회하는 API + produces: + - application/json + responses: + "200": + description: OK + schema: + additionalProperties: true + type: object + summary: 유저 Desktop 목록을 조회하는 API + tags: + - userDesktop /api/v1/workspace: delete: consumes: diff --git a/works-api/handshake.go b/works-api/handshake.go index 854c56c..b907753 100644 --- a/works-api/handshake.go +++ b/works-api/handshake.go @@ -8,6 +8,7 @@ import ( "net/http" "net/url" "os" + "strings" "time" ) @@ -95,13 +96,16 @@ func handshakeVdi(instanceInfo Instance, vdiType string) { log.WithFields(logrus.Fields{ "VDI_IP": vdiUrl, }).Infof("VDI AD join status. [%v]", statusString) - reqGetGpupdate, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%v/v1/cmd/?timeout=60&cmd=%v", vdiUrl, url.QueryEscape("gpupdate /force")), nil) + params := url.Values{ + "domain": {os.Getenv("SambaDomain")}, + } + reqGetGpupdate, err := http.NewRequest(http.MethodPatch, fmt.Sprintf("%v/v1", vdiUrl), strings.NewReader(params.Encode())) if err != nil { log.Errorf("An error occurred while setting the URL. [%v]", err) } reqGetGpupdate.Header.Add("Content-Type", "application/x-www-form-urlencoded") resp, err1 := client.Do(reqGetGpupdate) - log.Warnf("resp [%v], err1 [%v]", resp.StatusCode, err1) + log.Warnf("resp [%v], err1 [%v]", resp, err1) if err1 != nil { log.WithFields(logrus.Fields{ "VDI_IP": vdiUrl, diff --git a/works-api/main.go b/works-api/main.go index dc5add1..742acaf 100644 --- a/works-api/main.go +++ b/works-api/main.go @@ -9,8 +9,6 @@ import ( ginSwagger "github.com/swaggo/gin-swagger" "github.com/swaggo/gin-swagger/swaggerFiles" "net/http" - "os" - "os/exec" //_ "works-api/docs" ) @@ -22,20 +20,6 @@ var ( nodeContextCancel context.CancelFunc ) -func StartClientApp() (*exec.Cmd, error) { - var err error - - cmd := exec.Command("npm", "run", "serve") - cmd.Dir = "./app" - cmd.Stdout = os.Stdout - - if err = cmd.Start(); err != nil { - return cmd, fmt.Errorf("error starting NPM: %w", err) - } - - return cmd, nil -} - func main() { var ( err error @@ -53,8 +37,6 @@ func main() { router := gin.Default() router.Use(SetHeader) - //router.LoadHTMLGlob("templates/*") - //router.Use(static.Serve("/", static.LocalFile("./app/dist/", true))) router.Use(static.Serve("/swagger/", static.LocalFile("./docs", true))) api := router.Group("/api") { @@ -109,6 +91,9 @@ func main() { v1.PUT("/user", putUser) v1.DELETE("/user/:userName", deleteUser) + v1.PATCH("/passwordUser/:userName", patchPasswordUser) + v1.PATCH("/passwordAdmin/:userName", patchPasswordAdmin) + v1.GET("/group", getGroup) v1.GET("/group/:groupName", getGroupDetail) v1.DELETE("/group/:groupName", delGroupDetail) @@ -116,6 +101,8 @@ func main() { v1.PUT("/group/:groupName/:userName", putAddUserToGroup) v1.GET("/userdesktop/:userName", getUserDesktop) + + v1.PATCH("/policy/:workspaceUuid", patchPolicy) } test := api.Group("/test") { diff --git a/works-api/policyController.go b/works-api/policyController.go new file mode 100644 index 0000000..6b95ff8 --- /dev/null +++ b/works-api/policyController.go @@ -0,0 +1,31 @@ +package main + +import ( + "github.com/gin-gonic/gin" + "net/http" +) + +// patchPolicy godoc +// @Summary 정책을 변경하는 API +// @Description 정책을 변경하는 API 입니다. +// @Tags policy +// @Param policyName path string true "정책명" +// @Param policyValue path string true "정책값" +// @Accept json +// @Produce json +// @Router /api/v1/policy/:workspaceUuid [patch] +// @Success 200 {object} map[string]interface{} +func patchPolicy(c *gin.Context) { + policyInfo := Policy{} + policyInfo.WorkspacesUuid = c.Param("workspaceUuid") + policyInfo.Name = c.PostForm("policyName") + policyInfo.Value = c.PostForm("policyValue") + workspaceInfo := selectWorkspaceInfo(policyInfo.WorkspacesUuid) + returnCode := http.StatusOK + returnData := map[string]interface{}{} + + returnData["patchPolicy"] = updatePolicy(workspaceInfo, policyInfo) + c.JSON(returnCode, gin.H{ + "result": returnData, + }) +} diff --git a/works-api/policyDao.go b/works-api/policyDao.go new file mode 100644 index 0000000..09c3640 --- /dev/null +++ b/works-api/policyDao.go @@ -0,0 +1,293 @@ +package main + +import ( + "database/sql" + "github.com/sirupsen/logrus" + "net/http" + "os" +) + +type Policy struct { + Id int `json:"id"` + WorkspacesUuid string `json:"workspaces_uuid"` + Name string `json:"name"` + Description string `json:"description"` + I18n string `json:"i18N"` + Value string `json:"value"` + Type string `json:"type"` + SettableValue string `json:"settable_value"` + SettableType string `json:"settable_type"` + AdGroupName string `json:"ad_group_name"` +} + +type PolicyName struct { + Id int `json:"id"` + WorkspaceUuid string `json:"workspace_uuid"` + RdpPort int `json:"rdp_port"` + RdpAccessAllow int `json:"rdp_access_allow"` + ClipboardRedirection int `json:"clipboard_redirection"` + WindowsInstaller int `json:"windows_installer"` + NetworkFileShare int `json:"network_file_share"` + NetworkPrinterShare int `json:"network_printer_share"` + LocalPrinter int `json:"local_printer"` + WindowsAutoUpdate int `json:"windows_auto_update"` + RemovableStorage int `json:"removable_storage"` + CmdUse int `json:"cmd_use"` + SettingsUse int `json:"settings_use"` + PcPowerUse int `json:"pc_power_use"` + Remotefx int `json:"remotefx"` + Console int `json:"console"` + InitialProgram int `json:"initial_program"` + ServerLayout int `json:"server_layout"` + ColorDepth int `json:"color_depth"` + Width int `json:"width"` + Height int `json:"height"` + Dpi int `json:"dpi"` + ResizeMethod string `json:"resize_method"` + ForceLossless int `json:"force_lossless"` + DisableAudio int `json:"disable_audio"` + EnableAudioInput int `json:"enable_audio_input"` + EnablePrinting int `json:"enable_printing"` + PrinterName string `json:"printer_name"` + EnableDrive int `json:"enable_drive"` + DisableDownload int `json:"disable_download"` + DisableUpload int `json:"disable_upload"` + DrivePath string `json:"drive_path"` + CreateDrivePath int `json:"create_drive_path"` + ConsoleAudio int `json:"console_audio"` + EnableWallpaper int `json:"enable_wallpaper"` + EnableTheming int `json:"enable_theming"` + EnableFontSmoothing int `json:"enable_font_smoothing"` + EnableFullWindowDrag int `json:"enable_full_window_drag"` + EnableDesktopComposition int `json:"enable_desktop_composition"` + EnableMenuAnimations int `json:"enable_menu_animations"` +} + +func selectDefaultPolicyList() ([]Policy, error) { + log.WithFields(logrus.Fields{ + "policyDao": "selectDefaultPolicyList", + }).Infof("payload") + db, err := sql.Open(os.Getenv("MysqlType"), os.Getenv("DbInfo")) + if err != nil { + log.WithFields(logrus.Fields{ + "policyDao": "selectDefaultPolicyList", + }).Errorf("selectDefaultPolicyList DB Connect Error [%v]", err) + } + defer db.Close() + log.WithFields(logrus.Fields{ + "policyDao": "selectDefaultPolicyList", + }).Infof("select selectDefaultPolicyList DB Connect success") + + policyString := " id, name, description, i18n, IFNULL(value,'')," + + " type, settable_type, IFNULL(settable_value,''), IFNULL(ad_group_name,'')" + + queryString := "SELECT" + + policyString + + " FROM policy_list" + + " ORDER BY id DESC" + + log.WithFields(logrus.Fields{ + "policyDao": "selectDefaultPolicyList", + }).Infof("select selectDefaultPolicyList Query [%v]", queryString) + rows, err := db.Query(queryString) + if err != nil { + log.WithFields(logrus.Fields{ + "policyDao": "selectDefaultPolicyList", + }).Errorf("selectDefaultPolicyList Select Query FAILED [%v]", err) + } + var policyList []Policy + defer rows.Close() + for rows.Next() { + policy := Policy{} + err = rows.Scan( + &policy.Id, &policy.Name, &policy.Description, &policy.I18n, &policy.Value, + &policy.Type, &policy.SettableType, &policy.SettableValue, &policy.AdGroupName) + if err != nil { + log.WithFields(logrus.Fields{ + "policyDao": "selectDefaultPolicyList", + }).Errorf("WorkspacePolicy Select Query 이후 Scan 중 에러가 발생했습니다. [%v]", err) + } + + policyList = append(policyList, policy) + } + log.WithFields(logrus.Fields{ + "policyDao": "selectDefaultPolicyList", + }).Infof("selectDefaultPolicyList Query result [%v]", policyList) + + return policyList, err +} + +func selectDefaultPolicyInfo(policyName string) (Policy, error) { + log.WithFields(logrus.Fields{ + "policyDao": "selectDefaultPolicyList", + }).Infof("payload") + db, err := sql.Open(os.Getenv("MysqlType"), os.Getenv("DbInfo")) + if err != nil { + log.WithFields(logrus.Fields{ + "policyDao": "selectDefaultPolicyList", + }).Errorf("selectDefaultPolicyList DB Connect Error [%v]", err) + } + defer db.Close() + log.WithFields(logrus.Fields{ + "policyDao": "selectDefaultPolicyList", + }).Infof("select selectDefaultPolicyList DB Connect success") + + policyString := " id, name, description, i18n, value," + + " type, settable_type, settable_value, ad_group_name" + + queryString := "SELECT" + + policyString + + " FROM policy_list" + + " WHERE name = ?" + + " ORDER BY id DESC" + + log.WithFields(logrus.Fields{ + "policyDao": "selectDefaultPolicyList", + }).Infof("select selectDefaultPolicyList Query [%v]", queryString) + + var policy Policy + + err = db.QueryRow(queryString, policyName). + Scan(&policy.Id, &policy.Name, &policy.Description, &policy.I18n, &policy.Value, + &policy.Type, &policy.SettableType, &policy.SettableValue, &policy.AdGroupName) + + rows, err := db.Query(queryString, policyName) + + if err != nil { + log.WithFields(logrus.Fields{ + "policyDao": "selectDefaultPolicyList", + }).Errorf("selectDefaultPolicyList Select Query FAILED [%v]", err) + } + defer rows.Close() + //var policyList []Policy + //for rows.Next() { + // policy := Policy{} + // err = rows.Scan( + // &policy.Id, &policy.Name, &policy.Description, &policy.I18n, &policy.Value, + // &policy.Type, &policy.SettableType, &policy.SettableValue, &policy.AdGroupName) + // if err != nil { + // log.WithFields(logrus.Fields{ + // "policyDao": "selectDefaultPolicyList", + // }).Errorf("WorkspacePolicy Select Query 이후 Scan 중 에러가 발생했습니다. [%v]", err) + // } + // + // policyList = append(policyList, policy) + //} + log.WithFields(logrus.Fields{ + "policyDao": "selectDefaultPolicyList", + }).Infof("selectDefaultPolicyList Query result [%v]", policyList) + + return policy, err +} + +func selectWorkspacesPolicyList(workspaceUuid string) ([]Policy, error) { + log.WithFields(logrus.Fields{ + "policyDao": "selectWorkspacesPolicyList", + }).Infof("payload") + db, err := sql.Open(os.Getenv("MysqlType"), os.Getenv("DbInfo")) + if err != nil { + log.WithFields(logrus.Fields{ + "policyDao": "selectWorkspacesPolicyList", + }).Errorf("selectDefaultPolicyList DB Connect Error [%v]", err) + } + defer db.Close() + log.WithFields(logrus.Fields{ + "policyDao": "selectWorkspacesPolicyList", + }).Infof("select selectDefaultPolicyList DB Connect success") + + policyString := " id, name, workspaces_uuid, value" + + queryString := "SELECT" + + policyString + + " FROM workspaces_policy" + + " WHERE workspaces_uuid = ?" + + " ORDER BY id DESC" + log.WithFields(logrus.Fields{ + "policyDao": "selectWorkspacesPolicyList", + }).Infof("select selectWorkspacesPolicyList Query [%v]", queryString) + rows, err := db.Query(queryString, workspaceUuid) + if err != nil { + log.WithFields(logrus.Fields{ + "policyDao": "selectWorkspacesPolicyList", + }).Errorf("selectWorkspacesPolicyList Select Query FAILED [%v]", err) + } + var policyList []Policy + defer rows.Close() + for rows.Next() { + policy := Policy{} + err = rows.Scan( + &policy.Id, &policy.Name, &policy.WorkspacesUuid, &policy.Value) + if err != nil { + log.WithFields(logrus.Fields{ + "policyDao": "selectWorkspacesPolicyList", + }).Errorf("WorkspacePolicy Select Query 이후 Scan 중 에러가 발생했습니다. [%v]", err) + } + + policyList = append(policyList, policy) + } + log.WithFields(logrus.Fields{ + "policyDao": "selectWorkspacesPolicyList", + }).Infof("selectWorkspacesPolicyList Query result [%v]", policyList) + + return policyList, err +} + +func insertPolicy(policy Policy) (map[string]interface{}, error) { + log.WithFields(logrus.Fields{ + "policyDao": "insertPolicy", + }).Infof("payload") + db, err := sql.Open(os.Getenv("MysqlType"), os.Getenv("DbInfo")) + resultData := map[string]interface{}{} + if err != nil { + log.WithFields(logrus.Fields{ + "workspaceImpl": "insertPolicy", + }).Errorf("insertWorkspace DB connect error [%v]", err) + resultData["message"] = "DB connect error" + resultData["status"] = BaseErrorCode + } + defer db.Close() + + result, err := db.Exec("INSERT INTO workspaces_policy(name,workspaces_uuid, value) VALUES (?, ?, ?)", + policy.Name, policy.WorkspacesUuid, policy.Value) + if err != nil { + log.WithFields(logrus.Fields{ + "workspaceImpl": "insertPolicy", + }).Errorf("변경된 policy 저장중 에러가 발생 했습니다. [%v]", err) + resultData["message"] = "An error occurred while inserting the DB after generating the UUID." + resultData["status"] = BaseErrorCode + } + n, err := result.RowsAffected() + if n == 1 { + log.Info("변경된 policy 저장이 정상적으로 진행되었습니다.") + resultData["message"] = "The workspace has been successfully created." + resultData["status"] = http.StatusOK + } + + return resultData, err +} + +func deleteWorkspacesPolicy(policy Policy) map[string]interface{} { + db, err := sql.Open(os.Getenv("MysqlType"), os.Getenv("DbInfo")) + returnValue := map[string]interface{}{} + if err != nil { + log.Errorf("%v\n", "DB connect error") + log.Errorf("%v\n", err) + returnValue["message"] = MsgDBConnectError + returnValue["status"] = SQLConnectError + } + defer db.Close() + result, err := db.Exec("DELETE FROM workspaces_policy WHERE name =? AND workspaces_uuid = ?", policy.Name, policy.WorkspacesUuid) + if err != nil { + log.Error("deleteWorkspacesPolicy delete failed.") + returnValue["message"] = "deleteWorkspacesPolicy delete failed." + returnValue["status"] = BaseErrorCode + } + n, _ := result.RowsAffected() + if n > 1 { + log.Info("워크스페이스 정책 데이터를 삭제했습니다.") + returnValue["message"] = "Deleted deleteWorkspacesPolicy" + returnValue["status"] = http.StatusOK + } + + return returnValue +} diff --git a/works-api/policyService.go b/works-api/policyService.go new file mode 100644 index 0000000..0fd5fde --- /dev/null +++ b/works-api/policyService.go @@ -0,0 +1,41 @@ +package main + +import "github.com/sirupsen/logrus" + +func policyList(workspaceUuid string) []Policy { + + policyList, _ := selectDefaultPolicyList() + workspacesPolicyList, _ := selectWorkspacesPolicyList(workspaceUuid) + + log.WithFields(logrus.Fields{ + "policyService": "policyList", + }).Infof("policyList [%v], workspacesPolicyList [%v]", policyList, workspacesPolicyList) + + for _, workspacesPolicyInfo := range workspacesPolicyList { + for i, policyInfo := range policyList { + if workspacesPolicyInfo.Name == policyInfo.Name { + policyList[i].Value = workspacesPolicyInfo.Value + } + } + } + + return policyList +} + +func updatePolicy(workspace Workspace, policy Policy) map[string]interface{} { + + deleteWorkspacesPolicy(policy) + updateResult, _ := insertPolicy(policy) + defaultPolicyInfo, _ := selectDefaultPolicyInfo(policy.Name) + log.Debugf("workspace.Name [%v], policy.Value [%v]", workspace.Name, policy.Value) + if policy.Name == "" { + //TODO 정책 기간별 설정 필요 + } + if defaultPolicyInfo.Value == policy.Value { + deletePolicyDC(workspace.Name, defaultPolicyInfo) + } else { + insertPolicyDC(workspace.Name, defaultPolicyInfo) + } + + return updateResult +} diff --git a/works-api/structs.go b/works-api/structs.go index 62e3815..ba045f4 100644 --- a/works-api/structs.go +++ b/works-api/structs.go @@ -255,3 +255,8 @@ type ListPublicIpAddressesResponse struct { Hasannotations bool `json:"hasannotations"` } `json:"publicipaddress"` } + +type DatabaseReturnValue struct { + status int `json:"status"` + message string `json:"message"` +} diff --git a/works-api/userDesktopController.go b/works-api/userDesktopController.go index dce96ec..28f30a0 100644 --- a/works-api/userDesktopController.go +++ b/works-api/userDesktopController.go @@ -26,10 +26,8 @@ func getUserDesktop(c *gin.Context) { for _, workspaceUuid := range workspaceUuidList { userPassword, _ := selectUserPassword(userName) workspaceInfo, _ := selectWorkspaceList(workspaceUuid) - workspacePolicy, _ := selectWorkspacePolicyList(workspaceUuid) - workspaceInfo[0].Policy.RdpPort = workspacePolicy[0].Policy.RdpPort - workspaceInfo[0].Policy.RdpAccessAllow = workspacePolicy[0].Policy.RdpAccessAllow instanceList, _ := selectUserDesktopListForWorkspace(workspaceInfo[0].Uuid, userName) + policyList := policyList(workspaceInfo[0].Uuid) for _, instanceInfo := range instanceList { instanceInfo.Password = userPassword paramsMold := []MoldParams{ @@ -42,6 +40,7 @@ func getUserDesktop(c *gin.Context) { instanceInfo.MoldStatus = listVirtualMachinesMetrics.Virtualmachine[0].State workspaceInfo[0].InstanceList = append(workspaceInfo[0].InstanceList, instanceInfo) } + workspaceInfo[0].PolicyList = append(workspaceInfo[0].PolicyList, policyList...) workspaceList = append(workspaceList, workspaceInfo[0]) } } diff --git a/works-api/workspacesController.go b/works-api/workspacesController.go index 69a9564..dec9142 100644 --- a/works-api/workspacesController.go +++ b/works-api/workspacesController.go @@ -98,24 +98,23 @@ func getWorkspacesDetail(c *gin.Context) { } - workspacePolicy, _ := selectWorkspacePolicyList(workspaceInfo.Uuid) - log.Debugf("[%v] [%v]", workspacePolicy, workspacePolicy) + //workspacePolicy, _ := selectWorkspacePolicyList(workspaceInfo.Uuid) + policyList := policyList(workspaceInfo.Uuid) + + //log.Debugf("[%v] [%v]", workspacePolicy, workspacePolicy) //var workspacePolicyData []map[string]interface{} //err = json.NewDecoder(workspacePolicy.Body).Decode(&workspacePolicyData) //if err != nil { // log.Errorf("workspacePolicy error [%v]", err) //} - workspaceInfo.Policy.WorkspaceUuid = workspacePolicy[0].Policy.WorkspaceUuid - workspaceInfo.Policy.Id = workspacePolicy[0].Policy.Id - workspaceInfo.Policy.RdpPort = workspacePolicy[0].Policy.RdpPort - workspaceInfo.Policy.RdpAccessAllow = workspacePolicy[0].Policy.RdpAccessAllow + resultReturn["workspaceInfo"] = workspaceInfo resultReturn["templateInfo"] = templateResult["listtemplatesresponse"] resultReturn["serviceOfferingInfo"] = serviceOfferingResult["listserviceofferingsresponse"] resultReturn["networkInfo"] = networkResult["listnetworksresponse"] resultReturn["instanceList"] = instanceList resultReturn["groupDetail"] = groupData - //resultReturn["workspacePolicy"] = workspacePolicyData + resultReturn["workspacePolicy"] = policyList returnCode = http.StatusOK } else { resultReturn["message"] = fmt.Sprintf("There is no workspace for that UUID. [%v]", workspaceUuid) @@ -182,15 +181,11 @@ func postWorkspaces(c *gin.Context) { workspace.Shared, _ = strconv.ParseBool(c.PostForm("shared")) workspace.NetworkUuid = selectNetworkDetail() workspace.Postfix = 0 - workspace.Policy.RdpPort, _ = strconv.Atoi(c.PostForm("rdpPort")) - if workspace.Policy.RdpPort == 0 { - workspace.Policy.RdpPort = 3389 - } - workspace.Policy.RdpAccessAllow, _ = strconv.Atoi(c.PostForm("rdpAccessAllow")) + resultInsertGroup, err := insertGroup(workspace.Name) if resultInsertGroup.Status == Created201 { - resultInsertPolicyRemotefx, _ := insertPolicyRemotefx(workspace.Name) - log.Infof("resultInsertPolicyRemotefx [%v]", resultInsertPolicyRemotefx) + resultInsertPolicyRemotefx, err := insertPolicyRemotefx(workspace.Name) + log.Infof("resultInsertPolicyRemotefx [%v], [%v]", resultInsertPolicyRemotefx, err) } if err != nil { @@ -201,7 +196,7 @@ func postWorkspaces(c *gin.Context) { result["resultInsertGroup"] = res if resultInsertGroup.Status == Created201 { resultInsertWorkspace, _ := insertWorkspace(workspace) - insertWorkspacePolicy(workspace) + //insertWorkspacePolicy(workspace) log.Info(resultInsertWorkspace) result["insertWorkspace"] = resultInsertWorkspace if resultInsertWorkspace["status"] == http.StatusOK { @@ -275,7 +270,7 @@ func deleteWorkspaces(c *gin.Context) { log.Errorf("%v", errDeleteGroup) } else { resultDeleteWorkspace := deleteWorkspace(workspaceUuid) - deleteWorkspacePolicy(workspaceUuid) + //deleteWorkspacePolicy(workspaceUuid) if resultDeleteWorkspace["status"] == http.StatusOK { returnData["message"] = "workspace delete success" resultCode = http.StatusOK @@ -538,10 +533,17 @@ func getConnectionRdp(c *gin.Context) { "workspaceController": "getConnectionRdp", }).Infof("res [%v], userName [%v], userPassword [%v], res2 [%v]", res, userName, userPassword, strings.TrimSpace(res["stdout"])) + var rdpPort string + policyList := policyList(workspaceInfo.Uuid) + for _, policyInfo := range policyList { + if policyInfo.Name == "rdp_port" { + rdpPort = policyInfo.Value + } + } + instanceInfo.Password = userPassword instanceInfo.PublicPort = selectPublicPort(instanceInfo, workspaceInfo) - instanceInfo.PrivatePort = workspaceInfo.Policy.RdpPort - + instanceInfo.PrivatePort, _ = strconv.Atoi(rdpPort) updateRdpConnected(instanceInfo, 1) go checkRdpConnect(instanceInfo) diff --git a/works-api/workspacesDao.go b/works-api/workspacesDao.go index a68e240..2094000 100644 --- a/works-api/workspacesDao.go +++ b/works-api/workspacesDao.go @@ -28,12 +28,7 @@ type Workspace struct { CreateDate string `json:"create_date"` Removed *string `json:"removed"` InstanceList []Instance `json:"instanceList"` - Policy struct { - Id int `json:"id"` - WorkspaceUuid string `json:"workspace_uuid"` - RdpPort int `json:"rdp_port"` - RdpAccessAllow int `json:"rdp_access_allow"` - } `json:"policy"` + PolicyList []Policy `json:"policy"` } type Instance struct { @@ -119,59 +114,72 @@ func selectWorkspaceList(workspaceUuid string) ([]Workspace, error) { return workspaceList, err } -func selectWorkspacePolicyList(workspaceUuid string) ([]Workspace, error) { - log.WithFields(logrus.Fields{ - "workspaceImpl": "selectWorkspacePolicyList", - }).Infof("payload workspaceUuid [%v]", workspaceUuid) - db, err := sql.Open(os.Getenv("MysqlType"), os.Getenv("DbInfo")) - if err != nil { - log.WithFields(logrus.Fields{ - "workspaceImpl": "selectWorkspacePolicyList", - }).Errorf("selectWorkspacePolicyList DB Connect Error [%v]", err) - } - defer db.Close() - log.WithFields(logrus.Fields{ - "workspaceImpl": "selectWorkspacePolicyList", - }).Infof("select selectWorkspacePolicyList DB Connect success") - - log.WithFields(logrus.Fields{ - "workspaceImpl": "selectWorkspacePolicyList", - }).Warnf("payload workspaceUuid [%v]", workspaceUuid) - queryString := "SELECT" + - " id, workspaces_uuid, rdp_port, rdp_access_allow" + - " FROM workspaces_policy" + - " WHERE removed IS NULL" + - " AND workspaces_uuid = '" + workspaceUuid + "'" + - " ORDER BY id DESC" - log.WithFields(logrus.Fields{ - "workspaceImpl": "selectWorkspacePolicyList", - }).Infof("select WorkspacePolicyList Query [%v]", queryString) - rows, err := db.Query(queryString) - if err != nil { - log.WithFields(logrus.Fields{ - "workspaceImpl": "selectWorkspacePolicyList", - }).Errorf("WorkspacePolicyList Select Query FAILED [%v]", err) - } - var workspaceList []Workspace - defer rows.Close() - for rows.Next() { - workspace := Workspace{} - err = rows.Scan( - &workspace.Policy.Id, &workspace.Policy.WorkspaceUuid, &workspace.Policy.RdpPort, &workspace.Policy.RdpAccessAllow) - if err != nil { - log.WithFields(logrus.Fields{ - "workspaceImpl": "selectWorkspacePolicyList", - }).Errorf("WorkspacePolicy Select Query 이후 Scan 중 에러가 발생했습니다. [%v]", err) - } - - workspaceList = append(workspaceList, workspace) - } - log.WithFields(logrus.Fields{ - "workspaceImpl": "selectWorkspacePolicyList", - }).Infof("selectWorkspacePolicyList Query result [%v]", workspaceList) - - return workspaceList, err -} +//func selectWorkspacePolicyList(workspaceUuid string) (PolicyName, error) { +// log.WithFields(logrus.Fields{ +// "workspaceImpl": "selectWorkspacePolicyList", +// }).Infof("payload workspaceUuid [%v]", workspaceUuid) +// db, err := sql.Open(os.Getenv("MysqlType"), os.Getenv("DbInfo")) +// if err != nil { +// log.WithFields(logrus.Fields{ +// "workspaceImpl": "selectWorkspacePolicyList", +// }).Errorf("selectWorkspacePolicyList DB Connect Error [%v]", err) +// } +// defer db.Close() +// log.WithFields(logrus.Fields{ +// "workspaceImpl": "selectWorkspacePolicyList", +// }).Infof("select selectWorkspacePolicyList DB Connect success") +// +// log.WithFields(logrus.Fields{ +// "workspaceImpl": "selectWorkspacePolicyList", +// }).Warnf("payload workspaceUuid [%v]", workspaceUuid) +// +// policyString := " id, workspaces_uuid, rdp_port, rdp_access_allow, clipboard_redirection," + +// " windows_installer, network_file_share, network_printer_share, local_printer, windows_auto_update" + +// " removable_storage, cmd_use, settings_use, pc_power_use, remotefx," + +// " console, initial_program, server_layout, color_depth, width," + +// " height, dpi, resize_method, force_lossless, disable_audio," + +// " enable_audio_input, enable_printing, printer_name, enable_drive, disable_download," + +// " disable_upload, drive_path, create_drive_path, console_audio, enable_wallpaper," + +// " enable_theming, enable_font_smoothing, enable_full_window_drag, enable_desktop_composition, enable_menu_animations" +// +// queryString := "SELECT" + +// policyString + +// " FROM workspaces_policy" + +// " WHERE removed IS NULL" + +// " AND workspaces_uuid = '" + workspaceUuid + "'" + +// " ORDER BY id DESC" +// log.WithFields(logrus.Fields{ +// "workspaceImpl": "selectWorkspacePolicyList", +// }).Infof("select WorkspacePolicyList Query [%v]", queryString) +// rows, err := db.Query(queryString) +// if err != nil { +// log.WithFields(logrus.Fields{ +// "workspaceImpl": "selectWorkspacePolicyList", +// }).Errorf("WorkspacePolicyList Select Query FAILED [%v]", err) +// } +// +// policyName := PolicyName{} +// err = rows.Scan( +// &policyName.Id, &policyName.WorkspaceUuid, &policyName.RdpPort, &policyName.RdpAccessAllow, &policyName.ClipboardRedirection, +// &policyName.WindowsInstaller, &policyName.NetworkFileShare, &policyName.NetworkPrinterShare, &policyName.LocalPrinter, &policyName.WindowsAutoUpdate, +// &policyName.RemovableStorage, &policyName.CmdUse, &policyName.SettingsUse, &policyName.PcPowerUse, &policyName.Remotefx, +// &policyName.Console, &policyName.InitialProgram, &policyName.ServerLayout, &policyName.ColorDepth, &policyName.Width, +// &policyName.Height, &policyName.Dpi, &policyName.ResizeMethod, &policyName.ForceLossless, &policyName.DisableAudio, +// &policyName.EnableAudioInput, &policyName.EnablePrinting, &policyName.PrinterName, &policyName.EnableDrive, &policyName.DisableDownload, +// &policyName.DisableUpload, &policyName.DrivePath, &policyName.CreateDrivePath, &policyName.ConsoleAudio, &policyName.EnableWallpaper, +// &policyName.EnableTheming, &policyName.EnableFontSmoothing, &policyName.EnableFullWindowDrag, &policyName.EnableDesktopComposition, &policyName.EnableMenuAnimations) +// if err != nil { +// log.WithFields(logrus.Fields{ +// "workspaceImpl": "selectWorkspacePolicyList", +// }).Errorf("WorkspacePolicy Select Query 이후 Scan 중 에러가 발생했습니다. [%v]", err) +// } +// +// log.WithFields(logrus.Fields{ +// "workspaceImpl": "selectWorkspacePolicyList", +// }).Infof("selectWorkspacePolicyList Query result [%v]", policyName) +// +// return policyName, err +//} func selectCountWorkspace() (int, error) { db, err := sql.Open(os.Getenv("MysqlType"), os.Getenv("DbInfo")) @@ -363,36 +371,36 @@ func insertWorkspace(workspace Workspace) (map[string]interface{}, error) { return resultData, err } -func insertWorkspacePolicy(workspace Workspace) (map[string]interface{}, error) { - db, err := sql.Open(os.Getenv("MysqlType"), os.Getenv("DbInfo")) - resultData := map[string]interface{}{} - if err != nil { - log.WithFields(logrus.Fields{ - "workspaceImpl": "insertWorkspacePolicy", - }).Errorf("insertWorkspacePolicy DB connect error [%v]", err) - resultData["message"] = "DB connect error" - resultData["status"] = BaseErrorCode - } - defer db.Close() - - result, err := db.Exec("INSERT INTO workspaces_policy(workspaces_uuid, rdp_port, rdp_access_allow) VALUES (?, ?, ?)", - workspace.Uuid, workspace.Policy.RdpPort, workspace.Policy.RdpAccessAllow) - if err != nil { - log.WithFields(logrus.Fields{ - "workspaceImpl": "insertWorkspacePolicy", - }).Errorf("워크스페이스 정 DB Insert 중 오류가 발생하였습니다. [%v]", err) - resultData["message"] = "An error occurred while inserting the DB after generating the UUID." - resultData["status"] = BaseErrorCode - } - n, err := result.RowsAffected() - if n == 1 { - log.Info("워크스페이스가 정상적으로 생성되었습니다.") - resultData["message"] = "The workspace has been successfully created." - resultData["status"] = http.StatusOK - } - - return resultData, err -} +//func insertWorkspacePolicy(workspace Workspace) (map[string]interface{}, error) { +// db, err := sql.Open(os.Getenv("MysqlType"), os.Getenv("DbInfo")) +// resultData := map[string]interface{}{} +// if err != nil { +// log.WithFields(logrus.Fields{ +// "workspaceImpl": "insertWorkspacePolicy", +// }).Errorf("insertWorkspacePolicy DB connect error [%v]", err) +// resultData["message"] = "DB connect error" +// resultData["status"] = BaseErrorCode +// } +// defer db.Close() +// +// result, err := db.Exec("INSERT INTO workspaces_policy(workspaces_uuid) VALUES (?)", +// workspace.Uuid) +// if err != nil { +// log.WithFields(logrus.Fields{ +// "workspaceImpl": "insertWorkspacePolicy", +// }).Errorf("워크스페이스 정 DB Insert 중 오류가 발생하였습니다. [%v]", err) +// resultData["message"] = "An error occurred while inserting the DB after generating the UUID." +// resultData["status"] = BaseErrorCode +// } +// n, err := result.RowsAffected() +// if n == 1 { +// log.Info("워크스페이스가 정상적으로 생성되었습니다.") +// resultData["message"] = "The workspace has been successfully created." +// resultData["status"] = http.StatusOK +// } +// +// return resultData, err +//} func insertInstance(instance Instance) map[string]interface{} { db, err := sql.Open(os.Getenv("MysqlType"), os.Getenv("DbInfo")) @@ -736,34 +744,34 @@ func deleteWorkspace(workspaceUuid string) map[string]interface{} { return resultReturn } -func deleteWorkspacePolicy(workspaceUuid string) map[string]interface{} { - db, err := sql.Open(os.Getenv("MysqlType"), os.Getenv("DbInfo")) - resultReturn := map[string]interface{}{} - if err != nil { - log.Error("DB connect error") - log.Error(err) - resultReturn["message"] = MsgDBConnectError - resultReturn["status"] = BaseErrorCode - } - log.WithFields(logrus.Fields{ - "workspaceImpl": "deleteWorkspacePolicy", - }).Infof("workspaceUuid [%v]", workspaceUuid) - defer db.Close() - - result, err := db.Exec("UPDATE workspaces_policy SET removed=NOW() WHERE workspaces_uuid=?", workspaceUuid) - if err != nil { - log.Error(MsgDBConnectError) - log.Error(err) - resultReturn["message"] = MsgDBConnectError - resultReturn["status"] = SQLQueryError - } - n1, _ := result.RowsAffected() - if n1 == 1 { - resultReturn["status"] = http.StatusOK - } - - return resultReturn -} +//func deleteWorkspacePolicy(workspaceUuid string) map[string]interface{} { +// db, err := sql.Open(os.Getenv("MysqlType"), os.Getenv("DbInfo")) +// resultReturn := map[string]interface{}{} +// if err != nil { +// log.Error("DB connect error") +// log.Error(err) +// resultReturn["message"] = MsgDBConnectError +// resultReturn["status"] = BaseErrorCode +// } +// log.WithFields(logrus.Fields{ +// "workspaceImpl": "deleteWorkspacePolicy", +// }).Infof("workspaceUuid [%v]", workspaceUuid) +// defer db.Close() +// +// result, err := db.Exec("UPDATE workspaces_policy SET removed=NOW() WHERE workspaces_uuid=?", workspaceUuid) +// if err != nil { +// log.Error(MsgDBConnectError) +// log.Error(err) +// resultReturn["message"] = MsgDBConnectError +// resultReturn["status"] = SQLQueryError +// } +// n1, _ := result.RowsAffected() +// if n1 == 1 { +// resultReturn["status"] = http.StatusOK +// } +// +// return resultReturn +//} func selectPortForwardingNumber() int { diff --git a/works-api/workspacesService.go b/works-api/workspacesService.go index 75dfc9a..246124b 100644 --- a/works-api/workspacesService.go +++ b/works-api/workspacesService.go @@ -7,23 +7,12 @@ import ( "time" ) -func destroyWorkspaces(workspaceInfo Workspace) { - ResultDeleteGroup, errDeleteGroup := deleteGroup(workspaceInfo.Name) - ResultDeleteWorkspace := deleteWorkspace(workspaceInfo.Uuid) - log.Infof("%v%v%v", ResultDeleteGroup, errDeleteGroup, ResultDeleteWorkspace) -} - func selectWorkspaceInfo(workspaceUuid string) Workspace { workspaceList, _ := selectWorkspaceList(workspaceUuid) workspaceInfo := workspaceList[0] - workspacePolicyList, _ := selectWorkspacePolicyList(workspaceUuid) - - workspaceInfo.Policy.RdpPort = workspacePolicyList[0].Policy.RdpPort - workspaceInfo.Policy.RdpAccessAllow = workspacePolicyList[0].Policy.RdpAccessAllow - return workspaceInfo } @@ -61,10 +50,20 @@ func selectPublicPort(instanceInfo Instance, workspaceInfo Workspace) int { //portForwardingNumber := selectPortForwardingNumber() + policyList := policyList(workspaceInfo.Uuid) + + var rdpPort string + + for _, policyInfo := range policyList { + if policyInfo.Name == "rdp_port" { + rdpPort = policyInfo.Value + } + } + paramsCreatePortForwardingRule := []MoldParams{ {"ipaddressid": listPublicIpqAddressesResponse.Publicipaddress[0].Id}, {"networkid": listNetworksResponse.Network[0].Id}, - {"privateport": strconv.Itoa(workspaceInfo.Policy.RdpPort)}, + {"privateport": rdpPort}, {"protocol": "tcp"}, {"publicport": strconv.Itoa(publicPort)}, {"virtualmachineid": instanceInfo.MoldUuid}, diff --git a/works-db/user_create.sql b/works-db/user_create.sql deleted file mode 100644 index c0948f8..0000000 --- a/works-db/user_create.sql +++ /dev/null @@ -1,3 +0,0 @@ -CREATE USER works@'%' IDENTIFIED BY 'Ablecloud1!'; -GRANT ALL ON *.* TO works@'%'; -FLUSH PRIVILEGES; \ No newline at end of file diff --git a/works-db/works_configuration.sql b/works-db/works_configuration.sql deleted file mode 100644 index 6cf7d08..0000000 --- a/works-db/works_configuration.sql +++ /dev/null @@ -1,26 +0,0 @@ -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (1, 'mold.default.domain.account', 'Advanced', 'works', null, 'Mold 의 domain 계정', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (2, 'mold.default.domain.id', 'Advanced', '9ec3a06c-e8d7-46e6-9764-a871d23e69a0', null, 'Mold 의 domain ID', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (3, 'mold.default.api.key', 'Advanced', 'wDx5Cs6pwtDcg8IO8hBtdh_fJkGtTyJiKYVGyvuis4UQTWSwuCsClcUnSDo37bmprQceoGMktTlsaYg0DXDIcg', null, 'Mold 의 도메인 관리자의 API Key 를 설정하는 항목입니다.', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (4, 'mold.default.secret.key', 'Advanced', 'eU7qbJQE1QRk24wZXdoPjiO2RW8Ydg1h-lYB0meQXyh5Na1KJD2lg5M5LBtqD0kjsUqyxdO9RJXRhrIv5GpwUg', null, 'Mold 의 도메인 관리자의 Secret Key 를 설정하는 항목입니다.', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (5, 'mold.default.protocol', 'Advanced', 'http://', null, 'Mold 의 프로토콜 타입', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (6, 'mold.default.url', 'Advanced', '10.10.10.10', null, 'Mold 의 URL', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (7, 'mold.default.port', 'Advanced', '8080', null, 'Mold 의 Port', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (8, 'mold.default.url.postfix', 'Advanced', '/client/api', null, 'Mold 의 URL 의 Postfix', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (9, 'dc.default.protocol', 'Advanced', 'http://', null, 'Domain Controller 의 프로토콜 타입', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (10, 'dc.default.url', 'Advanced', '10.1.1.202', null, 'Domain Controller 의 URL', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (11, 'dc.default.port', 'Advanced', '8083', null, 'Domain Controller 의 Port', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (12, 'dc.default.url.postfix', 'Advanced', '/api', null, 'Domain Controller 의 URL 의 Postfix', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (13, 'mold.network.uuid', 'Advanced', '216', null, 'Works 에서 사용할 Mold network uuid', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (14, 'mold.zone.id', 'Advanced', '6ac55f6c-41e2-4e63-ad99-902739c2cee2', null, 'Works 가 생성된 Zone ID', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (15, 'works.default.url', 'Advanced', '10.1.1.201', null, 'Works 의 URL', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (16, 'works.default.port', 'Advanced', '8082', null, 'Works 의 Port', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (17, 'samba.default.url', 'Advanced', '10.1.1.201', null, 'Samba 의 URL', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (18, 'samba.default.domain', 'Advanced', 'pppp', null, 'Samba 의 Domain', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (19, 'guacamole.default.protocol', 'Advanced', 'http://', null, 'guacamole 의 protocol', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (20, 'guacamole.default.url', 'Advanced', '10.10.1.100', null, 'guacamole 의 URL', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (21, 'guacamole.default.port', 'Advanced', '8080', null, 'guacamole 의 Port', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (22, 'guacamole.default.url.postfix', 'Advanced', '/guacamole/api', null, 'guacamole 의 URL 의 Postfix', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (23, 'guacamole.default.username', 'Advanced', 'guacadmin', null, 'guacamole 의 기본 도메인', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (24, 'cluster.default.name', 'Advanced', 'pppp', null, 'Cluster 의 이름', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (25, 'log.default.level', 'Advanced', 'logrus.DebugLevel', null, 'Works-API 의 Log Level', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (26, 'rdp.default.port', 'Advanced', '3389', null, 'VDI 의 기본 RDP 포트', null); \ No newline at end of file diff --git a/works-db/works_schema.sql b/works-db/works_schema.sql index ad6358f..b23e675 100644 --- a/works-db/works_schema.sql +++ b/works-db/works_schema.sql @@ -1,14 +1,18 @@ -CREATE USER works@'%' IDENTIFIED BY 'Ablecloud1!'; -GRANT ALL ON *.* TO works@'%'; -FLUSH PRIVILEGES; - --- auto-generated definition -create schema works collate utf8mb4_0900_ai_ci; - -grant alter, alter routine, create, create routine, create temporary tables, create view, delete, drop, event, execute, index, insert, lock tables, references, select, show view, trigger, update on works.* to works; - +create table application +( + id int auto_increment + primary key, + uuid varchar(40) not null comment 'application Uuid', + workspace_uuid varchar(40) default '1' not null, + application_server varchar(40) null comment 'application server UUID', + path varchar(100) not null comment 'application 경로', + description varchar(100) null comment 'application 설명', + working_directory varchar(100) null comment 'application working_directory', + create_date datetime not null comment 'applicatin 등록일', + removed datetime null comment 'application 삭제일' +); -create table works.async_job +create table async_job ( id varchar(40) not null comment 'async_job UUID' primary key, @@ -22,7 +26,7 @@ create table works.async_job comment 'Works async 실행을 위한 테이블 해당 테이블은 VM 의 시작, 정지, 생성, 삭제를 등록하여 비동기 실행을 휘한 테이블 입니다.'; -create table works.configuration +create table configuration ( id int auto_increment primary key, @@ -31,11 +35,40 @@ create table works.configuration value varchar(256) not null comment '설정의 값', default_value varchar(256) null comment '설정 기본 값', description varchar(1024) not null comment '설정 설명', - update_date datetime null comment '설정 업데이트 일자' + update_date datetime null comment '설정 업데이트 일자', + input_type varchar(20) default 'input' not null comment '설정 입력값 타입', + input_value varchar(100) null comment '설정 입력 값' ) comment 'works API 설정값'; -create table works.users +create table guacamole_configuration +( + id int auto_increment + primary key +); + +create table policy_list +( + id int auto_increment + primary key, + name varchar(40) not null comment '정책 이름', + description varchar(140) not null comment '정책 설명', + i18n varchar(100) not null comment '정책 i18n 값', + value varchar(100) default '0' null comment '정책 기본값', + type varchar(2) default 'R' not null comment '정책적용 type', + settable_type varchar(2) default 'S' not null comment '정책에서 설정값의 input 유형 (''S''=input select 값, ''T''=input text 값)', + settable_value varchar(1024) null comment '정책에서 설정 가능한 값', + ad_group_name varchar(40) null +); + +create table port_forwarding_map +( + port_forwarding int not null comment '포워딩 포트 번호', + instance_uuid varchar(40) null comment '포트 포워딩된 인스턴스 UUID', + port_forwarding_rule_id varchar(40) null comment '포트 포워딩 룰 아이디' +); + +create table users ( id int auto_increment primary key, @@ -46,27 +79,33 @@ create table works.users removed timestamp null ); -create table works.vm_instances +create table vm_instances ( - id int auto_increment + id int auto_increment primary key, - name varchar(255) not null comment '가상머신 name', - uuid varchar(40) not null comment '가상머신 UUID', - workspace_uuid varchar(40) not null comment '워크스페이스 UUID', - workspace_name varchar(50) null comment '워크스페이스 이름', - mold_uuid varchar(40) null comment 'Mold 의 UUID', - status varchar(20) default 'Not Ready' not null comment '가상머신의 실행 여부', - owner_account_id varchar(100) null comment '가상머신 할당된 사용자 계정', - checked tinyint default 0 not null, - connected tinyint default 0 not null comment '가상머신 접속여부', - create_date datetime null comment '가상머신 생성일', - removed datetime null comment '가상머신 삭제일', - windows_uuid varchar(40) null, - checked_date datetime null + name varchar(255) not null comment '가상머신 name', + uuid varchar(40) not null comment '가상머신 UUID', + workspace_uuid varchar(40) not null comment '워크스페이스 UUID', + workspace_name varchar(50) null comment '워크스페이스 이름', + mold_uuid varchar(40) null comment 'Mold 의 UUID', + status varchar(20) default 'Not Ready' not null comment '가상머신의 실행 여부', + handshake_status varchar(40) default 'Not Ready' null comment '핸드쉐이커 상태값', + owner_account_id varchar(100) null comment '가상머신 할당된 사용자 계정', + ipaddress varchar(255) null comment 'VDI 의 아이피', + checked tinyint default 0 not null, + connected int default 0 not null comment '가상머신 접속여부', + create_date datetime null comment '가상머신 생성일', + removed datetime null comment '가상머신 삭제일', + windows_uuid varchar(40) null, + port_forwarding_check int default 0 not null, + checked_date datetime null, + port_forwarding_rule_id int null, + rdp_connected_check int default 0 not null, + hash varchar(40) null comment '가상머신 hash 값' ) comment '데스크탑 및 앱용 가상머신 정보 테이블'; -create table works.workspaces +create table workspaces ( id int auto_increment comment '워크스페이스 ID' primary key, @@ -74,7 +113,7 @@ create table works.workspaces description varchar(255) null comment '워크스페이스 설명', uuid varchar(40) not null comment '워크스페이스 UUID', state varchar(10) default 'Enable' not null comment '워크스페이스 상태', - workspace_type varchar(10) not null comment '워크스페이스 타입', + workspace_type varchar(20) not null comment '워크스페이스 타입', template_ok_check varchar(20) default 'BeforeStarting' not null comment 'Template 이 정상적으로 사용가능 여부 확인하는 컬럼 BeforeStarting - VM 생성전 Starting - VM 시작중 @@ -85,6 +124,10 @@ Desktop Type만 수량 입력', network_uuid varchar(48) not null comment '워크스페이스에서 사용할 network uuid', compute_offering_uuid varchar(48) not null comment '워크스페이스에서 사용할 compute offering uuid', template_uuid varchar(48) not null comment '워크스페이스에서 사용할 template uuid', + master_template_name varchar(255) null comment '마스터 템플릿 이름', + rbd_access_allow int default 0 not null comment 'RDP 접속 허용 여부 +0 : 허용 안함 +1 : 허용함', postfix int default 0 not null comment '워크스페이스 postfix', shared tinyint default 0 not null, create_date datetime not null comment '워크스페이스 생성일', @@ -93,28 +136,85 @@ Desktop Type만 수량 입력', ) comment '워크스페이스 관련 테이블'; -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (1, 'mold.default.domain.account', 'Advanced', 'works', null, 'Mold 의 domain 계정', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (2, 'mold.default.domain.id', 'Advanced', 'd294bfc7-f86e-4f67-ac83-80220110b23f', null, 'Mold 의 domain ID', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (3, 'mold.default.api.key', 'Advanced', 'WuiJ_rWUllvp5a9Wkj1ZzwE_VqShM-3eJr1O2Jvi4RmaIfsWgbJh-GKxMpJ78V47wVX8BWACi9KilsaRusjZ7w', null, 'Mold 의 도메인 관리자의 API Key 를 설정하는 항목입니다.', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (4, 'mold.default.secret.key', 'Advanced', 'Y3sJNJuK6fHuMigdOYqaJHAGgVaIb9RDUTfTfAAeQzR7UAUPUfcOjhekIHStirtLIfgb6Nbre_x1Lz9S7c7HHQ', null, 'Mold 의 도메인 관리자의 Secret Key 를 설정하는 항목입니다.', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (5, 'mold.default.protocol', 'Advanced', 'https://', null, 'Mold 의 프로토콜 타입', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (6, 'mold.default.url', 'Advanced', 'mold.ablecloud.io', null, 'Mold 의 URL', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (7, 'mold.default.port', 'Advanced', '80', null, 'Mold 의 Port', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (8, 'mold.default.url.postfix', 'Advanced', '/client/api', null, 'Mold 의 URL 의 Postfix', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (9, 'dc.default.protocol', 'Advanced', 'http://', null, 'Domain Controller 의 프로토콜 타입', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (10, 'dc.default.url', 'Advanced', '10.10.1.99', null, 'Domain Controller 의 URL', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (11, 'dc.default.port', 'Advanced', '8083', null, 'Domain Controller 의 Port', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (12, 'dc.default.url.postfix', 'Advanced', '/api', null, 'Domain Controller 의 URL 의 Postfix', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (13, 'mold.network.uuid', 'Advanced', '205', null, 'Works 에서 사용할 Mold network uuid', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (14, 'mold.zone.id', 'Advanced', '82bfaf86-ea6b-4cbc-88c5-0a951fd57aa0', null, 'Works 가 생성된 Zone ID', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (15, 'works.default.url', 'Advanced', '10.10.13.102', null, 'Works 의 URL', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (16, 'works.default.port', 'Advanced', '8083', null, 'Works 의 Port', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (17, 'samba.default.url', 'Advanced', '10.1.1.59', null, 'Samba 의 URL', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (18, 'samba.default.domain', 'Advanced', 'testdomain', null, 'Samba 의 Domain', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (19, 'guacamole.default.protocol', 'Advanced', 'http://', null, 'guacamole 의 protocol', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (20, 'guacamole.default.url', 'Advanced', '10.10.1.100', null, 'guacamole 의 URL', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (21, 'guacamole.default.port', 'Advanced', '8080', null, 'guacamole 의 Port', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (22, 'guacamole.default.url.postfix', 'Advanced', '/guacamole/api', null, 'guacamole 의 URL 의 Postfix', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (23, 'guacamole.default.username', 'Advanced', 'guacadmin', null, 'guacamole 의 기본 도메인', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (24, 'cluster.default.name', 'Advanced', 'clusterTestName', null, 'Cluster 의 이름', null); -INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date) VALUES (25, 'log.default.level', 'Advanced', 'logrus.DebugLevel', null, 'Works-API 의 Log Level', null); \ No newline at end of file +create table workspaces_policy +( + id int auto_increment + primary key, + name varchar(40) not null comment '워크스페이스에 적용된 정책 이름', + workspaces_uuid varchar(40) not null comment '워크스페이스 UUID', + value varchar(100) not null comment '정책 적용 값' +) + comment '워크스페이스 정책 테이블'; + + +-- configuration table default value insert +INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date, input_type, input_value) VALUES (1, 'mold.default.domain.account', 'Advanced', 'admin', 'C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe', 'Mold 의 domain 계정', null, 'input', null); +INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date, input_type, input_value) VALUES (2, 'mold.default.domain.id', 'Advanced', '244b7491-5cb4-11ec-b9cd-002481021c72', null, 'Mold 의 domain ID', null, 'input', null); +INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date, input_type, input_value) VALUES (3, 'mold.default.api.key', 'Advanced', 'XaGp5JK8exSk-nMDoEIAKFwAXPMI0V05hASU2E-0w7BibKGKVS32ye2U7vZL5A_FalIDyoyMqMJYY_44dnUHng', null, 'Mold 의 도메인 관리자의 API Key 를 설정하는 항목입니다.', null, 'input', null); +INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date, input_type, input_value) VALUES (4, 'mold.default.secret.key', 'Advanced', 'rT4GcYhiyXfu-O6L-9naVXMWLdilCCkmHmyclADU0uxikOcdc01gqPX_JakvG8S-83mHfqmIbZZ7ZJKr1OELxA', null, 'Mold 의 도메인 관리자의 Secret Key 를 설정하는 항목입니다.', null, 'input', null); +INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date, input_type, input_value) VALUES (5, 'mold.default.protocol', 'Advanced', 'http://', null, 'Mold 의 프로토콜 타입', null, 'select', '{http://,https://}'); +INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date, input_type, input_value) VALUES (6, 'mold.default.url', 'Advanced', '10.10.1.10', null, 'Mold 의 URL', null, 'input', null); +INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date, input_type, input_value) VALUES (7, 'mold.default.port', 'Advanced', '8080', null, 'Mold 의 Port', null, 'input', null); +INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date, input_type, input_value) VALUES (8, 'mold.default.url.postfix', 'Advanced', '/client/api', null, 'Mold 의 URL 의 Postfix', null, 'input', null); +INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date, input_type, input_value) VALUES (9, 'dc.default.protocol', 'Advanced', 'http://', null, 'Domain Controller 의 프로토콜 타입', null, 'select', '{http://,https://}'); +INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date, input_type, input_value) VALUES (10, 'dc.default.url', 'Advanced', '10.1.1.202', null, 'Domain Controller 의 URL', null, 'input', null); +INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date, input_type, input_value) VALUES (11, 'dc.default.port', 'Advanced', '8083', null, 'Domain Controller 의 Port', null, 'input', null); +INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date, input_type, input_value) VALUES (12, 'dc.default.url.postfix', 'Advanced', '/api', null, 'Domain Controller 의 URL 의 Postfix', null, 'input', null); +INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date, input_type, input_value) VALUES (13, 'mold.network.uuid', 'Advanced', '246', null, 'Works 에서 사용할 Mold network uuid', null, 'input', null); +INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date, input_type, input_value) VALUES (14, 'mold.zone.id', 'Advanced', '3d1447eb-b65c-44a5-9fae-e9d5a57dc31b', null, 'Works 가 생성된 Zone ID', null, 'input', null); +INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date, input_type, input_value) VALUES (15, 'works.default.url', 'Advanced', '10.1.1.201', null, 'Works 의 URL', null, 'input', null); +INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date, input_type, input_value) VALUES (16, 'works.default.port', 'Advanced', '8082', null, 'Works 의 Port', null, 'input', null); +INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date, input_type, input_value) VALUES (17, 'samba.default.url', 'Advanced', '10.1.1.201', null, 'Samba 의 URL', null, 'input', null); +INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date, input_type, input_value) VALUES (18, 'samba.default.domain', 'Advanced', 'able', null, 'Samba 의 Domain', null, 'input', null); +INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date, input_type, input_value) VALUES (19, 'guacamole.default.protocol', 'Advanced', 'http://', null, 'guacamole 의 protocol', null, 'select', '{http://,https://}'); +INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date, input_type, input_value) VALUES (20, 'guacamole.default.url', 'Advanced', '192.168.0.101', null, 'guacamole 의 URL', null, 'input', null); +INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date, input_type, input_value) VALUES (21, 'guacamole.default.port', 'Advanced', '8080', null, 'guacamole 의 Port', null, 'input', null); +INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date, input_type, input_value) VALUES (22, 'guacamole.default.url.postfix', 'Advanced', '/guacamole/api', null, 'guacamole 의 URL 의 Postfix', null, 'input', null); +INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date, input_type, input_value) VALUES (23, 'guacamole.default.username', 'Advanced', 'administrator', null, 'guacamole 의 기본 도메인', null, 'input', null); +INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date, input_type, input_value) VALUES (24, 'cluster.default.name', 'Advanced', 'able', null, 'Cluster 의 이름', null, 'input', null); +INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date, input_type, input_value) VALUES (25, 'log.default.level', 'Advanced', 'logrus.DebugLevel', null, 'Works-API 의 Log Level', null, 'input', null); +INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date, input_type, input_value) VALUES (26, 'rdp.default.port', 'Advanced', '3389', null, 'RDP 의 기본 Port', null, 'input', null); +INSERT INTO works.configuration (id, name, category, value, default_value, description, update_date, input_type, input_value) VALUES (27, 'rdp.default.forwarding.range', 'Advanced', '20001-20100', null, 'RDP 의 포트포워딩 범위', null, 'input', 'int'); + + +-- policy_list table default value insert +INSERT INTO works.policy_list (id, name, description, i18n, value, type, settable_type, settable_value, ad_group_name) VALUES (1, 'rdp_port', 'rdp 접속 port', 'label.policy.desc.rdp.port', '3389', 'R', 'T', '', null); +INSERT INTO works.policy_list (id, name, description, i18n, value, type, settable_type, settable_value, ad_group_name) VALUES (2, 'rdp_access_allow', 'RDP 접속 허용 여부', 'label.policy.desc.rdp.access.allow', 'false', 'R', 'S', 'true,false', null); +INSERT INTO works.policy_list (id, name, description, i18n, value, type, settable_type, settable_value, ad_group_name) VALUES (3, 'clipboard_redirection', '클립보드 리디렉션 허용 여부', 'label.policy.desc.clipboard.redirection', 'false', 'R', 'S', 'true,false', 'clipboard_block'); +INSERT INTO works.policy_list (id, name, description, i18n, value, type, settable_type, settable_value, ad_group_name) VALUES (4, 'windows_installer', '사용자 프로그램 설치 허용 여부', 'label.policy.desc.windows.installer', 'false', 'R', 'S', 'true,false', 'install_block'); +INSERT INTO works.policy_list (id, name, description, i18n, value, type, settable_type, settable_value, ad_group_name) VALUES (5, 'network_file_share', '네트워크 파일 공유 허용 여부', 'label.policy.desc.network.file.share', 'false', 'R', 'S', 'true,false', 'share_block'); +INSERT INTO works.policy_list (id, name, description, i18n, value, type, settable_type, settable_value, ad_group_name) VALUES (6, 'network_printer_share', '네트워크 프린터 공유 허용 여부', 'label.policy.desc.network.printer.share', 'false', 'R', 'S', 'true,false', 'network_printer_block'); +INSERT INTO works.policy_list (id, name, description, i18n, value, type, settable_type, settable_value, ad_group_name) VALUES (7, 'local_printer', '로컬 프린터 허용 여부', 'label.policy.desc.local.printer', 'false', 'R', 'S', 'true,false', 'local_printer_block'); +INSERT INTO works.policy_list (id, name, description, i18n, value, type, settable_type, settable_value, ad_group_name) VALUES (8, 'windows_auto_update', '윈도우 자동 업데이트 허용 여부', 'label.policy.desc.windows.auto.update', 'false', 'R', 'S', 'true,false', 'update_block'); +INSERT INTO works.policy_list (id, name, description, i18n, value, type, settable_type, settable_value, ad_group_name) VALUES (9, 'removable_storage', '미동식 저장소 허용 여부', 'label.policy.desc.removable.storage', 'false', 'R', 'S', 'true,false', 'usb_block'); +INSERT INTO works.policy_list (id, name, description, i18n, value, type, settable_type, settable_value, ad_group_name) VALUES (10, 'cmd_use', 'CMD 허용 여부', 'label.policy.desc.cmd.use', 'false', 'R', 'S', 'true,false', 'cmd_block'); +INSERT INTO works.policy_list (id, name, description, i18n, value, type, settable_type, settable_value, ad_group_name) VALUES (11, 'settings_use', '설정 허용 여부', 'label.policy.desc.settings.use', 'false', 'R', 'S', 'true,false', 'setting_block'); +INSERT INTO works.policy_list (id, name, description, i18n, value, type, settable_type, settable_value, ad_group_name) VALUES (12, 'password_expiration_date', '비밀번호 만료일 설정', 'label.policy.desc.password_expiration_date', '30', 'R', 'S', '0,30,60,90,180,365', 'passwordchangeday'); +INSERT INTO works.policy_list (id, name, description, i18n, value, type, settable_type, settable_value, ad_group_name) VALUES (13, 'pc-power-use', '사용자 데스크탑 온오프 사용 여부', 'label.policy.desc.pc.power.use', 'false', 'R', 'S', 'true,false', 'logoff_block'); +INSERT INTO works.policy_list (id, name, description, i18n, value, type, settable_type, settable_value, ad_group_name) VALUES (14, 'remotefx', 'remotefx 설정 여부', 'label.policy.desc.remotefx', 'true', 'R', 'S', 'true,false', 'remotefx'); +INSERT INTO works.policy_list (id, name, description, i18n, value, type, settable_type, settable_value, ad_group_name) VALUES (15, 'console', 'RDP 서버의 콘솔 세션 연결 여부', 'label.policy.desc.console', 'false', 'C', 'S', 'true,false', null); +INSERT INTO works.policy_list (id, name, description, i18n, value, type, settable_type, settable_value, ad_group_name) VALUES (16, 'initial-program', 'Client에서 실행할 프로그램의 전체 경로', 'label.policy.desc.initial.program', null, 'C', 'T', null, null); +INSERT INTO works.policy_list (id, name, description, i18n, value, type, settable_type, settable_value, ad_group_name) VALUES (17, 'server-layout', '서버측 키보드 레이아웃 설정 값', 'label.policy.desc.server.layout', null, 'C', 'T', null, null); +INSERT INTO works.policy_list (id, name, description, i18n, value, type, settable_type, settable_value, ad_group_name) VALUES (18, 'color-depth', '요청할 픽셀당 비트수 값', 'label.policy.desc.color.depth', '24', 'C', 'S', '8,16,24', null); +INSERT INTO works.policy_list (id, name, description, i18n, value, type, settable_type, settable_value, ad_group_name) VALUES (19, 'width', '디스플레이의 너비(픽셀)', 'label.policy.desc.width', null, 'C', 'T', null, null); +INSERT INTO works.policy_list (id, name, description, i18n, value, type, settable_type, settable_value, ad_group_name) VALUES (20, 'height', '디스플레이의 높이(픽셀)', 'label.policy.desc.height', null, 'C', 'T', null, null); +INSERT INTO works.policy_list (id, name, description, i18n, value, type, settable_type, settable_value, ad_group_name) VALUES (21, 'dpi', '디스플레이의 해상도(DPI)', 'label.policy.desc.dpi', null, 'C', 'T', null, null); +INSERT INTO works.policy_list (id, name, description, i18n, value, type, settable_type, settable_value, ad_group_name) VALUES (22, 'resize-method', '디스플레이 크기 변경시 RDP 서버를 업데이트 하는 방법', 'label.policy.desc.resize.method', 'display-update', 'C', 'S', 'display-update,reconnect', null); +INSERT INTO works.policy_list (id, name, description, i18n, value, type, settable_type, settable_value, ad_group_name) VALUES (23, 'force-lossless', '그래픽 압축 무손실 사용 여부', 'label.policy.desc.force.lossless', 'false', 'C', 'S', 'true,false', null); +INSERT INTO works.policy_list (id, name, description, i18n, value, type, settable_type, settable_value, ad_group_name) VALUES (24, 'disable-audio', '오디오 출력 사용 여부', 'label.policy.desc.disable.audio', 'false', 'C', 'S', 'true,false', null); +INSERT INTO works.policy_list (id, name, description, i18n, value, type, settable_type, settable_value, ad_group_name) VALUES (25, 'enable-audio-input', '오디오 입력 사용 여부', 'label.policy.desc.enable.audio.input', 'false', 'C', 'S', 'true,false', null); +INSERT INTO works.policy_list (id, name, description, i18n, value, type, settable_type, settable_value, ad_group_name) VALUES (26, 'enable-printing', '클라이언트에서 PDF 프린터 사용 여부', 'label.policy.desc.enable.printing', 'false', 'C', 'S', 'true,false', null); +INSERT INTO works.policy_list (id, name, description, i18n, value, type, settable_type, settable_value, ad_group_name) VALUES (27, 'printer-name', 'RDP 세션을 통해 전달되는 리디렉션된 프린터 장치의 이름 값', 'label.policy.desc.printer.name', 'VDI-PRINTER', 'C', 'T', null, null); +INSERT INTO works.policy_list (id, name, description, i18n, value, type, settable_type, settable_value, ad_group_name) VALUES (28, 'enable-drive', '클라이언트에서 Guacamole 서버에 있는 가상 드라이브와 파일 전송 허용 여부', 'label.policy.desc.enable.drive', 'true', 'C', 'S', 'true,false', null); +INSERT INTO works.policy_list (id, name, description, i18n, value, type, settable_type, settable_value, ad_group_name) VALUES (29, 'disable-download', '원격 서버에서 클라이언트로의 다운로드 사용 여부', 'label.policy.desc.disable.download', 'false', 'C', 'S', 'true,false', null); +INSERT INTO works.policy_list (id, name, description, i18n, value, type, settable_type, settable_value, ad_group_name) VALUES (30, 'disable-upload', '클라이언트에서 원격 서버 위치로의 업로드 허용 여부', 'label.policy.desc.disable.upload', 'false', 'C', 'S', 'true,false', null); +INSERT INTO works.policy_list (id, name, description, i18n, value, type, settable_type, settable_value, ad_group_name) VALUES (31, 'drive-name', 'RDP 세션으로 전달될 때 사용되는 파일 시스템 이름', 'label.policy.desc.drive.name', 'VDI-DRIVE', 'C', 'T', null, null); +INSERT INTO works.policy_list (id, name, description, i18n, value, type, settable_type, settable_value, ad_group_name) VALUES (32, 'drive-path', '전송된 파일이 저장되어야 하는 Guacamole 서버의 디렉토리', 'label.policy.desc.drive.path', '/share', 'C', 'T', null, null); +INSERT INTO works.policy_list (id, name, description, i18n, value, type, settable_type, settable_value, ad_group_name) VALUES (33, 'create-drive-path', 'drive_path 정책에서 적용된 디렉토리가 아직 존재 하지 않는경우 자동생성 여부', 'label.policy.desc.create.drive.path', 'false', 'C', 'S', 'true,false', null); +INSERT INTO works.policy_list (id, name, description, i18n, value, type, settable_type, settable_value, ad_group_name) VALUES (34, 'console-audio', 'RDP 서버의 콘솔 세션에서 오디오가 활성화 여부', 'label.policy.desc.console.audio', 'false', 'C', 'S', 'true,false', null); +INSERT INTO works.policy_list (id, name, description, i18n, value, type, settable_type, settable_value, ad_group_name) VALUES (35, 'enable-wallpaper', '바탕화면 랜더링 사용 여부', 'label.policy.desc.enable.wallpaper', 'false', 'C', 'S', 'true,false', null); +INSERT INTO works.policy_list (id, name, description, i18n, value, type, settable_type, settable_value, ad_group_name) VALUES (36, 'enable-theming', '창 및 컨트롤ㄹ의 테마 사용 여부', 'label.policy.desc.enable.theming', 'false', 'C', 'S', 'true,false', null); +INSERT INTO works.policy_list (id, name, description, i18n, value, type, settable_type, settable_value, ad_group_name) VALUES (37, 'enable-font-smoothing', '텍스트 가장자리 렌더링 사용 여부', 'label.policy.desc.enable.font.smoothing', 'false', 'C', 'S', 'true,false', null); +INSERT INTO works.policy_list (id, name, description, i18n, value, type, settable_type, settable_value, ad_group_name) VALUES (38, 'enable-full-window-drag', '창을 이동할 때 창의 내용 표시 여부', 'label.policy.desc.enable.full.window.drag', 'false', 'C', 'S', 'true,false', null); +INSERT INTO works.policy_list (id, name, description, i18n, value, type, settable_type, settable_value, ad_group_name) VALUES (39, 'enable-desktop-composition', '투명한 창 및 그림자와 같은 그래픽 효과 사용 여부', 'label.policy.desc.enable.desktop.composition', 'false', 'C', 'S', 'true,false', null); +INSERT INTO works.policy_list (id, name, description, i18n, value, type, settable_type, settable_value, ad_group_name) VALUES (40, 'enable-menu-animations', '시작 메뉴 열기 및 닫기 애니메이션이 허용 여부', 'label.policy.desc.enable.menu.animations', 'false', 'C', 'S', 'true,false', null); \ No newline at end of file diff --git a/works-shell/main.go b/works-shell/main.go index 72e0e6c..0095ae9 100644 --- a/works-shell/main.go +++ b/works-shell/main.go @@ -18,7 +18,8 @@ const ( WorksUi = "works-ui" WorksSamba = "works-samba" Guacd = "guacd" - Guacamole = "guacamole" + //Guacamole = "guacamole" + WorksLite = "works-lite" ) type Config struct { @@ -110,7 +111,7 @@ func main() { "--name", "works-samba", "-d", "-t", "--net", "host", - "localhost/works-ad:v3", + "docker.io/ablecloudteam/works-ad:latest", "config", "8.8.8.8", configStruct.SambaDefaultDomain, "Ablecloud1!", "ad", @@ -120,18 +121,29 @@ func main() { cmdGuacamole, errGuacamole := exec.Command( "podman", "run", - "--name", "guacamole", + "--name", "works-lite", "--net", "works", - "--ip", "10.88.2.10", - "-v", "share:/share", - "-e", "LDAP_HOSTNAME="+configStruct.SambaDefaultUrl, - "-e", "LDAP_USER_BASE_DN=CN=Users,DC="+configStruct.SambaDefaultDomain+",DC=local", - "-e", "LDAP_USERNAME_ATTRIBUTE=cn", - "-e", "LDAP_CONFIG_BASE_DN=CN=Users,DC="+configStruct.SambaDefaultDomain+",DC=local", - "-e", "GUACD_HOSTNAME=10.88.2.14", - "-d", "-p", "8080:8080", - "guacamole:v0.1", + "--ip", "10.88.2.15", + "-d", "-p", "8088:8080", + "docker.io/ablecloudteam/works-lite:latest", ).Output() + + +// cmdGuacamole, errGuacamole := exec.Command( +// "podman", "run", +// "--name", "guacamole", +// "--net", "works", +// "--ip", "10.88.2.10", +// "-v", "share:/share", +// "-e", "LDAP_HOSTNAME="+configStruct.SambaDefaultUrl, +// "-e", "LDAP_USER_BASE_DN=CN=Users,DC="+configStruct.SambaDefaultDomain+",DC=local", +// "-e", "LDAP_USERNAME_ATTRIBUTE=cn", +// "-e", "LDAP_CONFIG_BASE_DN=CN=Users,DC="+configStruct.SambaDefaultDomain+",DC=local", +// "-e", "GUACD_HOSTNAME=10.88.2.14", +// "-d", "-p", "8080:8080", +// "guacamole:v0.1", +// ).Output() + log.Infof("guacamole run exec [%v], error [%v]", string(cmdGuacamole), errGuacamole) time.Sleep(10 * time.Second) @@ -171,7 +183,7 @@ func main() { } } else { containers := []string{ - WorksSamba, WorksDB, Guacd, Guacamole, WorksApi, WorksUi, + WorksSamba, WorksDB, Guacd, WorksLite, WorksApi, WorksUi, } for _, container := range containers { for { diff --git a/works-shell/works-template-action.sh b/works-shell/works-template-action.sh new file mode 100644 index 0000000..cc5a71b --- /dev/null +++ b/works-shell/works-template-action.sh @@ -0,0 +1,46 @@ +#!/bin/bash + +podman network create --subnet 10.88.2.0/24 works +podman volume create works-db + +podman pull docker.io/library/mysql:latest +sleep 5 +podman run --name works-db --net works --ip 10.88.2.12 -p 3306:3306 -v works-db:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=Ablecloud1! -d mysql:latest + +podman pull docker.io/ablecloudteam/works-ad:latest && \ +podman pull docker.io/ablecloudteam/works-api:latest && \ +podman pull docker.io/ablecloudteam/works-lite:latest && \ +podman pull docker.io/ablecloudteam/works-ui:latest && \ +podman pull docker.io/ablecloudteam/works-ad:latest && \ +podman pull docker.io/guacamole/guacd:latest + + +podman run --name works-api --net works --ip 10.88.2.13 -p 8082:8080 -d docker.io/ablecloudteam/works-api:latest +podman run --name works-ui --net works --ip 10.88.2.11 -p 8081:8080 -d docker.io/ablecloudteam/works-ui:latest +podman run --name works-lite --net works --ip 10.88.2.15 -p 8088:8080 -d docker.io/ablecloudteam/works-lite:latest +podman run --name works-guacd --net works --ip 10.88.2.14 -d docker.io/guacamole/guacd:latest + +sleep 5 +echo 'CREATE DATABASE works start' +#podman exec -it works-db mysql -uroot -pAblecloud1! -e 'CREATE DATABASE works' +podman exec works-db sh -c "mysql -uroot -pAblecloud1! -e 'CREATE DATABASE works'" +echo 'CREATE DATABASE works end' + +sleep 5 +echo 'CREATE USER "works" IDENTIFIED BY "Ablecloud1!" start' +#podman exec -it works-db mysql -uroot -pAblecloud1! -e 'CREATE USER "works" IDENTIFIED BY "Ablecloud1!"' +podman exec works-db sh -c "mysql -uroot -pAblecloud1! -e 'CREATE USER \"works\" IDENTIFIED BY \"Ablecloud1!\"'" +echo 'CREATE USER "works" IDENTIFIED BY "Ablecloud1!" end' +sleep 5 +echo 'GRANT SELECT,INSERT,UPDATE,DELETE ON works.* TO "works" start' +#podman exec -it works-db mysql -uroot -pAblecloud1! -e 'GRANT SELECT,INSERT,UPDATE,DELETE ON works.* TO "works"' +podman exec works-db sh -c "mysql -uroot -pAblecloud1! -e 'GRANT SELECT,INSERT,UPDATE,DELETE ON works.* TO \"works\"'" +echo 'GRANT SELECT,INSERT,UPDATE,DELETE ON works.* TO "works" end' +sleep 5 +echo 'FLUSH PRIVILEGES start' +#podman exec -it works-db mysql -uroot -pAblecloud1! -e 'FLUSH PRIVILEGES' +podman exec works-db sh -c "mysql -uroot -pAblecloud1! -e 'FLUSH PRIVILEGES'" +echo 'FLUSH PRIVILEGES end' + +podman cp /root/works_schema.sql works-db:/mnt/works_schema.sql +podman exec works-db sh -c "mysql -uroot -pAblecloud1! works < /mnt/works_schema.sql" \ No newline at end of file diff --git a/works-ui/.env.development b/works-ui/.env.development index d64bef0..2b641ba 100644 --- a/works-ui/.env.development +++ b/works-ui/.env.development @@ -1,4 +1,4 @@ VUE_APP_I18N_LOCALE=ko VUE_APP_I18N_FALLBACK_LOCALE=ko -VUE_APP_API_URL=10.10.1.41 +VUE_APP_API_URL=10.10.1.100 VUE_APP_API_PORT=8082 \ No newline at end of file diff --git a/works-ui/.idea/jsLinters/eslint.xml b/works-ui/.idea/jsLinters/eslint.xml index 541945b..4c28db1 100644 --- a/works-ui/.idea/jsLinters/eslint.xml +++ b/works-ui/.idea/jsLinters/eslint.xml @@ -1,6 +1,8 @@ + + \ No newline at end of file diff --git a/works-ui/package-lock.json b/works-ui/package-lock.json index e6433fd..e836c0f 100644 --- a/works-ui/package-lock.json +++ b/works-ui/package-lock.json @@ -40,7 +40,7 @@ "async": "^3.2.1", "babel-eslint": "^10.1.0", "babel-plugin-transform-remove-console": "^6.9.4", - "eslint": "^6.7.2", + "eslint": "^6.8.0", "eslint-plugin-prettier": "^3.3.1", "eslint-plugin-vue": "^7.0.0", "less": "^3.0.4", diff --git a/works-ui/package.json b/works-ui/package.json index 5538fb6..058b9f3 100644 --- a/works-ui/package.json +++ b/works-ui/package.json @@ -42,7 +42,7 @@ "async": "^3.2.1", "babel-eslint": "^10.1.0", "babel-plugin-transform-remove-console": "^6.9.4", - "eslint": "^6.7.2", + "eslint": "^6.8.0", "eslint-plugin-prettier": "^3.3.1", "eslint-plugin-vue": "^7.0.0", "less": "^3.0.4", diff --git a/works-ui/src/components/TableContent.vue b/works-ui/src/components/TableContent.vue index cad6079..e0aef69 100644 --- a/works-ui/src/components/TableContent.vue +++ b/works-ui/src/components/TableContent.vue @@ -664,12 +664,12 @@ export default defineComponent({ dataIndex: "name", key: "name", slots: { customRender: "nameRender" }, - title: this.$t("label.name"), + title: this.$t("label.policy.name"), sorter: (a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0), sortDirections: ["descend", "ascend"], }, { - title: this.$t("label.description"), + title: this.$t("label.policy.value"), dataIndex: "description", key: "description", width: "60%", @@ -686,10 +686,32 @@ export default defineComponent({ this.workspacePolicyList !== undefined && this.workspacePolicyList !== null ) { + var arr = []; + var obj = {}; this.dataList = this.workspacePolicyList; - this.dataList.forEach((value, index, array) => { - this.dataList[index].key = index; + Object.keys(this.dataList).forEach((index) => { + console.log(index, this.dataList[index]); + if (index == "id" || index == "workspace_uuid"){ + } else { + obj["name"] = index; + obj["description"] = this.dataList[index]; + arr.push(obj); + obj = {}; + + } }); + console.log("this.dataList") + + console.log("arr"); + console.log(arr); + this.dataList = arr + // console.log(this.dataList) + // console.log(this.dataList[0].key) + // console.log(this.dataList[0].value) + + // this.dataList.forEach((value, index, array) => { + // this.dataList[index].key = index; + // }); } }, fetchNetwork() { diff --git a/works-ui/src/locales/en.json b/works-ui/src/locales/en.json index 28d6406..159b914 100644 --- a/works-ui/src/locales/en.json +++ b/works-ui/src/locales/en.json @@ -143,6 +143,9 @@ "label.desktop.vm.list": "Desktop VMs", "label.disk.list": "Data Disks", "label.network.list": "Networks", + "label.ad.policy.list": "Policy", + "label.policy.name": "Policy Name", + "label.policy.value": "Policy Value", "label.add.workspace": "Add Workspace", "label.name": "Name", "label.state": "State", diff --git a/works-ui/src/locales/ko.json b/works-ui/src/locales/ko.json index 06c37c3..267f958 100644 --- a/works-ui/src/locales/ko.json +++ b/works-ui/src/locales/ko.json @@ -143,6 +143,7 @@ "label.desktop.vm.list": "데스크톱 VM", "label.disk.list": "데이터 디스크", "label.network.list": "네트워크", + "label.ad.policy.list": "정책", "label.add.workspace": "워크스페이스 추가", "label.name": "이름", "label.state": "상태", @@ -190,6 +191,8 @@ "label.uuid": "UUID", "label.app.list": "애플리케이션", "label.policy.list": "정책", + "label.policy.name": "정책 이름", + "label.policy.value": "정책 값", "label.country": "국가", "label.countryCode": "국가 코드", "label.distinguishedName": "DN(Distinguished Name)", diff --git a/works-ui/src/views/workSpace/WorkSpaceDetail.vue b/works-ui/src/views/workSpace/WorkSpaceDetail.vue index cf0db37..145546d 100644 --- a/works-ui/src/views/workSpace/WorkSpaceDetail.vue +++ b/works-ui/src/views/workSpace/WorkSpaceDetail.vue @@ -114,7 +114,12 @@ export default defineComponent({ this.groupInfo = response.data.result.groupDetail; } if (response.data.result.workspacePolicy !== null) { - this.workspacePolicyList = response.data.result.workspacePolicy; + this.workspacePolicyList = response.data.result.workspaceInfo.policy; + console.log("response.data"); + console.log(response.data.result.workspaceInfo.policy); + console.log(response.data.result.workspaceInfo.policy.id); + console.log(Object.keys(response.data.result.workspaceInfo.policy)); + console.log(Object.values(response.data.result.workspaceInfo.policy)); } } else { message.error(this.$t("message.response.data.fail")); diff --git a/works-ui/src/views/workSpace/WorkSpaceTab.vue b/works-ui/src/views/workSpace/WorkSpaceTab.vue index e6ff93c..db22ceb 100644 --- a/works-ui/src/views/workSpace/WorkSpaceTab.vue +++ b/works-ui/src/views/workSpace/WorkSpaceTab.vue @@ -39,17 +39,29 @@ /> + + + + + + + + + + + + @@ -70,6 +82,11 @@ export default defineComponent({ required: false, default: null, }, + policyList: { + type: Object, + required: false, + default: null, + }, vmList: { type: Object, required: false, @@ -107,6 +124,7 @@ export default defineComponent({ this.$refs.listRefreshCall2.fetchRefresh(refreshClick); this.$refs.listRefreshCall3.fetchRefresh(refreshClick); this.$refs.listRefreshCall4.fetchRefresh(refreshClick); + this.$refs.listRefreshCall5.fetchRefresh(refreshClick); // }, 100); }, parentRefresh() { diff --git a/works-ui/yarn.lock b/works-ui/yarn.lock index b42e041..a39a36a 100644 --- a/works-ui/yarn.lock +++ b/works-ui/yarn.lock @@ -273,10 +273,10 @@ "chalk" "^2.0.0" "js-tokens" "^4.0.0" -"@babel/parser@^7.12.0", "@babel/parser@^7.13.9", "@babel/parser@^7.14.5", "@babel/parser@^7.15.0", "@babel/parser@^7.7.0": - "integrity" "sha512-0v7oNOjr6YT9Z2RAOTv4T9aP+ubfx4Q/OhVtAet7PFDt0t9Oy6Jn+/rfC6b8HJ5zEqrQCiMxJfgtHpmIminmJQ==" - "resolved" "https://registry.npmjs.org/@babel/parser/-/parser-7.15.0.tgz" - "version" "7.15.0" +"@babel/parser@^7.14.5", "@babel/parser@^7.15.0", "@babel/parser@^7.16.4", "@babel/parser@^7.7.0": + "integrity" "sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA==" + "resolved" "https://registry.npmjs.org/@babel/parser/-/parser-7.17.3.tgz" + "version" "7.17.3" "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.14.5": "integrity" "sha512-ZoJS2XCKPBfTmL122iP6NM9dOg+d4lc9fFk3zxc8iDjvt8Pk4+TlsHSKhIPf6X+L5ORCdBzqMZDjL/WHj7WknQ==" @@ -917,7 +917,7 @@ "debug" "^4.1.0" "globals" "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.12.0", "@babel/types@^7.13.0", "@babel/types@^7.14.5", "@babel/types@^7.14.8", "@babel/types@^7.15.0", "@babel/types@^7.4.4", "@babel/types@^7.7.0": +"@babel/types@^7.0.0", "@babel/types@^7.14.5", "@babel/types@^7.14.8", "@babel/types@^7.15.0", "@babel/types@^7.4.4", "@babel/types@^7.7.0": "integrity" "sha512-OBvfqnllOIdX4ojTHpwZbpvz4j3EWyjkZEdmjH0/cgsd6QOdSgU8rLSk6ard/pcW7rlmjdVSX/AWOaORR1uNOQ==" "resolved" "https://registry.npmjs.org/@babel/types/-/types-7.15.0.tgz" "version" "7.15.0" @@ -935,31 +935,43 @@ "resolved" "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.36.tgz" "version" "0.2.36" -"@fortawesome/fontawesome-svg-core@^1.2.35", "@fortawesome/fontawesome-svg-core@>= 1.2.0 < 1.3": - "integrity" "sha512-YUcsLQKYb6DmaJjIHdDWpBIGCcyE/W+p/LMGvjQem55Mm2XWVAP5kWTMKWLv9lwpCVjpLxPyOMOyUocP1GxrtA==" - "resolved" "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.36.tgz" - "version" "1.2.36" +"@fortawesome/fontawesome-common-types@^0.3.0": + "integrity" "sha512-CA3MAZBTxVsF6SkfkHXDerkhcQs0QPofy43eFdbWJJkZiq3SfiaH1msOkac59rQaqto5EqWnASboY1dBuKen5w==" + "resolved" "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.3.0.tgz" + "version" "0.3.0" + +"@fortawesome/fontawesome-svg-core@^1.3.0", "@fortawesome/fontawesome-svg-core@~1 || >=1.3.0-beta1": + "integrity" "sha512-UIL6crBWhjTNQcONt96ExjUnKt1D68foe3xjEensLDclqQ6YagwCRYVQdrp/hW0ALRp/5Fv/VKw+MqTUWYYvPg==" + "resolved" "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.3.0.tgz" + "version" "1.3.0" dependencies: - "@fortawesome/fontawesome-common-types" "^0.2.36" + "@fortawesome/fontawesome-common-types" "^0.3.0" -"@fortawesome/free-brands-svg-icons@^5.15.3": +"@fortawesome/free-brands-svg-icons@^5.15.4": "integrity" "sha512-f1witbwycL9cTENJegcmcZRYyawAFbm8+c6IirLmwbbpqz46wyjbQYLuxOc7weXFXfB7QR8/Vd2u5R3q6JYD9g==" "resolved" "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-5.15.4.tgz" "version" "5.15.4" dependencies: "@fortawesome/fontawesome-common-types" "^0.2.36" -"@fortawesome/free-solid-svg-icons@^5.15.3": +"@fortawesome/free-regular-svg-icons@^6.0.0": + "integrity" "sha512-lYK6oyQL8HwZUAVWGqF7TGuwQBVfphNBVTdvPSD3h4gmQfGazm/xcwg3kmtcRycu3y6QspOC7hPXSoJbVqSYCw==" + "resolved" "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.0.0.tgz" + "version" "6.0.0" + dependencies: + "@fortawesome/fontawesome-common-types" "^0.3.0" + +"@fortawesome/free-solid-svg-icons@^5.15.4": "integrity" "sha512-JLmQfz6tdtwxoihXLg6lT78BorrFyCf59SAwBM6qV/0zXyVeDygJVb3fk+j5Qat+Yvcxp1buLTY5iDh1ZSAQ8w==" "resolved" "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.15.4.tgz" "version" "5.15.4" dependencies: "@fortawesome/fontawesome-common-types" "^0.2.36" -"@fortawesome/vue-fontawesome@^3.0.0-4": - "integrity" "sha512-dQVhhMRcUPCb0aqk5ohm0KGk5OJ7wFZ9aYapLzJB3Z+xs7LhkRWLTb87reelUAG5PFDjutDAXuloT9hi6cz72A==" - "resolved" "https://registry.npmjs.org/@fortawesome/vue-fontawesome/-/vue-fontawesome-3.0.0-4.tgz" - "version" "3.0.0-4" +"@fortawesome/vue-fontawesome@^3.0.0-5": + "integrity" "sha512-aNmBT4bOecrFsZTog1l6AJDQHPP3ocXV+WQ3Ogy8WZCqstB/ahfhH4CPu5i4N9Hw0MBKXqE+LX+NbUxcj8cVTw==" + "resolved" "https://registry.npmjs.org/@fortawesome/vue-fontawesome/-/vue-fontawesome-3.0.0-5.tgz" + "version" "3.0.0-5" "@hapi/address@2.x.x": "integrity" "sha512-QD1PhQk+s31P1ixsX0H0Suoupp3VMXzIVMSwobR3F3MSUO2YCV0B7xqLcUw/Bh8yuvd3LhpyqLQWTNcRmp6IdQ==" @@ -1145,11 +1157,6 @@ dependencies: "@types/node" "*" -"@types/estree@^0.0.48": - "integrity" "sha512-LfZwXoGUDo0C3me81HXgkBg5CTQYb6xzEl+fNmbO4JdRiSKQ8A0GD1OBBvKAIsbCUgoyAty7m99GqqMQe784ew==" - "resolved" "https://registry.npmjs.org/@types/estree/-/estree-0.0.48.tgz" - "version" "0.0.48" - "@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.18": "integrity" "sha512-3UJuW+Qxhzwjq3xhwXm2onQcFHn76frIYVbTu+kn24LFxI+dEhdfISDFovPB8VpEgW8oQCTpRuCe+0zJxB7NEA==" "resolved" "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.24.tgz" @@ -1177,6 +1184,11 @@ "@types/minimatch" "*" "@types/node" "*" +"@types/guacamole-common-js@^1.3.1": + "integrity" "sha512-Btj/5nbYTjuXTM/D8MECAQdM5VJcWRkFMSkMMCPsV4Ev4jMGswh3cr3oViTCzW544IHkzJj2MGpCvK1VAetxiw==" + "resolved" "https://registry.npmjs.org/@types/guacamole-common-js/-/guacamole-common-js-1.3.1.tgz" + "version" "1.3.1" + "@types/http-proxy@^1.17.5": "integrity" "sha512-9hdj6iXH64tHSLTY+Vt2eYOGzSogC+JQ2H7bdPWkuh7KXP5qLllWx++t+K9Wk556c3dkDdPws/SpMRi0sdCT1w==" "resolved" "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.7.tgz" @@ -1553,55 +1565,47 @@ "semver" "^6.1.0" "strip-ansi" "^6.0.0" -"@vue/compiler-core@3.1.5": - "integrity" "sha512-TXBhFinoBaXKDykJzY26UEuQU1K07FOp/0Ie+OXySqqk0bS0ZO7Xvl7UmiTUPYcLrWbxWBR7Bs/y55AI0MNc2Q==" - "resolved" "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.1.5.tgz" - "version" "3.1.5" +"@vue/compiler-core@3.2.31": + "integrity" "sha512-aKno00qoA4o+V/kR6i/pE+aP+esng5siNAVQ422TkBNM6qA4veXiZbSe8OTXHXquEi/f6Akc+nLfB4JGfe4/WQ==" + "resolved" "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.31.tgz" + "version" "3.2.31" dependencies: - "@babel/parser" "^7.12.0" - "@babel/types" "^7.12.0" - "@vue/shared" "3.1.5" - "estree-walker" "^2.0.1" + "@babel/parser" "^7.16.4" + "@vue/shared" "3.2.31" + "estree-walker" "^2.0.2" "source-map" "^0.6.1" -"@vue/compiler-dom@3.1.5": - "integrity" "sha512-ZsL3jqJ52OjGU/YiT/9XiuZAmWClKInZM2aFJh9gnsAPqOrj2JIELMbkIFpVKR/CrVO/f2VxfPiiQdQTr65jcQ==" - "resolved" "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.1.5.tgz" - "version" "3.1.5" - dependencies: - "@vue/compiler-core" "3.1.5" - "@vue/shared" "3.1.5" - -"@vue/compiler-sfc@^3.0.0", "@vue/compiler-sfc@^3.0.0-beta.14", "@vue/compiler-sfc@^3.0.8", "@vue/compiler-sfc@>=3.1.0": - "integrity" "sha512-mtMY6xMvZeSRx9MTa1+NgJWndrkzVTdJ1pQAmAKQuxyb5LsHVvrgP7kcQFvxPHVpLVTORbTJWHaiqoKrJvi1iA==" - "resolved" "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.1.5.tgz" - "version" "3.1.5" - dependencies: - "@babel/parser" "^7.13.9" - "@babel/types" "^7.13.0" - "@types/estree" "^0.0.48" - "@vue/compiler-core" "3.1.5" - "@vue/compiler-dom" "3.1.5" - "@vue/compiler-ssr" "3.1.5" - "@vue/shared" "3.1.5" - "consolidate" "^0.16.0" - "estree-walker" "^2.0.1" - "hash-sum" "^2.0.0" - "lru-cache" "^5.1.1" +"@vue/compiler-dom@3.2.31": + "integrity" "sha512-60zIlFfzIDf3u91cqfqy9KhCKIJgPeqxgveH2L+87RcGU/alT6BRrk5JtUso0OibH3O7NXuNOQ0cDc9beT0wrg==" + "resolved" "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.31.tgz" + "version" "3.2.31" + dependencies: + "@vue/compiler-core" "3.2.31" + "@vue/shared" "3.2.31" + +"@vue/compiler-sfc@^3.0.0", "@vue/compiler-sfc@^3.0.0-beta.14", "@vue/compiler-sfc@^3.0.8", "@vue/compiler-sfc@>=3.1.0", "@vue/compiler-sfc@3.2.31": + "integrity" "sha512-748adc9msSPGzXgibHiO6T7RWgfnDcVQD+VVwYgSsyyY8Ans64tALHZANrKtOzvkwznV/F4H7OAod/jIlp/dkQ==" + "resolved" "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.31.tgz" + "version" "3.2.31" + dependencies: + "@babel/parser" "^7.16.4" + "@vue/compiler-core" "3.2.31" + "@vue/compiler-dom" "3.2.31" + "@vue/compiler-ssr" "3.2.31" + "@vue/reactivity-transform" "3.2.31" + "@vue/shared" "3.2.31" + "estree-walker" "^2.0.2" "magic-string" "^0.25.7" - "merge-source-map" "^1.1.0" "postcss" "^8.1.10" - "postcss-modules" "^4.0.0" - "postcss-selector-parser" "^6.0.4" "source-map" "^0.6.1" -"@vue/compiler-ssr@3.1.5": - "integrity" "sha512-CU5N7Di/a4lyJ18LGJxJYZS2a8PlLdWpWHX9p/XcsjT2TngMpj3QvHVRkuik2u8QrIDZ8OpYmTyj1WDNsOV+Dg==" - "resolved" "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.1.5.tgz" - "version" "3.1.5" +"@vue/compiler-ssr@3.2.31": + "integrity" "sha512-mjN0rqig+A8TVDnsGPYJM5dpbjlXeHUm2oZHZwGyMYiGT/F4fhJf/cXy8QpjnLQK4Y9Et4GWzHn9PS8AHUnSkw==" + "resolved" "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.31.tgz" + "version" "3.2.31" dependencies: - "@vue/compiler-dom" "3.1.5" - "@vue/shared" "3.1.5" + "@vue/compiler-dom" "3.2.31" + "@vue/shared" "3.2.31" "@vue/component-compiler-utils@^3.1.0", "@vue/component-compiler-utils@^3.1.2": "integrity" "sha512-rAYMLmgMuqJFWAOb3Awjqqv5X3Q3hVr4jH/kgrFJpiU0j3a90tnNBplqbj+snzrgZhC9W128z+dtgMifOiMfJg==" @@ -1636,34 +1640,53 @@ "resolved" "https://registry.npmjs.org/@vue/preload-webpack-plugin/-/preload-webpack-plugin-1.1.2.tgz" "version" "1.1.2" -"@vue/reactivity@3.1.5": - "integrity" "sha512-1tdfLmNjWG6t/CsPldh+foumYFo3cpyCHgBYQ34ylaMsJ+SNHQ1kApMIa8jN+i593zQuaw3AdWH0nJTARzCFhg==" - "resolved" "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.1.5.tgz" - "version" "3.1.5" +"@vue/reactivity-transform@3.2.31": + "integrity" "sha512-uS4l4z/W7wXdI+Va5pgVxBJ345wyGFKvpPYtdSgvfJfX/x2Ymm6ophQlXXB6acqGHtXuBqNyyO3zVp9b1r0MOA==" + "resolved" "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.31.tgz" + "version" "3.2.31" dependencies: - "@vue/shared" "3.1.5" + "@babel/parser" "^7.16.4" + "@vue/compiler-core" "3.2.31" + "@vue/shared" "3.2.31" + "estree-walker" "^2.0.2" + "magic-string" "^0.25.7" + +"@vue/reactivity@3.2.31": + "integrity" "sha512-HVr0l211gbhpEKYr2hYe7hRsV91uIVGFYNHj73njbARVGHQvIojkImKMaZNDdoDZOIkMsBc9a1sMqR+WZwfSCw==" + "resolved" "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.31.tgz" + "version" "3.2.31" + dependencies: + "@vue/shared" "3.2.31" -"@vue/runtime-core@3.1.5": - "integrity" "sha512-YQbG5cBktN1RowQDKA22itmvQ+b40f0WgQ6CXK4VYoYICAiAfu6Cc14777ve8zp1rJRGtk5oIeS149TOculrTg==" - "resolved" "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.1.5.tgz" - "version" "3.1.5" +"@vue/runtime-core@3.2.31": + "integrity" "sha512-Kcog5XmSY7VHFEMuk4+Gap8gUssYMZ2+w+cmGI6OpZWYOEIcbE0TPzzPHi+8XTzAgx1w/ZxDFcXhZeXN5eKWsA==" + "resolved" "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.31.tgz" + "version" "3.2.31" dependencies: - "@vue/reactivity" "3.1.5" - "@vue/shared" "3.1.5" + "@vue/reactivity" "3.2.31" + "@vue/shared" "3.2.31" -"@vue/runtime-dom@3.1.5": - "integrity" "sha512-tNcf3JhVR0RfW0kw1p8xZgv30nvX8Y9rsz7eiQ0dHe273sfoCngAG0y4GvMaY4Xd8FsjUwFedd4suQ8Lu8meXg==" - "resolved" "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.1.5.tgz" - "version" "3.1.5" +"@vue/runtime-dom@3.2.31": + "integrity" "sha512-N+o0sICVLScUjfLG7u9u5XCjvmsexAiPt17GNnaWHJUfsKed5e85/A3SWgKxzlxx2SW/Hw7RQxzxbXez9PtY3g==" + "resolved" "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.31.tgz" + "version" "3.2.31" dependencies: - "@vue/runtime-core" "3.1.5" - "@vue/shared" "3.1.5" + "@vue/runtime-core" "3.2.31" + "@vue/shared" "3.2.31" "csstype" "^2.6.8" -"@vue/shared@3.1.5": - "integrity" "sha512-oJ4F3TnvpXaQwZJNF3ZK+kLPHKarDmJjJ6jyzVNDKH9md1dptjC7lWR//jrGuLdek/U6iltWxqAnYOu8gCiOvA==" - "resolved" "https://registry.npmjs.org/@vue/shared/-/shared-3.1.5.tgz" - "version" "3.1.5" +"@vue/server-renderer@3.2.31": + "integrity" "sha512-8CN3Zj2HyR2LQQBHZ61HexF5NReqngLT3oahyiVRfSSvak+oAvVmu8iNLSu6XR77Ili2AOpnAt1y8ywjjqtmkg==" + "resolved" "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.31.tgz" + "version" "3.2.31" + dependencies: + "@vue/compiler-ssr" "3.2.31" + "@vue/shared" "3.2.31" + +"@vue/shared@3.2.31": + "integrity" "sha512-ymN2pj6zEjiKJZbrf98UM2pfDd6F2H7ksKw7NDt/ZZ1fh5Ei39X5tABugtT03ZRlWd9imccoK0hE8hpjpU7irQ==" + "resolved" "https://registry.npmjs.org/@vue/shared/-/shared-3.2.31.tgz" + "version" "3.2.31" "@vue/web-component-wrapper@^1.2.0": "integrity" "sha512-Iu8Tbg3f+emIIMmI2ycSI8QcEuAUgPTgHwesDU1eKMLE4YC/c/sFbGc70QgMq31ijRftV0R7vCm9co6rldCeOA==" @@ -2335,7 +2358,7 @@ dependencies: "file-uri-to-path" "1.0.0" -"bluebird@^3.1.1", "bluebird@^3.5.5", "bluebird@^3.7.2": +"bluebird@^3.1.1", "bluebird@^3.5.5": "integrity" "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" "resolved" "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz" "version" "3.7.2" @@ -3085,13 +3108,6 @@ dependencies: "bluebird" "^3.1.1" -"consolidate@^0.16.0": - "integrity" "sha512-Nhl1wzCslqXYTJVDyJCu3ODohy9OfBMB5uD2BiBTzd7w+QY0lBzafkR8y8755yMYHAaMD4NuzbAw03/xzfw+eQ==" - "resolved" "https://registry.npmjs.org/consolidate/-/consolidate-0.16.0.tgz" - "version" "0.16.0" - dependencies: - "bluebird" "^3.7.2" - "constants-browserify@^1.0.0": "integrity" "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=" "resolved" "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz" @@ -3443,9 +3459,9 @@ "css-tree" "^1.1.2" "csstype@^2.6.8": - "integrity" "sha512-u1wmTI1jJGzCJzWndZo8mk4wnPTZd1eOIYTYvuEyOQGfmDl3TrabCCfKnOC86FZwW/9djqTl933UF/cS425i9A==" - "resolved" "https://registry.npmjs.org/csstype/-/csstype-2.6.17.tgz" - "version" "2.6.17" + "integrity" "sha512-ZVxXaNy28/k3kJg0Fou5MiYpp88j7H9hLZp8PDC3jV0WFjfH5E9xHb56L0W59cPbKbcHXeP4qyT8PrHp8t6LcQ==" + "resolved" "https://registry.npmjs.org/csstype/-/csstype-2.6.19.tgz" + "version" "2.6.19" "cyclist@^1.0.1": "integrity" "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=" @@ -4106,7 +4122,7 @@ "table" "4.0.2" "text-table" "~0.2.0" -"eslint@^6.2.0 || ^7.0.0", "eslint@^6.7.2", "eslint@>= 4.12.1", "eslint@>= 5.0.0", "eslint@>=1.6.0 <7.0.0", "eslint@>=3.14.1", "eslint@>=5", "eslint@>=5.0.0": +"eslint@^6.2.0 || ^7.0.0", "eslint@^6.8.0", "eslint@>= 4.12.1", "eslint@>= 5.0.0", "eslint@>=1.6.0 <7.0.0", "eslint@>=3.14.1", "eslint@>=5", "eslint@>=5.0.0": "integrity" "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==" "resolved" "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz" "version" "6.8.0" @@ -4205,7 +4221,7 @@ "resolved" "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz" "version" "5.2.0" -"estree-walker@^2.0.1": +"estree-walker@^2.0.2": "integrity" "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" "resolved" "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz" "version" "2.0.2" @@ -4716,13 +4732,6 @@ "resolved" "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz" "version" "1.0.1" -"generic-names@^2.0.1": - "integrity" "sha512-kPCHWa1m9wGG/OwQpeweTwM/PYiQLrUIxXbt/P4Nic3LbGjCP0YwrALHW1uNLKZ0LIMg+RF+XRlj2ekT9ZlZAQ==" - "resolved" "https://registry.npmjs.org/generic-names/-/generic-names-2.0.1.tgz" - "version" "2.0.1" - dependencies: - "loader-utils" "^1.1.0" - "gensync@^1.0.0-beta.2": "integrity" "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" "resolved" "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" @@ -5192,11 +5201,6 @@ dependencies: "safer-buffer" ">= 2.1.2 < 3" -"icss-replace-symbols@^1.1.0": - "integrity" "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=" - "resolved" "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz" - "version" "1.1.0" - "icss-utils@^4.0.0", "icss-utils@^4.1.1": "integrity" "sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==" "resolved" "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.1.tgz" @@ -5204,11 +5208,6 @@ dependencies: "postcss" "^7.0.14" -"icss-utils@^5.0.0": - "integrity" "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==" - "resolved" "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz" - "version" "5.1.0" - "ieee754@^1.1.4": "integrity" "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" "resolved" "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz" @@ -6021,11 +6020,6 @@ "resolved" "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz" "version" "4.17.21" -"lodash.camelcase@^4.3.0": - "integrity" "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" - "resolved" "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz" - "version" "4.3.0" - "lodash.debounce@^4.0.8": "integrity" "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" "resolved" "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz" @@ -6427,10 +6421,10 @@ "resolved" "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz" "version" "2.15.0" -"nanoid@^3.1.23": - "integrity" "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==" - "resolved" "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz" - "version" "3.1.23" +"nanoid@^3.2.0": + "integrity" "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==" + "resolved" "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz" + "version" "3.3.1" "nanomatch@^1.2.9": "integrity" "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==" @@ -7008,6 +7002,11 @@ "resolved" "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz" "version" "2.1.0" +"picocolors@^1.0.0": + "integrity" "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "resolved" "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" + "version" "1.0.0" + "picomatch@^2.0.4", "picomatch@^2.2.1", "picomatch@^2.2.3": "integrity" "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==" "resolved" "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz" @@ -7230,11 +7229,6 @@ dependencies: "postcss" "^7.0.5" -"postcss-modules-extract-imports@^3.0.0": - "integrity" "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==" - "resolved" "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz" - "version" "3.0.0" - "postcss-modules-local-by-default@^3.0.2": "integrity" "sha512-e3xDq+LotiGesympRlKNgaJ0PCzoUIdpH0dj47iWAui/kyTgh3CiAr1qP54uodmJhl6p9rN6BoNcdEDVJx9RDw==" "resolved" "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.3.tgz" @@ -7245,15 +7239,6 @@ "postcss-selector-parser" "^6.0.2" "postcss-value-parser" "^4.1.0" -"postcss-modules-local-by-default@^4.0.0": - "integrity" "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==" - "resolved" "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz" - "version" "4.0.0" - dependencies: - "icss-utils" "^5.0.0" - "postcss-selector-parser" "^6.0.2" - "postcss-value-parser" "^4.1.0" - "postcss-modules-scope@^2.2.0": "integrity" "sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ==" "resolved" "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz" @@ -7262,13 +7247,6 @@ "postcss" "^7.0.6" "postcss-selector-parser" "^6.0.0" -"postcss-modules-scope@^3.0.0": - "integrity" "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==" - "resolved" "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz" - "version" "3.0.0" - dependencies: - "postcss-selector-parser" "^6.0.4" - "postcss-modules-values@^3.0.0": "integrity" "sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg==" "resolved" "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz" @@ -7277,27 +7255,6 @@ "icss-utils" "^4.0.0" "postcss" "^7.0.6" -"postcss-modules-values@^4.0.0": - "integrity" "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==" - "resolved" "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz" - "version" "4.0.0" - dependencies: - "icss-utils" "^5.0.0" - -"postcss-modules@^4.0.0": - "integrity" "sha512-/H08MGEmaalv/OU8j6bUKi/kZr2kqGF6huAW8m9UAgOLWtpFdhA14+gPBoymtqyv+D4MLsmqaF2zvIegdCxJXg==" - "resolved" "https://registry.npmjs.org/postcss-modules/-/postcss-modules-4.2.2.tgz" - "version" "4.2.2" - dependencies: - "generic-names" "^2.0.1" - "icss-replace-symbols" "^1.1.0" - "lodash.camelcase" "^4.3.0" - "postcss-modules-extract-imports" "^3.0.0" - "postcss-modules-local-by-default" "^4.0.0" - "postcss-modules-scope" "^3.0.0" - "postcss-modules-values" "^4.0.0" - "string-hash" "^1.1.1" - "postcss-normalize-charset@^4.0.1": "integrity" "sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==" "resolved" "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz" @@ -7417,7 +7374,7 @@ "indexes-of" "^1.0.1" "uniq" "^1.0.1" -"postcss-selector-parser@^6.0.0", "postcss-selector-parser@^6.0.2", "postcss-selector-parser@^6.0.4": +"postcss-selector-parser@^6.0.0", "postcss-selector-parser@^6.0.2": "integrity" "sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg==" "resolved" "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz" "version" "6.0.6" @@ -7467,14 +7424,14 @@ "source-map" "^0.6.1" "supports-color" "^6.1.0" -"postcss@^8.0.0", "postcss@^8.1.0", "postcss@^8.1.10": - "integrity" "sha512-wG1cc/JhRgdqB6WHEuyLTedf3KIRuD0hG6ldkFEZNCjRxiC+3i6kkWUUbiJQayP28iwG35cEmAbe98585BYV0A==" - "resolved" "https://registry.npmjs.org/postcss/-/postcss-8.3.6.tgz" - "version" "8.3.6" +"postcss@^8.1.10": + "integrity" "sha512-OovjwIzs9Te46vlEx7+uXB0PLijpwjXGKXjVGGPIGubGpq7uh5Xgf6D6FiJ/SzJMBosHDp6a2hiXOS97iBXcaA==" + "resolved" "https://registry.npmjs.org/postcss/-/postcss-8.4.6.tgz" + "version" "8.4.6" dependencies: - "colorette" "^1.2.2" - "nanoid" "^3.1.23" - "source-map-js" "^0.6.2" + "nanoid" "^3.2.0" + "picocolors" "^1.0.0" + "source-map-js" "^1.0.2" "prelude-ls@~1.1.2": "integrity" "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" @@ -8430,10 +8387,10 @@ "resolved" "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz" "version" "2.0.1" -"source-map-js@^0.6.2": - "integrity" "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==" - "resolved" "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz" - "version" "0.6.2" +"source-map-js@^1.0.2": + "integrity" "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" + "resolved" "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz" + "version" "1.0.2" "source-map-resolve@^0.5.0": "integrity" "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==" @@ -8653,11 +8610,6 @@ dependencies: "safe-buffer" "~5.1.0" -"string-hash@^1.1.1": - "integrity" "sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs=" - "resolved" "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz" - "version" "1.1.3" - "string-width@^2.0.0": "integrity" "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==" "resolved" "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz" @@ -9462,14 +9414,16 @@ dependencies: "is-plain-object" "3.0.1" -"vue@^2 || ^3.0.0-0", "vue@^3.0.0", "vue@^3.0.2", "vue@>= 2.0.0", "vue@>= 3.0.0 < 4", "vue@>=3.0.3", "vue@>=3.1.0", "vue@3.1.5": - "integrity" "sha512-Ho7HNb1nfDoO+HVb6qYZgeaobt1XbY6KXFe4HGs1b9X6RhkWG/113n4/SrtM1LUclM6OrP/Se5aPHHvAPG1iVQ==" - "resolved" "https://registry.npmjs.org/vue/-/vue-3.1.5.tgz" - "version" "3.1.5" +"vue@^2 || ^3.0.0-0", "vue@^3.0.0", "vue@^3.0.2", "vue@>= 2.0.0", "vue@>= 3.0.0 < 4", "vue@>=3.0.3", "vue@>=3.1.0", "vue@3.2.31": + "integrity" "sha512-odT3W2tcffTiQCy57nOT93INw1auq5lYLLYtWpPYQQYQOOdHiqFct9Xhna6GJ+pJQaF67yZABraH47oywkJgFw==" + "resolved" "https://registry.npmjs.org/vue/-/vue-3.2.31.tgz" + "version" "3.2.31" dependencies: - "@vue/compiler-dom" "3.1.5" - "@vue/runtime-dom" "3.1.5" - "@vue/shared" "3.1.5" + "@vue/compiler-dom" "3.2.31" + "@vue/compiler-sfc" "3.2.31" + "@vue/runtime-dom" "3.2.31" + "@vue/server-renderer" "3.2.31" + "@vue/shared" "3.2.31" "vue@^2.6.11": "integrity" "sha512-x2284lgYvjOMj3Za7kqzRcUSxBboHqtgRE2zlos1qWaOye5yUmHn42LB1250NJBLRwEcdrB0JRwyPTEPhfQjiQ=="