Compare commits

...

17 Commits

Author SHA1 Message Date
ljw
90b9b5adba up 2024-10-28 14:54:00 +08:00
ljw
5bf4bbe45f add address book name &
add share address book
2024-10-28 14:51:07 +08:00
ljw
036f928fa3 up readme 2024-10-23 11:09:28 +08:00
ljw
94e7b31fb6 fix group 2024-10-23 11:09:13 +08:00
ljw
be4742382d up build.yml 2024-10-23 09:19:02 +08:00
ljw
70d2f1a055 add armv7l build #21 2024-10-23 09:03:01 +08:00
ljw
877fe50049 add ru lang 2024-10-22 19:46:38 +08:00
ljw
7d505705ee add ko lang,but validator dont have translations ko 2024-10-22 12:21:32 +08:00
ljw
38f81a03b5 Merge branch 'master' of https://github.com/lejianwen/rustdesk-api 2024-10-22 11:31:01 +08:00
d549d23819 Merge pull request #19 from jkh0kr/master
Add Korean language file
2024-10-22 11:30:49 +08:00
ljw
934675e0f0 up 2024-10-22 11:28:27 +08:00
진기환
2be397aa38 Add Korean language file 2024-10-22 10:35:58 +09:00
ljw
a0a422ed45 up readme 2024-10-21 21:35:27 +08:00
ljw
fcce10c695 add file conn log 2024-10-21 21:08:25 +08:00
ljw
30eb14702f up build.yml 2024-10-20 20:26:08 +08:00
ljw
3679fcc874 fix group create type 2024-10-20 20:15:12 +08:00
ljw
d085b4e3c2 up readme 2024-10-20 19:40:49 +08:00
57 changed files with 4011 additions and 336 deletions

View File

@@ -39,7 +39,7 @@ env:
DOCKERHUB_IMAGE_NAMESPACE: ${{ github.event.inputs.DOCKERHUB_IMAGE_NAMESPACE || github.actor }} DOCKERHUB_IMAGE_NAMESPACE: ${{ github.event.inputs.DOCKERHUB_IMAGE_NAMESPACE || github.actor }}
GHCR_IMAGE_NAMESPACE: ${{ github.event.inputs.GHCR_IMAGE_NAMESPACE || github.actor }} GHCR_IMAGE_NAMESPACE: ${{ github.event.inputs.GHCR_IMAGE_NAMESPACE || github.actor }}
SKIP_DOCKER_HUB: ${{ github.event.inputs.SKIP_DOCKER_HUB || 'false' }} SKIP_DOCKER_HUB: ${{ github.event.inputs.SKIP_DOCKER_HUB || 'false' }}
SKIP_GHCR: ${{ github.event.inputs.SKIP_GHCR }} SKIP_GHCR: ${{ github.event.inputs.SKIP_GHCR || 'false' }}
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -48,10 +48,10 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
job: job:
- { platform: "amd64", goos: "linux" } - { platform: "amd64", goos: "linux", file_ext: "tar.gz" }
- { platform: "arm64", goos: "linux" } - { platform: "arm64", goos: "linux", file_ext: "tar.gz" }
- { platform: "amd64", goos: "windows" } - { platform: "armv7l", goos: "linux", file_ext: "tar.gz" }
- { platform: "amd64", goos: "windows", file_ext: "zip" }
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v4
@@ -96,18 +96,23 @@ jobs:
if [ "${{ matrix.job.goos }}" = "windows" ]; then if [ "${{ matrix.job.goos }}" = "windows" ]; then
sudo apt-get install gcc-mingw-w64-x86-64 zip -y sudo apt-get install gcc-mingw-w64-x86-64 zip -y
GOOS=${{ matrix.job.goos }} GOARCH=${{ matrix.job.platform }} CC=x86_64-w64-mingw32-gcc CGO_LDFLAGS="-static" CGO_ENABLED=1 go build -ldflags "-s -w" -o ./release/apimain.exe ./cmd/apimain.go GOOS=${{ matrix.job.goos }} GOARCH=${{ matrix.job.platform }} CC=x86_64-w64-mingw32-gcc CGO_LDFLAGS="-static" CGO_ENABLED=1 go build -ldflags "-s -w" -o ./release/apimain.exe ./cmd/apimain.go
zip -r ${{ matrix.job.goos}}-${{ matrix.job.platform }}.zip ./release zip -r ${{ matrix.job.goos}}-${{ matrix.job.platform }}.${{matrix.job.file_ext}} ./release
else else
if [ "${{ matrix.job.platform }}" = "arm64" ]; then if [ "${{ matrix.job.platform }}" = "arm64" ]; then
wget https://musl.cc/aarch64-linux-musl-cross.tgz wget https://musl.cc/aarch64-linux-musl-cross.tgz
tar -xf aarch64-linux-musl-cross.tgz tar -xf aarch64-linux-musl-cross.tgz
export PATH=$PATH:$PWD/aarch64-linux-musl-cross/bin export PATH=$PATH:$PWD/aarch64-linux-musl-cross/bin
GOOS=${{ matrix.job.goos }} GOARCH=${{ matrix.job.platform }} CC=aarch64-linux-musl-gcc CGO_LDFLAGS="-static" CGO_ENABLED=1 go build -ldflags "-s -w" -o ./release/apimain ./cmd/apimain.go GOOS=${{ matrix.job.goos }} GOARCH=${{ matrix.job.platform }} CC=aarch64-linux-musl-gcc CGO_LDFLAGS="-static" CGO_ENABLED=1 go build -ldflags "-s -w" -o ./release/apimain ./cmd/apimain.go
elif [ "${{ matrix.job.platform }}" = "armv7l" ]; then
wget https://musl.cc/armv7l-linux-musleabihf-cross.tgz
tar -xf armv7l-linux-musleabihf-cross.tgz
export PATH=$PATH:$PWD/armv7l-linux-musleabihf-cross/bin
GOOS=${{ matrix.job.goos }} GOARCH=arm GOARM=7 CC=armv7l-linux-musleabihf-gcc CGO_LDFLAGS="-static" CGO_ENABLED=1 go build -ldflags "-s -w" -o ./release/apimain ./cmd/apimain.go
else else
sudo apt-get install musl musl-dev musl-tools -y sudo apt-get install musl musl-dev musl-tools -y
GOOS=${{ matrix.job.goos }} GOARCH=${{ matrix.job.platform }} CC=musl-gcc CGO_LDFLAGS="-static" CGO_ENABLED=1 go build -ldflags "-s -w" -o ./release/apimain ./cmd/apimain.go GOOS=${{ matrix.job.goos }} GOARCH=${{ matrix.job.platform }} CC=musl-gcc CGO_LDFLAGS="-static" CGO_ENABLED=1 go build -ldflags "-s -w" -o ./release/apimain ./cmd/apimain.go
fi fi
tar -czf ${{ matrix.job.goos}}-${{ matrix.job.platform }}.tar.gz ./release tar -czf ${{ matrix.job.goos}}-${{ matrix.job.platform }}.${{matrix.job.file_ext}} ./release
fi fi
- name: Upload artifact - name: Upload artifact
@@ -115,14 +120,12 @@ jobs:
with: with:
name: rustdesk-api-${{ matrix.job.goos }}-${{ matrix.job.platform }} name: rustdesk-api-${{ matrix.job.goos }}-${{ matrix.job.platform }}
path: | path: |
${{ matrix.job.goos}}-${{ matrix.job.platform }}.tar.gz ${{ matrix.job.goos}}-${{ matrix.job.platform }}.${{matrix.job.file_ext}}
${{ matrix.job.goos}}-${{ matrix.job.platform }}.zip
- name: Upload to GitHub Release - name: Upload to GitHub Release
uses: softprops/action-gh-release@v2 uses: softprops/action-gh-release@v2
with: with:
files: | files: |
${{ matrix.job.goos}}-${{ matrix.job.platform }}.tar.gz ${{ matrix.job.goos}}-${{ matrix.job.platform }}.${{matrix.job.file_ext}}
${{ matrix.job.goos}}-${{ matrix.job.platform }}.zip
# tag_name: ${{ env.LATEST_TAG }} # tag_name: ${{ env.LATEST_TAG }}
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -137,6 +140,7 @@ jobs:
job: job:
- { platform: "amd64", goos: "linux", docker_platform: "linux/amd64" } - { platform: "amd64", goos: "linux", docker_platform: "linux/amd64" }
- { platform: "arm64", goos: "linux", docker_platform: "linux/arm64" } - { platform: "arm64", goos: "linux", docker_platform: "linux/arm64" }
- { platform: "armv7l", goos: "linux", docker_platform: "linux/arm/v7" }
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v4
@@ -257,6 +261,7 @@ jobs:
with: with:
base-image: ${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }} base-image: ${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}
extra-images: ${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-amd64, extra-images: ${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-amd64,
${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-armv7l,
${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-arm64 ${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-arm64
push: true push: true
@@ -266,6 +271,7 @@ jobs:
with: with:
base-image: ghcr.io/${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }} base-image: ghcr.io/${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}
extra-images: ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-amd64, extra-images: ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-amd64,
ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-armv7l,
ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-arm64 ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-arm64
push: true push: true
amend: true amend: true
@@ -276,6 +282,7 @@ jobs:
with: with:
base-image: ${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api:latest base-image: ${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api:latest
extra-images: ${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:latest-amd64, extra-images: ${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:latest-amd64,
${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:latest-armv7l,
${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:latest-arm64 ${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:latest-arm64
push: true push: true
@@ -285,6 +292,7 @@ jobs:
with: with:
base-image: ghcr.io/${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api:latest base-image: ghcr.io/${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api:latest
extra-images: ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:latest-amd64, extra-images: ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:latest-amd64,
ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:latest-armv7l,
ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:latest-arm64 ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:latest-arm64
push: true push: true
amend: true amend: true

View File

@@ -28,6 +28,9 @@
- 标签管理 - 标签管理
- 群组管理 - 群组管理
- Oauth 管理 - Oauth 管理
- 登录日志
- 链接日志
- 文件传输日志
- 快速使用web client - 快速使用web client
- i18n - i18n
- 通过 web client 分享给游客 - 通过 web client 分享给游客
@@ -44,7 +47,7 @@
#### PC客户端使用的是 ***1.3.0***,经测试 ***1.2.6+*** 都可以 #### PC客户端使用的是 ***1.3.0***,经测试 ***1.2.6+*** 都可以
#### 关于PC端链接超时或者链接不上的问题以及解决方案 #### 关于PC端链接超时或者链接不上的问题以及解决方案
##### 链接不上或者超时 ##### 链接不上或者超时
因为server端相对于客户端落后版本server不会响应客户端的`secure_tcp`请求,所以客户端超时。 因为server端相对于客户端落后版本server不会响应客户端的`secure_tcp`请求,所以客户端超时。
相关代码代码位置在`https://github.com/rustdesk/rustdesk/blob/master/src/client.rs#L322` 相关代码代码位置在`https://github.com/rustdesk/rustdesk/blob/master/src/client.rs#L322`
```rust ```rust
@@ -113,12 +116,13 @@
![web_admin](docs/web_admin.png) ![web_admin](docs/web_admin.png)
2. 普通用户界面 2. 普通用户界面
![web_user](docs/web_admin_user.png) ![web_user](docs/web_admin_user.png)
右上角可以更改密码,可以切换语言 右上角可以更改密码,可以切换语言,可以切换`白天/黑夜`模式
![web_resetpwd](docs/web_resetpwd.png) ![web_resetpwd](docs/web_resetpwd.png)
3. 分组可以自定义,方便管理,暂时支持两种类型: `共享组` 和 `普通组` 3. 分组可以自定义,方便管理,暂时支持两种类型: `共享组` 和 `普通组`
![web_admin_gr](docs/web_admin_gr.png) ![web_admin_gr](docs/web_admin_gr.png)
4. 可以直接打开webclient方便使用也可以分享给游客游客可以直接通过webclient远程到设备 4. 可以直接打开webclient方便使用也可以分享给游客游客可以直接通过webclient远程到设备
![web_webclient](docs/admin_webclient.png) ![web_webclient](docs/admin_webclient.png)
5. Oauth,暂时只支持了`Github`和`Google`, 需要创建一个`OAuth App`,然后配置到后台 5. Oauth,暂时只支持了`Github`和`Google`, 需要创建一个`OAuth App`,然后配置到后台
![web_admin_oauth](docs/web_admin_oauth.png) ![web_admin_oauth](docs/web_admin_oauth.png)
@@ -177,6 +181,9 @@ logger:
path: "./runtime/log.txt" path: "./runtime/log.txt"
level: "warn" #trace,debug,info,warn,error,fatal level: "warn" #trace,debug,info,warn,error,fatal
report-caller: true report-caller: true
proxy:
enable: false
host: ""
``` ```
### 环境变量 ### 环境变量
@@ -204,6 +211,10 @@ logger:
| RUSTDESK_API_RUSTDESK_RELAY_SERVER | Rustdesk的relay服务器地址 | 192.168.1.66:21117 | | RUSTDESK_API_RUSTDESK_RELAY_SERVER | Rustdesk的relay服务器地址 | 192.168.1.66:21117 |
| RUSTDESK_API_RUSTDESK_API_SERVER | Rustdesk的api服务器地址 | http://192.168.1.66:21114 | | RUSTDESK_API_RUSTDESK_API_SERVER | Rustdesk的api服务器地址 | http://192.168.1.66:21114 |
| RUSTDESK_API_RUSTDESK_KEY | Rustdesk的key | 123456789 | | RUSTDESK_API_RUSTDESK_KEY | Rustdesk的key | 123456789 |
| ----PROXY配置----- | --------------- | ---------- |
| RUSTDESK_API_PROXY_ENABLE | 是否启用代理:`false`, `true` | `false` |
| RUSTDESK_API_PROXY_HOST | 代理地址 | `http://127.0.0.1:1080` |
### 运行 ### 运行

View File

@@ -27,6 +27,9 @@ desktop software that provides self-hosted solutions.
- Tag Management - Tag Management
- Group Management - Group Management
- OAuth Management - OAuth Management
- Login Logs
- Connection Logs
- File Transfer Logs
- Quick access to web client - Quick access to web client
- i18n - i18n
- Share to guest by web client - Share to guest by web client
@@ -117,15 +120,16 @@ installation are `admin` `admin`, please change the password immediately.
![web_admin](docs/en_img/web_admin.png) ![web_admin](docs/en_img/web_admin.png)
2. Regular user interface: 2. Regular user interface:
![web_user](docs/en_img/web_admin_user.png) ![web_user](docs/en_img/web_admin_user.png)
You can change your password from the top right corner: In the top right corner, you can change the password, switch languages, and toggle between `day/night` mode.
![web_resetpwd](docs/en_img/web_resetpwd.png) ![web_resetpwd](docs/en_img/web_resetpwd.png)
3. Groups can be customized for easy management. Currently, two types are supported: `shared group` and `regular group`. 3. Groups can be customized for easy management. Currently, two types are supported: `shared group` and `regular group`.
![web_admin_gr](docs/en_img/web_admin_gr.png) ![web_admin_gr](docs/en_img/web_admin_gr.png)
4. You can directly open the web client for convenient use; it can also be shared with guests, allowing them to remotely access the device via the web client. 4. You can directly launch the client or open the web client for convenience; you can also share it with guests, who can remotely access the device via the web client.
![web_webclient](docs/en_img/admin_webclient.png) ![web_webclient](docs/en_img/admin_webclient.png)
5. OAuth support: Currently, `GitHub` and `Google` is supported. You need to create an `OAuth App` and configure it in 5. OAuth support: Currently, `GitHub` and `Google` is supported. You need to create an `OAuth App` and configure it in
the admin the admin panel.
panel.
![web_admin_oauth](docs/en_img/web_admin_oauth.png) ![web_admin_oauth](docs/en_img/web_admin_oauth.png)
- Create a `GitHub OAuth App` - Create a `GitHub OAuth App`
at `Settings` -> `Developer settings` -> `OAuth Apps` -> `New OAuth App` [here](https://github.com/settings/developers). at `Settings` -> `Developer settings` -> `OAuth Apps` -> `New OAuth App` [here](https://github.com/settings/developers).
@@ -135,7 +139,7 @@ installation are `admin` `admin`, please change the password immediately.
### Web Client: ### Web Client:
1. If you're already logged into the admin panel, the web client will log in automatically. 1. If you're already logged into the admin panel, the web client will log in automatically.
2. If you're not logged in, simply click the login button at the top right corner, and the API server will be 2. If you're not logged in, simply click the login button in the top right corner, and the API server will be
pre-configured. pre-configured.
![webclient_conf](docs/webclient_conf.png) ![webclient_conf](docs/webclient_conf.png)
3. After logging in, the ID server and key will be automatically synced. 3. After logging in, the ID server and key will be automatically synced.
@@ -183,6 +187,9 @@ logger:
path: "./runtime/log.txt" path: "./runtime/log.txt"
level: "warn" #trace,debug,info,warn,error,fatal level: "warn" #trace,debug,info,warn,error,fatal
report-caller: true report-caller: true
proxy:
enable: false
host: ""
``` ```
### Environment Variables ### Environment Variables
@@ -210,6 +217,9 @@ The prefix for variable names is `RUSTDESK_API`. If environment variables exist,
| RUSTDESK_API_RUSTDESK_RELAY_SERVER | Rustdesk relay server address | 192.168.1.66:21117 | | RUSTDESK_API_RUSTDESK_RELAY_SERVER | Rustdesk relay server address | 192.168.1.66:21117 |
| RUSTDESK_API_RUSTDESK_API_SERVER | Rustdesk API server address | http://192.168.1.66:21114 | | RUSTDESK_API_RUSTDESK_API_SERVER | Rustdesk API server address | http://192.168.1.66:21114 |
| RUSTDESK_API_RUSTDESK_KEY | Rustdesk key | 123456789 | | RUSTDESK_API_RUSTDESK_KEY | Rustdesk key | 123456789 |
| ---- PROXY ----- | --------------- | ---------- |
| RUSTDESK_API_PROXY_ENABLE | proxy_enable :`false`, `true` | `false` |
| RUSTDESK_API_PROXY_HOST | proxy_host | `http://127.0.0.1:1080` |
### Installation Steps ### Installation Steps

View File

@@ -12,19 +12,8 @@ import (
"Gwen/model" "Gwen/model"
"Gwen/service" "Gwen/service"
"fmt" "fmt"
"github.com/BurntSushi/toml"
"github.com/gin-gonic/gin"
"github.com/go-playground/locales/en"
"github.com/go-playground/locales/zh_Hans_CN"
ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
en_translations "github.com/go-playground/validator/v10/translations/en"
zh_translations "github.com/go-playground/validator/v10/translations/zh"
"github.com/go-redis/redis/v8" "github.com/go-redis/redis/v8"
"github.com/nicksnyder/go-i18n/v2/i18n" "github.com/nicksnyder/go-i18n/v2/i18n"
"golang.org/x/text/language"
nethttp "net/http"
"reflect"
) )
// @title 管理系统API // @title 管理系统API
@@ -48,7 +37,7 @@ func main() {
ReportCaller: global.Config.Logger.ReportCaller, ReportCaller: global.Config.Logger.ReportCaller,
}) })
InitI18n() global.InitI18n()
//redis //redis
global.Redis = redis.NewClient(&redis.Options{ global.Redis = redis.NewClient(&redis.Options{
@@ -87,7 +76,7 @@ func main() {
DatabaseAutoUpdate() DatabaseAutoUpdate()
//validator //validator
ApiInitValidator() global.ApiInitValidator()
//oss //oss
global.Oss = &upload.Oss{ global.Oss = &upload.Oss{
@@ -111,96 +100,8 @@ func main() {
} }
func ApiInitValidator() {
validate := validator.New()
// 定义不同的语言翻译
enT := en.New()
cn := zh_Hans_CN.New()
uni := ut.New(enT, cn)
enTrans, _ := uni.GetTranslator("en")
zhTrans, _ := uni.GetTranslator("zh_Hans_CN")
err := zh_translations.RegisterDefaultTranslations(validate, zhTrans)
if err != nil {
panic(err)
}
err = en_translations.RegisterDefaultTranslations(validate, enTrans)
if err != nil {
panic(err)
}
validate.RegisterTagNameFunc(func(field reflect.StructField) string {
label := field.Tag.Get("label")
if label == "" {
return field.Name
}
return label
})
global.Validator.Validate = validate
global.Validator.UT = uni // 存储 Universal Translator
global.Validator.VTrans = zhTrans
global.Validator.ValidStruct = func(ctx *gin.Context, i interface{}) []string {
err := global.Validator.Validate.Struct(i)
lang := ctx.GetHeader("Accept-Language")
if lang == "" {
lang = global.Config.Lang
}
trans := getTranslatorForLang(lang)
errList := make([]string, 0, 10)
if err != nil {
if _, ok := err.(*validator.InvalidValidationError); ok {
errList = append(errList, err.Error())
return errList
}
for _, err2 := range err.(validator.ValidationErrors) {
errList = append(errList, err2.Translate(trans))
}
}
return errList
}
global.Validator.ValidVar = func(ctx *gin.Context, field interface{}, tag string) []string {
err := global.Validator.Validate.Var(field, tag)
lang := ctx.GetHeader("Accept-Language")
if lang == "" {
lang = global.Config.Lang
}
trans := getTranslatorForLang(lang)
errList := make([]string, 0, 10)
if err != nil {
if _, ok := err.(*validator.InvalidValidationError); ok {
errList = append(errList, err.Error())
return errList
}
for _, err2 := range err.(validator.ValidationErrors) {
errList = append(errList, err2.Translate(trans))
}
}
return errList
}
}
func getTranslatorForLang(lang string) ut.Translator {
switch lang {
case "zh_CN":
fallthrough
case "zh-CN":
fallthrough
case "zh":
trans, _ := global.Validator.UT.GetTranslator("zh_Hans_CN")
return trans
case "en":
fallthrough
default:
trans, _ := global.Validator.UT.GetTranslator("en")
return trans
}
}
func DatabaseAutoUpdate() { func DatabaseAutoUpdate() {
version := 233 version := 240
db := global.DB db := global.DB
@@ -263,6 +164,9 @@ func Migrate(version uint) {
&model.LoginLog{}, &model.LoginLog{},
&model.ShareRecord{}, &model.ShareRecord{},
&model.AuditConn{}, &model.AuditConn{},
&model.AuditFile{},
&model.AddressBookCollection{},
&model.AddressBookCollectionRule{},
) )
if err != nil { if err != nil {
fmt.Println("migrate err :=>", err) fmt.Println("migrate err :=>", err)
@@ -272,9 +176,7 @@ func Migrate(version uint) {
var vc int64 var vc int64
global.DB.Model(&model.Version{}).Count(&vc) global.DB.Model(&model.Version{}).Count(&vc)
if vc == 1 { if vc == 1 {
localizer := global.Localizer(&gin.Context{ localizer := global.Localizer("")
Request: &nethttp.Request{},
})
defaultGroup, _ := localizer.LocalizeMessage(&i18n.Message{ defaultGroup, _ := localizer.LocalizeMessage(&i18n.Message{
ID: "DefaultGroup", ID: "DefaultGroup",
}) })
@@ -306,37 +208,3 @@ func Migrate(version uint) {
} }
} }
func InitI18n() {
bundle := i18n.NewBundle(language.English)
bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal)
bundle.LoadMessageFile(global.Config.Gin.ResourcesPath + "/i18n/en.toml")
bundle.LoadMessageFile(global.Config.Gin.ResourcesPath + "/i18n/zh_CN.toml")
global.Localizer = func(ctx *gin.Context) *i18n.Localizer {
lang := ctx.GetHeader("Accept-Language")
if lang == "" {
lang = global.Config.Lang
}
if lang == "en" {
return i18n.NewLocalizer(bundle, "en")
} else {
return i18n.NewLocalizer(bundle, lang, "en")
}
}
//personUnreadEmails := localizer.MustLocalize(&i18n.LocalizeConfig{
// DefaultMessage: &i18n.Message{
// ID: "PersonUnreadEmails",
// },
// PluralCount: 6,
// TemplateData: map[string]interface{}{
// "Name": "LE",
// "PluralCount": 6,
// },
//})
//personUnreadEmails, err := global.Localizer.LocalizeMessage(&i18n.Message{
// ID: "ParamsError",
//})
//fmt.Println(err, personUnreadEmails)
}

View File

@@ -25,6 +25,9 @@ logger:
path: "./runtime/log.txt" path: "./runtime/log.txt"
level: "warn" #trace,debug,info,warn,error,fatal level: "warn" #trace,debug,info,warn,error,fatal
report-caller: true report-caller: true
proxy:
enable: false
host: "http://127.0.0.1:1080"
redis: redis:
addr: "127.0.0.1:6379" addr: "127.0.0.1:6379"
password: "" password: ""
@@ -45,6 +48,3 @@ oss:
jwt: jwt:
private-key: "./conf/jwt_pri.pem" private-key: "./conf/jwt_pri.pem"
expire-duration: 360000 expire-duration: 360000
proxy:
enable: false
host: ""

View File

@@ -346,6 +346,554 @@ const docTemplateadmin = `{
} }
} }
}, },
"/admin/address_book_collection/create": {
"post": {
"security": [
{
"token": []
}
],
"description": "创建地址簿集合",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"summary": "创建地址簿集合",
"parameters": [
{
"description": "地址簿集合信息",
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/model.AddressBookCollection"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.Response"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/model.AddressBookCollection"
}
}
}
]
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/admin/address_book_collection/delete": {
"post": {
"security": [
{
"token": []
}
],
"description": "地址簿集合删除",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"summary": "地址簿集合删除",
"parameters": [
{
"description": "地址簿集合信息",
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/model.AddressBookCollection"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/response.Response"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/admin/address_book_collection/detail/{id}": {
"get": {
"security": [
{
"token": []
}
],
"description": "地址簿集合详情",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"summary": "地址簿集合详情",
"parameters": [
{
"type": "integer",
"description": "ID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.Response"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/model.AddressBookCollection"
}
}
}
]
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/admin/address_book_collection/list": {
"get": {
"security": [
{
"token": []
}
],
"description": "地址簿集合列表",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"summary": "地址簿集合列表",
"parameters": [
{
"type": "integer",
"description": "页码",
"name": "page",
"in": "query"
},
{
"type": "integer",
"description": "页大小",
"name": "page_size",
"in": "query"
},
{
"type": "integer",
"description": "是否是我的",
"name": "is_my",
"in": "query"
},
{
"type": "integer",
"description": "用户id",
"name": "user_id",
"in": "query"
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.Response"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/model.AddressBookCollectionList"
}
}
}
]
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/admin/address_book_collection/update": {
"post": {
"security": [
{
"token": []
}
],
"description": "地址簿集合编辑",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"summary": "地址簿集合编辑",
"parameters": [
{
"description": "地址簿集合信息",
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/model.AddressBookCollection"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.Response"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/model.AddressBookCollection"
}
}
}
]
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/admin/address_book_collection_rule/create": {
"post": {
"security": [
{
"token": []
}
],
"description": "创建地址簿集合规则",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"summary": "创建地址簿集合规则",
"parameters": [
{
"description": "地址簿集合规则信息",
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/model.AddressBookCollectionRule"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.Response"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/model.AddressBookCollection"
}
}
}
]
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/admin/address_book_collection_rule/delete": {
"post": {
"security": [
{
"token": []
}
],
"description": "地址簿集合规则删除",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"summary": "地址簿集合规则删除",
"parameters": [
{
"description": "地址簿集合规则信息",
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/model.AddressBookCollectionRule"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/response.Response"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/admin/address_book_collection_rule/detail/{id}": {
"get": {
"security": [
{
"token": []
}
],
"description": "地址簿集合规则详情",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"summary": "地址簿集合规则详情",
"parameters": [
{
"type": "integer",
"description": "ID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.Response"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/model.AddressBookCollectionRule"
}
}
}
]
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/admin/address_book_collection_rule/list": {
"get": {
"security": [
{
"token": []
}
],
"description": "地址簿集合规则列表",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"summary": "地址簿集合规则列表",
"parameters": [
{
"type": "integer",
"description": "页码",
"name": "page",
"in": "query"
},
{
"type": "integer",
"description": "页大小",
"name": "page_size",
"in": "query"
},
{
"type": "integer",
"description": "是否是我的",
"name": "is_my",
"in": "query"
},
{
"type": "integer",
"description": "用户id",
"name": "user_id",
"in": "query"
},
{
"type": "integer",
"description": "地址簿集合id",
"name": "collection_id",
"in": "query"
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.Response"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/model.AddressBookCollectionList"
}
}
}
]
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/admin/address_book_collection_rule/update": {
"post": {
"security": [
{
"token": []
}
],
"description": "地址簿集合规则编辑",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"summary": "地址簿集合规则编辑",
"parameters": [
{
"description": "地址簿集合规则信息",
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/model.AddressBookCollectionRule"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.Response"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/model.AddressBookCollection"
}
}
}
]
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/admin/app-config": { "/admin/app-config": {
"get": { "get": {
"security": [ "security": [
@@ -387,7 +935,7 @@ const docTemplateadmin = `{
"token": [] "token": []
} }
], ],
"description": "链接日志删除", "description": "文件日志删除",
"consumes": [ "consumes": [
"application/json" "application/json"
], ],
@@ -395,17 +943,17 @@ const docTemplateadmin = `{
"application/json" "application/json"
], ],
"tags": [ "tags": [
"链接日志" "文件日志"
], ],
"summary": "链接日志删除", "summary": "文件日志删除",
"parameters": [ "parameters": [
{ {
"description": "链接日志信息", "description": "文件日志信息",
"name": "body", "name": "body",
"in": "body", "in": "body",
"required": true, "required": true,
"schema": { "schema": {
"$ref": "#/definitions/model.AuditConn" "$ref": "#/definitions/model.AuditFile"
} }
} }
], ],
@@ -432,7 +980,7 @@ const docTemplateadmin = `{
"token": [] "token": []
} }
], ],
"description": "链接日志列表", "description": "文件日志列表",
"consumes": [ "consumes": [
"application/json" "application/json"
], ],
@@ -440,9 +988,9 @@ const docTemplateadmin = `{
"application/json" "application/json"
], ],
"tags": [ "tags": [
"链接日志" "文件日志"
], ],
"summary": "链接日志列表", "summary": "文件日志列表",
"parameters": [ "parameters": [
{ {
"type": "integer", "type": "integer",
@@ -481,7 +1029,7 @@ const docTemplateadmin = `{
"type": "object", "type": "object",
"properties": { "properties": {
"data": { "data": {
"$ref": "#/definitions/model.AuditConnList" "$ref": "#/definitions/model.AuditFileList"
} }
} }
} }
@@ -2480,6 +3028,9 @@ const docTemplateadmin = `{
"alias": { "alias": {
"type": "string" "type": "string"
}, },
"collection_id": {
"type": "integer"
},
"forceAlwaysRelay": { "forceAlwaysRelay": {
"type": "boolean" "type": "boolean"
}, },
@@ -2566,6 +3117,9 @@ const docTemplateadmin = `{
}, },
"name": { "name": {
"type": "string" "type": "string"
},
"type": {
"type": "integer"
} }
} }
}, },
@@ -2698,6 +3252,9 @@ const docTemplateadmin = `{
"name" "name"
], ],
"properties": { "properties": {
"collection_id": {
"type": "integer"
},
"color": { "color": {
"type": "integer" "type": "integer"
}, },
@@ -2785,6 +3342,12 @@ const docTemplateadmin = `{
"alias": { "alias": {
"type": "string" "type": "string"
}, },
"collection": {
"$ref": "#/definitions/model.AddressBookCollection"
},
"collection_id": {
"type": "integer"
},
"created_at": { "created_at": {
"type": "string" "type": "string"
}, },
@@ -2841,6 +3404,90 @@ const docTemplateadmin = `{
} }
} }
}, },
"model.AddressBookCollection": {
"type": "object",
"required": [
"name"
],
"properties": {
"created_at": {
"type": "string"
},
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"updated_at": {
"type": "string"
},
"user_id": {
"type": "integer"
}
}
},
"model.AddressBookCollectionList": {
"type": "object",
"properties": {
"list": {
"type": "array",
"items": {
"$ref": "#/definitions/model.AddressBookCollection"
}
},
"page": {
"type": "integer"
},
"page_size": {
"type": "integer"
},
"total": {
"type": "integer"
}
}
},
"model.AddressBookCollectionRule": {
"type": "object",
"required": [
"collection_id",
"rule",
"to_id",
"type"
],
"properties": {
"collection_id": {
"type": "integer"
},
"created_at": {
"type": "string"
},
"id": {
"type": "integer"
},
"rule": {
"description": "0: 无 1: 读 2: 读写 3: 完全控制",
"type": "integer",
"maximum": 3,
"minimum": 1
},
"to_id": {
"type": "integer"
},
"type": {
"description": "1: 个人 2: 群组",
"type": "integer",
"maximum": 2,
"minimum": 1
},
"updated_at": {
"type": "string"
},
"user_id": {
"type": "integer"
}
}
},
"model.AddressBookList": { "model.AddressBookList": {
"type": "object", "type": "object",
"properties": { "properties": {
@@ -2925,6 +3572,70 @@ const docTemplateadmin = `{
} }
} }
}, },
"model.AuditFile": {
"type": "object",
"properties": {
"created_at": {
"type": "string"
},
"from_name": {
"type": "string"
},
"from_peer": {
"type": "string"
},
"id": {
"type": "integer"
},
"info": {
"type": "string"
},
"ip": {
"type": "string"
},
"is_file": {
"type": "boolean"
},
"num": {
"type": "integer"
},
"path": {
"type": "string"
},
"peer_id": {
"type": "string"
},
"type": {
"type": "integer"
},
"updated_at": {
"type": "string"
},
"uuid": {
"type": "string"
}
}
},
"model.AuditFileList": {
"type": "object",
"properties": {
"list": {
"type": "array",
"items": {
"$ref": "#/definitions/model.AuditFile"
}
},
"page": {
"type": "integer"
},
"page_size": {
"type": "integer"
},
"total": {
"type": "integer"
}
}
},
"model.Group": { "model.Group": {
"type": "object", "type": "object",
"properties": { "properties": {
@@ -3154,6 +3865,12 @@ const docTemplateadmin = `{
"model.Tag": { "model.Tag": {
"type": "object", "type": "object",
"properties": { "properties": {
"collection": {
"$ref": "#/definitions/model.AddressBookCollection"
},
"collection_id": {
"type": "integer"
},
"color": { "color": {
"description": "color 是flutter的颜色值,从0x00000000 到 0xFFFFFFFF; 前两位表示透明度后面6位表示颜色, 可以转成rgba", "description": "color 是flutter的颜色值,从0x00000000 到 0xFFFFFFFF; 前两位表示透明度后面6位表示颜色, 可以转成rgba",
"type": "integer" "type": "integer"

View File

@@ -339,6 +339,554 @@
} }
} }
}, },
"/admin/address_book_collection/create": {
"post": {
"security": [
{
"token": []
}
],
"description": "创建地址簿集合",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"summary": "创建地址簿集合",
"parameters": [
{
"description": "地址簿集合信息",
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/model.AddressBookCollection"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.Response"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/model.AddressBookCollection"
}
}
}
]
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/admin/address_book_collection/delete": {
"post": {
"security": [
{
"token": []
}
],
"description": "地址簿集合删除",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"summary": "地址簿集合删除",
"parameters": [
{
"description": "地址簿集合信息",
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/model.AddressBookCollection"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/response.Response"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/admin/address_book_collection/detail/{id}": {
"get": {
"security": [
{
"token": []
}
],
"description": "地址簿集合详情",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"summary": "地址簿集合详情",
"parameters": [
{
"type": "integer",
"description": "ID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.Response"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/model.AddressBookCollection"
}
}
}
]
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/admin/address_book_collection/list": {
"get": {
"security": [
{
"token": []
}
],
"description": "地址簿集合列表",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"summary": "地址簿集合列表",
"parameters": [
{
"type": "integer",
"description": "页码",
"name": "page",
"in": "query"
},
{
"type": "integer",
"description": "页大小",
"name": "page_size",
"in": "query"
},
{
"type": "integer",
"description": "是否是我的",
"name": "is_my",
"in": "query"
},
{
"type": "integer",
"description": "用户id",
"name": "user_id",
"in": "query"
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.Response"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/model.AddressBookCollectionList"
}
}
}
]
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/admin/address_book_collection/update": {
"post": {
"security": [
{
"token": []
}
],
"description": "地址簿集合编辑",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"summary": "地址簿集合编辑",
"parameters": [
{
"description": "地址簿集合信息",
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/model.AddressBookCollection"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.Response"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/model.AddressBookCollection"
}
}
}
]
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/admin/address_book_collection_rule/create": {
"post": {
"security": [
{
"token": []
}
],
"description": "创建地址簿集合规则",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"summary": "创建地址簿集合规则",
"parameters": [
{
"description": "地址簿集合规则信息",
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/model.AddressBookCollectionRule"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.Response"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/model.AddressBookCollection"
}
}
}
]
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/admin/address_book_collection_rule/delete": {
"post": {
"security": [
{
"token": []
}
],
"description": "地址簿集合规则删除",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"summary": "地址簿集合规则删除",
"parameters": [
{
"description": "地址簿集合规则信息",
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/model.AddressBookCollectionRule"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/response.Response"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/admin/address_book_collection_rule/detail/{id}": {
"get": {
"security": [
{
"token": []
}
],
"description": "地址簿集合规则详情",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"summary": "地址簿集合规则详情",
"parameters": [
{
"type": "integer",
"description": "ID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.Response"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/model.AddressBookCollectionRule"
}
}
}
]
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/admin/address_book_collection_rule/list": {
"get": {
"security": [
{
"token": []
}
],
"description": "地址簿集合规则列表",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"summary": "地址簿集合规则列表",
"parameters": [
{
"type": "integer",
"description": "页码",
"name": "page",
"in": "query"
},
{
"type": "integer",
"description": "页大小",
"name": "page_size",
"in": "query"
},
{
"type": "integer",
"description": "是否是我的",
"name": "is_my",
"in": "query"
},
{
"type": "integer",
"description": "用户id",
"name": "user_id",
"in": "query"
},
{
"type": "integer",
"description": "地址簿集合id",
"name": "collection_id",
"in": "query"
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.Response"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/model.AddressBookCollectionList"
}
}
}
]
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/admin/address_book_collection_rule/update": {
"post": {
"security": [
{
"token": []
}
],
"description": "地址簿集合规则编辑",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"summary": "地址簿集合规则编辑",
"parameters": [
{
"description": "地址簿集合规则信息",
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/model.AddressBookCollectionRule"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.Response"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/model.AddressBookCollection"
}
}
}
]
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/admin/app-config": { "/admin/app-config": {
"get": { "get": {
"security": [ "security": [
@@ -380,7 +928,7 @@
"token": [] "token": []
} }
], ],
"description": "链接日志删除", "description": "文件日志删除",
"consumes": [ "consumes": [
"application/json" "application/json"
], ],
@@ -388,17 +936,17 @@
"application/json" "application/json"
], ],
"tags": [ "tags": [
"链接日志" "文件日志"
], ],
"summary": "链接日志删除", "summary": "文件日志删除",
"parameters": [ "parameters": [
{ {
"description": "链接日志信息", "description": "文件日志信息",
"name": "body", "name": "body",
"in": "body", "in": "body",
"required": true, "required": true,
"schema": { "schema": {
"$ref": "#/definitions/model.AuditConn" "$ref": "#/definitions/model.AuditFile"
} }
} }
], ],
@@ -425,7 +973,7 @@
"token": [] "token": []
} }
], ],
"description": "链接日志列表", "description": "文件日志列表",
"consumes": [ "consumes": [
"application/json" "application/json"
], ],
@@ -433,9 +981,9 @@
"application/json" "application/json"
], ],
"tags": [ "tags": [
"链接日志" "文件日志"
], ],
"summary": "链接日志列表", "summary": "文件日志列表",
"parameters": [ "parameters": [
{ {
"type": "integer", "type": "integer",
@@ -474,7 +1022,7 @@
"type": "object", "type": "object",
"properties": { "properties": {
"data": { "data": {
"$ref": "#/definitions/model.AuditConnList" "$ref": "#/definitions/model.AuditFileList"
} }
} }
} }
@@ -2473,6 +3021,9 @@
"alias": { "alias": {
"type": "string" "type": "string"
}, },
"collection_id": {
"type": "integer"
},
"forceAlwaysRelay": { "forceAlwaysRelay": {
"type": "boolean" "type": "boolean"
}, },
@@ -2559,6 +3110,9 @@
}, },
"name": { "name": {
"type": "string" "type": "string"
},
"type": {
"type": "integer"
} }
} }
}, },
@@ -2691,6 +3245,9 @@
"name" "name"
], ],
"properties": { "properties": {
"collection_id": {
"type": "integer"
},
"color": { "color": {
"type": "integer" "type": "integer"
}, },
@@ -2778,6 +3335,12 @@
"alias": { "alias": {
"type": "string" "type": "string"
}, },
"collection": {
"$ref": "#/definitions/model.AddressBookCollection"
},
"collection_id": {
"type": "integer"
},
"created_at": { "created_at": {
"type": "string" "type": "string"
}, },
@@ -2834,6 +3397,90 @@
} }
} }
}, },
"model.AddressBookCollection": {
"type": "object",
"required": [
"name"
],
"properties": {
"created_at": {
"type": "string"
},
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"updated_at": {
"type": "string"
},
"user_id": {
"type": "integer"
}
}
},
"model.AddressBookCollectionList": {
"type": "object",
"properties": {
"list": {
"type": "array",
"items": {
"$ref": "#/definitions/model.AddressBookCollection"
}
},
"page": {
"type": "integer"
},
"page_size": {
"type": "integer"
},
"total": {
"type": "integer"
}
}
},
"model.AddressBookCollectionRule": {
"type": "object",
"required": [
"collection_id",
"rule",
"to_id",
"type"
],
"properties": {
"collection_id": {
"type": "integer"
},
"created_at": {
"type": "string"
},
"id": {
"type": "integer"
},
"rule": {
"description": "0: 无 1: 读 2: 读写 3: 完全控制",
"type": "integer",
"maximum": 3,
"minimum": 1
},
"to_id": {
"type": "integer"
},
"type": {
"description": "1: 个人 2: 群组",
"type": "integer",
"maximum": 2,
"minimum": 1
},
"updated_at": {
"type": "string"
},
"user_id": {
"type": "integer"
}
}
},
"model.AddressBookList": { "model.AddressBookList": {
"type": "object", "type": "object",
"properties": { "properties": {
@@ -2918,6 +3565,70 @@
} }
} }
}, },
"model.AuditFile": {
"type": "object",
"properties": {
"created_at": {
"type": "string"
},
"from_name": {
"type": "string"
},
"from_peer": {
"type": "string"
},
"id": {
"type": "integer"
},
"info": {
"type": "string"
},
"ip": {
"type": "string"
},
"is_file": {
"type": "boolean"
},
"num": {
"type": "integer"
},
"path": {
"type": "string"
},
"peer_id": {
"type": "string"
},
"type": {
"type": "integer"
},
"updated_at": {
"type": "string"
},
"uuid": {
"type": "string"
}
}
},
"model.AuditFileList": {
"type": "object",
"properties": {
"list": {
"type": "array",
"items": {
"$ref": "#/definitions/model.AuditFile"
}
},
"page": {
"type": "integer"
},
"page_size": {
"type": "integer"
},
"total": {
"type": "integer"
}
}
},
"model.Group": { "model.Group": {
"type": "object", "type": "object",
"properties": { "properties": {
@@ -3147,6 +3858,12 @@
"model.Tag": { "model.Tag": {
"type": "object", "type": "object",
"properties": { "properties": {
"collection": {
"$ref": "#/definitions/model.AddressBookCollection"
},
"collection_id": {
"type": "integer"
},
"color": { "color": {
"description": "color 是flutter的颜色值,从0x00000000 到 0xFFFFFFFF; 前两位表示透明度后面6位表示颜色, 可以转成rgba", "description": "color 是flutter的颜色值,从0x00000000 到 0xFFFFFFFF; 前两位表示透明度后面6位表示颜色, 可以转成rgba",
"type": "integer" "type": "integer"

View File

@@ -16,6 +16,8 @@ definitions:
properties: properties:
alias: alias:
type: string type: string
collection_id:
type: integer
forceAlwaysRelay: forceAlwaysRelay:
type: boolean type: boolean
hash: hash:
@@ -75,6 +77,8 @@ definitions:
type: integer type: integer
name: name:
type: string type: string
type:
type: integer
required: required:
- name - name
type: object type: object
@@ -162,6 +166,8 @@ definitions:
type: object type: object
admin.TagForm: admin.TagForm:
properties: properties:
collection_id:
type: integer
color: color:
type: integer type: integer
id: id:
@@ -223,6 +229,10 @@ definitions:
properties: properties:
alias: alias:
type: string type: string
collection:
$ref: '#/definitions/model.AddressBookCollection'
collection_id:
type: integer
created_at: created_at:
type: string type: string
forceAlwaysRelay: forceAlwaysRelay:
@@ -260,6 +270,64 @@ definitions:
username: username:
type: string type: string
type: object type: object
model.AddressBookCollection:
properties:
created_at:
type: string
id:
type: integer
name:
type: string
updated_at:
type: string
user_id:
type: integer
required:
- name
type: object
model.AddressBookCollectionList:
properties:
list:
items:
$ref: '#/definitions/model.AddressBookCollection'
type: array
page:
type: integer
page_size:
type: integer
total:
type: integer
type: object
model.AddressBookCollectionRule:
properties:
collection_id:
type: integer
created_at:
type: string
id:
type: integer
rule:
description: '0: 无 1: 读 2: 读写 3: 完全控制'
maximum: 3
minimum: 1
type: integer
to_id:
type: integer
type:
description: '1: 个人 2: 群组'
maximum: 2
minimum: 1
type: integer
updated_at:
type: string
user_id:
type: integer
required:
- collection_id
- rule
- to_id
- type
type: object
model.AddressBookList: model.AddressBookList:
properties: properties:
list: list:
@@ -315,6 +383,48 @@ definitions:
total: total:
type: integer type: integer
type: object type: object
model.AuditFile:
properties:
created_at:
type: string
from_name:
type: string
from_peer:
type: string
id:
type: integer
info:
type: string
ip:
type: string
is_file:
type: boolean
num:
type: integer
path:
type: string
peer_id:
type: string
type:
type: integer
updated_at:
type: string
uuid:
type: string
type: object
model.AuditFileList:
properties:
list:
items:
$ref: '#/definitions/model.AuditFile'
type: array
page:
type: integer
page_size:
type: integer
total:
type: integer
type: object
model.Group: model.Group:
properties: properties:
created_at: created_at:
@@ -467,6 +577,10 @@ definitions:
- COMMON_STATUS_DISABLED - COMMON_STATUS_DISABLED
model.Tag: model.Tag:
properties: properties:
collection:
$ref: '#/definitions/model.AddressBookCollection'
collection_id:
type: integer
color: color:
description: color 是flutter的颜色值,从0x00000000 到 0xFFFFFFFF; 前两位表示透明度后面6位表示颜色, description: color 是flutter的颜色值,从0x00000000 到 0xFFFFFFFF; 前两位表示透明度后面6位表示颜色,
可以转成rgba 可以转成rgba
@@ -740,6 +854,328 @@ paths:
summary: 地址簿编辑 summary: 地址簿编辑
tags: tags:
- 地址簿 - 地址簿
/admin/address_book_collection/create:
post:
consumes:
- application/json
description: 创建地址簿集合
parameters:
- description: 地址簿集合信息
in: body
name: body
required: true
schema:
$ref: '#/definitions/model.AddressBookCollection'
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/response.Response'
- properties:
data:
$ref: '#/definitions/model.AddressBookCollection'
type: object
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.Response'
security:
- token: []
summary: 创建地址簿集合
/admin/address_book_collection/delete:
post:
consumes:
- application/json
description: 地址簿集合删除
parameters:
- description: 地址簿集合信息
in: body
name: body
required: true
schema:
$ref: '#/definitions/model.AddressBookCollection'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.Response'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.Response'
security:
- token: []
summary: 地址簿集合删除
/admin/address_book_collection/detail/{id}:
get:
consumes:
- application/json
description: 地址簿集合详情
parameters:
- description: ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/response.Response'
- properties:
data:
$ref: '#/definitions/model.AddressBookCollection'
type: object
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.Response'
security:
- token: []
summary: 地址簿集合详情
/admin/address_book_collection/list:
get:
consumes:
- application/json
description: 地址簿集合列表
parameters:
- description: 页码
in: query
name: page
type: integer
- description: 页大小
in: query
name: page_size
type: integer
- description: 是否是我的
in: query
name: is_my
type: integer
- description: 用户id
in: query
name: user_id
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/response.Response'
- properties:
data:
$ref: '#/definitions/model.AddressBookCollectionList'
type: object
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.Response'
security:
- token: []
summary: 地址簿集合列表
/admin/address_book_collection/update:
post:
consumes:
- application/json
description: 地址簿集合编辑
parameters:
- description: 地址簿集合信息
in: body
name: body
required: true
schema:
$ref: '#/definitions/model.AddressBookCollection'
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/response.Response'
- properties:
data:
$ref: '#/definitions/model.AddressBookCollection'
type: object
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.Response'
security:
- token: []
summary: 地址簿集合编辑
/admin/address_book_collection_rule/create:
post:
consumes:
- application/json
description: 创建地址簿集合规则
parameters:
- description: 地址簿集合规则信息
in: body
name: body
required: true
schema:
$ref: '#/definitions/model.AddressBookCollectionRule'
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/response.Response'
- properties:
data:
$ref: '#/definitions/model.AddressBookCollection'
type: object
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.Response'
security:
- token: []
summary: 创建地址簿集合规则
/admin/address_book_collection_rule/delete:
post:
consumes:
- application/json
description: 地址簿集合规则删除
parameters:
- description: 地址簿集合规则信息
in: body
name: body
required: true
schema:
$ref: '#/definitions/model.AddressBookCollectionRule'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.Response'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.Response'
security:
- token: []
summary: 地址簿集合规则删除
/admin/address_book_collection_rule/detail/{id}:
get:
consumes:
- application/json
description: 地址簿集合规则详情
parameters:
- description: ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/response.Response'
- properties:
data:
$ref: '#/definitions/model.AddressBookCollectionRule'
type: object
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.Response'
security:
- token: []
summary: 地址簿集合规则详情
/admin/address_book_collection_rule/list:
get:
consumes:
- application/json
description: 地址簿集合规则列表
parameters:
- description: 页码
in: query
name: page
type: integer
- description: 页大小
in: query
name: page_size
type: integer
- description: 是否是我的
in: query
name: is_my
type: integer
- description: 用户id
in: query
name: user_id
type: integer
- description: 地址簿集合id
in: query
name: collection_id
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/response.Response'
- properties:
data:
$ref: '#/definitions/model.AddressBookCollectionList'
type: object
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.Response'
security:
- token: []
summary: 地址簿集合规则列表
/admin/address_book_collection_rule/update:
post:
consumes:
- application/json
description: 地址簿集合规则编辑
parameters:
- description: 地址簿集合规则信息
in: body
name: body
required: true
schema:
$ref: '#/definitions/model.AddressBookCollectionRule'
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/response.Response'
- properties:
data:
$ref: '#/definitions/model.AddressBookCollection'
type: object
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.Response'
security:
- token: []
summary: 地址簿集合规则编辑
/admin/app-config: /admin/app-config:
get: get:
consumes: consumes:
@@ -765,14 +1201,14 @@ paths:
post: post:
consumes: consumes:
- application/json - application/json
description: 链接日志删除 description: 文件日志删除
parameters: parameters:
- description: 链接日志信息 - description: 文件日志信息
in: body in: body
name: body name: body
required: true required: true
schema: schema:
$ref: '#/definitions/model.AuditConn' $ref: '#/definitions/model.AuditFile'
produces: produces:
- application/json - application/json
responses: responses:
@@ -786,14 +1222,14 @@ paths:
$ref: '#/definitions/response.Response' $ref: '#/definitions/response.Response'
security: security:
- token: [] - token: []
summary: 链接日志删除 summary: 文件日志删除
tags: tags:
- 链接日志 - 文件日志
/admin/audit_conn/list: /admin/audit_conn/list:
get: get:
consumes: consumes:
- application/json - application/json
description: 链接日志列表 description: 文件日志列表
parameters: parameters:
- description: 页码 - description: 页码
in: query in: query
@@ -821,7 +1257,7 @@ paths:
- $ref: '#/definitions/response.Response' - $ref: '#/definitions/response.Response'
- properties: - properties:
data: data:
$ref: '#/definitions/model.AuditConnList' $ref: '#/definitions/model.AuditFileList'
type: object type: object
"500": "500":
description: Internal Server Error description: Internal Server Error
@@ -829,9 +1265,9 @@ paths:
$ref: '#/definitions/response.Response' $ref: '#/definitions/response.Response'
security: security:
- token: [] - token: []
summary: 链接日志列表 summary: 文件日志列表
tags: tags:
- 链接日志 - 文件日志
/admin/file/oss_token: /admin/file/oss_token:
get: get:
consumes: consumes:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 51 KiB

View File

@@ -727,6 +727,46 @@ const docTemplateapi = `{
} }
} }
}, },
"/audit/file": {
"post": {
"description": "审计文件",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"审计"
],
"summary": "审计文件",
"parameters": [
{
"description": "审计文件",
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/api.AuditFileForm"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "string"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/heartbeat": { "/heartbeat": {
"post": { "post": {
"description": "心跳", "description": "心跳",
@@ -1259,6 +1299,32 @@ const docTemplateapi = `{
} }
} }
}, },
"api.AuditFileForm": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"info": {
"type": "string"
},
"is_file": {
"type": "boolean"
},
"path": {
"type": "string"
},
"peer_id": {
"type": "string"
},
"type": {
"type": "integer"
},
"uuid": {
"type": "string"
}
}
},
"api.DeviceInfoInLogin": { "api.DeviceInfoInLogin": {
"type": "object", "type": "object",
"properties": { "properties": {
@@ -1379,9 +1445,38 @@ const docTemplateapi = `{
} }
} }
}, },
"model.AddressBookCollection": {
"type": "object",
"required": [
"name"
],
"properties": {
"created_at": {
"type": "string"
},
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"updated_at": {
"type": "string"
},
"user_id": {
"type": "integer"
}
}
},
"model.Tag": { "model.Tag": {
"type": "object", "type": "object",
"properties": { "properties": {
"collection": {
"$ref": "#/definitions/model.AddressBookCollection"
},
"collection_id": {
"type": "integer"
},
"color": { "color": {
"description": "color 是flutter的颜色值,从0x00000000 到 0xFFFFFFFF; 前两位表示透明度后面6位表示颜色, 可以转成rgba", "description": "color 是flutter的颜色值,从0x00000000 到 0xFFFFFFFF; 前两位表示透明度后面6位表示颜色, 可以转成rgba",
"type": "integer" "type": "integer"

View File

@@ -720,6 +720,46 @@
} }
} }
}, },
"/audit/file": {
"post": {
"description": "审计文件",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"审计"
],
"summary": "审计文件",
"parameters": [
{
"description": "审计文件",
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/api.AuditFileForm"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "string"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/heartbeat": { "/heartbeat": {
"post": { "post": {
"description": "心跳", "description": "心跳",
@@ -1252,6 +1292,32 @@
} }
} }
}, },
"api.AuditFileForm": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"info": {
"type": "string"
},
"is_file": {
"type": "boolean"
},
"path": {
"type": "string"
},
"peer_id": {
"type": "string"
},
"type": {
"type": "integer"
},
"uuid": {
"type": "string"
}
}
},
"api.DeviceInfoInLogin": { "api.DeviceInfoInLogin": {
"type": "object", "type": "object",
"properties": { "properties": {
@@ -1372,9 +1438,38 @@
} }
} }
}, },
"model.AddressBookCollection": {
"type": "object",
"required": [
"name"
],
"properties": {
"created_at": {
"type": "string"
},
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"updated_at": {
"type": "string"
},
"user_id": {
"type": "integer"
}
}
},
"model.Tag": { "model.Tag": {
"type": "object", "type": "object",
"properties": { "properties": {
"collection": {
"$ref": "#/definitions/model.AddressBookCollection"
},
"collection_id": {
"type": "integer"
},
"color": { "color": {
"description": "color 是flutter的颜色值,从0x00000000 到 0xFFFFFFFF; 前两位表示透明度后面6位表示颜色, 可以转成rgba", "description": "color 是flutter的颜色值,从0x00000000 到 0xFFFFFFFF; 前两位表示透明度后面6位表示颜色, 可以转成rgba",
"type": "integer" "type": "integer"

View File

@@ -27,6 +27,23 @@ definitions:
uuid: uuid:
type: string type: string
type: object type: object
api.AuditFileForm:
properties:
id:
type: string
info:
type: string
is_file:
type: boolean
path:
type: string
peer_id:
type: string
type:
type: integer
uuid:
type: string
type: object
api.DeviceInfoInLogin: api.DeviceInfoInLogin:
properties: properties:
name: name:
@@ -107,8 +124,27 @@ definitions:
status: status:
type: integer type: integer
type: object type: object
model.AddressBookCollection:
properties:
created_at:
type: string
id:
type: integer
name:
type: string
updated_at:
type: string
user_id:
type: integer
required:
- name
type: object
model.Tag: model.Tag:
properties: properties:
collection:
$ref: '#/definitions/model.AddressBookCollection'
collection_id:
type: integer
color: color:
description: color 是flutter的颜色值,从0x00000000 到 0xFFFFFFFF; 前两位表示透明度后面6位表示颜色, description: color 是flutter的颜色值,从0x00000000 到 0xFFFFFFFF; 前两位表示透明度后面6位表示颜色,
可以转成rgba 可以转成rgba
@@ -609,6 +645,32 @@ paths:
summary: 审计连接 summary: 审计连接
tags: tags:
- 审计 - 审计
/audit/file:
post:
consumes:
- application/json
description: 审计文件
parameters:
- description: 审计文件
in: body
name: body
required: true
schema:
$ref: '#/definitions/api.AuditFileForm'
produces:
- application/json
responses:
"200":
description: OK
schema:
type: string
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.Response'
summary: 审计文件
tags:
- 审计
/heartbeat: /heartbeat:
post: post:
consumes: consumes:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

124
global/apiValidator.go Normal file
View File

@@ -0,0 +1,124 @@
package global
import (
"github.com/gin-gonic/gin"
"github.com/go-playground/locales/en"
"github.com/go-playground/locales/ko"
"github.com/go-playground/locales/ru"
"github.com/go-playground/locales/zh_Hans_CN"
ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
en_translations "github.com/go-playground/validator/v10/translations/en"
ru_translations "github.com/go-playground/validator/v10/translations/ru"
zh_translations "github.com/go-playground/validator/v10/translations/zh"
"reflect"
)
func ApiInitValidator() {
validate := validator.New()
// 定义不同的语言翻译
enT := en.New()
cn := zh_Hans_CN.New()
koT := ko.New()
ruT := ru.New()
uni := ut.New(enT, cn, koT, ruT)
enTrans, _ := uni.GetTranslator("en")
zhTrans, _ := uni.GetTranslator("zh_Hans_CN")
koTrans, _ := uni.GetTranslator("ko")
ruTrans, _ := uni.GetTranslator("ru")
err := zh_translations.RegisterDefaultTranslations(validate, zhTrans)
if err != nil {
panic(err)
}
err = en_translations.RegisterDefaultTranslations(validate, enTrans)
if err != nil {
panic(err)
}
//validate没有ko的翻译使用zh的翻译
err = zh_translations.RegisterDefaultTranslations(validate, koTrans)
if err != nil {
panic(err)
}
err = ru_translations.RegisterDefaultTranslations(validate, ruTrans)
if err != nil {
panic(err)
}
validate.RegisterTagNameFunc(func(field reflect.StructField) string {
label := field.Tag.Get("label")
if label == "" {
return field.Name
}
return label
})
Validator.Validate = validate
Validator.UT = uni // 存储 Universal Translator
Validator.VTrans = zhTrans
Validator.ValidStruct = func(ctx *gin.Context, i interface{}) []string {
err := Validator.Validate.Struct(i)
lang := ctx.GetHeader("Accept-Language")
if lang == "" {
lang = Config.Lang
}
trans := getTranslatorForLang(lang)
errList := make([]string, 0, 10)
if err != nil {
if _, ok := err.(*validator.InvalidValidationError); ok {
errList = append(errList, err.Error())
return errList
}
for _, err2 := range err.(validator.ValidationErrors) {
errList = append(errList, err2.Translate(trans))
}
}
return errList
}
Validator.ValidVar = func(ctx *gin.Context, field interface{}, tag string) []string {
err := Validator.Validate.Var(field, tag)
lang := ctx.GetHeader("Accept-Language")
if lang == "" {
lang = Config.Lang
}
trans := getTranslatorForLang(lang)
errList := make([]string, 0, 10)
if err != nil {
if _, ok := err.(*validator.InvalidValidationError); ok {
errList = append(errList, err.Error())
return errList
}
for _, err2 := range err.(validator.ValidationErrors) {
errList = append(errList, err2.Translate(trans))
}
}
return errList
}
}
func getTranslatorForLang(lang string) ut.Translator {
switch lang {
case "zh_CN":
fallthrough
case "zh-CN":
fallthrough
case "zh":
trans, _ := Validator.UT.GetTranslator("zh_Hans_CN")
return trans
case "ko":
trans, _ := Validator.UT.GetTranslator("ko")
return trans
case "ru":
trans, _ := Validator.UT.GetTranslator("ru")
return trans
case "en":
fallthrough
default:
trans, _ := Validator.UT.GetTranslator("en")
return trans
}
}

View File

@@ -33,5 +33,5 @@ var (
Oss *upload.Oss Oss *upload.Oss
Jwt *jwt.Jwt Jwt *jwt.Jwt
Lock lock.Locker Lock lock.Locker
Localizer func(ctx *gin.Context) *i18n.Localizer Localizer func(lang string) *i18n.Localizer
) )

53
global/i18n.go Normal file
View File

@@ -0,0 +1,53 @@
package global
import (
"github.com/BurntSushi/toml"
"github.com/nicksnyder/go-i18n/v2/i18n"
"golang.org/x/text/language"
"os"
)
func InitI18n() {
bundle := i18n.NewBundle(language.English)
bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal)
//读取global.Config.Gin.ResourcesPath下的所有语言文件
dir := Config.Gin.ResourcesPath + "/i18n"
fileInfos, err := os.ReadDir(dir)
if err != nil {
panic(err)
return
}
for _, fileInfo := range fileInfos {
//如果文件名不是.toml结尾
if fileInfo.IsDir() || fileInfo.Name()[len(fileInfo.Name())-5:] != ".toml" {
continue
}
bundle.LoadMessageFile(Config.Gin.ResourcesPath + "/i18n/" + fileInfo.Name())
}
Localizer = func(lang string) *i18n.Localizer {
if lang == "" {
lang = Config.Lang
}
if lang == "en" {
return i18n.NewLocalizer(bundle, "en")
} else {
return i18n.NewLocalizer(bundle, lang, "en")
}
}
//personUnreadEmails := localizer.MustLocalize(&i18n.LocalizeConfig{
// DefaultMessage: &i18n.Message{
// ID: "PersonUnreadEmails",
// },
// PluralCount: 6,
// TemplateData: map[string]interface{}{
// "Name": "LE",
// "PluralCount": 6,
// },
//})
//personUnreadEmails, err := global.Localizer.LocalizeMessage(&i18n.Message{
// ID: "ParamsError",
//})
//fmt.Println(err, personUnreadEmails)
}

View File

@@ -70,9 +70,14 @@ func (ct *AddressBook) Create(c *gin.Context) {
if !service.AllService.UserService.IsAdmin(u) || t.UserId == 0 { if !service.AllService.UserService.IsAdmin(u) || t.UserId == 0 {
t.UserId = u.Id t.UserId = u.Id
} }
ex := service.AllService.AddressBookService.InfoByUserIdAndId(t.UserId, t.Id) if t.CollectionId > 0 && !service.AllService.AddressBookService.CheckCollectionOwner(t.UserId, t.CollectionId) {
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
return
}
ex := service.AllService.AddressBookService.InfoByUserIdAndIdAndCid(t.UserId, t.Id, t.CollectionId)
if ex.RowId > 0 { if ex.RowId > 0 {
response.Fail(c, 101, response.TranslateMsg(c, "ItemExist")) response.Fail(c, 101, response.TranslateMsg(c, "ItemExists"))
return return
} }
@@ -81,7 +86,7 @@ func (ct *AddressBook) Create(c *gin.Context) {
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error()) response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
return return
} }
response.Success(c, u) response.Success(c, nil)
} }
// BatchCreate 批量创建地址簿 // BatchCreate 批量创建地址簿
@@ -113,7 +118,7 @@ func (ct *AddressBook) BatchCreate(c *gin.Context) {
continue continue
} }
for _, ft := range f.Tags { for _, ft := range f.Tags {
exTag := service.AllService.TagService.InfoByUserIdAndName(fu, ft) exTag := service.AllService.TagService.InfoByUserIdAndNameAndCollectionId(fu, ft, 0)
if exTag.Id == 0 { if exTag.Id == 0 {
service.AllService.TagService.Create(&model.Tag{ service.AllService.TagService.Create(&model.Tag{
UserId: fu, UserId: fu,
@@ -161,6 +166,9 @@ func (ct *AddressBook) List(c *gin.Context) {
query.UserId = int(u.Id) query.UserId = int(u.Id)
} }
res := service.AllService.AddressBookService.List(query.Page, query.PageSize, func(tx *gorm.DB) { res := service.AllService.AddressBookService.List(query.Page, query.PageSize, func(tx *gorm.DB) {
tx.Preload("Collection", func(txc *gorm.DB) *gorm.DB {
return txc.Select("id,name")
})
if query.Id != "" { if query.Id != "" {
tx.Where("id like ?", "%"+query.Id+"%") tx.Where("id like ?", "%"+query.Id+"%")
} }
@@ -173,7 +181,20 @@ func (ct *AddressBook) List(c *gin.Context) {
if query.Hostname != "" { if query.Hostname != "" {
tx.Where("hostname like ?", "%"+query.Hostname+"%") tx.Where("hostname like ?", "%"+query.Hostname+"%")
} }
if query.CollectionId != nil && *query.CollectionId >= 0 {
tx.Where("collection_id = ?", query.CollectionId)
}
}) })
abCIds := make([]uint, 0)
for _, ab := range res.AddressBooks {
abCIds = append(abCIds, ab.CollectionId)
}
//获取地址簿名称
//cRes := service.AllService.AddressBookService.ListCollection(1, 999, func(tx *gorm.DB) {
// tx.Where("id in ?", abCIds)
//})
//
response.Success(c, res) response.Success(c, res)
} }
@@ -209,6 +230,10 @@ func (ct *AddressBook) Update(c *gin.Context) {
response.Fail(c, 101, response.TranslateMsg(c, "NoAccess")) response.Fail(c, 101, response.TranslateMsg(c, "NoAccess"))
return return
} }
if t.CollectionId > 0 && !service.AllService.AddressBookService.CheckCollectionOwner(t.UserId, t.CollectionId) {
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
return
}
err := service.AllService.AddressBookService.Update(t) err := service.AllService.AddressBookService.Update(t)
if err != nil { if err != nil {
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error()) response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
@@ -241,6 +266,10 @@ func (ct *AddressBook) Delete(c *gin.Context) {
return return
} }
t := service.AllService.AddressBookService.InfoByRowId(f.RowId) t := service.AllService.AddressBookService.InfoByRowId(f.RowId)
if t.RowId == 0 {
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
return
}
u := service.AllService.UserService.CurUser(c) u := service.AllService.UserService.CurUser(c)
if !service.AllService.UserService.IsAdmin(u) && t.UserId != u.Id { if !service.AllService.UserService.IsAdmin(u) && t.UserId != u.Id {
response.Fail(c, 101, response.TranslateMsg(c, "NoAccess")) response.Fail(c, 101, response.TranslateMsg(c, "NoAccess"))

View File

@@ -0,0 +1,192 @@
package admin
import (
"Gwen/global"
"Gwen/http/request/admin"
"Gwen/http/response"
"Gwen/model"
"Gwen/service"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
"strconv"
)
type AddressBookCollection struct {
}
// Detail 地址簿集合
// @AddressBookCollections 地址簿集合
// @Summary 地址簿集合详情
// @Description 地址簿集合详情
// @Accept json
// @Produce json
// @Param id path int true "ID"
// @Success 200 {object} response.Response{data=model.AddressBookCollection}
// @Failure 500 {object} response.Response
// @Router /admin/address_book_collection/detail/{id} [get]
// @Security token
func (abc *AddressBookCollection) Detail(c *gin.Context) {
id := c.Param("id")
iid, _ := strconv.Atoi(id)
t := service.AllService.AddressBookService.CollectionInfoById(uint(iid))
u := service.AllService.UserService.CurUser(c)
if !service.AllService.UserService.IsAdmin(u) && t.UserId != u.Id {
response.Fail(c, 101, response.TranslateMsg(c, "NoAccess"))
return
}
if t.Id > 0 {
response.Success(c, t)
return
}
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
return
}
// Create 创建地址簿集合
// @AddressBookCollections 地址簿集合
// @Summary 创建地址簿集合
// @Description 创建地址簿集合
// @Accept json
// @Produce json
// @Param body body model.AddressBookCollection true "地址簿集合信息"
// @Success 200 {object} response.Response{data=model.AddressBookCollection}
// @Failure 500 {object} response.Response
// @Router /admin/address_book_collection/create [post]
// @Security token
func (abc *AddressBookCollection) Create(c *gin.Context) {
f := &model.AddressBookCollection{}
if err := c.ShouldBindJSON(f); err != nil {
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
return
}
errList := global.Validator.ValidStruct(c, f)
if len(errList) > 0 {
response.Fail(c, 101, errList[0])
return
}
//t := f.ToAddressBookCollection()
t := f
u := service.AllService.UserService.CurUser(c)
if !service.AllService.UserService.IsAdmin(u) || t.UserId == 0 {
t.UserId = u.Id
}
err := service.AllService.AddressBookService.CreateCollection(t)
if err != nil {
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
return
}
response.Success(c, nil)
}
// List 列表
// @AddressBookCollections 地址簿集合
// @Summary 地址簿集合列表
// @Description 地址簿集合列表
// @Accept json
// @Produce json
// @Param page query int false "页码"
// @Param page_size query int false "页大小"
// @Param is_my query int false "是否是我的"
// @Param user_id query int false "用户id"
// @Success 200 {object} response.Response{data=model.AddressBookCollectionList}
// @Failure 500 {object} response.Response
// @Router /admin/address_book_collection/list [get]
// @Security token
func (abc *AddressBookCollection) List(c *gin.Context) {
query := &admin.AddressBookCollectionQuery{}
if err := c.ShouldBindQuery(query); err != nil {
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
return
}
u := service.AllService.UserService.CurUser(c)
if !service.AllService.UserService.IsAdmin(u) || query.IsMy == 1 {
query.UserId = int(u.Id)
}
res := service.AllService.AddressBookService.ListCollection(query.Page, query.PageSize, func(tx *gorm.DB) {
if query.UserId > 0 {
tx.Where("user_id = ?", query.UserId)
}
})
response.Success(c, res)
}
// Update 编辑
// @AddressBookCollections 地址簿集合
// @Summary 地址簿集合编辑
// @Description 地址簿集合编辑
// @Accept json
// @Produce json
// @Param body body model.AddressBookCollection true "地址簿集合信息"
// @Success 200 {object} response.Response{data=model.AddressBookCollection}
// @Failure 500 {object} response.Response
// @Router /admin/address_book_collection/update [post]
// @Security token
func (abc *AddressBookCollection) Update(c *gin.Context) {
f := &model.AddressBookCollection{}
if err := c.ShouldBindJSON(f); err != nil {
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
return
}
errList := global.Validator.ValidStruct(c, f)
if len(errList) > 0 {
response.Fail(c, 101, errList[0])
return
}
if f.Id == 0 {
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
return
}
t := f //f.ToAddressBookCollection()
u := service.AllService.UserService.CurUser(c)
if !service.AllService.UserService.IsAdmin(u) && t.UserId != u.Id {
response.Fail(c, 101, response.TranslateMsg(c, "NoAccess"))
return
}
err := service.AllService.AddressBookService.UpdateCollection(t)
if err != nil {
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
return
}
response.Success(c, nil)
}
// Delete 删除
// @AddressBookCollections 地址簿集合
// @Summary 地址簿集合删除
// @Description 地址簿集合删除
// @Accept json
// @Produce json
// @Param body body model.AddressBookCollection true "地址簿集合信息"
// @Success 200 {object} response.Response
// @Failure 500 {object} response.Response
// @Router /admin/address_book_collection/delete [post]
// @Security token
func (abc *AddressBookCollection) Delete(c *gin.Context) {
f := &model.AddressBookCollection{}
if err := c.ShouldBindJSON(f); err != nil {
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
return
}
id := f.Id
errList := global.Validator.ValidVar(c, id, "required,gt=0")
if len(errList) > 0 {
response.Fail(c, 101, errList[0])
return
}
t := service.AllService.AddressBookService.CollectionInfoById(f.Id)
u := service.AllService.UserService.CurUser(c)
if !service.AllService.UserService.IsAdmin(u) && t.UserId != u.Id {
response.Fail(c, 101, response.TranslateMsg(c, "NoAccess"))
return
}
if u.Id > 0 {
err := service.AllService.AddressBookService.DeleteCollection(t)
if err == nil {
response.Success(c, nil)
return
}
response.Fail(c, 101, err.Error())
return
}
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
}

View File

@@ -0,0 +1,251 @@
package admin
import (
"Gwen/global"
"Gwen/http/request/admin"
"Gwen/http/response"
"Gwen/model"
"Gwen/service"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
"strconv"
)
type AddressBookCollectionRule struct {
}
// List 列表
// @AddressBookCollectionRule 地址簿集合规则
// @Summary 地址簿集合规则列表
// @Description 地址簿集合规则列表
// @Accept json
// @Produce json
// @Param page query int false "页码"
// @Param page_size query int false "页大小"
// @Param is_my query int false "是否是我的"
// @Param user_id query int false "用户id"
// @Param collection_id query int false "地址簿集合id"
// @Success 200 {object} response.Response{data=model.AddressBookCollectionList}
// @Failure 500 {object} response.Response
// @Router /admin/address_book_collection_rule/list [get]
// @Security token
func (abcr *AddressBookCollectionRule) List(c *gin.Context) {
query := &admin.AddressBookCollectionRuleQuery{}
if err := c.ShouldBindQuery(query); err != nil {
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
return
}
u := service.AllService.UserService.CurUser(c)
if !service.AllService.UserService.IsAdmin(u) || query.IsMy == 1 {
query.UserId = int(u.Id)
}
res := service.AllService.AddressBookService.ListRules(query.Page, query.PageSize, func(tx *gorm.DB) {
if query.UserId > 0 {
tx.Where("user_id = ?", query.UserId)
}
if query.CollectionId > 0 {
tx.Where("collection_id = ?", query.CollectionId)
}
})
response.Success(c, res)
}
// Detail 地址簿集合规则
// @AddressBookCollectionRule 地址簿集合规则
// @Summary 地址簿集合规则详情
// @Description 地址簿集合规则详情
// @Accept json
// @Produce json
// @Param id path int true "ID"
// @Success 200 {object} response.Response{data=model.AddressBookCollectionRule}
// @Failure 500 {object} response.Response
// @Router /admin/address_book_collection_rule/detail/{id} [get]
// @Security token
func (abcr *AddressBookCollectionRule) Detail(c *gin.Context) {
id := c.Param("id")
iid, _ := strconv.Atoi(id)
t := service.AllService.AddressBookService.RuleInfoById(uint(iid))
u := service.AllService.UserService.CurUser(c)
if !service.AllService.UserService.IsAdmin(u) && t.UserId != u.Id {
response.Fail(c, 101, response.TranslateMsg(c, "NoAccess"))
return
}
if t.Id > 0 {
response.Success(c, t)
return
}
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
return
}
// Create 创建地址簿集合规则
// @AddressBookCollectionRule 地址簿集合规则
// @Summary 创建地址簿集合规则
// @Description 创建地址簿集合规则
// @Accept json
// @Produce json
// @Param body body model.AddressBookCollectionRule true "地址簿集合规则信息"
// @Success 200 {object} response.Response{data=model.AddressBookCollection}
// @Failure 500 {object} response.Response
// @Router /admin/address_book_collection_rule/create [post]
// @Security token
func (abcr *AddressBookCollectionRule) Create(c *gin.Context) {
f := &model.AddressBookCollectionRule{}
if err := c.ShouldBindJSON(f); err != nil {
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
return
}
errList := global.Validator.ValidStruct(c, f)
if len(errList) > 0 {
response.Fail(c, 101, errList[0])
return
}
if f.Type != model.ShareAddressBookRuleTypePersonal && f.Type != model.ShareAddressBookRuleTypeGroup {
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
return
}
//t := f.ToAddressBookCollection()
t := f
u := service.AllService.UserService.CurUser(c)
if t.UserId == 0 {
t.UserId = u.Id
}
msg, res := abcr.CheckForm(u, t)
if !res {
response.Fail(c, 101, response.TranslateMsg(c, msg))
return
}
err := service.AllService.AddressBookService.CreateRule(t)
if err != nil {
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
return
}
response.Success(c, nil)
}
func (abcr *AddressBookCollectionRule) CheckForm(u *model.User, t *model.AddressBookCollectionRule) (string, bool) {
if !service.AllService.UserService.IsAdmin(u) && t.UserId != u.Id {
return "NoAccess", false
}
if t.CollectionId > 0 && !service.AllService.AddressBookService.CheckCollectionOwner(t.UserId, t.CollectionId) {
return "ParamsError", false
}
//check to_id
if t.Type == model.ShareAddressBookRuleTypePersonal {
if t.ToId == t.UserId {
return "ParamsError", false
}
tou := service.AllService.UserService.InfoById(t.ToId)
if tou.Id == 0 {
return "ItemNotFound", false
}
//非管理员不能分享给非本组织用户
if tou.GroupId != u.GroupId && !service.AllService.UserService.IsAdmin(u) {
return "NoAccess", false
}
} else if t.Type == model.ShareAddressBookRuleTypeGroup {
if t.ToId != u.GroupId && !service.AllService.UserService.IsAdmin(u) {
return "NoAccess", false
}
tog := service.AllService.GroupService.InfoById(t.ToId)
if tog.Id == 0 {
return "ItemNotFound", false
}
} else {
return "ParamsError", false
}
// 重复检查
ex := service.AllService.AddressBookService.RulePersonalInfoByToIdAndCid(t.ToId, t.CollectionId)
if t.Id == 0 && ex.Id > 0 {
return "ItemExists", false
}
if t.Id > 0 && ex.Id > 0 && t.Id != ex.Id {
return "ItemExists", false
}
return "", true
}
// Update 编辑
// @AddressBookCollectionRule 地址簿集合规则
// @Summary 地址簿集合规则编辑
// @Description 地址簿集合规则编辑
// @Accept json
// @Produce json
// @Param body body model.AddressBookCollectionRule true "地址簿集合规则信息"
// @Success 200 {object} response.Response{data=model.AddressBookCollection}
// @Failure 500 {object} response.Response
// @Router /admin/address_book_collection_rule/update [post]
// @Security token
func (abcr *AddressBookCollectionRule) Update(c *gin.Context) {
f := &model.AddressBookCollectionRule{}
if err := c.ShouldBindJSON(f); err != nil {
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
return
}
errList := global.Validator.ValidStruct(c, f)
if len(errList) > 0 {
response.Fail(c, 101, errList[0])
return
}
if f.Id == 0 {
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
return
}
t := f //f.ToAddressBookCollection()
u := service.AllService.UserService.CurUser(c)
msg, res := abcr.CheckForm(u, t)
if !res {
response.Fail(c, 101, response.TranslateMsg(c, msg))
return
}
err := service.AllService.AddressBookService.UpdateRule(t)
if err != nil {
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
return
}
response.Success(c, nil)
}
// Delete 删除
// @AddressBookCollectionRule 地址簿集合规则
// @Summary 地址簿集合规则删除
// @Description 地址簿集合规则删除
// @Accept json
// @Produce json
// @Param body body model.AddressBookCollectionRule true "地址簿集合规则信息"
// @Success 200 {object} response.Response
// @Failure 500 {object} response.Response
// @Router /admin/address_book_collection_rule/delete [post]
// @Security token
func (abcr *AddressBookCollectionRule) Delete(c *gin.Context) {
f := &model.AddressBookCollectionRule{}
if err := c.ShouldBindJSON(f); err != nil {
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
return
}
id := f.Id
errList := global.Validator.ValidVar(c, id, "required,gt=0")
if len(errList) > 0 {
response.Fail(c, 101, errList[0])
return
}
t := service.AllService.AddressBookService.RuleInfoById(f.Id)
u := service.AllService.UserService.CurUser(c)
if !service.AllService.UserService.IsAdmin(u) && t.UserId != u.Id {
response.Fail(c, 101, response.TranslateMsg(c, "NoAccess"))
return
}
if t.Id > 0 {
err := service.AllService.AddressBookService.DeleteRule(t)
if err == nil {
response.Success(c, nil)
return
}
response.Fail(c, 101, err.Error())
return
}
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
}

View File

@@ -40,6 +40,7 @@ func (a *Audit) ConnList(c *gin.Context) {
if query.FromPeer != "" { if query.FromPeer != "" {
tx.Where("from_peer like ?", "%"+query.FromPeer+"%") tx.Where("from_peer like ?", "%"+query.FromPeer+"%")
} }
tx.Order("id desc")
}) })
response.Success(c, res) response.Success(c, res)
} }
@@ -67,7 +68,7 @@ func (a *Audit) ConnDelete(c *gin.Context) {
response.Fail(c, 101, errList[0]) response.Fail(c, 101, errList[0])
return return
} }
l := service.AllService.AuditService.InfoById(f.Id) l := service.AllService.AuditService.ConnInfoById(f.Id)
if l.Id > 0 { if l.Id > 0 {
err := service.AllService.AuditService.DeleteAuditConn(l) err := service.AllService.AuditService.DeleteAuditConn(l)
if err == nil { if err == nil {
@@ -79,3 +80,71 @@ func (a *Audit) ConnDelete(c *gin.Context) {
} }
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound")) response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
} }
// FileList 列表
// @Tags 文件日志
// @Summary 文件日志列表
// @Description 文件日志列表
// @Accept json
// @Produce json
// @Param page query int false "页码"
// @Param page_size query int false "页大小"
// @Param peer_id query int false "目标设备"
// @Param from_peer query int false "来源设备"
// @Success 200 {object} response.Response{data=model.AuditFileList}
// @Failure 500 {object} response.Response
// @Router /admin/audit_conn/list [get]
// @Security token
func (a *Audit) FileList(c *gin.Context) {
query := &admin.AuditQuery{}
if err := c.ShouldBindQuery(query); err != nil {
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
return
}
res := service.AllService.AuditService.AuditFileList(query.Page, query.PageSize, func(tx *gorm.DB) {
if query.PeerId != "" {
tx.Where("peer_id like ?", "%"+query.PeerId+"%")
}
if query.FromPeer != "" {
tx.Where("from_peer like ?", "%"+query.FromPeer+"%")
}
tx.Order("id desc")
})
response.Success(c, res)
}
// FileDelete 删除
// @Tags 文件日志
// @Summary 文件日志删除
// @Description 文件日志删除
// @Accept json
// @Produce json
// @Param body body model.AuditFile true "文件日志信息"
// @Success 200 {object} response.Response
// @Failure 500 {object} response.Response
// @Router /admin/audit_conn/delete [post]
// @Security token
func (a *Audit) FileDelete(c *gin.Context) {
f := &model.AuditFile{}
if err := c.ShouldBindJSON(f); err != nil {
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
return
}
id := f.Id
errList := global.Validator.ValidVar(c, id, "required,gt=0")
if len(errList) > 0 {
response.Fail(c, 101, errList[0])
return
}
l := service.AllService.AuditService.FileInfoById(f.Id)
if l.Id > 0 {
err := service.AllService.AuditService.DeleteAuditFile(l)
if err == nil {
response.Success(c, nil)
return
}
response.Fail(c, 101, err.Error())
return
}
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
}

View File

@@ -63,7 +63,7 @@ func (ct *Group) Create(c *gin.Context) {
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error()) response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
return return
} }
response.Success(c, u) response.Success(c, nil)
} }
// List 列表 // List 列表

View File

@@ -64,6 +64,7 @@ func (ct *LoginLog) List(c *gin.Context) {
if query.UserId > 0 { if query.UserId > 0 {
tx.Where("user_id = ?", query.UserId) tx.Where("user_id = ?", query.UserId)
} }
tx.Order("id desc")
}) })
response.Success(c, res) response.Success(c, res)
} }

View File

@@ -202,7 +202,7 @@ func (o *Oauth) Create(c *gin.Context) {
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error()) response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
return return
} }
response.Success(c, u) response.Success(c, nil)
} }
// List 列表 // List 列表

View File

@@ -59,13 +59,13 @@ func (ct *Peer) Create(c *gin.Context) {
response.Fail(c, 101, errList[0]) response.Fail(c, 101, errList[0])
return return
} }
u := f.ToPeer() p := f.ToPeer()
err := service.AllService.PeerService.Create(u) err := service.AllService.PeerService.Create(p)
if err != nil { if err != nil {
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error()) response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
return return
} }
response.Success(c, u) response.Success(c, nil)
} }
// List 列表 // List 列表

View File

@@ -73,7 +73,7 @@ func (ct *Tag) Create(c *gin.Context) {
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error()) response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
return return
} }
response.Success(c, u) response.Success(c, nil)
} }
// List 列表 // List 列表
@@ -101,9 +101,15 @@ func (ct *Tag) List(c *gin.Context) {
query.UserId = int(u.Id) query.UserId = int(u.Id)
} }
res := service.AllService.TagService.List(query.Page, query.PageSize, func(tx *gorm.DB) { res := service.AllService.TagService.List(query.Page, query.PageSize, func(tx *gorm.DB) {
tx.Preload("Collection", func(txc *gorm.DB) *gorm.DB {
return txc.Select("id,name")
})
if query.UserId > 0 { if query.UserId > 0 {
tx.Where("user_id = ?", query.UserId) tx.Where("user_id = ?", query.UserId)
} }
if query.CollectionId != nil && *query.CollectionId >= 0 {
tx.Where("collection_id = ?", query.CollectionId)
}
}) })
response.Success(c, res) response.Success(c, res)
} }

View File

@@ -65,7 +65,7 @@ func (ct *User) Create(c *gin.Context) {
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error()) response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
return return
} }
response.Success(c, u) response.Success(c, nil)
} }
// List 列表 // List 列表
@@ -293,3 +293,33 @@ func (ct *User) MyOauth(c *gin.Context) {
} }
response.Success(c, res) response.Success(c, res)
} }
// groupUsers
func (ct *User) GroupUsers(c *gin.Context) {
q := &admin.GroupUsersQuery{}
if err := c.ShouldBindJSON(q); err != nil {
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
return
}
u := service.AllService.UserService.CurUser(c)
gid := u.GroupId
uid := u.Id
if service.AllService.UserService.IsAdmin(u) && q.UserId > 0 {
nu := service.AllService.UserService.InfoById(q.UserId)
gid = nu.GroupId
uid = q.UserId
}
res := service.AllService.UserService.List(1, 999, func(tx *gorm.DB) {
tx.Where("group_id = ?", gid)
})
var data []*adResp.GroupUsersPayload
for _, _u := range res.Users {
gup := &adResp.GroupUsersPayload{}
gup.FromUser(_u)
if _u.Id == uid {
gup.Status = 0
}
data = append(data, gup)
}
response.Success(c, data)
}

View File

@@ -7,10 +7,13 @@ import (
"Gwen/http/response/api" "Gwen/http/response/api"
"Gwen/model" "Gwen/model"
"Gwen/service" "Gwen/service"
"Gwen/utils"
"encoding/json" "encoding/json"
"errors"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"net/http" "net/http"
"strconv" "strconv"
"strings"
) )
type Ab struct { type Ab struct {
@@ -112,6 +115,35 @@ func (a *Ab) Tags(c *gin.Context) {
c.JSON(http.StatusOK, tags.Tags) c.JSON(http.StatusOK, tags.Tags)
} }
// PTags
// @Tags 地址[Personal]
// @Summary 标签
// @Description 标签
// @Accept json
// @Produce json
// @Param guid path string true "guid"
// @Success 200 {object} model.TagList
// @Failure 500 {object} response.ErrorResponse
// @Router /ab/tags/{guid} [post]
// @Security BearerAuth
func (a *Ab) PTags(c *gin.Context) {
u := service.AllService.UserService.CurUser(c)
guid := c.Param("guid")
_, uid, cid, err := a.CheckGuid(u, guid)
if err != nil {
response.Error(c, response.TranslateMsg(c, err.Error()))
return
}
//check privileges
if !service.AllService.AddressBookService.CheckUserReadPrivilege(u, uid, cid) {
response.Error(c, response.TranslateMsg(c, "NoAccess"))
return
}
tags := service.AllService.TagService.ListByUserIdAndCollectionId(uid, cid)
c.JSON(http.StatusOK, tags.Tags)
}
// TagAdd // TagAdd
// @Tags 地址[Personal] // @Tags 地址[Personal]
// @Summary 标签添加 // @Summary 标签添加
@@ -124,19 +156,35 @@ func (a *Ab) Tags(c *gin.Context) {
// @Router /ab/tag/add/{guid} [post] // @Router /ab/tag/add/{guid} [post]
// @Security BearerAuth // @Security BearerAuth
func (a *Ab) TagAdd(c *gin.Context) { func (a *Ab) TagAdd(c *gin.Context) {
t := &model.Tag{} t := &model.Tag{}
err := c.ShouldBindJSON(t) err := c.ShouldBindJSON(t)
if err != nil { if err != nil {
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error()) response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
return return
} }
u := service.AllService.UserService.CurUser(c) u := service.AllService.UserService.CurUser(c)
tag := service.AllService.TagService.InfoByUserIdAndName(u.Id, t.Name) guid := c.Param("guid")
_, uid, cid, err := a.CheckGuid(u, guid)
if err != nil {
response.Error(c, response.TranslateMsg(c, err.Error()))
return
}
//check privileges
if !service.AllService.AddressBookService.CheckUserWritePrivilege(u, uid, cid) {
response.Error(c, response.TranslateMsg(c, "NoAccess"))
return
}
tag := service.AllService.TagService.InfoByUserIdAndNameAndCollectionId(uid, t.Name, cid)
if tag != nil && tag.Id != 0 { if tag != nil && tag.Id != 0 {
response.Error(c, response.TranslateMsg(c, "ItemExists")) response.Error(c, response.TranslateMsg(c, "ItemExists"))
return return
} }
t.UserId = u.Id t.UserId = uid
t.CollectionId = cid
err = service.AllService.TagService.Create(t) err = service.AllService.TagService.Create(t)
if err != nil { if err != nil {
response.Error(c, response.TranslateMsg(c, "OperationFailed")+err.Error()) response.Error(c, response.TranslateMsg(c, "OperationFailed")+err.Error())
@@ -157,6 +205,7 @@ func (a *Ab) TagAdd(c *gin.Context) {
// @Router /ab/tag/rename/{guid} [put] // @Router /ab/tag/rename/{guid} [put]
// @Security BearerAuth // @Security BearerAuth
func (a *Ab) TagRename(c *gin.Context) { func (a *Ab) TagRename(c *gin.Context) {
t := &requstform.TagRenameForm{} t := &requstform.TagRenameForm{}
err := c.ShouldBindJSON(t) err := c.ShouldBindJSON(t)
if err != nil { if err != nil {
@@ -164,12 +213,25 @@ func (a *Ab) TagRename(c *gin.Context) {
return return
} }
u := service.AllService.UserService.CurUser(c) u := service.AllService.UserService.CurUser(c)
tag := service.AllService.TagService.InfoByUserIdAndName(u.Id, t.Old) guid := c.Param("guid")
_, uid, cid, err := a.CheckGuid(u, guid)
if err != nil {
response.Error(c, response.TranslateMsg(c, err.Error()))
return
}
//check privileges
if !service.AllService.AddressBookService.CheckUserWritePrivilege(u, uid, cid) {
response.Error(c, response.TranslateMsg(c, "NoAccess"))
return
}
tag := service.AllService.TagService.InfoByUserIdAndNameAndCollectionId(uid, t.Old, cid)
if tag == nil || tag.Id == 0 { if tag == nil || tag.Id == 0 {
response.Error(c, response.TranslateMsg(c, "ItemNotFound")) response.Error(c, response.TranslateMsg(c, "ItemNotFound"))
return return
} }
ntag := service.AllService.TagService.InfoByUserIdAndName(u.Id, t.New) ntag := service.AllService.TagService.InfoByUserIdAndNameAndCollectionId(uid, t.New, cid)
if ntag != nil && ntag.Id != 0 { if ntag != nil && ntag.Id != 0 {
response.Error(c, response.TranslateMsg(c, "ItemExists")) response.Error(c, response.TranslateMsg(c, "ItemExists"))
return return
@@ -202,7 +264,20 @@ func (a *Ab) TagUpdate(c *gin.Context) {
return return
} }
u := service.AllService.UserService.CurUser(c) u := service.AllService.UserService.CurUser(c)
tag := service.AllService.TagService.InfoByUserIdAndName(u.Id, t.Name) guid := c.Param("guid")
_, uid, cid, err := a.CheckGuid(u, guid)
if err != nil {
response.Error(c, response.TranslateMsg(c, err.Error()))
return
}
//check privileges
if !service.AllService.AddressBookService.CheckUserWritePrivilege(u, uid, cid) {
response.Error(c, response.TranslateMsg(c, "NoAccess"))
return
}
tag := service.AllService.TagService.InfoByUserIdAndNameAndCollectionId(uid, t.Name, cid)
if tag == nil || tag.Id == 0 { if tag == nil || tag.Id == 0 {
response.Error(c, response.TranslateMsg(c, "ItemNotFound")) response.Error(c, response.TranslateMsg(c, "ItemNotFound"))
return return
@@ -228,6 +303,7 @@ func (a *Ab) TagUpdate(c *gin.Context) {
// @Router /ab/tag/{guid} [delete] // @Router /ab/tag/{guid} [delete]
// @Security BearerAuth // @Security BearerAuth
func (a *Ab) TagDel(c *gin.Context) { func (a *Ab) TagDel(c *gin.Context) {
t := &[]string{} t := &[]string{}
err := c.ShouldBind(t) err := c.ShouldBind(t)
if err != nil { if err != nil {
@@ -236,8 +312,21 @@ func (a *Ab) TagDel(c *gin.Context) {
} }
//fmt.Println(t) //fmt.Println(t)
u := service.AllService.UserService.CurUser(c) u := service.AllService.UserService.CurUser(c)
guid := c.Param("guid")
_, uid, cid, err := a.CheckGuid(u, guid)
if err != nil {
response.Error(c, response.TranslateMsg(c, err.Error()))
return
}
//check privileges
if !service.AllService.AddressBookService.CheckUserFullControlPrivilege(u, uid, cid) {
response.Error(c, response.TranslateMsg(c, "NoAccess"))
return
}
for _, name := range *t { for _, name := range *t {
tag := service.AllService.TagService.InfoByUserIdAndName(u.Id, name) tag := service.AllService.TagService.InfoByUserIdAndNameAndCollectionId(uid, name, cid)
if tag == nil || tag.Id == 0 { if tag == nil || tag.Id == 0 {
response.Error(c, response.TranslateMsg(c, "ItemNotFound")) response.Error(c, response.TranslateMsg(c, "ItemNotFound"))
return return
@@ -272,7 +361,7 @@ func (a *Ab) Personal(c *gin.Context) {
rule = json['rule'] ?? 0; rule = json['rule'] ?? 0;
*/ */
if global.Config.Rustdesk.Personal == 1 { if global.Config.Rustdesk.Personal == 1 {
guid := strconv.Itoa(int(user.GroupId)) + "-" + strconv.Itoa(int(user.Id)) guid := a.ComposeGuid(user.GroupId, user.Id, 0)
//如果返回了guid后面的请求会有变化 //如果返回了guid后面的请求会有变化
c.JSON(http.StatusOK, gin.H{ c.JSON(http.StatusOK, gin.H{
"guid": guid, "guid": guid,
@@ -315,38 +404,139 @@ func (a *Ab) Settings(c *gin.Context) {
// @Router /ab/shared/profiles [post] // @Router /ab/shared/profiles [post]
// @Security BearerAuth // @Security BearerAuth
func (a *Ab) SharedProfiles(c *gin.Context) { func (a *Ab) SharedProfiles(c *gin.Context) {
//AbProfile.fromJson(Map<String, dynamic> json)
//: guid = json['guid'] ?? '', var res []*api.SharedProfilesPayload
// name = json['name'] ?? '',
// owner = json['owner'] ?? '', user := service.AllService.UserService.CurUser(c)
// note = json['note'] ?? '', myAbCollectionList := service.AllService.AddressBookService.ListCollectionByUserId(user.Id)
// rule = json['rule'] ?? 0; for _, ab := range myAbCollectionList.AddressBookCollection {
//暂时没必要返回数据,可能是为了共享地址簿 res = append(res, &api.SharedProfilesPayload{
/*item := map[string]interface{}{ Guid: a.ComposeGuid(user.GroupId, user.Id, ab.Id),
"guid": "1", Name: ab.Name,
"name": "admin", Owner: user.Username,
"owner": "admin", Rule: model.ShareAddressBookRuleRuleFullControl,
"note": "admin11", })
"rule": 3,
} }
item2 := map[string]interface{}{
"guid": "2", allAbIds := make(map[uint]int) //用map去重并保留最大Rule
"name": "admin2", allUserIds := make(map[uint]*model.User)
"owner": "admin2", rules := service.AllService.AddressBookService.CollectionReadRules(user)
"note": "admin22", for _, rule := range rules {
"rule": 2, //先判断是否存在
r, ok := allAbIds[rule.CollectionId]
if ok {
//再判断权限大小
if r < rule.Rule {
allAbIds[rule.CollectionId] = rule.Rule
}
} else {
allAbIds[rule.CollectionId] = rule.Rule
allUserIds[rule.UserId] = nil
}
}
abids := utils.Keys(allAbIds)
collections := service.AllService.AddressBookService.ListCollectionByIds(abids)
ids := utils.Keys(allUserIds)
allUsers := service.AllService.UserService.ListByIds(ids)
for _, u := range allUsers {
allUserIds[u.Id] = u
}
for _, collection := range collections {
_u, ok := allUserIds[collection.UserId]
if !ok {
continue
}
res = append(res, &api.SharedProfilesPayload{
Guid: a.ComposeGuid(_u.GroupId, _u.Id, collection.Id),
Name: collection.Name,
Owner: _u.Username,
Rule: allAbIds[collection.Id],
})
} }
c.JSON(http.StatusOK, gin.H{
"total": 2,
"data": []interface{}{item, item2},
})*/
c.JSON(http.StatusOK, gin.H{ c.JSON(http.StatusOK, gin.H{
"total": 0, "total": 0, //len(res),
"data": nil, "data": res,
}) })
} }
// ParseGuid
func (a *Ab) ParseGuid(guid string) (gid, uid, cid uint) {
//用-切割 guid
guids := strings.Split(guid, "-")
if len(guids) < 2 {
return 0, 0, 0
}
if len(guids) != 3 {
cid = 0
} else {
s, err := strconv.Atoi(guids[2])
if err != nil {
return 0, 0, 0
}
cid = uint(s)
}
g, err := strconv.Atoi(guids[0])
if err != nil {
return 0, 0, 0
}
gid = uint(g)
u, err := strconv.Atoi(guids[1])
if err != nil {
return 0, 0, 0
}
uid = uint(u)
return
}
// ComposeGuid
func (a *Ab) ComposeGuid(gid, uid, cid uint) string {
return strconv.Itoa(int(gid)) + "-" + strconv.Itoa(int(uid)) + "-" + strconv.Itoa(int(cid))
}
// CheckGuid
func (a *Ab) CheckGuid(cu *model.User, guid string) (gid, uid, cid uint, err error) {
gid, uid, cid = a.ParseGuid(guid)
err = nil
if gid == 0 || uid == 0 {
err = errors.New("ParamsError")
return
}
u := &model.User{}
if cu.Id == uid {
u = cu
} else {
u = service.AllService.UserService.InfoById(uid)
}
if u == nil || u.Id == 0 {
err = errors.New("ParamsError")
return
}
if u.GroupId != gid {
err = errors.New("ParamsError")
return
}
if cid == 0 && cu.Id != uid {
err = errors.New("ParamsError")
return
}
if cid > 0 {
c := service.AllService.AddressBookService.CollectionInfoById(cid)
if c == nil || c.Id == 0 {
err = errors.New("ParamsError")
return
}
if c.UserId != uid {
err = errors.New("ParamsError")
return
}
}
return
}
// Peers // Peers
// @Tags 地址[Personal] // @Tags 地址[Personal]
// @Summary 地址列表 // @Summary 地址列表
@@ -361,8 +551,21 @@ func (a *Ab) SharedProfiles(c *gin.Context) {
// @Router /ab/peers [post] // @Router /ab/peers [post]
// @Security BearerAuth // @Security BearerAuth
func (a *Ab) Peers(c *gin.Context) { func (a *Ab) Peers(c *gin.Context) {
user := service.AllService.UserService.CurUser(c) u := service.AllService.UserService.CurUser(c)
al := service.AllService.AddressBookService.ListByUserId(user.Id, 1, 1000) guid := c.Query("ab")
_, uid, cid, err := a.CheckGuid(u, guid)
if err != nil {
response.Error(c, response.TranslateMsg(c, err.Error()))
return
}
//check privileges
if !service.AllService.AddressBookService.CheckUserReadPrivilege(u, uid, cid) {
response.Error(c, response.TranslateMsg(c, "NoAccess"))
return
}
al := service.AllService.AddressBookService.ListByUserIdAndCollectionId(uid, cid, 1, 1000)
c.JSON(http.StatusOK, gin.H{ c.JSON(http.StatusOK, gin.H{
"total": al.Total, "total": al.Total,
"data": al.AddressBooks, "data": al.AddressBooks,
@@ -370,24 +573,6 @@ func (a *Ab) Peers(c *gin.Context) {
}) })
} }
// PTags
// @Tags 地址[Personal]
// @Summary 标签
// @Description 标签
// @Accept json
// @Produce json
// @Param guid path string true "guid"
// @Success 200 {object} model.TagList
// @Failure 500 {object} response.ErrorResponse
// @Router /ab/tags/{guid} [post]
// @Security BearerAuth
func (a *Ab) PTags(c *gin.Context) {
user := service.AllService.UserService.CurUser(c)
tags := service.AllService.TagService.ListByUserId(user.Id)
c.JSON(http.StatusOK, tags.Tags)
}
// PeerAdd // PeerAdd
// @Tags 地址[Personal] // @Tags 地址[Personal]
// @Summary 添加地址 // @Summary 添加地址
@@ -402,18 +587,31 @@ func (a *Ab) PTags(c *gin.Context) {
func (a *Ab) PeerAdd(c *gin.Context) { func (a *Ab) PeerAdd(c *gin.Context) {
// forceAlwaysRelay永远是字符串"false" // forceAlwaysRelay永远是字符串"false"
//f := &gin.H{} //f := &gin.H{}
//guid := c.Param("guid")
f := &requstform.PersonalAddressBookForm{} f := &requstform.PersonalAddressBookForm{}
err := c.ShouldBindJSON(f) err := c.ShouldBindJSON(f)
if err != nil { if err != nil {
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error()) response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
return return
} }
//fmt.Println(f)
u := service.AllService.UserService.CurUser(c)
f.UserId = u.Id
ab := f.ToAddressBook()
u := service.AllService.UserService.CurUser(c)
guid := c.Param("guid")
_, uid, cid, err := a.CheckGuid(u, guid)
if err != nil {
response.Error(c, response.TranslateMsg(c, err.Error()))
return
}
//check privileges
if !service.AllService.AddressBookService.CheckUserWritePrivilege(u, uid, cid) {
response.Error(c, response.TranslateMsg(c, "NoAccess"))
return
}
//fmt.Println(f)
f.UserId = uid
ab := f.ToAddressBook()
ab.CollectionId = cid
if ab.Platform == "" || ab.Username == "" || ab.Hostname == "" { if ab.Platform == "" || ab.Username == "" || ab.Hostname == "" {
peer := service.AllService.PeerService.FindById(ab.Id) peer := service.AllService.PeerService.FindById(ab.Id)
if peer.RowId != 0 { if peer.RowId != 0 {
@@ -450,8 +648,21 @@ func (a *Ab) PeerDel(c *gin.Context) {
return return
} }
u := service.AllService.UserService.CurUser(c) u := service.AllService.UserService.CurUser(c)
guid := c.Param("guid")
_, uid, cid, err := a.CheckGuid(u, guid)
if err != nil {
response.Error(c, response.TranslateMsg(c, err.Error()))
return
}
//check privileges
if !service.AllService.AddressBookService.CheckUserFullControlPrivilege(u, uid, cid) {
response.Error(c, response.TranslateMsg(c, "NoAccess"))
return
}
for _, id := range *f { for _, id := range *f {
ab := service.AllService.AddressBookService.InfoByUserIdAndId(u.Id, id) ab := service.AllService.AddressBookService.InfoByUserIdAndIdAndCid(uid, id, cid)
if ab == nil || ab.RowId == 0 { if ab == nil || ab.RowId == 0 {
response.Error(c, response.TranslateMsg(c, "ItemNotFound")) response.Error(c, response.TranslateMsg(c, "ItemNotFound"))
return return
@@ -485,10 +696,23 @@ func (a *Ab) PeerUpdate(c *gin.Context) {
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error()) response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
return return
} }
u := service.AllService.UserService.CurUser(c)
guid := c.Param("guid")
_, uid, cid, err := a.CheckGuid(u, guid)
if err != nil {
response.Error(c, response.TranslateMsg(c, err.Error()))
return
}
//check privileges
if !service.AllService.AddressBookService.CheckUserWritePrivilege(u, uid, cid) {
response.Error(c, response.TranslateMsg(c, "NoAccess"))
return
}
//fmt.Println(f) //fmt.Println(f)
//return //return
u := service.AllService.UserService.CurUser(c) ab := service.AllService.AddressBookService.InfoByUserIdAndIdAndCid(uid, f.Id, cid)
ab := service.AllService.AddressBookService.InfoByUserIdAndId(u.Id, f.Id)
if ab == nil || ab.RowId == 0 { if ab == nil || ab.RowId == 0 {
response.Error(c, response.TranslateMsg(c, "ItemNotFound")) response.Error(c, response.TranslateMsg(c, "ItemNotFound"))
return return

View File

@@ -30,7 +30,9 @@ func (a *Audit) AuditConn(c *gin.Context) {
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error()) response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
return return
} }
//fmt.Println(af) /*ttt := &gin.H{}
c.ShouldBindBodyWith(ttt, binding.JSON)
fmt.Println(ttt)*/
ac := af.ToAuditConn() ac := af.ToAuditConn()
if af.Action == model.AuditActionNew { if af.Action == model.AuditActionNew {
service.AllService.AuditService.CreateAuditConn(ac) service.AllService.AuditService.CreateAuditConn(ac)
@@ -48,9 +50,35 @@ func (a *Audit) AuditConn(c *gin.Context) {
FromPeer: ac.FromPeer, FromPeer: ac.FromPeer,
FromName: ac.FromName, FromName: ac.FromName,
SessionId: ac.SessionId, SessionId: ac.SessionId,
Type: ac.Type,
} }
service.AllService.AuditService.UpdateAuditConn(up) service.AllService.AuditService.UpdateAuditConn(up)
} }
} }
response.Success(c, "") response.Success(c, "")
} }
// AuditFile
// @Tags 审计
// @Summary 审计文件
// @Description 审计文件
// @Accept json
// @Produce json
// @Param body body request.AuditFileForm true "审计文件"
// @Success 200 {string} string ""
// @Failure 500 {object} response.Response
// @Router /audit/file [post]
func (a *Audit) AuditFile(c *gin.Context) {
aff := &request.AuditFileForm{}
err := c.ShouldBindBodyWith(aff, binding.JSON)
if err != nil {
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
return
}
//ttt := &gin.H{}
//c.ShouldBindBodyWith(ttt, binding.JSON)
//fmt.Println(ttt)
af := aff.ToAuditFile()
service.AllService.AuditService.CreateAuditFile(af)
response.Success(c, "")
}

View File

@@ -28,23 +28,23 @@ type Group struct {
// @Router /users [get] // @Router /users [get]
// @Security BearerAuth // @Security BearerAuth
func (g *Group) Users(c *gin.Context) { func (g *Group) Users(c *gin.Context) {
u := service.AllService.UserService.CurUser(c)
if !*u.IsAdmin {
gr := service.AllService.GroupService.InfoById(u.GroupId)
if gr.Type != model.GroupTypeShare {
response.Error(c, response.TranslateMsg(c, "NoAccess"))
return
}
}
q := &apiReq.UserListQuery{} q := &apiReq.UserListQuery{}
err := c.ShouldBindQuery(&q) err := c.ShouldBindQuery(&q)
if err != nil { if err != nil {
response.Error(c, err.Error()) response.Error(c, err.Error())
return return
} }
userList := service.AllService.UserService.ListByGroupId(u.GroupId, q.Page, q.PageSize) u := service.AllService.UserService.CurUser(c)
gr := service.AllService.GroupService.InfoById(u.GroupId)
userList := &model.UserList{}
if !*u.IsAdmin && gr.Type != model.GroupTypeShare {
//仅能获取到自己
userList.Users = append(userList.Users, u)
userList.Total = 1
} else {
userList = service.AllService.UserService.ListByGroupId(u.GroupId, q.Page, q.PageSize)
}
var data []*apiResp.UserPayload var data []*apiResp.UserPayload
for _, user := range userList.Users { for _, user := range userList.Users {
up := &apiResp.UserPayload{} up := &apiResp.UserPayload{}
@@ -73,23 +73,21 @@ func (g *Group) Users(c *gin.Context) {
// @Security BearerAuth // @Security BearerAuth
func (g *Group) Peers(c *gin.Context) { func (g *Group) Peers(c *gin.Context) {
u := service.AllService.UserService.CurUser(c) u := service.AllService.UserService.CurUser(c)
if !*u.IsAdmin {
gr := service.AllService.GroupService.InfoById(u.GroupId)
if gr.Type != model.GroupTypeShare {
response.Error(c, response.TranslateMsg(c, "NoAccess"))
return
}
}
q := &apiReq.PeerListQuery{} q := &apiReq.PeerListQuery{}
err := c.ShouldBindQuery(&q) err := c.ShouldBindQuery(&q)
if err != nil { if err != nil {
response.Error(c, err.Error()) response.Error(c, err.Error())
return return
} }
gr := service.AllService.GroupService.InfoById(u.GroupId)
users := make([]*model.User, 0, 1)
if !*u.IsAdmin && gr.Type != model.GroupTypeShare {
//仅能获取到自己
users = append(users, u)
} else {
users = service.AllService.UserService.ListIdAndNameByGroupId(u.GroupId)
}
users := service.AllService.UserService.ListIdAndNameByGroupId(u.GroupId)
namesById := make(map[uint]string) namesById := make(map[uint]string)
userIds := make([]uint, 0) userIds := make([]uint, 0)
for _, user := range users { for _, user := range users {

View File

@@ -50,7 +50,7 @@ func (i *Index) Heartbeat(c *gin.Context) {
return return
} }
peer := service.AllService.PeerService.FindByUuid(info.Uuid) peer := service.AllService.PeerService.FindByUuid(info.Uuid)
if peer == nil { if peer == nil || peer.RowId == 0 {
c.JSON(http.StatusOK, gin.H{}) c.JSON(http.StatusOK, gin.H{})
return return
} }

View File

@@ -23,6 +23,7 @@ type AddressBookForm struct {
Online bool `json:"online"` Online bool `json:"online"`
LoginName string `json:"loginName" ` LoginName string `json:"loginName" `
SameServer bool `json:"sameServer"` SameServer bool `json:"sameServer"`
CollectionId uint `json:"collection_id"`
} }
func (a AddressBookForm) ToAddressBook() *model.AddressBook { func (a AddressBookForm) ToAddressBook() *model.AddressBook {
@@ -46,6 +47,7 @@ func (a AddressBookForm) ToAddressBook() *model.AddressBook {
Online: a.Online, Online: a.Online,
LoginName: a.LoginName, LoginName: a.LoginName,
SameServer: a.SameServer, SameServer: a.SameServer,
CollectionId: a.CollectionId,
} }
} }
@@ -72,17 +74,19 @@ func (a AddressBookForm) ToAddressBooks() []*model.AddressBook {
Online: a.Online, Online: a.Online,
LoginName: a.LoginName, LoginName: a.LoginName,
SameServer: a.SameServer, SameServer: a.SameServer,
CollectionId: a.CollectionId,
}) })
} }
return abs return abs
} }
type AddressBookQuery struct { type AddressBookQuery struct {
UserId int `form:"user_id"` UserId int `form:"user_id"`
IsMy int `form:"is_my"` CollectionId *int `form:"collection_id"`
Username string `form:"username"` IsMy int `form:"is_my"`
Hostname string `form:"hostname"` Username string `form:"username"`
Id string `form:"id"` Hostname string `form:"hostname"`
Id string `form:"id"`
PageQuery PageQuery
} }
@@ -102,3 +106,19 @@ func (sbwcf ShareByWebClientForm) ToShareRecord() *model.ShareRecord {
Expire: sbwcf.Expire, Expire: sbwcf.Expire,
} }
} }
type AddressBookCollectionQuery struct {
UserId int `form:"user_id"`
IsMy int `form:"is_my"`
PageQuery
}
type AddressBookCollectionSimpleListQuery struct {
UserIds []uint `form:"user_ids"`
}
type AddressBookCollectionRuleQuery struct {
UserId int `form:"user_id"`
CollectionId int `form:"collection_id"`
IsMy int `form:"is_my"`
PageQuery
}

View File

@@ -5,11 +5,13 @@ import "Gwen/model"
type GroupForm struct { type GroupForm struct {
Id uint `json:"id"` Id uint `json:"id"`
Name string `json:"name" validate:"required"` Name string `json:"name" validate:"required"`
Type int `json:"type"`
} }
func (gf *GroupForm) FromGroup(group *model.Group) *GroupForm { func (gf *GroupForm) FromGroup(group *model.Group) *GroupForm {
gf.Id = group.Id gf.Id = group.Id
gf.Name = group.Name gf.Name = group.Name
gf.Type = group.Type
return gf return gf
} }
@@ -17,5 +19,6 @@ func (gf *GroupForm) ToGroup() *model.Group {
group := &model.Group{} group := &model.Group{}
group.Id = gf.Id group.Id = gf.Id
group.Name = gf.Name group.Name = gf.Name
group.Type = gf.Type
return group return group
} }

View File

@@ -3,10 +3,11 @@ package admin
import "Gwen/model" import "Gwen/model"
type TagForm struct { type TagForm struct {
Id uint `json:"id"` Id uint `json:"id"`
Name string `json:"name" validate:"required"` Name string `json:"name" validate:"required"`
Color uint `json:"color" validate:"required"` Color uint `json:"color" validate:"required"`
UserId uint `json:"user_id"` UserId uint `json:"user_id"`
CollectionId uint `json:"collection_id"`
} }
func (f *TagForm) FromTag(group *model.Tag) *TagForm { func (f *TagForm) FromTag(group *model.Tag) *TagForm {
@@ -14,6 +15,7 @@ func (f *TagForm) FromTag(group *model.Tag) *TagForm {
f.Name = group.Name f.Name = group.Name
f.Color = group.Color f.Color = group.Color
f.UserId = group.UserId f.UserId = group.UserId
f.CollectionId = group.CollectionId
return f return f
} }
@@ -23,11 +25,13 @@ func (f *TagForm) ToTag() *model.Tag {
i.Name = f.Name i.Name = f.Name
i.Color = f.Color i.Color = f.Color
i.UserId = f.UserId i.UserId = f.UserId
i.CollectionId = f.CollectionId
return i return i
} }
type TagQuery struct { type TagQuery struct {
UserId int `form:"user_id"` UserId int `form:"user_id"`
IsMy int `form:"is_my"` IsMy int `form:"is_my"`
CollectionId *int `form:"collection_id"`
PageQuery PageQuery
} }

View File

@@ -55,3 +55,7 @@ type ChangeCurPasswordForm struct {
OldPassword string `json:"old_password" validate:"required,gte=4,lte=20"` OldPassword string `json:"old_password" validate:"required,gte=4,lte=20"`
NewPassword string `json:"new_password" validate:"required,gte=4,lte=20"` NewPassword string `json:"new_password" validate:"required,gte=4,lte=20"`
} }
type GroupUsersQuery struct {
IsMy int `json:"is_my"`
UserId uint `json:"user_id"`
}

View File

@@ -1,7 +1,9 @@
package api package api
import ( import (
"Gwen/global"
"Gwen/model" "Gwen/model"
"encoding/json"
"strconv" "strconv"
) )
@@ -38,3 +40,39 @@ func (a *AuditConnForm) ToAuditConn() *model.AuditConn {
Uuid: a.Uuid, Uuid: a.Uuid,
} }
} }
type AuditFileForm struct {
Id string `json:"id"`
Info string `json:"info"`
IsFile bool `json:"is_file"`
Path string `json:"path"`
PeerId string `json:"peer_id"`
Type int `json:"type"`
Uuid string `json:"uuid"`
}
type AuditFileInfo struct {
Ip string `json:"ip"`
Name string `json:"name"`
Num int `json:"num"`
}
func (a *AuditFileForm) ToAuditFile() *model.AuditFile {
fi := &AuditFileInfo{}
err := json.Unmarshal([]byte(a.Info), fi)
if err != nil {
global.Logger.Warn("ToAuditFile", err)
}
return &model.AuditFile{
PeerId: a.Id,
Info: a.Info,
IsFile: a.IsFile,
FromPeer: a.PeerId,
Path: a.Path,
Type: a.Type,
Uuid: a.Uuid,
FromName: fi.Name,
Ip: fi.Ip,
Num: fi.Num,
}
}

View File

@@ -1,5 +1,7 @@
package admin package admin
import "Gwen/model"
type LoginPayload struct { type LoginPayload struct {
Username string `json:"username"` Username string `json:"username"`
Token string `json:"token"` Token string `json:"token"`
@@ -8,7 +10,7 @@ type LoginPayload struct {
} }
var UserRouteNames = []string{ var UserRouteNames = []string{
"MyTagList", "MyAddressBookList", "MyInfo", "MyTagList", "MyAddressBookList", "MyInfo", "MyAddressBookCollection",
} }
var AdminRouteNames = []string{"*"} var AdminRouteNames = []string{"*"}
@@ -16,3 +18,15 @@ type UserOauthItem struct {
ThirdType string `json:"third_type"` ThirdType string `json:"third_type"`
Status int `json:"status"` Status int `json:"status"`
} }
type GroupUsersPayload struct {
Id uint `json:"id"`
Username string `json:"username"`
Status int `json:"status"`
}
func (g *GroupUsersPayload) FromUser(user *model.User) {
g.Id = user.Id
g.Username = user.Username
g.Status = 1
}

View File

@@ -7,3 +7,11 @@ type AbList struct {
Tags []string `json:"tags,omitempty"` Tags []string `json:"tags,omitempty"`
TagColors string `json:"tag_colors,omitempty"` TagColors string `json:"tag_colors,omitempty"`
} }
type SharedProfilesPayload struct {
Guid string `json:"guid"`
Name string `json:"name"`
Owner string `json:"owner"`
Note string `json:"note"`
Rule int `json:"rule"`
}

View File

@@ -56,7 +56,7 @@ type ServerConfigResponse struct {
} }
func TranslateMsg(c *gin.Context, messageId string) string { func TranslateMsg(c *gin.Context, messageId string) string {
localizer := global.Localizer(c) localizer := global.Localizer(c.GetHeader("Accept-Language"))
errMsg, err := localizer.LocalizeMessage(&i18n.Message{ errMsg, err := localizer.LocalizeMessage(&i18n.Message{
ID: messageId, ID: messageId,
}) })
@@ -67,7 +67,7 @@ func TranslateMsg(c *gin.Context, messageId string) string {
return errMsg return errMsg
} }
func TranslateTempMsg(c *gin.Context, messageId string, templateData map[string]interface{}) string { func TranslateTempMsg(c *gin.Context, messageId string, templateData map[string]interface{}) string {
localizer := global.Localizer(c) localizer := global.Localizer(c.GetHeader("Accept-Language"))
errMsg, err := localizer.Localize(&i18n.LocalizeConfig{ errMsg, err := localizer.Localize(&i18n.LocalizeConfig{
DefaultMessage: &i18n.Message{ DefaultMessage: &i18n.Message{
ID: messageId, ID: messageId,
@@ -81,7 +81,7 @@ func TranslateTempMsg(c *gin.Context, messageId string, templateData map[string]
return errMsg return errMsg
} }
func TranslateParamMsg(c *gin.Context, messageId string, params ...string) string { func TranslateParamMsg(c *gin.Context, messageId string, params ...string) string {
localizer := global.Localizer(c) localizer := global.Localizer(c.GetHeader("Accept-Language"))
templateData := make(map[string]interface{}) templateData := make(map[string]interface{})
for i, v := range params { for i, v := range params {
k := fmt.Sprintf("P%d", i) k := fmt.Sprintf("P%d", i)

View File

@@ -28,6 +28,8 @@ func Init(g *gin.Engine) {
OauthBind(adg) OauthBind(adg)
LoginLogBind(adg) LoginLogBind(adg)
AuditBind(adg) AuditBind(adg)
AddressBookCollectionBind(adg)
AddressBookCollectionRuleBind(adg)
rs := &admin.Rustdesk{} rs := &admin.Rustdesk{}
adg.GET("/server-config", rs.ServerConfig) adg.GET("/server-config", rs.ServerConfig)
adg.GET("/app-config", rs.AppConfig) adg.GET("/app-config", rs.AppConfig)
@@ -48,6 +50,7 @@ func UserBind(rg *gin.RouterGroup) {
aR.GET("/current", cont.Current) aR.GET("/current", cont.Current)
aR.POST("/changeCurPwd", cont.ChangeCurPwd) aR.POST("/changeCurPwd", cont.ChangeCurPwd)
aR.POST("/myOauth", cont.MyOauth) aR.POST("/myOauth", cont.MyOauth)
aR.POST("/groupUsers", cont.GroupUsers)
} }
aRP := rg.Group("/user").Use(middleware.AdminPrivilege()) aRP := rg.Group("/user").Use(middleware.AdminPrivilege())
{ {
@@ -148,6 +151,32 @@ func AuditBind(rg *gin.RouterGroup) {
aR := rg.Group("/audit_conn").Use(middleware.AdminPrivilege()) aR := rg.Group("/audit_conn").Use(middleware.AdminPrivilege())
aR.GET("/list", cont.ConnList) aR.GET("/list", cont.ConnList)
aR.POST("/delete", cont.ConnDelete) aR.POST("/delete", cont.ConnDelete)
afR := rg.Group("/audit_file").Use(middleware.AdminPrivilege())
afR.GET("/list", cont.FileList)
afR.POST("/delete", cont.FileDelete)
}
func AddressBookCollectionBind(rg *gin.RouterGroup) {
aR := rg.Group("/address_book_collection")
{
cont := &admin.AddressBookCollection{}
aR.GET("/list", cont.List)
aR.GET("/detail/:id", cont.Detail)
aR.POST("/create", cont.Create)
aR.POST("/update", cont.Update)
aR.POST("/delete", cont.Delete)
}
}
func AddressBookCollectionRuleBind(rg *gin.RouterGroup) {
aR := rg.Group("/address_book_collection_rule")
{
cont := &admin.AddressBookCollectionRule{}
aR.GET("/list", cont.List)
aR.GET("/detail/:id", cont.Detail)
aR.POST("/create", cont.Create)
aR.POST("/update", cont.Update)
aR.POST("/delete", cont.Delete)
}
} }
/* /*

View File

@@ -53,6 +53,8 @@ func ApiInit(g *gin.Engine) {
au := &api.Audit{} au := &api.Audit{}
//[method:POST] [uri:/api/audit/conn] //[method:POST] [uri:/api/audit/conn]
frg.POST("/audit/conn", au.AuditConn) frg.POST("/audit/conn", au.AuditConn)
//[method:POST] [uri:/api/audit/file]
frg.POST("/audit/file", au.AuditFile)
frg.Use(middleware.RustAuth()) frg.Use(middleware.RustAuth())
{ {
u := &api.User{} u := &api.User{}

View File

@@ -17,6 +17,7 @@ func WebInit(g *gin.Engine) {
if global.Config.App.WebClient == 1 { if global.Config.App.WebClient == 1 {
g.StaticFS("/webclient", http.Dir(global.Config.Gin.ResourcesPath+"/web")) g.StaticFS("/webclient", http.Dir(global.Config.Gin.ResourcesPath+"/web"))
g.StaticFS("/webclient2", http.Dir(global.Config.Gin.ResourcesPath+"/web2"))
} }
g.StaticFS("/_admin", http.Dir(global.Config.Gin.ResourcesPath+"/admin")) g.StaticFS("/_admin", http.Dir(global.Config.Gin.ResourcesPath+"/admin"))
} }

View File

@@ -19,22 +19,24 @@ import "Gwen/model/custom_types"
// AddressBook 有些字段是Personal才会上传的 // AddressBook 有些字段是Personal才会上传的
type AddressBook struct { type AddressBook struct {
RowId uint `gorm:"primaryKey" json:"row_id"` RowId uint `gorm:"primaryKey" json:"row_id"`
Id string `json:"id" gorm:"default:0;not null;index"` Id string `json:"id" gorm:"default:0;not null;index"`
Username string `json:"username" gorm:"default:'';not null;"` Username string `json:"username" gorm:"default:'';not null;"`
Password string `json:"password" gorm:"default:'';not null;"` Password string `json:"password" gorm:"default:'';not null;"`
Hostname string `json:"hostname" gorm:"default:'';not null;"` Hostname string `json:"hostname" gorm:"default:'';not null;"`
Alias string `json:"alias" gorm:"default:'';not null;"` Alias string `json:"alias" gorm:"default:'';not null;"`
Platform string `json:"platform" gorm:"default:'';not null;"` Platform string `json:"platform" gorm:"default:'';not null;"`
Tags custom_types.AutoJson `json:"tags" gorm:"not null;" swaggertype:"array,string"` Tags custom_types.AutoJson `json:"tags" gorm:"not null;" swaggertype:"array,string"`
Hash string `json:"hash" gorm:"default:'';not null;"` Hash string `json:"hash" gorm:"default:'';not null;"`
UserId uint `json:"user_id" gorm:"default:0;not null;index"` UserId uint `json:"user_id" gorm:"default:0;not null;index"`
ForceAlwaysRelay bool `json:"forceAlwaysRelay" gorm:"default:0;not null;"` ForceAlwaysRelay bool `json:"forceAlwaysRelay" gorm:"default:0;not null;"`
RdpPort string `json:"rdpPort" gorm:"default:'';not null;"` RdpPort string `json:"rdpPort" gorm:"default:'';not null;"`
RdpUsername string `json:"rdpUsername" gorm:"default:'';not null;"` RdpUsername string `json:"rdpUsername" gorm:"default:'';not null;"`
Online bool `json:"online" gorm:"default:0;not null;"` Online bool `json:"online" gorm:"default:0;not null;"`
LoginName string `json:"loginName" gorm:"default:'';not null;"` LoginName string `json:"loginName" gorm:"default:'';not null;"`
SameServer bool `json:"sameServer" gorm:"default:0;not null;"` SameServer bool `json:"sameServer" gorm:"default:0;not null;"`
CollectionId uint `json:"collection_id" gorm:"default:0;not null;index"`
Collection *AddressBookCollection `json:"collection,omitempty"`
TimeModel TimeModel
} }
@@ -42,3 +44,37 @@ type AddressBookList struct {
AddressBooks []*AddressBook `json:"list"` AddressBooks []*AddressBook `json:"list"`
Pagination Pagination
} }
type AddressBookCollection struct {
IdModel
UserId uint `json:"user_id" gorm:"default:0;not null;index"`
Name string `json:"name" gorm:"default:'';not null;" validate:"required"`
TimeModel
}
type AddressBookCollectionList struct {
AddressBookCollection []*AddressBookCollection `json:"list"`
Pagination
}
type AddressBookCollectionRule struct {
IdModel
UserId uint `json:"user_id" gorm:"default:0;not null;"`
CollectionId uint `json:"collection_id" gorm:"default:0;not null;index" validate:"required"`
Rule int `json:"rule" gorm:"default:0;not null;" validate:"required,gte=1,lte=3"` // 0: 无 1: 读 2: 读写 3: 完全控制
Type int `json:"type" gorm:"default:1;not null;" validate:"required,gte=1,lte=2"` // 1: 个人 2: 群组
ToId uint `json:"to_id" gorm:"default:0;not null;" validate:"required,gt=0"`
TimeModel
}
type AddressBookCollectionRuleList struct {
AddressBookCollectionRule []*AddressBookCollectionRule `json:"list"`
Pagination
}
const (
ShareAddressBookRuleTypePersonal = 1
ShareAddressBookRuleTypeGroup = 2
)
const (
ShareAddressBookRuleRuleRead = 1
ShareAddressBookRuleRuleReadWrite = 2
ShareAddressBookRuleRuleFullControl = 3
)

View File

@@ -24,3 +24,23 @@ type AuditConnList struct {
AuditConns []*AuditConn `json:"list"` AuditConns []*AuditConn `json:"list"`
Pagination Pagination
} }
type AuditFile struct {
IdModel
FromPeer string `json:"from_peer" gorm:"default:'';not null;index"`
Info string `json:"info" gorm:"default:'';not null;"`
IsFile bool `json:"is_file" gorm:"default:0;not null;"`
Path string `json:"path" gorm:"default:'';not null;"`
PeerId string `json:"peer_id" gorm:"default:'';not null;index"`
Type int `json:"type" gorm:"default:0;not null;"`
Uuid string `json:"uuid" gorm:"default:'';not null;"`
Ip string `json:"ip" gorm:"default:'';not null;"`
Num int `json:"num" gorm:"default:0;not null;"`
FromName string `json:"from_name" gorm:"default:'';not null;"`
TimeModel
}
type AuditFileList struct {
AuditFiles []*AuditFile `json:"list"`
Pagination
}

View File

@@ -2,9 +2,11 @@ package model
type Tag struct { type Tag struct {
IdModel IdModel
Name string `json:"name" gorm:"default:'';not null;"` Name string `json:"name" gorm:"default:'';not null;"`
UserId uint `json:"user_id" gorm:"default:0;not null;index"` UserId uint `json:"user_id" gorm:"default:0;not null;index"`
Color uint `json:"color" gorm:"default:0;not null;"` //color 是flutter的颜色值,从0x00000000 到 0xFFFFFFFF; 前两位表示透明度后面6位表示颜色, 可以转成rgba Color uint `json:"color" gorm:"default:0;not null;"` //color 是flutter的颜色值,从0x00000000 到 0xFFFFFFFF; 前两位表示透明度后面6位表示颜色, 可以转成rgba
CollectionId uint `json:"collection_id" gorm:"default:0;not null;index"`
Collection *AddressBookCollection `json:"collection,omitempty"`
TimeModel TimeModel
} }

123
resources/i18n/ko.toml Normal file
View File

@@ -0,0 +1,123 @@
[Test]
description = "test"
one = "테스트1 {{.P0}}"
other = "테스트2 {{.P0}}"
[ParamsError]
description = "Params validation failed."
one = "매개변수 검증에 실패했습니다."
other = "매개변수 검증에 실패했습니다."
[OperationFailed]
description = "OperationFailed."
one = "작업 실패."
other = "작업 실패."
[OperationSuccess]
description = "OperationSuccess."
one = "작업 성공."
other = "작업 성공."
[ItemExists]
description = "Item already exists."
one = "항목이 이미 존재합니다."
other = "항목이 이미 존재합니다."
[ItemNotFound]
description = "Item not found."
one = "항목을 찾을 수 없습니다."
other = "항목을 찾을 수 없습니다."
[NoAccess]
description = "No access."
one = "접근할 수 없습니다."
other = "접근할 수 없습니다."
[UsernameOrPasswordError]
description = "Username or password error."
one = "사용자 이름이나 비밀번호가 올바르지 않습니다."
other = "사용자 이름이나 비밀번호가 올바르지 않습니다."
[SystemError]
description = "System error."
one = "시스템 오류."
other = "시스템 오류."
[ConfigNotFound]
description = "Config not found."
one = "구성이 존재하지 않습니다."
other = "구성이 존재하지 않습니다."
#授权过期
[OauthExpired]
description = "Oauth expired."
one = "인증이 만료되었습니다. 다시 승인해 주세요."
other = "인증이 만료되었습니다. 다시 승인해 주세요."
[OauthFailed]
description = "Oauth failed."
one = "인증에 실패했습니다."
other = "인증에 실패했습니다."
[OauthHasBindOtherUser]
description = "Oauth has bind other user."
one = "권한이 다른 사용자에게 바인딩되었습니다."
other = "권한이 다른 사용자에게 바인딩되었습니다."
[ParamIsEmpty]
description = "Param is empty."
one = "{{.P0}} 비어 있습니다."
other = "{{.P0}} 비어 있습니다."
[BindFail]
description = "Bind fail."
one = "바인딩 실패."
other = "바인딩 실패."
[BindSuccess]
description = "Bind success."
one = "바인딩 성공."
other = "바인딩 성공."
[OauthHasBeenSuccess]
description = "Oauth has been success."
one = "인증이 완료되었습니다."
other = "인증이 완료되었습니다."
[OauthSuccess]
description = "Oauth success."
one = "인증 성공."
other = "인증 성공."
[OauthRegisterSuccess]
description = "Oauth register success."
one = "인증 등록이 완료되었습니다."
other = "인증 등록이 완료되었습니다."
[OauthRegisterFailed]
description = "Oauth register failed."
one = "인증 등록에 실패했습니다."
other = "인증 등록에 실패했습니다."
[GetOauthTokenError]
description = "Get oauth token error."
one = "인증 토큰을 획득하지 못했습니다."
other = "인증 토큰을 획득하지 못했습니다."
[GetOauthUserInfoError]
description = "Get oauth user info error."
one = "인증된 사용자 정보를 획득하지 못했습니다."
other = "인증된 사용자 정보를 획득하지 못했습니다."
[DecodeOauthUserInfoError]
description = "Decode oauth user info error."
one = "인증된 사용자 정보를 구문 분석하지 못했습니다."
other = "인증된 사용자 정보를 구문 분석하지 못했습니다."
[OldPasswordError]
description = "Old password error."
one = "이전 비밀번호가 잘못되었습니다."
other = "이전 비밀번호가 잘못되었습니다."
[DefaultGroup]
description = "Default group."
one = "기본 그룹"
other = "기본 그룹"
[ShareGroup]
description = "Share group."
one = "공유 그룹"
other = "공유 그룹"

129
resources/i18n/ru.toml Normal file
View File

@@ -0,0 +1,129 @@
[Test]
description = "test"
one = "тест 1 {{.P0}}"
other = "тест 2 {{.P0}}"
[ParamsError]
description = "Params validation failed."
one = "Ошибка параметра."
other = "Ошибка параметра."
[OperationFailed]
description = "OperationFailed."
one = "Операция не удалась."
other = "Операция не удалась."
[OperationSuccess]
description = "OperationSuccess."
one = "Операция успешна."
other = "Операция успешна."
[ItemExists]
description = "Item already exists."
one = "Данные уже существуют."
other = "Данные уже существуют."
[ItemNotFound]
description = "Item not found."
one = "Данные не найдены."
other = "Данные не найдены."
[NoAccess]
description = "No access."
one = "Нет доступа."
other = "Нет доступа."
[UsernameOrPasswordError]
description = "Username or password error."
one = "Неправильное имя пользователя или пароль."
other = "Неправильное имя пользователя или пароль."
[SystemError]
description = "System error."
one = "Системная ошибка."
other = "Системная ошибка."
[ConfigNotFound]
description = "Config not found."
one = "Конфигурация не найдена."
other = "Конфигурация не найдена."
[OauthExpired]
description = "Oauth expired."
one = "Авторизация истекла, пожалуйста, авторизуйтесь снова."
other = "Авторизация истекла, пожалуйста, авторизуйтесь снова."
[OauthFailed]
description = "Oauth failed."
one = "Авторизация не удалась."
other = "Авторизация не удалась."
[OauthHasBindOtherUser]
description = "Oauth has bind other user."
one = "Авторизация уже привязана к другому пользователю."
other = "Авторизация уже привязана к другому пользователю."
[ParamIsEmpty]
description = "Param is empty."
one = "{{.P0}} пуст."
other = "{{.P0}} пуст."
[BindFail]
description = "Bind fail."
one = "Привязка не удалась."
other = "Привязка не удалась."
[BindSuccess]
description = "Bind success."
one = "Привязка успешна."
other = "Привязка успешна."
[OauthHasBeenSuccess]
description = "Oauth has been success."
one = "Авторизация уже выполнена успешно."
other = "Авторизация уже выполнена успешно."
[OauthSuccess]
description = "Oauth success."
one = "Авторизация успешна."
other = "Авторизация успешна."
[OauthRegisterSuccess]
description = "Oauth register success."
one = "Регистрация авторизации успешна."
other = "Регистрация авторизации успешна."
[OauthRegisterFailed]
description = "Oauth register failed."
one = "Ошибка регистрации авторизации."
other = "Ошибка регистрации авторизации."
[GetOauthTokenError]
description = "Get oauth token error."
one = "Не удалось получить токен авторизации."
other = "Не удалось получить токен авторизации."
[GetOauthUserInfoError]
description = "Get oauth user info error."
one = "Не удалось получить информацию о пользователе авторизации."
other = "Не удалось получить информацию о пользователе авторизации."
[DecodeOauthUserInfoError]
description = "Decode oauth user info error."
one = "Не удалось декодировать информацию о пользователе авторизации."
other = "Не удалось декодировать информацию о пользователе авторизации."
[OldPasswordError]
description = "Old password error."
one = "Неправильный старый пароль."
other = "Неправильный старый пароль."
[DefaultGroup]
description = "Default group."
one = "Группа по умолчанию"
other = "Группа по умолчанию"
[ShareGroup]
description = "Share group."
one = "Общая группа"
other = "Общая группа"

View File

@@ -22,6 +22,12 @@ func (s *AddressBookService) InfoByUserIdAndId(userid uint, id string) *model.Ad
global.DB.Where("user_id = ? and id = ?", userid, id).First(p) global.DB.Where("user_id = ? and id = ?", userid, id).First(p)
return p return p
} }
func (s *AddressBookService) InfoByUserIdAndIdAndCid(userid uint, id string, cid uint) *model.AddressBook {
p := &model.AddressBook{}
global.DB.Where("user_id = ? and id = ? and collection_id = ?", userid, id, cid).First(p)
return p
}
func (s *AddressBookService) InfoByRowId(id uint) *model.AddressBook { func (s *AddressBookService) InfoByRowId(id uint) *model.AddressBook {
p := &model.AddressBook{} p := &model.AddressBook{}
global.DB.Where("row_id = ?", id).First(p) global.DB.Where("row_id = ?", id).First(p)
@@ -96,7 +102,7 @@ func (s *AddressBookService) UpdateAddressBook(abs []*model.AddressBook, userId
} }
func (t *AddressBookService) List(page, pageSize uint, where func(tx *gorm.DB)) (res *model.AddressBookList) { func (s *AddressBookService) List(page, pageSize uint, where func(tx *gorm.DB)) (res *model.AddressBookList) {
res = &model.AddressBookList{} res = &model.AddressBookList{}
res.Page = int64(page) res.Page = int64(page)
res.PageSize = int64(pageSize) res.PageSize = int64(pageSize)
@@ -111,34 +117,34 @@ func (t *AddressBookService) List(page, pageSize uint, where func(tx *gorm.DB))
} }
// Create 创建 // Create 创建
func (t *AddressBookService) Create(u *model.AddressBook) error { func (s *AddressBookService) Create(u *model.AddressBook) error {
res := global.DB.Create(u).Error res := global.DB.Create(u).Error
return res return res
} }
func (t *AddressBookService) Delete(u *model.AddressBook) error { func (s *AddressBookService) Delete(u *model.AddressBook) error {
return global.DB.Delete(u).Error return global.DB.Delete(u).Error
} }
// Update 更新 // Update 更新
func (t *AddressBookService) Update(u *model.AddressBook) error { func (s *AddressBookService) Update(u *model.AddressBook) error {
return global.DB.Model(u).Updates(u).Error return global.DB.Model(u).Select("*").Omit("created_at").Updates(u).Error
} }
// ShareByWebClient 分享 // ShareByWebClient 分享
func (t *AddressBookService) ShareByWebClient(m *model.ShareRecord) error { func (s *AddressBookService) ShareByWebClient(m *model.ShareRecord) error {
m.ShareToken = uuid.New().String() m.ShareToken = uuid.New().String()
return global.DB.Create(m).Error return global.DB.Create(m).Error
} }
// SharedPeer // SharedPeer
func (t *AddressBookService) SharedPeer(shareToken string) *model.ShareRecord { func (s *AddressBookService) SharedPeer(shareToken string) *model.ShareRecord {
m := &model.ShareRecord{} m := &model.ShareRecord{}
global.DB.Where("share_token = ?", shareToken).First(m) global.DB.Where("share_token = ?", shareToken).First(m)
return m return m
} }
// PlatformFromOs // PlatformFromOs
func (t *AddressBookService) PlatformFromOs(os string) string { func (s *AddressBookService) PlatformFromOs(os string) string {
if strings.Contains(os, "Android") || strings.Contains(os, "android") { if strings.Contains(os, "Android") || strings.Contains(os, "android") {
return "Android" return "Android"
} }
@@ -153,3 +159,152 @@ func (t *AddressBookService) PlatformFromOs(os string) string {
} }
return "" return ""
} }
func (s *AddressBookService) ListByUserIdAndCollectionId(userId, cid, page, pageSize uint) (res *model.AddressBookList) {
res = s.List(page, pageSize, func(tx *gorm.DB) {
tx.Where("user_id = ? and collection_id = ?", userId, cid)
})
return
}
func (s *AddressBookService) ListCollection(page, pageSize uint, where func(tx *gorm.DB)) (res *model.AddressBookCollectionList) {
res = &model.AddressBookCollectionList{}
res.Page = int64(page)
res.PageSize = int64(pageSize)
tx := global.DB.Model(&model.AddressBookCollection{})
if where != nil {
where(tx)
}
tx.Count(&res.Total)
tx.Scopes(Paginate(page, pageSize))
tx.Find(&res.AddressBookCollection)
return
}
func (s *AddressBookService) ListCollectionByIds(ids []uint) (res []*model.AddressBookCollection) {
global.DB.Where("id in ?", ids).Find(&res)
return res
}
func (s *AddressBookService) ListCollectionByUserId(userId uint) (res *model.AddressBookCollectionList) {
res = s.ListCollection(1, 100, func(tx *gorm.DB) {
tx.Where("user_id = ?", userId)
})
return
}
func (s *AddressBookService) CollectionInfoById(id uint) *model.AddressBookCollection {
p := &model.AddressBookCollection{}
global.DB.Where("id = ?", id).First(p)
return p
}
func (s *AddressBookService) CollectionReadRules(user *model.User) (res []*model.AddressBookCollectionRule) {
// personalRules
var personalRules []*model.AddressBookCollectionRule
tx2 := global.DB.Model(&model.AddressBookCollectionRule{})
tx2.Where("type = ? and to_id = ? and rule > 0", model.ShareAddressBookRuleTypePersonal, user.Id).Find(&personalRules)
res = append(res, personalRules...)
//group
var groupRules []*model.AddressBookCollectionRule
tx3 := global.DB.Model(&model.AddressBookCollectionRule{})
tx3.Where("type = ? and to_id = ? and rule > 0", model.ShareAddressBookRuleTypeGroup, user.GroupId).Find(&groupRules)
res = append(res, groupRules...)
return
}
func (s *AddressBookService) UserMaxRule(user *model.User, uid, cid uint) int {
// ismy?
if user.Id == uid {
return model.ShareAddressBookRuleRuleFullControl
}
max := 0
personalRules := &model.AddressBookCollectionRule{}
tx := global.DB.Model(personalRules)
tx.Where("type = ? and collection_id = ? and to_id = ?", model.ShareAddressBookRuleTypePersonal, cid, user.Id).First(&personalRules)
if personalRules.Id != 0 {
max = personalRules.Rule
if max == model.ShareAddressBookRuleRuleFullControl {
return max
}
}
groupRules := &model.AddressBookCollectionRule{}
tx2 := global.DB.Model(groupRules)
tx2.Where("type = ? and collection_id = ? and to_id = ?", model.ShareAddressBookRuleTypeGroup, cid, user.GroupId).First(&groupRules)
if groupRules.Id != 0 {
if groupRules.Rule > max {
max = groupRules.Rule
}
if max == model.ShareAddressBookRuleRuleFullControl {
return max
}
}
return max
}
func (s *AddressBookService) CheckUserReadPrivilege(user *model.User, uid, cid uint) bool {
return s.UserMaxRule(user, uid, cid) >= model.ShareAddressBookRuleRuleRead
}
func (s *AddressBookService) CheckUserWritePrivilege(user *model.User, uid, cid uint) bool {
return s.UserMaxRule(user, uid, cid) >= model.ShareAddressBookRuleRuleReadWrite
}
func (s *AddressBookService) CheckUserFullControlPrivilege(user *model.User, uid, cid uint) bool {
return s.UserMaxRule(user, uid, cid) >= model.ShareAddressBookRuleRuleFullControl
}
func (s *AddressBookService) CreateCollection(t *model.AddressBookCollection) error {
return global.DB.Create(t).Error
}
func (s *AddressBookService) UpdateCollection(t *model.AddressBookCollection) error {
return global.DB.Model(t).Updates(t).Error
}
func (s *AddressBookService) DeleteCollection(t *model.AddressBookCollection) error {
//删除集合下的所有规则、地址簿,再删除集合
tx := global.DB.Begin()
tx.Where("collection_id = ?", t.Id).Delete(&model.AddressBookCollectionRule{})
tx.Where("collection_id = ?", t.Id).Delete(&model.AddressBook{})
tx.Delete(t)
return tx.Commit().Error
}
func (s *AddressBookService) RuleInfoById(u uint) *model.AddressBookCollectionRule {
p := &model.AddressBookCollectionRule{}
global.DB.Where("id = ?", u).First(p)
return p
}
func (s *AddressBookService) RulePersonalInfoByToIdAndCid(toid, cid uint) *model.AddressBookCollectionRule {
p := &model.AddressBookCollectionRule{}
global.DB.Where("type = ? and to_id = ? and collection_id = ?", model.ShareAddressBookRuleTypePersonal, toid, cid).First(p)
return p
}
func (s *AddressBookService) CreateRule(t *model.AddressBookCollectionRule) error {
return global.DB.Create(t).Error
}
func (s *AddressBookService) ListRules(page uint, size uint, f func(tx *gorm.DB)) *model.AddressBookCollectionRuleList {
res := &model.AddressBookCollectionRuleList{}
res.Page = int64(page)
res.PageSize = int64(size)
tx := global.DB.Model(&model.AddressBookCollectionRule{})
if f != nil {
f(tx)
}
tx.Count(&res.Total)
tx.Scopes(Paginate(page, size))
tx.Find(&res.AddressBookCollectionRule)
return res
}
func (s *AddressBookService) UpdateRule(t *model.AddressBookCollectionRule) error {
return global.DB.Model(t).Updates(t).Error
}
func (s *AddressBookService) DeleteRule(t *model.AddressBookCollectionRule) error {
return global.DB.Delete(t).Error
}
// CheckCollectionOwner 检查Collection的所有者
func (s *AddressBookService) CheckCollectionOwner(uid uint, cid uint) bool {
p := s.CollectionInfoById(cid)
return p.UserId == uid
}

View File

@@ -44,9 +44,44 @@ func (as *AuditService) InfoByPeerIdAndConnId(peerId string, connId int64) (res
return return
} }
// InfoById // ConnInfoById
func (as *AuditService) InfoById(id uint) (res *model.AuditConn) { func (as *AuditService) ConnInfoById(id uint) (res *model.AuditConn) {
res = &model.AuditConn{} res = &model.AuditConn{}
global.DB.Where("id = ?", id).First(res) global.DB.Where("id = ?", id).First(res)
return return
} }
// FileInfoById
func (as *AuditService) FileInfoById(id uint) (res *model.AuditFile) {
res = &model.AuditFile{}
global.DB.Where("id = ?", id).First(res)
return
}
func (as *AuditService) AuditFileList(page, pageSize uint, where func(tx *gorm.DB)) (res *model.AuditFileList) {
res = &model.AuditFileList{}
res.Page = int64(page)
res.PageSize = int64(pageSize)
tx := global.DB.Model(&model.AuditFile{})
if where != nil {
where(tx)
}
tx.Count(&res.Total)
tx.Scopes(Paginate(page, pageSize))
tx.Find(&res.AuditFiles)
return
}
// CreateAuditFile
func (as *AuditService) CreateAuditFile(u *model.AuditFile) error {
res := global.DB.Create(u).Error
return res
}
func (as *AuditService) DeleteAuditFile(u *model.AuditFile) error {
return global.DB.Delete(u).Error
}
// Update 更新
func (as *AuditService) UpdateAuditFile(u *model.AuditFile) error {
return global.DB.Model(u).Updates(u).Error
}

View File

@@ -14,9 +14,9 @@ func (s *TagService) Info(id uint) *model.Tag {
global.DB.Where("id = ?", id).First(p) global.DB.Where("id = ?", id).First(p)
return p return p
} }
func (s *TagService) InfoByUserIdAndName(userid uint, name string) *model.Tag { func (s *TagService) InfoByUserIdAndNameAndCollectionId(userid uint, name string, cid uint) *model.Tag {
p := &model.Tag{} p := &model.Tag{}
global.DB.Where("user_id = ? and name = ?", userid, name).First(p) global.DB.Where("user_id = ? and name = ? and collection_id = ?", userid, name, cid).First(p)
return p return p
} }
@@ -26,7 +26,12 @@ func (s *TagService) ListByUserId(userId uint) (res *model.TagList) {
}) })
return return
} }
func (s *TagService) ListByUserIdAndCollectionId(userId, cid uint) (res *model.TagList) {
res = s.List(1, 1000, func(tx *gorm.DB) {
tx.Where("user_id = ? and collection_id = ?", userId, cid)
})
return
}
func (s *TagService) UpdateTags(userId uint, tags map[string]uint) { func (s *TagService) UpdateTags(userId uint, tags map[string]uint) {
tx := global.DB.Begin() tx := global.DB.Begin()
//先查询所有tag //先查询所有tag
@@ -58,13 +63,13 @@ func (s *TagService) UpdateTags(userId uint, tags map[string]uint) {
} }
// InfoById 根据用户id取用户信息 // InfoById 根据用户id取用户信息
func (t *TagService) InfoById(id uint) *model.Tag { func (s *TagService) InfoById(id uint) *model.Tag {
u := &model.Tag{} u := &model.Tag{}
global.DB.Where("id = ?", id).First(u) global.DB.Where("id = ?", id).First(u)
return u return u
} }
func (t *TagService) List(page, pageSize uint, where func(tx *gorm.DB)) (res *model.TagList) { func (s *TagService) List(page, pageSize uint, where func(tx *gorm.DB)) (res *model.TagList) {
res = &model.TagList{} res = &model.TagList{}
res.Page = int64(page) res.Page = int64(page)
res.PageSize = int64(pageSize) res.PageSize = int64(pageSize)
@@ -79,15 +84,15 @@ func (t *TagService) List(page, pageSize uint, where func(tx *gorm.DB)) (res *mo
} }
// Create 创建 // Create 创建
func (t *TagService) Create(u *model.Tag) error { func (s *TagService) Create(u *model.Tag) error {
res := global.DB.Create(u).Error res := global.DB.Create(u).Error
return res return res
} }
func (t *TagService) Delete(u *model.Tag) error { func (s *TagService) Delete(u *model.Tag) error {
return global.DB.Delete(u).Error return global.DB.Delete(u).Error
} }
// Update 更新 // Update 更新
func (t *TagService) Update(u *model.Tag) error { func (s *TagService) Update(u *model.Tag) error {
return global.DB.Model(u).Updates(u).Error return global.DB.Model(u).Select("*").Omit("created_at").Updates(u).Error
} }

View File

@@ -101,6 +101,11 @@ func (us *UserService) List(page, pageSize uint, where func(tx *gorm.DB)) (res *
return return
} }
func (us *UserService) ListByIds(ids []uint) (res []*model.User) {
global.DB.Where("id in ?", ids).Find(&res)
return res
}
// ListByGroupId 根据组id取用户列表 // ListByGroupId 根据组id取用户列表
func (us *UserService) ListByGroupId(groupId, page, pageSize uint) (res *model.UserList) { func (us *UserService) ListByGroupId(groupId, page, pageSize uint) (res *model.UserList) {
res = us.List(page, pageSize, func(tx *gorm.DB) { res = us.List(page, pageSize, func(tx *gorm.DB) {

View File

@@ -73,3 +73,21 @@ func RandomString(n int) string {
} }
return string(b) return string(b)
} }
// Keys 泛型函数K 是键类型V 是值类型
func Keys[K comparable, V any](m map[K]V) []K {
keys := make([]K, 0, len(m))
for k := range m {
keys = append(keys, k)
}
return keys
}
// Values 泛型函数K 是键类型V 是值类型
func Values[K comparable, V any](m map[K]V) []V {
values := make([]V, 0, len(m))
for _, v := range m {
values = append(values, v)
}
return values
}