Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e28d3bf53d | ||
|
|
6dfd40a10f | ||
|
|
05f919777f | ||
|
|
0735892b46 | ||
|
|
16e97c8efa | ||
|
|
c5687e1506 | ||
|
|
222792419f | ||
|
|
04789e08d5 | ||
|
|
929f6ddf20 | ||
|
|
6e3b16d425 | ||
|
|
ce0291a8f9 | ||
|
|
faee954f6d | ||
|
|
f09c898f16 | ||
|
|
a7c087afbb | ||
|
|
07dfba9d59 | ||
|
|
448725b760 | ||
|
|
b6be4dea21 | ||
|
|
862a1d431e | ||
|
|
8819c85ef4 | ||
|
|
e2ec387ba2 | ||
|
|
1d2d1d4c98 | ||
|
|
16b941e37f | ||
|
|
ff2c79a316 | ||
|
|
b3aee87655 | ||
|
|
73a8461a2d | ||
|
|
af4813db30 | ||
|
|
9d2b589faa | ||
|
|
aa04b225b9 | ||
|
|
fb34d0ac83 | ||
|
|
f68ec8f3a1 | ||
|
|
4b16ad29bb | ||
|
|
c554ff4a31 | ||
|
|
791a1850b8 | ||
|
|
175fdc3bd4 | ||
|
|
f20414b3a5 | ||
|
|
bf39a29e6c | ||
|
|
4ba805ac5f | ||
|
|
b2d71d4312 | ||
|
|
a35fa6f9a8 | ||
|
|
83baa140f5 | ||
|
|
b6eaa4b061 | ||
|
|
d4fdf3785b | ||
|
|
f2ea022965 | ||
|
|
fe4a115c9d | ||
|
|
4412f0309c | ||
|
|
dd78911ed9 | ||
|
|
b23a9bde8e | ||
|
|
3fe7184b4b | ||
|
|
4637879091 | ||
|
|
6d1184d332 | ||
|
|
fb8ef8a1fd | ||
|
|
ae59b6a733 | ||
|
|
605e88e04c | ||
|
|
3ef4454c05 | ||
|
|
35be09b37c | ||
|
|
891469909c | ||
|
|
6ed75bc517 | ||
|
|
caea60c732 | ||
|
|
0a78c206de | ||
|
|
a7f7c76e0e | ||
|
|
c10d132b3c | ||
|
|
8b951065ce | ||
|
|
08420f9db6 | ||
|
|
5db3c8bf0b | ||
|
|
403d9c2233 | ||
|
|
0f16f61ab3 | ||
|
|
0dd92311b2 | ||
|
|
ef4af39f94 | ||
|
|
73f3056878 | ||
|
|
f0b4b0d7c6 | ||
|
|
5d5aae6b3c | ||
|
|
4b5e316475 | ||
|
|
8ff9a12a34 | ||
|
|
6f55c5b642 | ||
|
|
99e63cadcf | ||
|
|
c0346ff9e1 | ||
|
|
d85a00f748 | ||
|
|
6a6a1ed02b | ||
|
|
4b3bbe809d | ||
|
|
63cf231bdc | ||
|
|
6aebf061a4 | ||
|
|
a2672c9489 | ||
|
|
a304da6e02 | ||
|
|
0e160f110b | ||
|
|
32a9eda8ca | ||
|
|
8622c78da0 | ||
|
|
7d6bc2a74f | ||
|
|
5224c31d61 | ||
|
|
983025538f | ||
|
|
cd5b247356 | ||
|
|
e2d72530b1 | ||
|
|
5660d40514 | ||
|
|
d486444680 | ||
|
|
2261a4292a | ||
|
|
829f8799dd | ||
|
|
e549416d94 | ||
|
|
ff77014acb | ||
|
|
daab7112be | ||
|
|
12442f1ba0 | ||
|
|
0e3f204327 | ||
|
|
d9fcfdde6a | ||
|
|
44fa22b7e5 | ||
|
|
59038e27f8 | ||
|
|
7d23ce3caf | ||
|
|
7c528facf9 | ||
|
|
f8548a6589 | ||
|
|
23c5a96fe1 | ||
|
|
c72865b181 | ||
|
|
9a2f7010e1 | ||
|
|
a72096b56d | ||
|
|
56014d35bd | ||
|
|
a7e4ce4f72 | ||
|
|
f2cf3e1060 | ||
|
|
a4433e6113 | ||
|
|
cca191aad3 | ||
|
|
edb095ab0b | ||
|
|
ac45a1b5ad | ||
|
|
83279a553a | ||
|
|
a5671e692d | ||
|
|
63f2fd2f07 | ||
|
|
5a09850fc4 | ||
|
|
aac44835ed | ||
|
|
4eed76d674 | ||
|
|
d1fc0036cb | ||
|
|
1555865612 | ||
|
|
147de065fa | ||
|
|
8dc5f82a0e | ||
|
|
3f8cb4dac5 | ||
|
|
4b9e1f02f2 | ||
|
|
18312336a4 | ||
|
|
72e3a9a841 | ||
|
|
16427164f8 | ||
|
|
5c96350e7d | ||
|
|
1dd920d192 | ||
|
|
c41038d2d8 | ||
|
|
88ec961312 | ||
|
|
a64b9ced1c | ||
|
|
c778990cf9 | ||
|
|
ba46dbbf7e | ||
|
|
3b8b8f37dd | ||
|
|
51db63cf35 | ||
|
|
9ebfd6de85 | ||
|
|
1c3afa4a70 | ||
|
|
5cddbf14c8 | ||
|
|
88765302e8 | ||
|
|
034ec6ca1b | ||
|
|
a55e501b50 | ||
|
|
e36d307d28 | ||
|
|
1e15287c83 | ||
|
|
c298ddea0c | ||
|
|
41fd387baf | ||
|
|
bf8eadfbaa | ||
|
|
a3012cfa18 | ||
|
|
592b04746d | ||
|
|
ef0410a8b9 | ||
|
|
3a430c72a2 | ||
|
|
1eaae8f213 | ||
|
|
8c0ac5621a | ||
|
|
cd74cd19ef | ||
|
|
1c5cd3ae62 | ||
|
|
7749ff0729 | ||
|
|
b77a104d9c | ||
|
|
fc898ba30c | ||
|
|
287bbd43fb | ||
|
|
65571ab2f5 | ||
|
|
17b65b412f | ||
|
|
b06d9c4e22 | ||
|
|
601d47570e | ||
|
|
29d6e36d50 | ||
|
|
abca3a9300 | ||
|
|
22e470fee5 | ||
|
|
78869a4a57 | ||
|
|
d0f8d79efb | ||
|
|
5417e383c7 | ||
|
|
49eaa831ed | ||
|
|
ae2e78e373 | ||
|
|
7bb2ce0a43 | ||
|
|
15a518c1ac | ||
|
|
4915cfa9ba | ||
|
|
de712ba9c5 | ||
|
|
c58f08af27 | ||
|
|
5609a1a618 | ||
|
|
70a03f1aba | ||
|
|
7c6aaa171e | ||
|
|
34a27ba073 | ||
|
|
956700c27f | ||
|
|
197a718f03 | ||
|
|
2c1892f40c | ||
|
|
943b1f8077 | ||
|
|
e71ea2243f | ||
|
|
daeae19194 | ||
|
|
4321a41cd7 | ||
|
|
3acfb36c5d | ||
|
|
5a53f180e4 | ||
|
|
ca79a63492 | ||
|
|
9dfe745629 | ||
|
|
18d59d7047 | ||
|
|
aee25a6c99 | ||
|
|
fea3960672 | ||
|
|
da7b70c471 | ||
|
|
3cd90c8f74 | ||
|
|
fb9173ed53 | ||
|
|
b9efc73025 | ||
|
|
64f28c17d8 | ||
|
|
1ca50b5e9d | ||
|
|
9ed376715f | ||
|
|
6698877761 | ||
|
|
2ceaa0091b | ||
|
|
6fb1fbc5b1 | ||
|
|
4909beee32 | ||
|
|
d85a799d0b | ||
|
|
d38117107d | ||
|
|
6a7ef29089 | ||
|
|
a4dd39043e | ||
|
|
dfcc7d54c1 | ||
|
|
71d1c431a9 | ||
|
|
d31d669734 | ||
|
|
c021ebfbdf | ||
|
|
485ae54e9e | ||
|
|
c5e3482538 | ||
|
|
c4b45a51d5 | ||
|
|
51186b66dc | ||
|
|
2627f6fb06 | ||
|
|
a6a6c3aefe | ||
|
|
d21b5809c4 | ||
|
|
503e908eb6 | ||
|
|
6c94566e83 | ||
|
|
095640af3f | ||
|
|
5488babfb3 | ||
|
|
962e07d65f | ||
|
|
bd2eeae01a | ||
|
|
efead3f9c7 | ||
|
|
7cb838693a | ||
|
|
e2fda47cbb | ||
|
|
0ed40318cb | ||
|
|
122b3baf6f | ||
|
|
06f007ebd9 | ||
|
|
7c1fc4fa6d | ||
|
|
e1424bcea7 | ||
|
|
b3edc9d112 | ||
|
|
68065d3372 | ||
|
|
f6a0c6466f | ||
|
|
1070022277 | ||
|
|
f9a8a966e5 | ||
|
|
3041fb82d9 | ||
|
|
0ddfbdbd23 | ||
|
|
eada376783 | ||
|
|
bc92ffc106 | ||
|
|
60b7ccdb3a | ||
|
|
9eff8ea33a | ||
|
|
17305b6a6f | ||
|
|
7d83226655 | ||
|
|
001884a4d8 | ||
|
|
461b100b6c | ||
|
|
4105f14a3f | ||
|
|
4baa8d392e | ||
|
|
bf48e8ba19 | ||
|
|
991fc86fa6 | ||
|
|
1191ade8af | ||
|
|
02232fc343 | ||
|
|
497dfb2402 | ||
|
|
f21fb5d437 | ||
|
|
8ee93b530d | ||
|
|
e833c0e0c0 | ||
|
|
d5cf3544f1 | ||
|
|
ca9a3155af | ||
|
|
b1817ca63f | ||
|
|
476f251d2c | ||
|
|
e2fa928648 | ||
|
|
3f9b370dd6 | ||
|
|
7cf4fb4157 | ||
|
|
6fb1235dd8 | ||
|
|
8aa779f611 | ||
|
|
5c4b6b5cd0 | ||
|
|
47ab3958c9 | ||
|
|
cbb3764b60 | ||
|
|
f5aadec6c0 | ||
|
|
de0523852a | ||
|
|
ba85790d8c | ||
|
|
0091a9dd7f | ||
|
|
e142cc00c6 | ||
|
|
488fedf784 | ||
|
|
ceb65cd391 | ||
|
|
72c196c6f9 | ||
|
|
28f047ec79 | ||
|
|
7e0cc33c91 | ||
|
|
05a2961814 | ||
|
|
dc8af3a460 | ||
|
|
e269341d51 | ||
|
|
ebe5bc4c3a | ||
|
|
b4965e8885 | ||
|
|
0eb733cc33 | ||
|
|
1e41784bb9 | ||
|
|
3d4e068266 | ||
|
|
abc0e9d907 | ||
|
|
5d361d05cc | ||
|
|
823c052d6d | ||
|
|
ebe39af682 | ||
|
|
8b266d4fee | ||
|
|
2ab61512cf | ||
|
|
ee679d09f7 | ||
|
|
71c44a501b | ||
|
|
f8a672070f | ||
|
|
609dfaeea0 | ||
|
|
71e3529c2f | ||
|
|
61fc53858b | ||
|
|
a843748f60 | ||
|
|
c266f57a46 | ||
|
|
86f22e2666 | ||
|
|
c42e865784 | ||
|
|
5ad31679a8 | ||
|
|
56c84c854a | ||
|
|
8118107f0f | ||
|
|
d3aebec722 | ||
|
|
808aa47856 | ||
|
|
90f8c6b4e6 | ||
|
|
5de0b522f1 | ||
|
|
98e9828e1f | ||
|
|
71ff7ebd42 | ||
|
|
bd084ced52 | ||
|
|
cab04765f0 | ||
|
|
5deaaa8a00 | ||
|
|
58d39c7aa3 | ||
|
|
87bec98a7f | ||
|
|
74662ae58b | ||
|
|
814bf48a54 | ||
|
|
a1dba6c564 | ||
|
|
418b182641 | ||
|
|
bcbbf1099d | ||
|
|
85c8377240 | ||
|
|
264ae2dffa | ||
|
|
b069e7876d | ||
|
|
41670b0d00 | ||
|
|
5bf8e176aa | ||
|
|
9787ca0895 | ||
|
|
04098cb6e1 | ||
|
|
6411be66ba | ||
|
|
0d3fd56c5e | ||
|
|
9e7908c035 | ||
|
|
08c7647c10 | ||
|
|
cbbc8259e8 | ||
|
|
aff735335b | ||
|
|
47f1043cc2 | ||
|
|
871bb328f0 | ||
|
|
d18d8c0e3f | ||
|
|
db7c43353d | ||
|
|
1847697ceb | ||
|
|
f5ffc433f7 | ||
|
|
fe36f7b2f0 | ||
|
|
4f2216d023 | ||
|
|
a214113de5 | ||
|
|
ea9dc84b91 | ||
|
|
cf6bd41319 | ||
|
|
0ab1ff9e18 | ||
|
|
c7b0996443 | ||
|
|
62ebc66259 | ||
|
|
6ce6a95e07 | ||
|
|
467b61fb20 | ||
|
|
c99261c12d | ||
|
|
c9d70584cc | ||
|
|
0a81b5b5f8 | ||
|
|
95a1bd6c21 | ||
|
|
8c2f6f0929 | ||
|
|
c5b43fae08 | ||
|
|
c485035e74 | ||
|
|
a161e3ba10 | ||
|
|
5b5943b287 | ||
|
|
69ad1b2e80 | ||
|
|
01aad9bb15 | ||
|
|
b4b246def5 | ||
|
|
752d376dd7 | ||
|
|
601e1de3b3 | ||
|
|
758f1fb1c9 | ||
|
|
d394931fce | ||
|
|
192b3b11a9 | ||
|
|
4ec08cf03a | ||
|
|
cb1a06e4a9 | ||
|
|
67b4678b2d | ||
|
|
8d390dae50 | ||
|
|
a4b40d746b | ||
|
|
ddfd9f7923 | ||
|
|
521e2c72f5 | ||
|
|
79aa573e0f | ||
|
|
5b6e56a8ec |
@@ -0,0 +1,61 @@
|
|||||||
|
name: Build & Push Docker Image
|
||||||
|
|
||||||
|
# Builds the Docker image and publishes it to the Gitea container registry
|
||||||
|
# at git.hackner.dev/thomas/rustdesk-api.
|
||||||
|
#
|
||||||
|
# Requires a running Gitea Actions runner (act_runner) and two repo secrets
|
||||||
|
# (Settings -> Actions -> Secrets):
|
||||||
|
# REGISTRY_USER - Gitea username (e.g. thomas)
|
||||||
|
# REGISTRY_PASSWORD - a Gitea access token with "write:package" scope
|
||||||
|
#
|
||||||
|
# (Alternatively the built-in ${{ secrets.GITHUB_TOKEN }} can be used with
|
||||||
|
# username ${{ gitea.actor }} if your Gitea grants it package write access.)
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
tags:
|
||||||
|
- 'v*.*.*'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
REGISTRY: git.hackner.dev
|
||||||
|
IMAGE_NAME: ${{ github.repository }} # -> thomas/rustdesk-api
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
docker:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Log in to the Gitea container registry
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: ${{ env.REGISTRY }}
|
||||||
|
username: ${{ secrets.REGISTRY_USER }}
|
||||||
|
password: ${{ secrets.REGISTRY_PASSWORD }}
|
||||||
|
|
||||||
|
- name: Extract metadata (tags, labels)
|
||||||
|
id: meta
|
||||||
|
uses: docker/metadata-action@v5
|
||||||
|
with:
|
||||||
|
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||||
|
tags: |
|
||||||
|
type=semver,pattern={{version}}
|
||||||
|
type=raw,value=latest,enable={{is_default_branch}}
|
||||||
|
|
||||||
|
- name: Build and push image
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
file: ./Dockerfile.dev
|
||||||
|
push: true
|
||||||
|
build-args: |
|
||||||
|
GO_VERSION=1.23
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
@@ -1,298 +0,0 @@
|
|||||||
name: Build
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
BASE_IMAGE_NAMESPACE:
|
|
||||||
description: 'Base image namespace (Default: Your Github username)'
|
|
||||||
required: false
|
|
||||||
default: ''
|
|
||||||
DOCKERHUB_IMAGE_NAMESPACE:
|
|
||||||
description: 'Docker Hub image namespace (Default: Your Github username)'
|
|
||||||
required: false
|
|
||||||
default: ''
|
|
||||||
GHCR_IMAGE_NAMESPACE:
|
|
||||||
description: 'GitHub Container Registry image namespace (Default: Your Github username)'
|
|
||||||
required: false
|
|
||||||
default: ''
|
|
||||||
SKIP_DOCKER_HUB:
|
|
||||||
description: 'Set to true to skip pushing to Docker Hub (default: false)'
|
|
||||||
required: false
|
|
||||||
default: 'false'
|
|
||||||
SKIP_GHCR:
|
|
||||||
description: 'Set to true to skip pushing to GHCR (default: false)'
|
|
||||||
required: false
|
|
||||||
default: 'false'
|
|
||||||
WEBCLIENT_SOURCE_LOCATION:
|
|
||||||
description: 'Web Client API Repository'
|
|
||||||
required: true
|
|
||||||
default: 'https://github.com/lejianwen/rustdesk-api-web'
|
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- 'v*.*.*' # 当推送带有版本号的 tag(例如 v1.0.0)时触发工作流
|
|
||||||
- 'test*'
|
|
||||||
|
|
||||||
env:
|
|
||||||
LATEST_TAG: latest
|
|
||||||
WEBCLIENT_SOURCE_LOCATION: ${{ github.event.inputs.WEBCLIENT_SOURCE_LOCATION || 'https://github.com/lejianwen/rustdesk-api-web' }}
|
|
||||||
BASE_IMAGE_NAMESPACE: ${{ github.event.inputs.BASE_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 }}
|
|
||||||
SKIP_DOCKER_HUB: ${{ github.event.inputs.SKIP_DOCKER_HUB || 'false' }}
|
|
||||||
SKIP_GHCR: ${{ github.event.inputs.SKIP_GHCR || 'false' }}
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
job:
|
|
||||||
- { platform: "amd64", goos: "linux", file_ext: "tar.gz" }
|
|
||||||
- { platform: "arm64", goos: "linux", file_ext: "tar.gz" }
|
|
||||||
- { platform: "armv7l", goos: "linux", file_ext: "tar.gz" }
|
|
||||||
- { platform: "amd64", goos: "windows", file_ext: "zip" }
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Set up Go environment
|
|
||||||
uses: actions/setup-go@v4
|
|
||||||
with:
|
|
||||||
go-version: '1.22' # 选择 Go 版本
|
|
||||||
|
|
||||||
- name: Set up npm
|
|
||||||
uses: actions/setup-node@v2
|
|
||||||
with:
|
|
||||||
node-version: '20'
|
|
||||||
|
|
||||||
|
|
||||||
- name: build rustdesk-api-web
|
|
||||||
run: |
|
|
||||||
git clone ${{ env.WEBCLIENT_SOURCE_LOCATION }}
|
|
||||||
cd rustdesk-api-web
|
|
||||||
npm install
|
|
||||||
npm run build
|
|
||||||
mkdir ../resources/admin/ -p
|
|
||||||
cp -ar dist/* ../resources/admin/
|
|
||||||
|
|
||||||
- name: tidy
|
|
||||||
run: go mod tidy
|
|
||||||
|
|
||||||
- name: swag
|
|
||||||
run: |
|
|
||||||
go install github.com/swaggo/swag/cmd/swag@latest
|
|
||||||
swag init -g cmd/apimain.go --output docs/api --instanceName api --exclude http/controller/admin
|
|
||||||
swag init -g cmd/apimain.go --output docs/admin --instanceName admin --exclude http/controller/api
|
|
||||||
|
|
||||||
- name: Build for ${{ matrix.job.goos }}-${{ matrix.job.platform }}
|
|
||||||
run: |
|
|
||||||
mkdir release -p
|
|
||||||
cp -ar resources release/
|
|
||||||
cp -ar docs release/
|
|
||||||
cp -ar conf release/
|
|
||||||
mkdir -p release/data
|
|
||||||
mkdir -p release/runtime
|
|
||||||
if [ "${{ matrix.job.goos }}" = "windows" ]; then
|
|
||||||
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
|
|
||||||
zip -r ${{ matrix.job.goos}}-${{ matrix.job.platform }}.${{matrix.job.file_ext}} ./release
|
|
||||||
else
|
|
||||||
if [ "${{ matrix.job.platform }}" = "arm64" ]; then
|
|
||||||
wget https://musl.cc/aarch64-linux-musl-cross.tgz
|
|
||||||
tar -xf aarch64-linux-musl-cross.tgz
|
|
||||||
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
|
|
||||||
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
|
|
||||||
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
|
|
||||||
fi
|
|
||||||
tar -czf ${{ matrix.job.goos}}-${{ matrix.job.platform }}.${{matrix.job.file_ext}} ./release
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Upload artifact
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: rustdesk-api-${{ matrix.job.goos }}-${{ matrix.job.platform }}
|
|
||||||
path: |
|
|
||||||
${{ matrix.job.goos}}-${{ matrix.job.platform }}.${{matrix.job.file_ext}}
|
|
||||||
- name: Upload to GitHub Release
|
|
||||||
uses: softprops/action-gh-release@v2
|
|
||||||
with:
|
|
||||||
files: |
|
|
||||||
${{ matrix.job.goos}}-${{ matrix.job.platform }}.${{matrix.job.file_ext}}
|
|
||||||
# tag_name: ${{ env.LATEST_TAG }}
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
docker:
|
|
||||||
name: Push Docker Image
|
|
||||||
needs: build
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
job:
|
|
||||||
- { platform: "amd64", goos: "linux", docker_platform: "linux/amd64" }
|
|
||||||
- { platform: "arm64", goos: "linux", docker_platform: "linux/arm64" }
|
|
||||||
- { platform: "armv7l", goos: "linux", docker_platform: "linux/arm/v7" }
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v2
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v2
|
|
||||||
|
|
||||||
- name: Log in to Docker Hub
|
|
||||||
if: ${{ env.SKIP_DOCKER_HUB == 'false' }} # Only log in if SKIP_DOCKER_HUB is false
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKER_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
|
|
||||||
|
|
||||||
- name: Log in to GitHub Container Registry
|
|
||||||
if: ${{ env.SKIP_GHCR == 'false' }} # Only log in if GHCR push is enabled
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Extract version from tag
|
|
||||||
id: vars
|
|
||||||
run: |
|
|
||||||
if [[ "${GITHUB_REF}" == refs/tags/* ]]; then
|
|
||||||
echo "TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
|
|
||||||
else
|
|
||||||
echo "TAG=latest" >> $GITHUB_ENV # Default to 'latest' if not a tag
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Extract metadata (tags, labels) for Docker
|
|
||||||
id: meta
|
|
||||||
uses: docker/metadata-action@v4
|
|
||||||
with:
|
|
||||||
images: ${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api
|
|
||||||
|
|
||||||
- name: Download binaries
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
name: rustdesk-api-${{ matrix.job.goos }}-${{ matrix.job.platform }}
|
|
||||||
path: ./
|
|
||||||
|
|
||||||
- name: Unzip binaries
|
|
||||||
run: |
|
|
||||||
mkdir -p ${{ matrix.job.platform }}
|
|
||||||
tar -xzf ${{ matrix.job.goos }}-${{ matrix.job.platform }}.tar.gz -C ${{ matrix.job.platform }}
|
|
||||||
file ${{ matrix.job.platform }}/apimain
|
|
||||||
|
|
||||||
- name: Build and push Docker image to Docker Hub ${{ matrix.job.platform }}
|
|
||||||
if: ${{ env.SKIP_DOCKER_HUB == 'false' }} # Only run this step if SKIP_DOCKER_HUB is false
|
|
||||||
uses: docker/build-push-action@v5
|
|
||||||
with:
|
|
||||||
context: "."
|
|
||||||
file: ./Dockerfile
|
|
||||||
platforms: ${{ matrix.job.docker_platform }}
|
|
||||||
push: true
|
|
||||||
provenance: false
|
|
||||||
build-args: |
|
|
||||||
BUILDARCH=${{ matrix.job.platform }}
|
|
||||||
tags: |
|
|
||||||
${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.LATEST_TAG }}-${{ matrix.job.platform }},
|
|
||||||
${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-${{ matrix.job.platform }}
|
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
|
||||||
|
|
||||||
- name: Build and push Docker image to GHCR ${{ matrix.job.platform }}
|
|
||||||
if: ${{ env.SKIP_GHCR == 'false' }} # Only run this step if SKIP_GHCR is false
|
|
||||||
uses: docker/build-push-action@v5
|
|
||||||
with:
|
|
||||||
context: "."
|
|
||||||
file: ./Dockerfile
|
|
||||||
platforms: ${{ matrix.job.docker_platform }}
|
|
||||||
push: true
|
|
||||||
provenance: false
|
|
||||||
build-args: |
|
|
||||||
BUILDARCH=${{ matrix.job.platform }}
|
|
||||||
tags: |
|
|
||||||
ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.LATEST_TAG }}-${{ matrix.job.platform }},
|
|
||||||
ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-${{ matrix.job.platform }}
|
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
|
||||||
|
|
||||||
#
|
|
||||||
docker-manifest:
|
|
||||||
name: Push Docker Manifest
|
|
||||||
needs: docker
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Extract version from tag
|
|
||||||
id: vars
|
|
||||||
run: |
|
|
||||||
if [[ "${GITHUB_REF}" == refs/tags/* ]]; then
|
|
||||||
echo "TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
|
|
||||||
else
|
|
||||||
echo "TAG=latest" >> $GITHUB_ENV # Default to 'latest' if not a tag
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Log in to Docker Hub
|
|
||||||
if: ${{ env.SKIP_DOCKER_HUB == 'false' }} # Only log in if Docker Hub push is enabled
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKER_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
|
|
||||||
|
|
||||||
- name: Log in to GitHub Container Registry
|
|
||||||
if: ${{ env.SKIP_GHCR == 'false' }} # Only log in if GHCR push is enabled
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Create and push manifest Docker Hub (:version)
|
|
||||||
if: ${{ env.SKIP_DOCKER_HUB == 'false' }}
|
|
||||||
uses: Noelware/docker-manifest-action@master
|
|
||||||
with:
|
|
||||||
base-image: ${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}
|
|
||||||
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
|
|
||||||
push: true
|
|
||||||
|
|
||||||
- name: Create and push manifest GHCR (:version)
|
|
||||||
if: ${{ env.SKIP_GHCR == 'false' }}
|
|
||||||
uses: Noelware/docker-manifest-action@master
|
|
||||||
with:
|
|
||||||
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,
|
|
||||||
ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-armv7l,
|
|
||||||
ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-arm64
|
|
||||||
push: true
|
|
||||||
amend: true
|
|
||||||
|
|
||||||
- name: Create and push manifest Docker Hub (:latest)
|
|
||||||
if: ${{ env.SKIP_DOCKER_HUB == 'false' }}
|
|
||||||
uses: Noelware/docker-manifest-action@master
|
|
||||||
with:
|
|
||||||
base-image: ${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api:latest
|
|
||||||
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
|
|
||||||
push: true
|
|
||||||
|
|
||||||
- name: Create and push manifest GHCR (:latest)
|
|
||||||
if: ${{ env.SKIP_GHCR == 'false' }}
|
|
||||||
uses: Noelware/docker-manifest-action@master
|
|
||||||
with:
|
|
||||||
base-image: ghcr.io/${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api:latest
|
|
||||||
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
|
|
||||||
push: true
|
|
||||||
amend: true
|
|
||||||
@@ -1,271 +0,0 @@
|
|||||||
name: Build Test
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
BASE_IMAGE_NAMESPACE:
|
|
||||||
description: 'Base image namespace (Default: Your Github username)'
|
|
||||||
required: false
|
|
||||||
default: ''
|
|
||||||
DOCKERHUB_IMAGE_NAMESPACE:
|
|
||||||
description: 'Docker Hub image namespace (Default: Your Github username)'
|
|
||||||
required: false
|
|
||||||
default: ''
|
|
||||||
GHCR_IMAGE_NAMESPACE:
|
|
||||||
description: 'GitHub Container Registry image namespace (Default: Your Github username)'
|
|
||||||
required: false
|
|
||||||
default: ''
|
|
||||||
SKIP_DOCKER_HUB:
|
|
||||||
description: 'Set to true to skip pushing to Docker Hub (default: false)'
|
|
||||||
required: false
|
|
||||||
default: 'false'
|
|
||||||
SKIP_GHCR:
|
|
||||||
description: 'Set to true to skip pushing to GHCR (default: false)'
|
|
||||||
required: false
|
|
||||||
default: 'false'
|
|
||||||
WEBCLIENT_SOURCE_LOCATION:
|
|
||||||
description: 'Web Client API Repository'
|
|
||||||
required: true
|
|
||||||
default: 'https://github.com/lejianwen/rustdesk-api-web'
|
|
||||||
|
|
||||||
env:
|
|
||||||
LATEST_TAG: latest
|
|
||||||
WEBCLIENT_SOURCE_LOCATION: ${{ github.event.inputs.WEBCLIENT_SOURCE_LOCATION || 'https://github.com/lejianwen/rustdesk-api-web' }}
|
|
||||||
BASE_IMAGE_NAMESPACE: ${{ github.event.inputs.BASE_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 }}
|
|
||||||
SKIP_DOCKER_HUB: ${{ github.event.inputs.SKIP_DOCKER_HUB || 'false' }}
|
|
||||||
SKIP_GHCR: ${{ github.event.inputs.SKIP_GHCR || 'false' }}
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
job:
|
|
||||||
- { platform: "amd64", goos: "linux", file_ext: "tar.gz" }
|
|
||||||
- { platform: "arm64", goos: "linux", file_ext: "tar.gz" }
|
|
||||||
- { platform: "armv7l", goos: "linux", file_ext: "tar.gz" }
|
|
||||||
- { platform: "amd64", goos: "windows", file_ext: "zip" }
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Set up Go environment
|
|
||||||
uses: actions/setup-go@v4
|
|
||||||
with:
|
|
||||||
go-version: '1.22' # 选择 Go 版本
|
|
||||||
|
|
||||||
- name: Set up npm
|
|
||||||
uses: actions/setup-node@v2
|
|
||||||
with:
|
|
||||||
node-version: '20'
|
|
||||||
|
|
||||||
|
|
||||||
- name: build rustdesk-api-web
|
|
||||||
run: |
|
|
||||||
git clone ${{ env.WEBCLIENT_SOURCE_LOCATION }}
|
|
||||||
cd rustdesk-api-web
|
|
||||||
npm install
|
|
||||||
npm run build
|
|
||||||
mkdir ../resources/admin/ -p
|
|
||||||
cp -ar dist/* ../resources/admin/
|
|
||||||
|
|
||||||
- name: tidy
|
|
||||||
run: go mod tidy
|
|
||||||
|
|
||||||
- name: swag
|
|
||||||
run: |
|
|
||||||
go install github.com/swaggo/swag/cmd/swag@latest
|
|
||||||
swag init -g cmd/apimain.go --output docs/api --instanceName api --exclude http/controller/admin
|
|
||||||
swag init -g cmd/apimain.go --output docs/admin --instanceName admin --exclude http/controller/api
|
|
||||||
|
|
||||||
- name: Build for ${{ matrix.job.goos }}-${{ matrix.job.platform }}
|
|
||||||
run: |
|
|
||||||
mkdir release -p
|
|
||||||
cp -ar resources release/
|
|
||||||
cp -ar docs release/
|
|
||||||
cp -ar conf release/
|
|
||||||
mkdir -p release/data
|
|
||||||
mkdir -p release/runtime
|
|
||||||
if [ "${{ matrix.job.goos }}" = "windows" ]; then
|
|
||||||
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
|
|
||||||
zip -r ${{ matrix.job.goos}}-${{ matrix.job.platform }}.${{matrix.job.file_ext}} ./release
|
|
||||||
else
|
|
||||||
if [ "${{ matrix.job.platform }}" = "arm64" ]; then
|
|
||||||
wget https://musl.cc/aarch64-linux-musl-cross.tgz
|
|
||||||
tar -xf aarch64-linux-musl-cross.tgz
|
|
||||||
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
|
|
||||||
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
|
|
||||||
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
|
|
||||||
fi
|
|
||||||
tar -czf ${{ matrix.job.goos}}-${{ matrix.job.platform }}.${{matrix.job.file_ext}} ./release
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Upload artifact
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: rustdesk-api-${{ matrix.job.goos }}-${{ matrix.job.platform }}
|
|
||||||
path: |
|
|
||||||
${{ matrix.job.goos}}-${{ matrix.job.platform }}.${{matrix.job.file_ext}}
|
|
||||||
- name: Upload to GitHub Release
|
|
||||||
uses: softprops/action-gh-release@v2
|
|
||||||
with:
|
|
||||||
files: |
|
|
||||||
${{ matrix.job.goos}}-${{ matrix.job.platform }}.${{matrix.job.file_ext}}
|
|
||||||
tag_name: test
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
docker:
|
|
||||||
name: Push Docker Image
|
|
||||||
needs: build
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
job:
|
|
||||||
- { platform: "amd64", goos: "linux", docker_platform: "linux/amd64" }
|
|
||||||
- { platform: "arm64", goos: "linux", docker_platform: "linux/arm64" }
|
|
||||||
- { platform: "armv7l", goos: "linux", docker_platform: "linux/arm/v7" }
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v2
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v2
|
|
||||||
|
|
||||||
- name: Log in to Docker Hub
|
|
||||||
if: ${{ env.SKIP_DOCKER_HUB == 'false' }} # Only log in if SKIP_DOCKER_HUB is false
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKER_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
|
|
||||||
|
|
||||||
- name: Log in to GitHub Container Registry
|
|
||||||
if: ${{ env.SKIP_GHCR == 'false' }} # Only log in if GHCR push is enabled
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Extract version from tag
|
|
||||||
id: vars
|
|
||||||
run: |
|
|
||||||
if [[ "${GITHUB_REF}" == refs/tags/* ]]; then
|
|
||||||
echo "TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
|
|
||||||
else
|
|
||||||
echo "TAG=test" >> $GITHUB_ENV # Default to 'test' if not a tag
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Extract metadata (tags, labels) for Docker
|
|
||||||
id: meta
|
|
||||||
uses: docker/metadata-action@v4
|
|
||||||
with:
|
|
||||||
images: ${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api
|
|
||||||
|
|
||||||
- name: Download binaries
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
name: rustdesk-api-${{ matrix.job.goos }}-${{ matrix.job.platform }}
|
|
||||||
path: ./
|
|
||||||
|
|
||||||
- name: Unzip binaries
|
|
||||||
run: |
|
|
||||||
mkdir -p ${{ matrix.job.platform }}
|
|
||||||
tar -xzf ${{ matrix.job.goos }}-${{ matrix.job.platform }}.tar.gz -C ${{ matrix.job.platform }}
|
|
||||||
file ${{ matrix.job.platform }}/apimain
|
|
||||||
|
|
||||||
- name: Build and push Docker image to Docker Hub ${{ matrix.job.platform }}
|
|
||||||
if: ${{ env.SKIP_DOCKER_HUB == 'false' }} # Only run this step if SKIP_DOCKER_HUB is false
|
|
||||||
uses: docker/build-push-action@v5
|
|
||||||
with:
|
|
||||||
context: "."
|
|
||||||
file: ./Dockerfile
|
|
||||||
platforms: ${{ matrix.job.docker_platform }}
|
|
||||||
push: true
|
|
||||||
provenance: false
|
|
||||||
build-args: |
|
|
||||||
BUILDARCH=${{ matrix.job.platform }}
|
|
||||||
tags: |
|
|
||||||
${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-${{ matrix.job.platform }}
|
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
|
||||||
|
|
||||||
- name: Build and push Docker image to GHCR ${{ matrix.job.platform }}
|
|
||||||
if: ${{ env.SKIP_GHCR == 'false' }} # Only run this step if SKIP_GHCR is false
|
|
||||||
uses: docker/build-push-action@v5
|
|
||||||
with:
|
|
||||||
context: "."
|
|
||||||
file: ./Dockerfile
|
|
||||||
platforms: ${{ matrix.job.docker_platform }}
|
|
||||||
push: true
|
|
||||||
provenance: false
|
|
||||||
build-args: |
|
|
||||||
BUILDARCH=${{ matrix.job.platform }}
|
|
||||||
tags: |
|
|
||||||
ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-${{ matrix.job.platform }}
|
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
|
||||||
|
|
||||||
#
|
|
||||||
docker-manifest:
|
|
||||||
name: Push Docker Manifest
|
|
||||||
needs: docker
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Extract version from tag
|
|
||||||
id: vars
|
|
||||||
run: |
|
|
||||||
if [[ "${GITHUB_REF}" == refs/tags/* ]]; then
|
|
||||||
echo "TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
|
|
||||||
else
|
|
||||||
echo "TAG=test" >> $GITHUB_ENV # Default to 'test' if not a tag
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Log in to Docker Hub
|
|
||||||
if: ${{ env.SKIP_DOCKER_HUB == 'false' }} # Only log in if Docker Hub push is enabled
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKER_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
|
|
||||||
|
|
||||||
- name: Log in to GitHub Container Registry
|
|
||||||
if: ${{ env.SKIP_GHCR == 'false' }} # Only log in if GHCR push is enabled
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Create and push manifest Docker Hub (:version)
|
|
||||||
if: ${{ env.SKIP_DOCKER_HUB == 'false' }}
|
|
||||||
uses: Noelware/docker-manifest-action@master
|
|
||||||
with:
|
|
||||||
base-image: ${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}
|
|
||||||
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
|
|
||||||
push: true
|
|
||||||
|
|
||||||
- name: Create and push manifest GHCR (:version)
|
|
||||||
if: ${{ env.SKIP_GHCR == 'false' }}
|
|
||||||
uses: Noelware/docker-manifest-action@master
|
|
||||||
with:
|
|
||||||
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,
|
|
||||||
ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-armv7l,
|
|
||||||
ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-arm64
|
|
||||||
push: true
|
|
||||||
amend: true
|
|
||||||
@@ -1,13 +1,8 @@
|
|||||||
.idea
|
.idea
|
||||||
runtime/*
|
runtime/*
|
||||||
!runtime
|
!runtime
|
||||||
!runtime/cache
|
|
||||||
!runtime/cache/.gitkeep
|
!runtime/cache/.gitkeep
|
||||||
go.sum
|
go.sum
|
||||||
resources/*
|
resources/admin
|
||||||
!resources/public/upload/.gitignore
|
|
||||||
!resources/web
|
|
||||||
!resources/web2
|
|
||||||
!resources/i18n
|
|
||||||
release
|
release
|
||||||
data
|
data/rustdeskapi.db
|
||||||
@@ -2,9 +2,8 @@ FROM alpine
|
|||||||
|
|
||||||
ARG BUILDARCH
|
ARG BUILDARCH
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
RUN apk add --no-cache tzdata file
|
RUN apk add --no-cache tzdata
|
||||||
COPY ./${BUILDARCH}/release /app/
|
COPY ./${BUILDARCH}/release /app/
|
||||||
RUN file /app/apimain
|
|
||||||
VOLUME /app/data
|
VOLUME /app/data
|
||||||
|
|
||||||
EXPOSE 21114
|
EXPOSE 21114
|
||||||
|
|||||||
@@ -42,11 +42,11 @@ RUN if [ "$COUNTRY" = "CN" ] ; then \
|
|||||||
fi && \
|
fi && \
|
||||||
apk update && apk add --no-cache git
|
apk update && apk add --no-cache git
|
||||||
|
|
||||||
ARG FREONTEND_GIT_REPO=https://github.com/lejianwen/rustdesk-api-web.git
|
ARG FRONTEND_GIT_REPO=https://github.com/lejianwen/rustdesk-api-web.git
|
||||||
ARG FRONTEND_GIT_BRANCH=master
|
ARG FRONTEND_GIT_BRANCH=master
|
||||||
# Clone the frontend repository
|
# Clone the frontend repository
|
||||||
|
|
||||||
RUN git clone -b $FRONTEND_GIT_BRANCH $FREONTEND_GIT_REPO .
|
RUN git clone -b $FRONTEND_GIT_BRANCH $FRONTEND_GIT_REPO .
|
||||||
|
|
||||||
# Install required tools without caching index to minimize image size
|
# Install required tools without caching index to minimize image size
|
||||||
RUN if [ "$COUNTRY" = "CN" ] ; then \
|
RUN if [ "$COUNTRY" = "CN" ] ; then \
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
FROM rustdesk/rustdesk-server-s6:latest AS server
|
||||||
|
|
||||||
|
FROM alpine
|
||||||
|
|
||||||
|
ARG BUILDARCH
|
||||||
|
WORKDIR /app
|
||||||
|
RUN apk add --no-cache tzdata
|
||||||
|
COPY ./${BUILDARCH}/release /app/
|
||||||
|
|
||||||
|
COPY --from=server /init /init
|
||||||
|
COPY --from=server /etc/s6-overlay /etc/s6-overlay
|
||||||
|
COPY --from=server /package /package
|
||||||
|
COPY --from=server /usr/bin/healthcheck.sh /usr/bin/healthcheck.sh
|
||||||
|
COPY --from=server /usr/bin/hbbr /usr/bin/hbbr
|
||||||
|
COPY --from=server /usr/bin/hbbs /usr/bin/hbbs
|
||||||
|
COPY --from=server /usr/bin/rustdesk-utils /usr/bin/rustdesk-utils
|
||||||
|
COPY --from=server /command /command
|
||||||
|
|
||||||
|
RUN \
|
||||||
|
mkdir -p /etc/s6-overlay/s6-rc.d/api && \
|
||||||
|
echo -e "key-secret\nhbbs" > /etc/s6-overlay/s6-rc.d/api/dependencies && \
|
||||||
|
echo "longrun" > /etc/s6-overlay/s6-rc.d/api/type && \
|
||||||
|
echo "#!/command/with-contenv sh" > /etc/s6-overlay/s6-rc.d/api/run && \
|
||||||
|
echo "cd /app" >> /etc/s6-overlay/s6-rc.d/api/run && \
|
||||||
|
echo "./apimain" >> /etc/s6-overlay/s6-rc.d/api/run && \
|
||||||
|
touch /etc/s6-overlay/s6-rc.d/user/contents.d/api && \
|
||||||
|
echo "/package/admin/s6/command/s6-svstat /run/s6-rc/servicedirs/api || exit 1" >> /usr/bin/healthcheck.sh && \
|
||||||
|
ln -s /run /var/run
|
||||||
|
|
||||||
|
ENV RELAY=relay.example.com
|
||||||
|
ENV ENCRYPTED_ONLY=0
|
||||||
|
|
||||||
|
VOLUME /data
|
||||||
|
VOLUME /app/data
|
||||||
|
|
||||||
|
EXPOSE 21114 21115 21116 21116/udp 21117 21118 21119
|
||||||
|
|
||||||
|
ENTRYPOINT ["/init"]
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2024-present Lejianwen and contributors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -1,471 +1,250 @@
|
|||||||
# RustDesk API
|
# RustDesk API
|
||||||
|
|
||||||
[English Doc](README_EN.md)
|
[中文文档](README_EN.md)
|
||||||
|
|
||||||
本项目使用 Go 实现了 RustDesk 的 API,并包含了 Web Admin 和 Web 客户端。RustDesk 是一个远程桌面软件,提供了自托管的解决方案。
|
This project implements the RustDesk API using Go, and includes both a web UI and web client. RustDesk is a remote
|
||||||
|
desktop software that provides self-hosted solutions.
|
||||||
|
|
||||||
<div align=center>
|
<div align=center>
|
||||||
<img src="https://img.shields.io/badge/golang-1.22-blue"/>
|
<img src="https://img.shields.io/badge/golang-1.22-blue"/>
|
||||||
<img src="https://img.shields.io/badge/gin-v1.9.0-lightBlue"/>
|
<img src="https://img.shields.io/badge/gin-v1.9.0-lightBlue"/>
|
||||||
<img src="https://img.shields.io/badge/gorm-v1.25.7-green"/>
|
<img src="https://img.shields.io/badge/gorm-v1.25.7-green"/>
|
||||||
<img src="https://img.shields.io/badge/swag-v1.16.3-yellow"/>
|
<img src="https://img.shields.io/badge/swag-v1.16.3-yellow"/>
|
||||||
|
<img src="https://goreportcard.com/badge/github.com/lejianwen/rustdesk-api/v2"/>
|
||||||
<img src="https://github.com/lejianwen/rustdesk-api/actions/workflows/build.yml/badge.svg"/>
|
<img src="https://github.com/lejianwen/rustdesk-api/actions/workflows/build.yml/badge.svg"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
# 特性
|
## Better used with [lejianwen/rustdesk-server].
|
||||||
|
> [lejianwen/rustdesk-server] is a fork of the official RustDesk Server repository.
|
||||||
|
> 1. Solves the API connection timeout issue.
|
||||||
|
> 2. Can enforce login before initiating a connection.
|
||||||
|
> 3. Supports client websocket.
|
||||||
|
|
||||||
- PC端API
|
|
||||||
- 个人版API
|
# Features
|
||||||
- 登录
|
|
||||||
- 地址簿
|
- PC API
|
||||||
- 群组
|
- Personal API
|
||||||
- 授权登录,支持`github`, `google` 和 `OIDC` 登录,支持`web后台`授权登录
|
- Login
|
||||||
|
- Address Book
|
||||||
|
- Groups
|
||||||
|
- Authorized login,
|
||||||
|
- supports `GitHub`, `Google` and `OIDC` login,
|
||||||
|
- supports `web admin` authorized login,
|
||||||
|
- supports LDAP(test AD and openladp) if API Server config
|
||||||
- i18n
|
- i18n
|
||||||
- Web Admin
|
- Web Admin
|
||||||
- 用户管理
|
- User Management
|
||||||
- 设备管理
|
- Device Management
|
||||||
- 地址簿管理
|
- Address Book Management
|
||||||
- 标签管理
|
- Tag Management
|
||||||
- 群组管理
|
- Group Management
|
||||||
- Oauth 管理
|
- OAuth Management
|
||||||
- 登录日志
|
- LDAP Config by config file or ENV
|
||||||
- 链接日志
|
- Login Logs
|
||||||
- 文件传输日志
|
- Connection Logs
|
||||||
- 快速使用web client
|
- File Transfer Logs
|
||||||
|
- Quick access to web client
|
||||||
- i18n
|
- i18n
|
||||||
- 通过 web client 分享给游客
|
- Share to guest by web client
|
||||||
|
- Server control (some simple official commands [WIKI](https://github.com/lejianwen/rustdesk-api/wiki/Rustdesk-Command))
|
||||||
- Web Client
|
- Web Client
|
||||||
- 自动获取API server
|
- Automatically obtain API server
|
||||||
- 自动获取ID服务器和KEY
|
- Automatically obtain ID server and KEY
|
||||||
- 自动获取地址簿
|
- Automatically obtain address book
|
||||||
- 游客通过临时分享链接直接远程到设备
|
- Visitors are remotely to the device via a temporary sharing link
|
||||||
- v2 Preview
|
|
||||||
- CLI
|
- CLI
|
||||||
- 重置管理员密码
|
- Reset admin password
|
||||||
|
|
||||||
## 使用前准备
|
## Overview
|
||||||
|
|
||||||
### [Rustdesk](https://github.com/rustdesk/rustdesk)
|
### API Service
|
||||||
|
Basic implementation of the PC client's primary interfaces.Supports the Personal version api, which can be enabled by configuring the `rustdesk.personal` file or the `RUSTDESK_API_RUSTDESK_PERSONAL` environment variable.
|
||||||
|
|
||||||
#### PC客户端使用的是 ***1.3.0***,经测试 ***1.2.6+*** 都可以
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td width="50%" align="center" colspan="2"><b>Login</b></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="50%" align="center" colspan="2"><img src="docs/en_img/pc_login.png"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="50%" align="center"><b>Address Book</b></td>
|
||||||
|
<td width="50%" align="center"><b>Groups</b></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="50%" align="center"><img src="docs/en_img/pc_ab.png"></td>
|
||||||
|
<td width="50%" align="center"><img src="docs/en_img/pc_gr.png"></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
#### 关于PC端链接超时或者链接不上的问题以及解决方案
|
### Web Admin
|
||||||
##### 链接不上或者超时
|
|
||||||
因为server端相对于客户端落后版本,server不会响应客户端的`secure_tcp`请求,所以客户端超时。
|
|
||||||
相关代码代码位置在`https://github.com/rustdesk/rustdesk/blob/master/src/client.rs#L322`
|
|
||||||
```rust
|
|
||||||
if !key.is_empty() && !token.is_empty() {
|
|
||||||
// mainly for the security of token
|
|
||||||
allow_err!(secure_tcp(&mut socket, key).await);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
可看到当`key`和`token`都不为空时,会调用`secure_tcp`,但是server端不会响应,所以客户端超时
|
|
||||||
`secure_tcp` 代码位置在 `https://github.com/rustdesk/rustdesk/blob/master/src/common.rs#L1203`
|
|
||||||
|
|
||||||
##### 4种解决方案
|
* The frontend and backend are separated to provide a user-friendly management interface, primarily for managing and
|
||||||
1. server端指定key。
|
displaying data.Frontend code is available at [rustdesk-api-web](https://github.com/lejianwen/rustdesk-api-web)
|
||||||
- 优点:简单
|
|
||||||
- 缺点:链接不是加密的
|
|
||||||
```bash
|
|
||||||
hbbs -r <relay-server-ip[:port]> -k <key>
|
|
||||||
hbbr -k <key>
|
|
||||||
```
|
|
||||||
比如
|
|
||||||
```bash
|
|
||||||
hbbs -r <relay-server-ip[:port]> -k abc1234567
|
|
||||||
hbbr -k abc1234567
|
|
||||||
```
|
|
||||||
2. server端使用系统生成的key,或者自定义的密钥对,但如果client已登录,链接时容易超时或者链接不上,可以退出登录后再链接就可以了,webclient可以不用退出登录
|
|
||||||
- 优点:链接加密
|
|
||||||
- 缺点:操作麻烦
|
|
||||||
3. server端使用系统生成的key,或者自定义的密钥对,fork官方客户端的代码将`secure_tcp`修改成直接返回,然后通过`Github Actions`编译,下载编译后的客户端。
|
|
||||||
参考[官方文档](https://rustdesk.com/docs/en/dev/build/all/)
|
|
||||||
- 优点:链接加密,可以自定义客户端一些功能,编译后直接可用
|
|
||||||
- 缺点:需要自己fork代码,编译,有点难度
|
|
||||||
4. 使用[我fork的代码](https://github.com/lejianwen/rustdesk),已经修改了`secure_tcp`,可以直接下载使用,[下载地址](https://github.com/lejianwen/rustdesk/releases)
|
|
||||||
- 优点:代码改动可查看,`Github Actions`编译,链接加密,直接下载使用
|
|
||||||
- 缺点:可能跟不上官方版本更新
|
|
||||||
|
|
||||||
***对链接加密要求不高的可以使用`1`,对链接加密要求高的可以使用`3`或`4`***
|
* Admin panel URL: `http://<your server[:port]>/_admin/`
|
||||||
|
* For the initial installation, the admin username is `admin`, and the password will be printed in the console. You can change the password via the [command line](#CLI).
|
||||||
|
|
||||||
## 功能
|

|
||||||
|
|
||||||
### API 服务
|
|
||||||
基本实现了PC端基础的接口。支持Personal版本接口,可以通过配置文件`rustdesk.personal`或环境变量`RUSTDESK_API_RUSTDESK_PERSONAL`来控制是否启用
|
|
||||||
|
|
||||||
#### 登录
|
1. Admin interface:
|
||||||
|

|
||||||
|
2. Regular user interface:
|
||||||
|

|
||||||
|
|
||||||
- 添加了`github`, `google` 以及`OIDC`授权登录,需要在后台配置好就可以用了,具体可看后台OAuth配置
|
3. Each user can have multiple address books, which can also be shared with other users.
|
||||||
- 添加了web后台授权登录,点击后直接登录后台就自动登录客户端了
|
4. Groups can be customized for easy management. Currently, two types are supported: `shared group` and `regular group`.
|
||||||
|
5. 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.
|
||||||
|
6. OAuth support: Currently, `GitHub`, `Google` and `OIDC` are supported. You need to create an `OAuth App` and configure it in
|
||||||
|
the admin panel.
|
||||||
|
- For `Google` and `Github`, you don't need to fill the `Issuer` and `Scpoes`
|
||||||
|
- For `OIDC`, you must set the `Issuer`. And `Scopes` is optional which default is `openid,email,profile`, please make sure this `Oauth App` can access `sub`, `email` and `preferred_username`
|
||||||
|
- Create a `GitHub OAuth App`
|
||||||
|
at `Settings` -> `Developer settings` -> `OAuth Apps` -> `New OAuth App` [here](https://github.com/settings/developers).
|
||||||
|
- Set the `Authorization callback URL` to `http://<your server[:port]>/api/oidc/callback`,
|
||||||
|
e.g., `http://127.0.0.1:21114/api/oidc/callback`.
|
||||||
|
|
||||||

|
7. Login logs
|
||||||
|
8. Connection logs
|
||||||
|
9. File transfer logs
|
||||||
|
10. Server control
|
||||||
|
- `Simple mode`, some simple commands have been GUI-ized and can be executed directly in the backend
|
||||||
|

|
||||||
|
|
||||||
#### 地址簿
|
- `Advanced mode`, commands can be executed directly in the backend
|
||||||
|
* Official commands can be used
|
||||||
|
* Custom commands can be added
|
||||||
|
* Custom commands can be executed
|
||||||
|
|
||||||

|
11. **LDAP Support**, When you setup the LDAP(test for OpenLDAP and AD), you can login with the LDAP's user. https://github.com/lejianwen/rustdesk-api/issues/114 , if LDAP fail fallback local user
|
||||||
|
|
||||||
#### 群组
|
|
||||||
群组分为`共享组`和`普通组`,共享组中所有人都能看到小组成员的设备,普通组只有管理员能看到所有小组成员的设备
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### Web Admin:
|
|
||||||
|
|
||||||
* 使用前后端分离,提供用户友好的管理界面,主要用来管理和展示。前端代码在[rustdesk-api-web](https://github.com/lejianwen/rustdesk-api-web)
|
|
||||||
|
|
||||||
* 后台访问地址是`http://<your server>[:port]/_admin/`初次安装管理员为用户名密码为`admin` `admin`,请即时更改密码
|
|
||||||
|
|
||||||
1. 管理员界面
|
|
||||||

|
|
||||||
2. 普通用户界面
|
|
||||||

|
|
||||||
右上角可以更改密码,可以切换语言,可以切换`白天/黑夜`模式
|
|
||||||

|
|
||||||
|
|
||||||
3. 分组可以自定义,方便管理,暂时支持两种类型: `共享组` 和 `普通组`
|
|
||||||

|
|
||||||
4. 可以直接打开webclient,方便使用;也可以分享给游客,游客可以直接通过webclient远程到设备
|
|
||||||
|
|
||||||

|
|
||||||
5. Oauth,支持了`Github`, `Google` 以及 `OIDC`, 需要创建一个`OAuth App`,然后配置到后台
|
|
||||||

|
|
||||||
- 对于`Google` 和 `Github`, `Issuer` 和 `Scopes`不需要填写.
|
|
||||||
- 对于`OIDC`, `Issuer`是必须的。`Scopes`是可选的,默认为 `openid,profile,email`. 确保可以获取 `sub`,`email` 和`preferred_username`
|
|
||||||
- `github oauth app`在`Settings`->`Developer settings`->`OAuth Apps`->`New OAuth App`
|
|
||||||
中创建,地址 [https://github.com/settings/developers](https://github.com/settings/developers)
|
|
||||||
- `Authorization callback URL`填写`http://<your server[:port]>/api/oauth/callback`
|
|
||||||
,比如`http://127.0.0.1:21114/api/oauth/callback`
|
|
||||||
|
|
||||||
### Web Client:
|
### Web Client:
|
||||||
|
|
||||||
1. 如果已经登录了后台,web client将自动直接登录
|
1. If you're already logged into the admin panel, the web client will log in automatically.
|
||||||
2. 如果没登录后台,点击右上角登录即可,api server已经自动配置好了
|
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.
|
||||||
3. 登录后,会自动同步ID服务器和KEY
|
3. After logging in, the ID server and key will be automatically synced.
|
||||||
4. 登录后,会将地址簿自动保存到web client中,方便使用
|
4. The address book will also be automatically saved to the web client for convenient use.
|
||||||
5. 现已支持`v2 Preview`,访问路径是`/webclient2`
|
|
||||||

|
|
||||||
6. `v2 preview` 部署
|
|
||||||
- 如果是通过`443`端口的`https`部署,必须配置反向代理,可以参考[官方文档](https://rustdesk.com/docs/en/self-host/rustdesk-server-pro/faq/#8-add-websocket-secure-wss-support-for-the-id-server-and-relay-server-to-enable-secure-communication-for-the-web-client)
|
|
||||||
- 如果是`http`或者其他的`https`端口部署,则和`v1`一样,配置好`21118`,`21119`即可
|
|
||||||
|
|
||||||
### 自动化文档: 使用 Swag 生成 API 文档,方便开发者理解和使用 API。
|
### Automated Documentation : API documentation is generated using Swag, making it easier for developers to understand and use the API.
|
||||||
|
|
||||||
1. 后台文档 `<youer server[:port]>/admin/swagger/index.html`
|
1. Admin panel docs: `<your server[:port]>/admin/swagger/index.html`
|
||||||
2. PC端文档 `<youer server[:port]>/swagger/index.html`
|
2. PC client docs: `<your server[:port]>/swagger/index.html`
|
||||||

|

|
||||||
|
|
||||||
### CLI
|
### CLI
|
||||||
```bash
|
```bash
|
||||||
# 查看帮助
|
# help
|
||||||
./apimain -h
|
./apimain -h
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 重置管理员密码
|
#### Reset admin password
|
||||||
```bash
|
```bash
|
||||||
./apimain reset-admin-pwd <pwd>
|
./apimain reset-admin-pwd <pwd>
|
||||||
```
|
```
|
||||||
|
|
||||||
## 安装与运行
|
## Installation and Setup
|
||||||
|
|
||||||
### 相关配置
|
### Configuration
|
||||||
|
|
||||||
* 参考`conf/config.yaml`配置文件,修改相关配置。
|
* [Config File](./conf/config.yaml)
|
||||||
* 如果`gorm.type`是`sqlite`,则不需要配置mysql相关配置。
|
* Modify the configuration in `conf/config.yaml`.
|
||||||
* 语言如果不设置默认为`zh-CN`
|
* If `gorm.type` is set to `sqlite`, MySQL-related configurations are not required.
|
||||||
|
* Language support: `en` and `zh-CN` are supported. The default is `zh-CN`.
|
||||||
```yaml
|
|
||||||
lang: "en"
|
|
||||||
app:
|
|
||||||
web-client: 1 # 1:启用 0:禁用
|
|
||||||
register: false #是否开启注册
|
|
||||||
gin:
|
|
||||||
api-addr: "0.0.0.0:21114"
|
|
||||||
mode: "release"
|
|
||||||
resources-path: 'resources'
|
|
||||||
trust-proxy: ""
|
|
||||||
gorm:
|
|
||||||
type: "sqlite"
|
|
||||||
max-idle-conns: 10
|
|
||||||
max-open-conns: 100
|
|
||||||
mysql:
|
|
||||||
username: "root"
|
|
||||||
password: "111111"
|
|
||||||
addr: "192.168.1.66:3308"
|
|
||||||
dbname: "rustdesk"
|
|
||||||
rustdesk:
|
|
||||||
id-server: "192.168.1.66:21116"
|
|
||||||
relay-server: "192.168.1.66:21117"
|
|
||||||
api-server: "http://192.168.1.66:21114"
|
|
||||||
key: "123456789"
|
|
||||||
personal: 1
|
|
||||||
logger:
|
|
||||||
path: "./runtime/log.txt"
|
|
||||||
level: "warn" #trace,debug,info,warn,error,fatal
|
|
||||||
report-caller: true
|
|
||||||
proxy:
|
|
||||||
enable: false
|
|
||||||
host: ""
|
|
||||||
```
|
|
||||||
|
|
||||||
### 环境变量
|
|
||||||
变量名前缀是`RUSTDESK_API`,环境变量如果存在将覆盖配置文件中的配置
|
|
||||||
|
|
||||||
| 变量名 | 说明 | 示例 |
|
|
||||||
|------------------------------------|---------------------------------------------------------|------------------------------|
|
|
||||||
| TZ | 时区 | Asia/Shanghai |
|
|
||||||
| RUSTDESK_API_LANG | 语言 | `en`,`zh-CN` |
|
|
||||||
| RUSTDESK_API_APP_WEB_CLIENT | 是否启用web-client; 1:启用,0:不启用; 默认启用 | 1 |
|
|
||||||
| RUSTDESK_API_APP_REGISTER | 是否开启注册; `true`, `false` 默认`false` | `false` |
|
|
||||||
| -----ADMIN配置----- | ---------- | ---------- |
|
|
||||||
| RUSTDESK_API_ADMIN_TITLE | 后台标题 | `RustDesk Api Admin` |
|
|
||||||
| RUSTDESK_API_ADMIN_HELLO | 后台欢迎语,可以使用`html` | |
|
|
||||||
| RUSTDESK_API_ADMIN_HELLO_FILE | 后台欢迎语文件,如果内容多,使用文件更方便。<br>会覆盖`RUSTDESK_API_ADMIN_HELLO` | `./conf/admin/hello.html` |
|
|
||||||
| -----GIN配置----- | ---------- | ---------- |
|
|
||||||
| RUSTDESK_API_GIN_TRUST_PROXY | 信任的代理IP列表,以`,`分割,默认信任所有 | 192.168.1.2,192.168.1.3 |
|
|
||||||
| -----------GORM配置---------------- | ------------------------------------ | --------------------------- |
|
|
||||||
| RUSTDESK_API_GORM_TYPE | 数据库类型sqlite或者mysql,默认sqlite | sqlite |
|
|
||||||
| RUSTDESK_API_GORM_MAX_IDLE_CONNS | 数据库最大空闲连接数 | 10 |
|
|
||||||
| RUSTDESK_API_GORM_MAX_OPEN_CONNS | 数据库最大打开连接数 | 100 |
|
|
||||||
| RUSTDESK_API_RUSTDESK_PERSONAL | 是否启用个人版API, 1:启用,0:不启用; 默认启用 | 1 |
|
|
||||||
| -----MYSQL配置----- | ---------- | ---------- |
|
|
||||||
| RUSTDESK_API_MYSQL_USERNAME | mysql用户名 | root |
|
|
||||||
| RUSTDESK_API_MYSQL_PASSWORD | mysql密码 | 111111 |
|
|
||||||
| RUSTDESK_API_MYSQL_ADDR | mysql地址 | 192.168.1.66:3306 |
|
|
||||||
| RUSTDESK_API_MYSQL_DBNAME | mysql数据库名 | rustdesk |
|
|
||||||
| -----RUSTDESK配置----- | --------------- | ---------- |
|
|
||||||
| RUSTDESK_API_RUSTDESK_ID_SERVER | Rustdesk的id服务器地址 | 192.168.1.66:21116 |
|
|
||||||
| 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_KEY | Rustdesk的key | 123456789 |
|
|
||||||
| RUSTDESK_API_RUSTDESK_KEY_FILE | Rustdesk存放key的文件 | `./conf/data/id_ed25519.pub` |
|
|
||||||
| ----PROXY配置----- | --------------- | ---------- |
|
|
||||||
| RUSTDESK_API_PROXY_ENABLE | 是否启用代理:`false`, `true` | `false` |
|
|
||||||
| RUSTDESK_API_PROXY_HOST | 代理地址 | `http://127.0.0.1:1080` |
|
|
||||||
|
|
||||||
|
|
||||||
### 运行
|
### Environment Variables
|
||||||
|
The environment variables correspond one-to-one with the configurations in the `conf/config.yaml` file. The prefix for variable names is `RUSTDESK_API`.
|
||||||
|
The table below does not list all configurations. Please refer to the configurations in `conf/config.yaml`.
|
||||||
|
|
||||||
#### docker运行
|
| Variable Name | Description | Example |
|
||||||
|
|--------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------|
|
||||||
|
| TZ | timezone | Asia/Shanghai |
|
||||||
|
| RUSTDESK_API_LANG | Language | `en`,`zh-CN` |
|
||||||
|
| RUSTDESK_API_APP_WEB_CLIENT | web client on/off; 1: on, 0 off, default: 1 | 1 |
|
||||||
|
| RUSTDESK_API_APP_REGISTER | register enable; `true`, `false`; default:`false` | `false` |
|
||||||
|
| RUSTDESK_API_APP_SHOW_SWAGGER | swagger visible; 1: yes, 0: no; default: 0 | `0` |
|
||||||
|
| RUSTDESK_API_APP_TOKEN_EXPIRE | token expire duration | `168h` |
|
||||||
|
| RUSTDESK_API_APP_DISABLE_PWD_LOGIN | disable password login | `false` |
|
||||||
|
| RUSTDESK_API_APP_REGISTER_STATUS | register user default status ; 1 enabled , 2 disabled ; default 1 | `1` |
|
||||||
|
| RUSTDESK_API_APP_CAPTCHA_THRESHOLD | captcha threshold; -1 disabled, 0 always enable, >0 threshold ;default `3` | `3` |
|
||||||
|
| RUSTDESK_API_APP_BAN_THRESHOLD | ban ip threshold; 0 disabled, >0 threshold ; default `0` | `0` |
|
||||||
|
| ----- ADMIN Configuration----- | ---------- | ---------- |
|
||||||
|
| RUSTDESK_API_ADMIN_TITLE | Admin Title | `RustDesk Api Admin` |
|
||||||
|
| RUSTDESK_API_ADMIN_HELLO | Admin welcome message, you can use `html` | |
|
||||||
|
| RUSTDESK_API_ADMIN_HELLO_FILE | Admin welcome message file,<br>will override `RUSTDESK_API_ADMIN_HELLO` | `./conf/admin/hello.html` |
|
||||||
|
| ----- GIN Configuration ----- | --------------------------------------- | ----------------------------- |
|
||||||
|
| RUSTDESK_API_GIN_TRUST_PROXY | Trusted proxy IPs, separated by commas. | 192.168.1.2,192.168.1.3 |
|
||||||
|
| ----- GORM Configuration ----- | --------------------------------------- | ----------------------------- |
|
||||||
|
| RUSTDESK_API_GORM_TYPE | Database type (`sqlite` or `mysql`). Default is `sqlite`. | sqlite |
|
||||||
|
| RUSTDESK_API_GORM_MAX_IDLE_CONNS | Maximum idle connections | 10 |
|
||||||
|
| RUSTDESK_API_GORM_MAX_OPEN_CONNS | Maximum open connections | 100 |
|
||||||
|
| RUSTDESK_API_RUSTDESK_PERSONAL | Open Personal Api 1:Enable,0:Disable | 1 |
|
||||||
|
| ----- MYSQL Configuration ----- | --------------------------------------- | ----------------------------- |
|
||||||
|
| RUSTDESK_API_MYSQL_USERNAME | MySQL username | root |
|
||||||
|
| RUSTDESK_API_MYSQL_PASSWORD | MySQL password | 111111 |
|
||||||
|
| RUSTDESK_API_MYSQL_ADDR | MySQL address | 192.168.1.66:3306 |
|
||||||
|
| RUSTDESK_API_MYSQL_DBNAME | MySQL database name | rustdesk |
|
||||||
|
| RUSTDESK_API_MYSQL_TLS | Whether to enable TLS, optional values: `true`, `false`, `skip-verify`, `custom` | `false` |
|
||||||
|
| ----- RUSTDESK Configuration ----- | --------------------------------------- | ----------------------------- |
|
||||||
|
| RUSTDESK_API_RUSTDESK_ID_SERVER | Rustdesk ID server address | 192.168.1.66:21116 |
|
||||||
|
| 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_KEY | Rustdesk key | 123456789 |
|
||||||
|
| RUSTDESK_API_RUSTDESK_KEY_FILE | Rustdesk key file | `./conf/data/id_ed25519.pub` |
|
||||||
|
| RUSTDESK_API_RUSTDESK<br/>_WEBCLIENT_MAGIC_QUERYONLINE | New online query method is enabled in the web client v2; '1': Enabled, '0': Disabled, not enabled by default | `0` |
|
||||||
|
| RUSTDESK_API_RUSTDESK_WS_HOST | Custom Websocket Host | `wss://192.168.1.123:1234` |
|
||||||
|
| ---- PROXY ----- | --------------- | ---------- |
|
||||||
|
| RUSTDESK_API_PROXY_ENABLE | proxy_enable :`false`, `true` | `false` |
|
||||||
|
| RUSTDESK_API_PROXY_HOST | proxy_host | `http://127.0.0.1:1080` |
|
||||||
|
| ----JWT---- | -------- | -------- |
|
||||||
|
| RUSTDESK_API_JWT_KEY | Custom JWT KEY, if empty JWT is not enabled.<br/>If `MUST_LOGIN` from `lejianwen/rustdesk-server` is not used, it is recommended to leave it empty. | |
|
||||||
|
| RUSTDESK_API_JWT_EXPIRE_DURATION | JWT expire duration | `168h` |
|
||||||
|
|
||||||
1. 直接docker运行,配置可以通过挂载配置文件`/app/conf/config.yaml`来修改,或者通过环境变量覆盖配置文件中的配置
|
### Installation Steps
|
||||||
|
|
||||||
|
#### Running via Docker
|
||||||
|
|
||||||
|
1. Run directly with Docker. Configuration can be modified by mounting the config file `/app/conf/config.yaml`, or by
|
||||||
|
using environment variables to override settings.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run -d --name rustdesk-api -p 21114:21114 \
|
docker run -d --name rustdesk-api -p 21114:21114 \
|
||||||
-v /data/rustdesk/api:/app/data \
|
-v /data/rustdesk/api:/app/data \
|
||||||
-e TZ=Asia/Shanghai \
|
-e RUSTDESK_API_LANG=en \
|
||||||
-e RUSTDESK_API_LANG=zh-CN \
|
|
||||||
-e RUSTDESK_API_RUSTDESK_ID_SERVER=192.168.1.66:21116 \
|
-e RUSTDESK_API_RUSTDESK_ID_SERVER=192.168.1.66:21116 \
|
||||||
-e RUSTDESK_API_RUSTDESK_RELAY_SERVER=192.168.1.66:21117 \
|
-e RUSTDESK_API_RUSTDESK_RELAY_SERVER=192.168.1.66:21117 \
|
||||||
-e RUSTDESK_API_RUSTDESK_API_SERVER=http://192.168.1.66:21114 \
|
-e RUSTDESK_API_RUSTDESK_API_SERVER=http://192.168.1.66:21114 \
|
||||||
-e RUSTDESK_API_RUSTDESK_KEY=<key> \
|
-e RUSTDESK_API_RUSTDESK_KEY=abc123456 \
|
||||||
lejianwen/rustdesk-api
|
lejianwen/rustdesk-api
|
||||||
```
|
```
|
||||||
|
|
||||||
2. 使用`docker compose`
|
2. Using `docker-compose`,look [WIKI](https://github.com/lejianwen/rustdesk-api/wiki)
|
||||||
- 简单示例
|
|
||||||
```yaml
|
|
||||||
services:
|
|
||||||
rustdesk-api:
|
|
||||||
container_name: rustdesk-api
|
|
||||||
environment:
|
|
||||||
- TZ=Asia/Shanghai
|
|
||||||
- RUSTDESK_API_RUSTDESK_ID_SERVER=192.168.1.66:21116
|
|
||||||
- RUSTDESK_API_RUSTDESK_RELAY_SERVER=192.168.1.66:21117
|
|
||||||
- RUSTDESK_API_RUSTDESK_API_SERVER=http://192.168.1.66:21114
|
|
||||||
- RUSTDESK_API_RUSTDESK_KEY=<key>
|
|
||||||
ports:
|
|
||||||
- 21114:21114
|
|
||||||
image: lejianwen/rustdesk-api
|
|
||||||
volumes:
|
|
||||||
- /data/rustdesk/api:/app/data #将数据库挂载出来方便备份
|
|
||||||
networks:
|
|
||||||
- rustdesk-net
|
|
||||||
restart: unless-stopped
|
|
||||||
```
|
|
||||||
|
|
||||||
- 根据rustdesk官方提供的示例,加上自己的rustdesk-api
|
#### Running from Release
|
||||||
- 如果是使用的系统生成的KEY,去掉`-k <key>`参数,在启动后运行`docker-compose logs hbbs`或者`cat ./data/id_ed25519.pub`查看KEY,然后再修改`RUSTDESK_API_RUSTDESK_KEY=<key>`再执行`docker-compose up -d`
|
|
||||||
```yaml
|
|
||||||
networks:
|
|
||||||
rustdesk-net:
|
|
||||||
external: false
|
|
||||||
services:
|
|
||||||
hbbs:
|
|
||||||
container_name: hbbs
|
|
||||||
ports:
|
|
||||||
- 21115:21115
|
|
||||||
- 21116:21116 # 自定义 hbbs 映射端口
|
|
||||||
- 21116:21116/udp # 自定义 hbbs 映射端口
|
|
||||||
- 21118:21118 # web client
|
|
||||||
image: rustdesk/rustdesk-server
|
|
||||||
command: hbbs -r <relay-server-ip[:port]> -k <key> # 填入个人域名或 IP + hbbr 暴露端口
|
|
||||||
volumes:
|
|
||||||
- ./data:/root # 自定义挂载目录
|
|
||||||
networks:
|
|
||||||
- rustdesk-net
|
|
||||||
depends_on:
|
|
||||||
- hbbr
|
|
||||||
restart: unless-stopped
|
|
||||||
deploy:
|
|
||||||
resources:
|
|
||||||
limits:
|
|
||||||
memory: 64M
|
|
||||||
hbbr:
|
|
||||||
container_name: hbbr
|
|
||||||
ports:
|
|
||||||
- 21117:21117 # 自定义 hbbr 映射端口
|
|
||||||
- 21119:21119 # web client
|
|
||||||
image: rustdesk/rustdesk-server
|
|
||||||
command: hbbr -k <key>
|
|
||||||
volumes:
|
|
||||||
- ./data:/root
|
|
||||||
networks:
|
|
||||||
- rustdesk-net
|
|
||||||
restart: unless-stopped
|
|
||||||
deploy:
|
|
||||||
resources:
|
|
||||||
limits:
|
|
||||||
memory: 64M
|
|
||||||
rustdesk-api:
|
|
||||||
container_name: rustdesk-api
|
|
||||||
environment:
|
|
||||||
- TZ=Asia/Shanghai
|
|
||||||
- RUSTDESK_API_RUSTDESK_ID_SERVER=192.168.1.66:21116
|
|
||||||
- RUSTDESK_API_RUSTDESK_RELAY_SERVER=192.168.1.66:21117
|
|
||||||
- RUSTDESK_API_RUSTDESK_API_SERVER=http://192.168.1.66:21114
|
|
||||||
- RUSTDESK_API_RUSTDESK_KEY=<key>
|
|
||||||
ports:
|
|
||||||
- 21114:21114
|
|
||||||
image: lejianwen/rustdesk-api
|
|
||||||
volumes:
|
|
||||||
- /data/rustdesk/api:/app/data #将数据库挂载出来方便备份
|
|
||||||
networks:
|
|
||||||
- rustdesk-net
|
|
||||||
restart: unless-stopped
|
|
||||||
```
|
|
||||||
|
|
||||||
- S6的镜像
|
Download the release from [release](https://github.com/lejianwen/rustdesk-api/releases).
|
||||||
- 如果使用***自定义KEY***,会需要修改启动脚本,覆盖镜像中的`/etc/s6-overlay/s6-rc.d/hbbr/run`和`/etc/s6-overlay/s6-rc.d/hbbr/run`
|
|
||||||
1. 创建`hbbr/run`,自定义KEY才需要
|
|
||||||
```bash
|
|
||||||
#!/command/with-contenv sh
|
|
||||||
cd /data
|
|
||||||
PARAMS=
|
|
||||||
[ "${ENCRYPTED_ONLY}" = "1" ] && PARAMS="-k ${KEY}"
|
|
||||||
/usr/bin/hbbr $PARAMS
|
|
||||||
```
|
|
||||||
2. 创建`hbbs/run`,自定义KEY才需要
|
|
||||||
```bash
|
|
||||||
#!/command/with-contenv sh
|
|
||||||
sleep 2
|
|
||||||
cd /data
|
|
||||||
PARAMS=
|
|
||||||
[ "${ENCRYPTED_ONLY}" = "1" ] && PARAMS="-k ${KEY}"
|
|
||||||
/usr/bin/hbbs -r $RELAY $PARAMS
|
|
||||||
```
|
|
||||||
3. 修改`docker-compose.yml`中的`s6`部分
|
|
||||||
```yaml
|
|
||||||
networks:
|
|
||||||
rustdesk-net:
|
|
||||||
external: false
|
|
||||||
services:
|
|
||||||
rustdesk-server:
|
|
||||||
container_name: rustdesk-server
|
|
||||||
ports:
|
|
||||||
- 21115:21115
|
|
||||||
- 21116:21116
|
|
||||||
- 21116:21116/udp
|
|
||||||
- 21117:21117
|
|
||||||
- 21118:21118
|
|
||||||
- 21119:21119
|
|
||||||
image: rustdesk/rustdesk-server-s6:latest
|
|
||||||
environment:
|
|
||||||
- RELAY=192.168.1.66:21117
|
|
||||||
- ENCRYPTED_ONLY=1
|
|
||||||
- KEY=<key> #自定义KEY
|
|
||||||
volumes:
|
|
||||||
- ./data:/data
|
|
||||||
- ./hbbr/run:/etc/s6-overlay/s6-rc.d/hbbr/run
|
|
||||||
- ./hbbs/run:/etc/s6-overlay/s6-rc.d/hbbs/run
|
|
||||||
restart: unless-stopped
|
|
||||||
rustdesk-api:
|
|
||||||
container_name: rustdesk-api
|
|
||||||
ports:
|
|
||||||
- 21114:21114
|
|
||||||
image: lejianwen/rustdesk-api
|
|
||||||
environment:
|
|
||||||
- TZ=Asia/Shanghai
|
|
||||||
- RUSTDESK_API_RUSTDESK_ID_SERVER=192.168.1.66:21116
|
|
||||||
- RUSTDESK_API_RUSTDESK_RELAY_SERVER=192.168.1.66:21117
|
|
||||||
- RUSTDESK_API_RUSTDESK_API_SERVER=http://192.168.1.66:21114
|
|
||||||
- RUSTDESK_API_RUSTDESK_KEY=<key>
|
|
||||||
volumes:
|
|
||||||
- /data/rustdesk/api:/app/data #将数据库挂载
|
|
||||||
networks:
|
|
||||||
- rustdesk-net
|
|
||||||
restart: unless-stopped
|
|
||||||
```
|
|
||||||
- 如果使用***系统生成的KEY***或者***自定义KEY_PUB,KEY_PRIV***,不需要修改启动脚本,但要在生成KEY后获取到KEY再`docker-compose up -d`
|
|
||||||
```yaml
|
|
||||||
networks:
|
|
||||||
rustdesk-net:
|
|
||||||
external: false
|
|
||||||
services:
|
|
||||||
rustdesk-server:
|
|
||||||
container_name: rustdesk-server
|
|
||||||
ports:
|
|
||||||
- 21115:21115
|
|
||||||
- 21116:21116
|
|
||||||
- 21116:21116/udp
|
|
||||||
- 21117:21117
|
|
||||||
- 21118:21118
|
|
||||||
- 21119:21119
|
|
||||||
image: rustdesk/rustdesk-server-s6:latest
|
|
||||||
environment:
|
|
||||||
- RELAY=192.168.1.66:21117
|
|
||||||
- ENCRYPTED_ONLY=1
|
|
||||||
volumes:
|
|
||||||
- ./data:/data
|
|
||||||
restart: unless-stopped
|
|
||||||
rustdesk-api:
|
|
||||||
container_name: rustdesk-api
|
|
||||||
ports:
|
|
||||||
- 21114:21114
|
|
||||||
image: lejianwen/rustdesk-api
|
|
||||||
environment:
|
|
||||||
- TZ=Asia/Shanghai
|
|
||||||
- RUSTDESK_API_RUSTDESK_ID_SERVER=192.168.1.66:21116
|
|
||||||
- RUSTDESK_API_RUSTDESK_RELAY_SERVER=192.168.1.66:21117
|
|
||||||
- RUSTDESK_API_RUSTDESK_API_SERVER=http://192.168.1.66:21114
|
|
||||||
- RUSTDESK_API_RUSTDESK_KEY=<key> #系统生成的KEY
|
|
||||||
volumes:
|
|
||||||
- /data/rustdesk/api:/app/data #将数据库挂载
|
|
||||||
networks:
|
|
||||||
- rustdesk-net
|
|
||||||
restart: unless-stopped
|
|
||||||
```
|
|
||||||
#### 下载release直接运行
|
|
||||||
|
|
||||||
[下载地址](https://github.com/lejianwen/rustdesk-api/releases)
|
#### Source Installation
|
||||||
|
|
||||||
#### 源码安装
|
1. Clone the repository:
|
||||||
|
|
||||||
1. 克隆仓库
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/lejianwen/rustdesk-api.git
|
git clone https://github.com/lejianwen/rustdesk-api.git
|
||||||
cd rustdesk-api
|
cd rustdesk-api
|
||||||
```
|
```
|
||||||
|
|
||||||
2. 安装依赖
|
2. Install dependencies:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
go mod tidy
|
go mod tidy
|
||||||
#安装swag,如果不需要生成文档,可以不安装
|
# Install Swag if you need to generate documentation; otherwise, you can skip this step
|
||||||
go install github.com/swaggo/swag/cmd/swag@latest
|
go install github.com/swaggo/swag/cmd/swag@latest
|
||||||
```
|
```
|
||||||
|
|
||||||
3. 编译后台前端,前端代码在[rustdesk-api-web](https://github.com/lejianwen/rustdesk-api-web)中
|
3. Build the admin front-end (the front-end code is
|
||||||
|
in [rustdesk-api-web](https://github.com/lejianwen/rustdesk-api-web)):
|
||||||
```bash
|
```bash
|
||||||
cd resources
|
cd resources
|
||||||
mkdir -p admin
|
mkdir -p admin
|
||||||
@@ -475,34 +254,84 @@ proxy:
|
|||||||
npm run build
|
npm run build
|
||||||
cp -ar dist/* ../admin/
|
cp -ar dist/* ../admin/
|
||||||
```
|
```
|
||||||
4. 运行
|
|
||||||
|
4. Run:
|
||||||
```bash
|
```bash
|
||||||
#直接运行
|
# Run directly
|
||||||
go run cmd/apimain.go
|
go run cmd/apimain.go
|
||||||
#或者使用generate_api.go生成api并运行
|
# Or generate and run the API using generate_api.go
|
||||||
go generate generate_api.go
|
go generate generate_api.go
|
||||||
```
|
```
|
||||||
5. 编译,如果想自己编译,先cd到项目根目录,然后windows下直接运行`build.bat`,linux下运行`build.sh`,编译后会在`release`
|
> **Note:** When using `go run` or the compiled binary, the `conf` and `resources`
|
||||||
目录下生成对应的可执行文件。直接运行编译后的可执行文件即可。
|
> directories must exist relative to the current working directory. If you run
|
||||||
|
> the program from another location, specify absolute paths with `-c` and the
|
||||||
|
> `RUSTDESK_API_GIN_RESOURCES_PATH` environment variable. Example:
|
||||||
|
> ```bash
|
||||||
|
> RUSTDESK_API_GIN_RESOURCES_PATH=/opt/rustdesk-api/resources ./apimain -c /opt/rustdesk-api/conf/config.yaml
|
||||||
|
> ```
|
||||||
|
|
||||||
6. 打开浏览器访问`http://<your server[:port]>/_admin/`,默认用户名密码为`admin`,请及时更改密码。
|
5. To compile, change to the project root directory. For Windows, run `build.bat`, and for Linux, run `build.sh`. After
|
||||||
|
compiling, the corresponding executables will be generated in the `release` directory. Run the compiled executables
|
||||||
|
directly.
|
||||||
|
|
||||||
|
6. Open your browser and visit `http://<your server[:port]>/_admin/`, with default credentials `admin admin`. Please
|
||||||
|
change the password promptly.
|
||||||
|
|
||||||
|
#### Running with my forked server-s6 image
|
||||||
|
|
||||||
|
- Connection timeout issue resolved
|
||||||
|
- Can enforce login before initiating a connection
|
||||||
|
- github https://github.com/lejianwen/rustdesk-server
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
networks:
|
||||||
|
rustdesk-net:
|
||||||
|
external: false
|
||||||
|
services:
|
||||||
|
rustdesk:
|
||||||
|
ports:
|
||||||
|
- 21114:21114
|
||||||
|
- 21115:21115
|
||||||
|
- 21116:21116
|
||||||
|
- 21116:21116/udp
|
||||||
|
- 21117:21117
|
||||||
|
- 21118:21118
|
||||||
|
- 21119:21119
|
||||||
|
image: lejianwen/rustdesk-server-s6:latest
|
||||||
|
environment:
|
||||||
|
- RELAY=<relay_server[:port]>
|
||||||
|
- ENCRYPTED_ONLY=1
|
||||||
|
- MUST_LOGIN=N
|
||||||
|
- TZ=Asia/Shanghai
|
||||||
|
- RUSTDESK_API_RUSTDESK_ID_SERVER=<id_server[:21116]>
|
||||||
|
- RUSTDESK_API_RUSTDESK_RELAY_SERVER=<relay_server[:21117]>
|
||||||
|
- RUSTDESK_API_RUSTDESK_API_SERVER=http://<api_server[:21114]>
|
||||||
|
- RUSTDESK_API_KEY_FILE=/data/id_ed25519.pub
|
||||||
|
- RUSTDESK_API_JWT_KEY=xxxxxx # jwt key
|
||||||
|
volumes:
|
||||||
|
- /data/rustdesk/server:/data
|
||||||
|
- /data/rustdesk/api:/app/data # mount the database
|
||||||
|
networks:
|
||||||
|
- rustdesk-net
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
#### nginx反代
|
|
||||||
在`nginx`中配置反代
|
|
||||||
```
|
```
|
||||||
server {
|
## Others
|
||||||
listen <your port>;
|
|
||||||
server_name <your server>;
|
|
||||||
location / {
|
|
||||||
proxy_pass http://<api-server[:port]>;
|
|
||||||
proxy_set_header Host $host;
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
## 其他
|
|
||||||
|
|
||||||
- [修改客户端ID](https://github.com/abdullah-erturk/RustDesk-ID-Changer)
|
- [WIKI](https://github.com/lejianwen/rustdesk-api/wiki)
|
||||||
- [webclient来源](https://hub.docker.com/r/keyurbhole/flutter_web_desk)
|
- [Connection Timeout](https://github.com/lejianwen/rustdesk-api/issues/92)
|
||||||
|
- [Change client ID](https://github.com/abdullah-erturk/RustDesk-ID-Changer)
|
||||||
|
- [Web client source](https://hub.docker.com/r/keyurbhole/flutter_web_desk)
|
||||||
|
|
||||||
|
## Acknowledgements
|
||||||
|
|
||||||
|
Thanks to everyone who contributed!
|
||||||
|
|
||||||
|
<a href="https://github.com/lejianwen/rustdesk-api/graphs/contributors">
|
||||||
|
<img src="https://contrib.rocks/image?repo=lejianwen/rustdesk-api" />
|
||||||
|
</a>
|
||||||
|
|
||||||
|
## Thanks for your support! If you find this project useful, please give it a ⭐️. Thank you!
|
||||||
|
|
||||||
|
|
||||||
|
[lejianwen/rustdesk-server]: https://github.com/lejianwen/rustdesk-server
|
||||||
@@ -1,477 +1,250 @@
|
|||||||
# RustDesk API
|
# RustDesk API
|
||||||
|
|
||||||
This project implements the RustDesk API using Go, and includes both a web UI and web client. RustDesk is a remote
|
[English Doc](README.md)
|
||||||
desktop software that provides self-hosted solutions.
|
|
||||||
|
本项目使用 Go 实现了 RustDesk 的 API,并包含了 Web Admin 和 Web 客户端。
|
||||||
|
|
||||||
|
|
||||||
<div align=center>
|
<div align=center>
|
||||||
<img src="https://img.shields.io/badge/golang-1.22-blue"/>
|
<img src="https://img.shields.io/badge/golang-1.22-blue"/>
|
||||||
<img src="https://img.shields.io/badge/gin-v1.9.0-lightBlue"/>
|
<img src="https://img.shields.io/badge/gin-v1.9.0-lightBlue"/>
|
||||||
<img src="https://img.shields.io/badge/gorm-v1.25.7-green"/>
|
<img src="https://img.shields.io/badge/gorm-v1.25.7-green"/>
|
||||||
<img src="https://img.shields.io/badge/swag-v1.16.3-yellow"/>
|
<img src="https://img.shields.io/badge/swag-v1.16.3-yellow"/>
|
||||||
|
<img src="https://goreportcard.com/badge/github.com/lejianwen/rustdesk-api/v2"/>
|
||||||
<img src="https://github.com/lejianwen/rustdesk-api/actions/workflows/build.yml/badge.svg"/>
|
<img src="https://github.com/lejianwen/rustdesk-api/actions/workflows/build.yml/badge.svg"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
# Features
|
## 搭配[lejianwen/rustdesk-server]使用更佳。
|
||||||
|
> [lejianwen/rustdesk-server]fork自RustDesk Server官方仓库
|
||||||
|
> 1. 解决了使用API链接超时问题
|
||||||
|
> 2. 可以强制登录后才能发起链接
|
||||||
|
> 3. 支持客户端websocket
|
||||||
|
|
||||||
- PC API
|
|
||||||
- Personal API
|
|
||||||
- Login
|
# 特性
|
||||||
- Address Book
|
|
||||||
- Groups
|
- PC端API
|
||||||
- Authorized login, supports `GitHub`, `Google` and `OIDC` login, supports `web admin` authorized login
|
- 个人版API
|
||||||
|
- 登录
|
||||||
|
- 地址簿
|
||||||
|
- 群组
|
||||||
|
- 授权登录
|
||||||
|
- 支持`github`, `google` 和 `OIDC` 登录,
|
||||||
|
- 支持`web后台`授权登录
|
||||||
|
- 支持`LDAP`(AD和OpenLDAP已测试), 如果API Server配置了LDAP
|
||||||
- i18n
|
- i18n
|
||||||
- Web Admin
|
- Web Admin
|
||||||
- User Management
|
- 用户管理
|
||||||
- Device Management
|
- 设备管理
|
||||||
- Address Book Management
|
- 地址簿管理
|
||||||
- Tag Management
|
- 标签管理
|
||||||
- Group Management
|
- 群组管理
|
||||||
- OAuth Management
|
- Oauth 管理
|
||||||
- Login Logs
|
- 配置LDAP, 配置文件或者环境变量
|
||||||
- Connection Logs
|
- 登录日志
|
||||||
- File Transfer Logs
|
- 链接日志
|
||||||
- Quick access to web client
|
- 文件传输日志
|
||||||
|
- 快速使用web client
|
||||||
- i18n
|
- i18n
|
||||||
- Share to guest by web client
|
- 通过 web client 分享给游客
|
||||||
|
- server控制(一些官方的简单的指令 [WIKI](https://github.com/lejianwen/rustdesk-api/wiki/Rustdesk-Command))
|
||||||
- Web Client
|
- Web Client
|
||||||
- Automatically obtain API server
|
- 自动获取API server
|
||||||
- Automatically obtain ID server and KEY
|
- 自动获取ID服务器和KEY
|
||||||
- Automatically obtain address book
|
- 自动获取地址簿
|
||||||
- Visitors are remotely to the device via a temporary sharing link
|
- 游客通过临时分享链接直接远程到设备
|
||||||
- CLI
|
- CLI
|
||||||
- Reset admin password
|
- 重置管理员密码
|
||||||
## Prerequisites
|
|
||||||
|
|
||||||
### [Rustdesk](https://github.com/rustdesk/rustdesk)
|
## 功能
|
||||||
|
|
||||||
|
|
||||||
#### The PC client uses version ***1.3.0***, and versions ***1.2.6+*** have been tested to work.
|
### API 服务
|
||||||
|
基本实现了PC端基础的接口。支持Personal版本接口,可以通过配置文件`rustdesk.personal`或环境变量`RUSTDESK_API_RUSTDESK_PERSONAL`来控制是否启用
|
||||||
|
|
||||||
#### Solutions for PC client connection timeout or connection issues
|
<table>
|
||||||
##### Connection issues or timeouts
|
<tr>
|
||||||
Because the server version lags behind the client version, the server does not respond to the client's `secure_tcp` request, causing the client to timeout.
|
<td width="50%" align="center" colspan="2"><b>登录</b></td>
|
||||||
Relevant code can be found at `https://github.com/rustdesk/rustdesk/blob/master/src/client.rs#L322`
|
</tr>
|
||||||
```rust
|
<tr>
|
||||||
if !key.is_empty() && !token.is_empty() {
|
<td width="50%" align="center" colspan="2"><img src="docs/pc_login.png"></td>
|
||||||
// mainly for the security of token
|
</tr>
|
||||||
allow_err!(secure_tcp(&mut socket, key).await);
|
<tr>
|
||||||
}
|
<td width="50%" align="center"><b>地址簿</b></td>
|
||||||
```
|
<td width="50%" align="center"><b>群组</b></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="50%" align="center"><img src="docs/pc_ab.png"></td>
|
||||||
|
<td width="50%" align="center"><img src="docs/pc_gr.png"></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
As seen, when both `key` and `token` are not empty, `secure_tcp` is called, but the server does not respond, causing the client to timeout.
|
### Web Admin:
|
||||||
The `secure_tcp` code is located at `https://github.com/rustdesk/rustdesk/blob/master/src/common.rs#L1203`
|
|
||||||
|
|
||||||
##### Four Solutions
|
* 使用前后端分离,提供用户友好的管理界面,主要用来管理和展示。前端代码在[rustdesk-api-web](https://github.com/lejianwen/rustdesk-api-web)
|
||||||
1. Specify the key on the server.
|
|
||||||
- Advantage: Simple
|
|
||||||
- Disadvantage: The connection is not encrypted
|
|
||||||
```bash
|
|
||||||
hbbs -r <relay-server-ip[:port]> -k <key>
|
|
||||||
hbbr -k <key>
|
|
||||||
```
|
|
||||||
For example
|
|
||||||
```bash
|
|
||||||
hbbs -r <relay-server-ip[:port]> -k abc1234567
|
|
||||||
hbbr -k abc1234567
|
|
||||||
```
|
|
||||||
2. Use a system-generated key or a custom key pair on the server. If the client is already logged in, it may timeout or fail to connect. Logging out and reconnecting usually resolves the issue, and the web client does not need to log out.
|
|
||||||
- Advantage: Encrypted connection
|
|
||||||
- Disadvantage: Complicated operation
|
|
||||||
3. Use a system-generated key or a custom key pair on the server, fork the official client code to modify `secure_tcp` to return directly, then compile using `Github Actions` and download the compiled client.
|
|
||||||
Refer to [official documentation](https://rustdesk.com/docs/en/dev/build/all/)
|
|
||||||
- Advantage: Encrypted connection, customizable client features, ready to use after compilation
|
|
||||||
- Disadvantage: Requires forking code and compiling, which can be challenging
|
|
||||||
4. Use [my forked code](https://github.com/lejianwen/rustdesk), which has already modified `secure_tcp`. You can download and use it directly from [here](https://github.com/lejianwen/rustdesk/releases)
|
|
||||||
- Advantage: Code changes are viewable, compiled with `Github Actions`, encrypted connection, ready to use
|
|
||||||
- Disadvantage: May not keep up with official version updates
|
|
||||||
|
|
||||||
***If encryption is not a high priority, use `1`. If encryption is important, use `3` or `4`.***
|
* 后台访问地址是`http://<your server>[:port]/_admin/`
|
||||||
|
* 初次安装管理员为用户名为`admin`,密码将在控制台打印,可以通过[命令行](#CLI)更改密码
|
||||||
|
|
||||||
## Overview
|

|
||||||
|
|
||||||
### API Service
|
1. 管理员界面
|
||||||
Basic implementation of the PC client's primary interfaces.Supports the Personal version api, which can be enabled by configuring the `rustdesk.personal` file or the `RUSTDESK_API_RUSTDESK_PERSONAL` environment variable.
|

|
||||||
|
2. 普通用户界面
|
||||||
|

|
||||||
|
|
||||||
#### Login
|
3. 每个用户可以多个地址簿,也可以将地址簿共享给其他用户
|
||||||
|
4. 分组可以自定义,方便管理,暂时支持两种类型: `共享组` 和 `普通组`
|
||||||
|
5. 可以直接打开webclient,方便使用;也可以分享给游客,游客可以直接通过webclient远程到设备
|
||||||
|
6. Oauth,支持了`Github`, `Google` 以及 `OIDC`, 需要创建一个`OAuth App`,然后配置到后台
|
||||||
|
- 对于`Google` 和 `Github`, `Issuer` 和 `Scopes`不需要填写.
|
||||||
|
- 对于`OIDC`, `Issuer`是必须的。`Scopes`是可选的,默认为 `openid,profile,email`. 确保可以获取 `sub`,`email` 和`preferred_username`
|
||||||
|
- `github oauth app`在`Settings`->`Developer settings`->`OAuth Apps`->`New OAuth App`
|
||||||
|
中创建,地址 [https://github.com/settings/developers](https://github.com/settings/developers)
|
||||||
|
- `Authorization callback URL`填写`http://<your server[:port]>/api/oidc/callback`
|
||||||
|
,比如`http://127.0.0.1:21114/api/oidc/callback`
|
||||||
|
7. 登录日志
|
||||||
|
8. 链接日志
|
||||||
|
9. 文件传输日志
|
||||||
|
10. server控制
|
||||||
|
|
||||||
- Added `GitHub`, `Google` and `OIDC` login, which can be used after configuration in the admin panel. See the OAuth
|
- `简易模式`,已经界面化了一些简单的指令,可以直接在后台执行
|
||||||
configuration section for details.
|

|
||||||
- Added authorization login for the web admin panel.
|
|
||||||
|
|
||||||

|
- `高级模式`,直接在后台执行指令
|
||||||
|
* 可以官方指令
|
||||||
|
* 可以添加自定义指令
|
||||||
|
* 可以执行自定义指令
|
||||||
|
|
||||||
#### Address Book
|
|
||||||
|
|
||||||

|
11. **LDAP 支持**, 当在API Server上设置了LDAP(已测试AD和LDAP),可以通过LDAP中的用户信息进行登录 https://github.com/lejianwen/rustdesk-api/issues/114 ,如果LDAP验证失败,返回本地用户
|
||||||
|
|
||||||
#### Groups
|
|
||||||
Groups are divided into `shared groups` and `regular groups`. In shared groups, everyone can see the peers of all group members, while in regular groups, only administrators can see all members' peers.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### Web Admin
|
|
||||||
|
|
||||||
* The frontend and backend are separated to provide a user-friendly management interface, primarily for managing and
|
|
||||||
displaying data.Frontend code is available at [rustdesk-api-web](https://github.com/lejianwen/rustdesk-api-web)
|
|
||||||
|
|
||||||
* Admin panel URL: `http://<your server[:port]>/_admin/`. The default username and password for the initial
|
|
||||||
installation are `admin` `admin`, please change the password immediately.
|
|
||||||
|
|
||||||
1. Admin interface:
|
|
||||||

|
|
||||||
2. Regular user interface:
|
|
||||||

|
|
||||||
In the top right corner, you can change the password, switch languages, and toggle between `day/night` mode.
|
|
||||||
|
|
||||||

|
|
||||||
3. Groups can be customized for easy management. Currently, two types are supported: `shared group` and `regular group`.
|
|
||||||

|
|
||||||
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.
|
|
||||||
|
|
||||||

|
|
||||||
5. OAuth support: Currently, `GitHub`, `Google` and `OIDC` are supported. You need to create an `OAuth App` and configure it in
|
|
||||||
the admin panel.
|
|
||||||

|
|
||||||
- For `Google` and `Github`, you don't need to fill the `Issuer` and `Scpoes`
|
|
||||||
- For `OIDC`, you must set the `Issuer`. And `Scopes` is optional which default is `openid,email,profile`, please make sure this `Oauth App` can access `sub`, `email` and `preferred_username`
|
|
||||||
- Create a `GitHub OAuth App`
|
|
||||||
at `Settings` -> `Developer settings` -> `OAuth Apps` -> `New OAuth App` [here](https://github.com/settings/developers).
|
|
||||||
- Set the `Authorization callback URL` to `http://<your server[:port]>/api/oauth/callback`,
|
|
||||||
e.g., `http://127.0.0.1:21114/api/oauth/callback`.
|
|
||||||
|
|
||||||
### Web Client:
|
### Web Client:
|
||||||
|
|
||||||
1. If you're already logged into the admin panel, the web client will log in automatically.
|
1. 如果已经登录了后台,web client将自动直接登录
|
||||||
2. If you're not logged in, simply click the login button in the top right corner, and the API server will be
|
2. 如果没登录后台,点击右上角登录即可,api server已经自动配置好了
|
||||||
pre-configured.
|
3. 登录后,会自动同步ID服务器和KEY
|
||||||

|
4. 登录后,会将地址簿自动保存到web client中,方便使用
|
||||||
3. After logging in, the ID server and key will be automatically synced.
|
|
||||||
4. The address book will also be automatically saved to the web client for convenient use.
|
|
||||||
5. Now supports `v2 Preview`, accessible at `/webclient2`
|
|
||||||

|
|
||||||
6. `v2 preview` deployment
|
|
||||||
- If deploying via `https` on port `443`, you must configure a reverse proxy. Refer to the [official documentation](https://rustdesk.com/docs/en/self-host/rustdesk-server-pro/faq/#8-add-websocket-secure-wss-support-for-the-id-server-and-relay-server-to-enable-secure-communication-for-the-web-client)
|
|
||||||
- If deploying via `http` or other `https` ports, configure `21118` and `21119` as with `v1`
|
|
||||||
|
|
||||||
|
|
||||||
### Automated Documentation : API documentation is generated using Swag, making it easier for developers to understand and use the API.
|
### 自动化文档: 使用 Swag 生成 API 文档,方便开发者理解和使用 API。
|
||||||
|
|
||||||
1. Admin panel docs: `<your server[:port]>/admin/swagger/index.html`
|
1. 后台文档 `<youer server[:port]>/admin/swagger/index.html`
|
||||||
2. PC client docs: `<your server[:port]>/swagger/index.html`
|
2. PC端文档 `<youer server[:port]>/swagger/index.html`
|
||||||

|

|
||||||
|
|
||||||
### CLI
|
### CLI
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# help
|
# 查看帮助
|
||||||
./apimain -h
|
./apimain -h
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Reset admin password
|
#### 重置管理员密码
|
||||||
```bash
|
```bash
|
||||||
./apimain reset-admin-pwd <pwd>
|
./apimain reset-admin-pwd <pwd>
|
||||||
```
|
```
|
||||||
|
|
||||||
## Installation and Setup
|
## 安装与运行
|
||||||
|
|
||||||
### Configuration
|
### 相关配置
|
||||||
|
|
||||||
* Modify the configuration in `conf/config.yaml`.
|
* [配置文件](./conf/config.yaml)
|
||||||
* If `gorm.type` is set to `sqlite`, MySQL-related configurations are not required.
|
* 参考`conf/config.yaml`配置文件,修改相关配置。
|
||||||
* Language support: `en` and `zh-CN` are supported. The default is `zh-CN`.
|
* 如果`gorm.type`是`sqlite`,则不需要配置mysql相关配置。
|
||||||
|
* 语言如果不设置默认为`zh-CN`
|
||||||
|
|
||||||
```yaml
|
### 环境变量
|
||||||
lang: "en"
|
环境变量和配置文件`conf/config.yaml`中的配置一一对应,变量名前缀是`RUSTDESK_API`
|
||||||
app:
|
下面表格并未全部列出,可以参考`conf/config.yaml`中的配置。
|
||||||
web-client: 1 # web client route 1:open 0:close
|
|
||||||
register: false #register enable
|
|
||||||
gin:
|
|
||||||
api-addr: "0.0.0.0:21114"
|
|
||||||
mode: "release"
|
|
||||||
resources-path: 'resources'
|
|
||||||
trust-proxy: ""
|
|
||||||
gorm:
|
|
||||||
type: "sqlite"
|
|
||||||
max-idle-conns: 10
|
|
||||||
max-open-conns: 100
|
|
||||||
mysql:
|
|
||||||
username: "root"
|
|
||||||
password: "111111"
|
|
||||||
addr: "192.168.1.66:3308"
|
|
||||||
dbname: "rustdesk"
|
|
||||||
rustdesk:
|
|
||||||
id-server: "192.168.1.66:21116"
|
|
||||||
relay-server: "192.168.1.66:21117"
|
|
||||||
api-server: "http://192.168.1.66:21114"
|
|
||||||
key: "123456789"
|
|
||||||
personal: 1
|
|
||||||
logger:
|
|
||||||
path: "./runtime/log.txt"
|
|
||||||
level: "warn" #trace,debug,info,warn,error,fatal
|
|
||||||
report-caller: true
|
|
||||||
proxy:
|
|
||||||
enable: false
|
|
||||||
host: ""
|
|
||||||
```
|
|
||||||
|
|
||||||
### Environment Variables
|
| 变量名 | 说明 | 示例 |
|
||||||
The prefix for variable names is `RUSTDESK_API`. If environment variables exist, they will override the configurations in the configuration file.
|
|--------------------------------------------------------|--------------------------------------------------------------------------------|------------------------------|
|
||||||
|
| TZ | 时区 | Asia/Shanghai |
|
||||||
| Variable Name | Description | Example |
|
| RUSTDESK_API_LANG | 语言 | `en`,`zh-CN` |
|
||||||
|------------------------------------|-------------------------------------------------------------------------|-------------------------------|
|
| RUSTDESK_API_APP_WEB_CLIENT | 是否启用web-client; 1:启用,0:不启用; 默认启用 | 1 |
|
||||||
| TZ | timezone | Asia/Shanghai |
|
| RUSTDESK_API_APP_REGISTER | 是否开启注册; `true`, `false` 默认`false` | `false` |
|
||||||
| RUSTDESK_API_LANG | Language | `en`,`zh-CN` |
|
| RUSTDESK_API_APP_SHOW_SWAGGER | 是否可见swagger文档;`1`显示,`0`不显示,默认`0`不显示 | `1` |
|
||||||
| RUSTDESK_API_APP_WEB_CLIENT | web client on/off; 1: on, 0 off, deault 1 | 1 |
|
| RUSTDESK_API_APP_TOKEN_EXPIRE | token有效时长 | `168h` |
|
||||||
| RUSTDESK_API_APP_REGISTER | register enable; `true`, `false`; default:`false` | `false` |
|
| RUSTDESK_API_APP_DISABLE_PWD_LOGIN | 是否禁用密码登录; `true`, `false` 默认`false` | `false` |
|
||||||
| ----- ADMIN Configuration----- | ---------- | ---------- |
|
| RUSTDESK_API_APP_REGISTER_STATUS | 注册用户默认状态; 1 启用,2 禁用, 默认 1 | `1` |
|
||||||
| RUSTDESK_API_ADMIN_TITLE | Admin Title | `RustDesk Api Admin` |
|
| RUSTDESK_API_APP_CAPTCHA_THRESHOLD | 验证码触发次数; -1 不启用, 0 一直启用, >0 登录错误次数后启用 ;默认 `3` | `3` |
|
||||||
| RUSTDESK_API_ADMIN_HELLO | Admin welcome message, you can use `html` | |
|
| RUSTDESK_API_APP_BAN_THRESHOLD | 封禁IP触发次数; 0 不启用, >0 登录错误次数后封禁IP; 默认 `0` | `0` |
|
||||||
| RUSTDESK_API_ADMIN_HELLO_FILE | Admin welcome message file,<br>will override `RUSTDESK_API_ADMIN_HELLO` | `./conf/admin/hello.html` |
|
| -----ADMIN配置----- | ---------- | ---------- |
|
||||||
| ----- GIN Configuration ----- | --------------------------------------- | ----------------------------- |
|
| RUSTDESK_API_ADMIN_TITLE | 后台标题 | `RustDesk Api Admin` |
|
||||||
| RUSTDESK_API_GIN_TRUST_PROXY | Trusted proxy IPs, separated by commas. | 192.168.1.2,192.168.1.3 |
|
| RUSTDESK_API_ADMIN_HELLO | 后台欢迎语,可以使用`html` | |
|
||||||
| ----- GORM Configuration ----- | --------------------------------------- | ----------------------------- |
|
| RUSTDESK_API_ADMIN_HELLO_FILE | 后台欢迎语文件,如果内容多,使用文件更方便。<br>会覆盖`RUSTDESK_API_ADMIN_HELLO` | `./conf/admin/hello.html` |
|
||||||
| RUSTDESK_API_GORM_TYPE | Database type (`sqlite` or `mysql`). Default is `sqlite`. | sqlite |
|
| -----GIN配置----- | ---------- | ---------- |
|
||||||
| RUSTDESK_API_GORM_MAX_IDLE_CONNS | Maximum idle connections | 10 |
|
| RUSTDESK_API_GIN_TRUST_PROXY | 信任的代理IP列表,以`,`分割,默认信任所有 | 192.168.1.2,192.168.1.3 |
|
||||||
| RUSTDESK_API_GORM_MAX_OPEN_CONNS | Maximum open connections | 100 |
|
| -----GORM配置----- | ---------- | --------------------------- |
|
||||||
| RUSTDESK_API_RUSTDESK_PERSONAL | Open Personal Api 1:Enable,0:Disable | 1 |
|
| RUSTDESK_API_GORM_TYPE | 数据库类型sqlite或者mysql,默认sqlite | sqlite |
|
||||||
| ----- MYSQL Configuration ----- | --------------------------------------- | ----------------------------- |
|
| RUSTDESK_API_GORM_MAX_IDLE_CONNS | 数据库最大空闲连接数 | 10 |
|
||||||
| RUSTDESK_API_MYSQL_USERNAME | MySQL username | root |
|
| RUSTDESK_API_GORM_MAX_OPEN_CONNS | 数据库最大打开连接数 | 100 |
|
||||||
| RUSTDESK_API_MYSQL_PASSWORD | MySQL password | 111111 |
|
| RUSTDESK_API_RUSTDESK_PERSONAL | 是否启用个人版API, 1:启用,0:不启用; 默认启用 | 1 |
|
||||||
| RUSTDESK_API_MYSQL_ADDR | MySQL address | 192.168.1.66:3306 |
|
| -----MYSQL配置----- | ---------- | ---------- |
|
||||||
| RUSTDESK_API_MYSQL_DBNAME | MySQL database name | rustdesk |
|
| RUSTDESK_API_MYSQL_USERNAME | mysql用户名 | root |
|
||||||
| ----- RUSTDESK Configuration ----- | --------------------------------------- | ----------------------------- |
|
| RUSTDESK_API_MYSQL_PASSWORD | mysql密码 | 111111 |
|
||||||
| RUSTDESK_API_RUSTDESK_ID_SERVER | Rustdesk ID server address | 192.168.1.66:21116 |
|
| RUSTDESK_API_MYSQL_ADDR | mysql地址 | 192.168.1.66:3306 |
|
||||||
| RUSTDESK_API_RUSTDESK_RELAY_SERVER | Rustdesk relay server address | 192.168.1.66:21117 |
|
| RUSTDESK_API_MYSQL_DBNAME | mysql数据库名 | rustdesk |
|
||||||
| RUSTDESK_API_RUSTDESK_API_SERVER | Rustdesk API server address | http://192.168.1.66:21114 |
|
| RUSTDESK_API_MYSQL_TLS | 是否启用TLS, 可选值: `true`, `false`, `skip-verify`, `custom` | `false` |
|
||||||
| RUSTDESK_API_RUSTDESK_KEY | Rustdesk key | 123456789 |
|
| -----RUSTDESK配置----- | ---------- | ---------- |
|
||||||
|
| RUSTDESK_API_RUSTDESK_ID_SERVER | Rustdesk的id服务器地址 | 192.168.1.66:21116 |
|
||||||
|
| 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_KEY | Rustdesk的key | 123456789 |
|
||||||
| RUSTDESK_API_RUSTDESK_KEY_FILE | Rustdesk存放key的文件 | `./conf/data/id_ed25519.pub` |
|
| RUSTDESK_API_RUSTDESK_KEY_FILE | Rustdesk存放key的文件 | `./conf/data/id_ed25519.pub` |
|
||||||
| ---- PROXY ----- | --------------- | ---------- |
|
| RUSTDESK_API_RUSTDESK_WEBCLIENT<br/>_MAGIC_QUERYONLINE | Web client v2 中是否启用新的在线状态查询方法; `1`:启用,`0`:不启用,默认不启用 | `0` |
|
||||||
| RUSTDESK_API_PROXY_ENABLE | proxy_enable :`false`, `true` | `false` |
|
| RUSTDESK_API_RUSTDESK_WS_HOST | 自定义Websocket Host | `wss://192.168.1.123:1234` |
|
||||||
| RUSTDESK_API_PROXY_HOST | proxy_host | `http://127.0.0.1:1080` |
|
| ----PROXY配置----- | ---------- | ---------- |
|
||||||
|
| RUSTDESK_API_PROXY_ENABLE | 是否启用代理:`false`, `true` | `false` |
|
||||||
|
| RUSTDESK_API_PROXY_HOST | 代理地址 | `http://127.0.0.1:1080` |
|
||||||
|
| ----JWT配置---- | -------- | -------- |
|
||||||
|
| RUSTDESK_API_JWT_KEY | 自定义JWT KEY,为空则不启用JWT<br/>如果没使用`lejianwen/rustdesk-server`中的`MUST_LOGIN`,建议设置为空 | |
|
||||||
|
| RUSTDESK_API_JWT_EXPIRE_DURATION | JWT有效时间 | `168h` |
|
||||||
|
|
||||||
### Installation Steps
|
|
||||||
|
|
||||||
#### Running via Docker
|
### 运行
|
||||||
|
|
||||||
1. Run directly with Docker. Configuration can be modified by mounting the config file `/app/conf/config.yaml`, or by
|
#### docker运行
|
||||||
using environment variables to override settings.
|
|
||||||
|
1. 直接docker运行,配置可以通过挂载配置文件`/app/conf/config.yaml`来修改,或者通过环境变量覆盖配置文件中的配置
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run -d --name rustdesk-api -p 21114:21114 \
|
docker run -d --name rustdesk-api -p 21114:21114 \
|
||||||
-v /data/rustdesk/api:/app/data \
|
-v /data/rustdesk/api:/app/data \
|
||||||
-e RUSTDESK_API_LANG=en \
|
-e TZ=Asia/Shanghai \
|
||||||
|
-e RUSTDESK_API_LANG=zh-CN \
|
||||||
-e RUSTDESK_API_RUSTDESK_ID_SERVER=192.168.1.66:21116 \
|
-e RUSTDESK_API_RUSTDESK_ID_SERVER=192.168.1.66:21116 \
|
||||||
-e RUSTDESK_API_RUSTDESK_RELAY_SERVER=192.168.1.66:21117 \
|
-e RUSTDESK_API_RUSTDESK_RELAY_SERVER=192.168.1.66:21117 \
|
||||||
-e RUSTDESK_API_RUSTDESK_API_SERVER=http://192.168.1.66:21114 \
|
-e RUSTDESK_API_RUSTDESK_API_SERVER=http://192.168.1.66:21114 \
|
||||||
-e RUSTDESK_API_RUSTDESK_KEY=abc123456 \
|
-e RUSTDESK_API_RUSTDESK_KEY=<key> \
|
||||||
lejianwen/rustdesk-api
|
lejianwen/rustdesk-api
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Using `docker-compose`
|
2. 使用`docker compose`,参考[WIKI](https://github.com/lejianwen/rustdesk-api/wiki)
|
||||||
- Simple example:
|
|
||||||
```yaml
|
|
||||||
services:
|
|
||||||
rustdesk-api:
|
|
||||||
container_name: rustdesk-api
|
|
||||||
environment:
|
|
||||||
- RUSTDESK_API_LANG=en
|
|
||||||
- RUSTDESK_API_RUSTDESK_ID_SERVER=192.168.1.66:21116
|
|
||||||
- RUSTDESK_API_RUSTDESK_RELAY_SERVER=192.168.1.66:21117
|
|
||||||
- RUSTDESK_API_RUSTDESK_API_SERVER=http://192.168.1.66:21114
|
|
||||||
- RUSTDESK_API_RUSTDESK_KEY=<key>
|
|
||||||
ports:
|
|
||||||
- 21114:21114
|
|
||||||
image: lejianwen/rustdesk-api
|
|
||||||
volumes:
|
|
||||||
- /data/rustdesk/api:/app/data # Mount the database for easy backup
|
|
||||||
networks:
|
|
||||||
- rustdesk-net
|
|
||||||
restart: unless-stopped
|
|
||||||
```
|
|
||||||
|
|
||||||
- Example with RustDesk's official Docker Compose file, adding your `rustdesk-api` service:
|
#### 下载release直接运行
|
||||||
- If you are using a system-generated KEY, remove the `-k <key>` parameter. However, after the first startup, run `docker-compose logs hbbs` or `cat ./data/id_ed25519.pub` to view the KEY, then modify `RUSTDESK_API_RUSTDESK_KEY=<key>` and execute `docker-compose up -d` again.
|
|
||||||
```yaml
|
|
||||||
networks:
|
|
||||||
rustdesk-net:
|
|
||||||
external: false
|
|
||||||
services:
|
|
||||||
hbbs:
|
|
||||||
container_name: hbbs
|
|
||||||
ports:
|
|
||||||
- 21115:21115
|
|
||||||
- 21116:21116 # 自定义 hbbs 映射端口
|
|
||||||
- 21116:21116/udp # 自定义 hbbs 映射端口
|
|
||||||
- 21118:21118 # web client
|
|
||||||
image: rustdesk/rustdesk-server
|
|
||||||
command: hbbs -r <relay-server-ip[:port]> -k <key> # 填入个人域名或 IP + hbbr 暴露端口
|
|
||||||
volumes:
|
|
||||||
- ./data:/root # 自定义挂载目录
|
|
||||||
networks:
|
|
||||||
- rustdesk-net
|
|
||||||
depends_on:
|
|
||||||
- hbbr
|
|
||||||
restart: unless-stopped
|
|
||||||
deploy:
|
|
||||||
resources:
|
|
||||||
limits:
|
|
||||||
memory: 64M
|
|
||||||
hbbr:
|
|
||||||
container_name: hbbr
|
|
||||||
ports:
|
|
||||||
- 21117:21117 # 自定义 hbbr 映射端口
|
|
||||||
- 21119:21119 # web client
|
|
||||||
image: rustdesk/rustdesk-server
|
|
||||||
command: hbbr -k <key>
|
|
||||||
volumes:
|
|
||||||
- ./data:/root
|
|
||||||
networks:
|
|
||||||
- rustdesk-net
|
|
||||||
restart: unless-stopped
|
|
||||||
deploy:
|
|
||||||
resources:
|
|
||||||
limits:
|
|
||||||
memory: 64M
|
|
||||||
rustdesk-api:
|
|
||||||
container_name: rustdesk-api
|
|
||||||
environment:
|
|
||||||
- TZ=Asia/Shanghai
|
|
||||||
- RUSTDESK_API_RUSTDESK_ID_SERVER=192.168.1.66:21116
|
|
||||||
- RUSTDESK_API_RUSTDESK_RELAY_SERVER=192.168.1.66:21117
|
|
||||||
- RUSTDESK_API_RUSTDESK_API_SERVER=http://192.168.1.66:21114
|
|
||||||
- RUSTDESK_API_RUSTDESK_KEY=<key>
|
|
||||||
ports:
|
|
||||||
- 21114:21114
|
|
||||||
image: lejianwen/rustdesk-api
|
|
||||||
volumes:
|
|
||||||
- /data/rustdesk/api:/app/data #将数据库挂载出来方便备份
|
|
||||||
networks:
|
|
||||||
- rustdesk-net
|
|
||||||
restart: unless-stopped
|
|
||||||
```
|
|
||||||
|
|
||||||
- S6 image
|
[下载地址](https://github.com/lejianwen/rustdesk-api/releases)
|
||||||
- - If using ***custom KEY***, you will need to modify the startup script to override the `/etc/s6-overlay/s6-rc.d/hbbr/run` and `/etc/s6-overlay/s6-rc.d/hbbr/run` in the image.
|
|
||||||
1. Create `hbbr/run`, only needed for custom KEY
|
|
||||||
```bash
|
|
||||||
#!/command/with-contenv sh
|
|
||||||
cd /data
|
|
||||||
PARAMS=
|
|
||||||
[ "${ENCRYPTED_ONLY}" = "1" ] && PARAMS="-k ${KEY}"
|
|
||||||
/usr/bin/hbbr $PARAMS
|
|
||||||
```
|
|
||||||
2. Create `hbbs/run`, only needed for custom KEY
|
|
||||||
```bash
|
|
||||||
#!/command/with-contenv sh
|
|
||||||
sleep 2
|
|
||||||
cd /data
|
|
||||||
PARAMS=
|
|
||||||
[ "${ENCRYPTED_ONLY}" = "1" ] && PARAMS="-k ${KEY}"
|
|
||||||
/usr/bin/hbbs -r $RELAY $PARAMS
|
|
||||||
```
|
|
||||||
3. Modify the `s6` section in `docker-compose.yml`
|
|
||||||
```yaml
|
|
||||||
networks:
|
|
||||||
rustdesk-net:
|
|
||||||
external: false
|
|
||||||
services:
|
|
||||||
rustdesk-server:
|
|
||||||
container_name: rustdesk-server
|
|
||||||
ports:
|
|
||||||
- 21115:21115
|
|
||||||
- 21116:21116
|
|
||||||
- 21116:21116/udp
|
|
||||||
- 21117:21117
|
|
||||||
- 21118:21118
|
|
||||||
- 21119:21119
|
|
||||||
image: rustdesk/rustdesk-server-s6:latest
|
|
||||||
environment:
|
|
||||||
- RELAY=192.168.1.66:21117
|
|
||||||
- ENCRYPTED_ONLY=1
|
|
||||||
- KEY=<key> #KEY
|
|
||||||
volumes:
|
|
||||||
- ./data:/data
|
|
||||||
- ./hbbr/run:/etc/s6-overlay/s6-rc.d/hbbr/run
|
|
||||||
- ./hbbs/run:/etc/s6-overlay/s6-rc.d/hbbs/run
|
|
||||||
restart: unless-stopped
|
|
||||||
rustdesk-api:
|
|
||||||
container_name: rustdesk-api
|
|
||||||
ports:
|
|
||||||
- 21114:21114
|
|
||||||
image: lejianwen/rustdesk-api
|
|
||||||
environment:
|
|
||||||
- TZ=Asia/Shanghai
|
|
||||||
- RUSTDESK_API_RUSTDESK_ID_SERVER=192.168.1.66:21116
|
|
||||||
- RUSTDESK_API_RUSTDESK_RELAY_SERVER=192.168.1.66:21117
|
|
||||||
- RUSTDESK_API_RUSTDESK_API_SERVER=http://192.168.1.66:21114
|
|
||||||
- RUSTDESK_API_RUSTDESK_KEY=<key>
|
|
||||||
volumes:
|
|
||||||
- /data/rustdesk/api:/app/data
|
|
||||||
networks:
|
|
||||||
- rustdesk-net
|
|
||||||
restart: unless-stopped
|
|
||||||
```
|
|
||||||
- If using ***system-generated KEY*** or ***custom KEY_PUB, KEY_PRIV***, you do not need to modify the startup script, but you need to obtain the KEY after it is generated and then run `docker-compose up -d`
|
|
||||||
```yaml
|
|
||||||
networks:
|
|
||||||
rustdesk-net:
|
|
||||||
external: false
|
|
||||||
services:
|
|
||||||
rustdesk-server:
|
|
||||||
container_name: rustdesk-server
|
|
||||||
ports:
|
|
||||||
- 21115:21115
|
|
||||||
- 21116:21116
|
|
||||||
- 21116:21116/udp
|
|
||||||
- 21117:21117
|
|
||||||
- 21118:21118
|
|
||||||
- 21119:21119
|
|
||||||
image: rustdesk/rustdesk-server-s6:latest
|
|
||||||
environment:
|
|
||||||
- RELAY=192.168.1.66:21117
|
|
||||||
- ENCRYPTED_ONLY=1
|
|
||||||
volumes:
|
|
||||||
- ./data:/data
|
|
||||||
restart: unless-stopped
|
|
||||||
rustdesk-api:
|
|
||||||
container_name: rustdesk-api
|
|
||||||
ports:
|
|
||||||
- 21114:21114
|
|
||||||
image: lejianwen/rustdesk-api
|
|
||||||
environment:
|
|
||||||
- TZ=Asia/Shanghai
|
|
||||||
- RUSTDESK_API_RUSTDESK_ID_SERVER=192.168.1.66:21116
|
|
||||||
- RUSTDESK_API_RUSTDESK_RELAY_SERVER=192.168.1.66:21117
|
|
||||||
- RUSTDESK_API_RUSTDESK_API_SERVER=http://192.168.1.66:21114
|
|
||||||
- RUSTDESK_API_RUSTDESK_KEY=<key>
|
|
||||||
volumes:
|
|
||||||
- /data/rustdesk/api:/app/data
|
|
||||||
networks:
|
|
||||||
- rustdesk-net
|
|
||||||
restart: unless-stopped
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Running from Release
|
#### 源码安装
|
||||||
|
|
||||||
Download the release from [release](https://github.com/lejianwen/rustdesk-api/releases).
|
1. 克隆仓库
|
||||||
|
|
||||||
#### Source Installation
|
|
||||||
|
|
||||||
1. Clone the repository:
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/lejianwen/rustdesk-api.git
|
git clone https://github.com/lejianwen/rustdesk-api.git
|
||||||
cd rustdesk-api
|
cd rustdesk-api
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Install dependencies:
|
2. 安装依赖
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
go mod tidy
|
go mod tidy
|
||||||
# Install Swag if you need to generate documentation; otherwise, you can skip this step
|
#安装swag,如果不需要生成文档,可以不安装
|
||||||
go install github.com/swaggo/swag/cmd/swag@latest
|
go install github.com/swaggo/swag/cmd/swag@latest
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Build the admin front-end (the front-end code is
|
3. 编译后台前端,前端代码在[rustdesk-api-web](https://github.com/lejianwen/rustdesk-api-web)中
|
||||||
in [rustdesk-api-web](https://github.com/lejianwen/rustdesk-api-web)):
|
|
||||||
```bash
|
```bash
|
||||||
cd resources
|
cd resources
|
||||||
mkdir -p admin
|
mkdir -p admin
|
||||||
@@ -481,38 +254,82 @@ Download the release from [release](https://github.com/lejianwen/rustdesk-api/re
|
|||||||
npm run build
|
npm run build
|
||||||
cp -ar dist/* ../admin/
|
cp -ar dist/* ../admin/
|
||||||
```
|
```
|
||||||
|
4. 运行
|
||||||
4. Run:
|
|
||||||
```bash
|
```bash
|
||||||
# Run directly
|
#直接运行
|
||||||
go run cmd/apimain.go
|
go run cmd/apimain.go
|
||||||
# Or generate and run the API using generate_api.go
|
#或者使用generate_api.go生成api并运行
|
||||||
go generate generate_api.go
|
go generate generate_api.go
|
||||||
```
|
```
|
||||||
|
> 注意:使用 `go run` 或编译后的二进制时,当前目录下必须存在 `conf` 和 `resources`
|
||||||
|
> 目录。如果在其他目录运行,可通过 `-c` 和环境变量
|
||||||
|
> `RUSTDESK_API_GIN_RESOURCES_PATH` 指定绝对路径,例如:
|
||||||
|
> ```bash
|
||||||
|
> RUSTDESK_API_GIN_RESOURCES_PATH=/opt/rustdesk-api/resources ./apimain -c /opt/rustdesk-api/conf/config.yaml
|
||||||
|
> ```
|
||||||
|
5. 编译,如果想自己编译,先cd到项目根目录,然后windows下直接运行`build.bat`,linux下运行`build.sh`,编译后会在`release`
|
||||||
|
目录下生成对应的可执行文件。直接运行编译后的可执行文件即可。
|
||||||
|
|
||||||
5. To compile, change to the project root directory. For Windows, run `build.bat`, and for Linux, run `build.sh`. After
|
6. 打开浏览器访问`http://<your server[:port]>/_admin/`,默认用户名密码为`admin`,请及时更改密码。
|
||||||
compiling, the corresponding executables will be generated in the `release` directory. Run the compiled executables
|
|
||||||
directly.
|
|
||||||
|
|
||||||
6. Open your browser and visit `http://<your server[:port]>/_admin/`, with default credentials `admin admin`. Please
|
|
||||||
change the password promptly.
|
|
||||||
|
|
||||||
#### nginx reverse proxy
|
#### 使用`lejianwen/server-s6`镜像运行
|
||||||
Configure reverse proxy in `nginx`
|
|
||||||
|
- 已解决链接超时问题
|
||||||
|
- 可以强制登录后才能发起链接
|
||||||
|
- github https://github.com/lejianwen/rustdesk-server
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
networks:
|
||||||
|
rustdesk-net:
|
||||||
|
external: false
|
||||||
|
services:
|
||||||
|
rustdesk:
|
||||||
|
ports:
|
||||||
|
- 21114:21114
|
||||||
|
- 21115:21115
|
||||||
|
- 21116:21116
|
||||||
|
- 21116:21116/udp
|
||||||
|
- 21117:21117
|
||||||
|
- 21118:21118
|
||||||
|
- 21119:21119
|
||||||
|
image: lejianwen/rustdesk-server-s6:latest
|
||||||
|
environment:
|
||||||
|
- RELAY=<relay_server[:port]>
|
||||||
|
- ENCRYPTED_ONLY=1
|
||||||
|
- MUST_LOGIN=N
|
||||||
|
- TZ=Asia/Shanghai
|
||||||
|
- RUSTDESK_API_RUSTDESK_ID_SERVER=<id_server[:21116]>
|
||||||
|
- RUSTDESK_API_RUSTDESK_RELAY_SERVER=<relay_server[:21117]>
|
||||||
|
- RUSTDESK_API_RUSTDESK_API_SERVER=http://<api_server[:21114]>
|
||||||
|
- RUSTDESK_API_KEY_FILE=/data/id_ed25519.pub
|
||||||
|
- RUSTDESK_API_JWT_KEY=xxxxxx # jwt key
|
||||||
|
volumes:
|
||||||
|
- /data/rustdesk/server:/data
|
||||||
|
- /data/rustdesk/api:/app/data #将数据库挂载
|
||||||
|
networks:
|
||||||
|
- rustdesk-net
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
```
|
```
|
||||||
server {
|
|
||||||
listen <your port>;
|
|
||||||
server_name <your server>;
|
|
||||||
location / {
|
|
||||||
proxy_pass http://<api-server[:port]>;
|
|
||||||
proxy_set_header Host $host;
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
## Others
|
|
||||||
|
|
||||||
- [Change client ID](https://github.com/abdullah-erturk/RustDesk-ID-Changer)
|
|
||||||
- [Web client source](https://hub.docker.com/r/keyurbhole/flutter_web_desk)
|
## 其他
|
||||||
|
|
||||||
|
- [WIKI](https://github.com/lejianwen/rustdesk-api/wiki)
|
||||||
|
- [链接超时问题](https://github.com/lejianwen/rustdesk-api/issues/92)
|
||||||
|
- [修改客户端ID](https://github.com/abdullah-erturk/RustDesk-ID-Changer)
|
||||||
|
- [webclient来源](https://hub.docker.com/r/keyurbhole/flutter_web_desk)
|
||||||
|
|
||||||
|
|
||||||
|
## 鸣谢
|
||||||
|
|
||||||
|
感谢所有做过贡献的人!
|
||||||
|
|
||||||
|
<a href="https://github.com/lejianwen/rustdesk-api/graphs/contributors">
|
||||||
|
<img src="https://contrib.rocks/image?repo=lejianwen/rustdesk-api" />
|
||||||
|
</a>
|
||||||
|
|
||||||
|
## 感谢你的支持!如果这个项目对你有帮助,请点个⭐️鼓励一下,谢谢!
|
||||||
|
|
||||||
|
[lejianwen/rustdesk-server]: https://github.com/lejianwen/rustdesk-server
|
||||||
@@ -1,27 +1,33 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"Gwen/config"
|
|
||||||
"Gwen/global"
|
|
||||||
"Gwen/http"
|
|
||||||
"Gwen/lib/cache"
|
|
||||||
"Gwen/lib/lock"
|
|
||||||
"Gwen/lib/logger"
|
|
||||||
"Gwen/lib/orm"
|
|
||||||
"Gwen/lib/upload"
|
|
||||||
"Gwen/model"
|
|
||||||
"Gwen/service"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/go-redis/redis/v8"
|
|
||||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-redis/redis/v8"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/config"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/lib/cache"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/lib/jwt"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/lib/lock"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/lib/logger"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/lib/orm"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/lib/upload"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/utils"
|
||||||
|
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
// @title 管理系统API
|
const DatabaseVersion = 265
|
||||||
|
|
||||||
|
// @title Management System API
|
||||||
// @version 1.0
|
// @version 1.0
|
||||||
// @description 接口
|
// @description API
|
||||||
// @basePath /api
|
// @basePath /api
|
||||||
// @securityDefinitions.apikey token
|
// @securityDefinitions.apikey token
|
||||||
// @in header
|
// @in header
|
||||||
@@ -37,7 +43,7 @@ var rootCmd = &cobra.Command{
|
|||||||
InitGlobal()
|
InitGlobal()
|
||||||
},
|
},
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
//gin
|
global.Logger.Info("API SERVER START")
|
||||||
http.ApiInit()
|
http.ApiInit()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -50,12 +56,16 @@ var resetPwdCmd = &cobra.Command{
|
|||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
pwd := args[0]
|
pwd := args[0]
|
||||||
admin := service.AllService.UserService.InfoById(1)
|
admin := service.AllService.UserService.InfoById(1)
|
||||||
err := service.AllService.UserService.UpdatePassword(admin, pwd)
|
if admin.Id == 0 {
|
||||||
if err != nil {
|
global.Logger.Warn("user not found! ")
|
||||||
fmt.Printf("reset password fail! %v \n", err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Printf("reset password success! \n")
|
err := service.AllService.UserService.UpdatePassword(admin, pwd)
|
||||||
|
if err != nil {
|
||||||
|
global.Logger.Error("reset password fail! ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
global.Logger.Info("reset password success! ")
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
var resetUserPwdCmd = &cobra.Command{
|
var resetUserPwdCmd = &cobra.Command{
|
||||||
@@ -68,20 +78,24 @@ var resetUserPwdCmd = &cobra.Command{
|
|||||||
pwd := args[1]
|
pwd := args[1]
|
||||||
uid, err := strconv.Atoi(userId)
|
uid, err := strconv.Atoi(userId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("userId must be int! \n")
|
global.Logger.Warn("userId must be int!")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if uid <= 0 {
|
if uid <= 0 {
|
||||||
fmt.Printf("userId must be greater than 0! \n")
|
global.Logger.Warn("userId must be greater than 0! ")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
u := service.AllService.UserService.InfoById(uint(uid))
|
u := service.AllService.UserService.InfoById(uint(uid))
|
||||||
err = service.AllService.UserService.UpdatePassword(u, pwd)
|
if u.Id == 0 {
|
||||||
if err != nil {
|
global.Logger.Warn("user not found! ")
|
||||||
fmt.Printf("reset password fail! %v \n", err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Printf("reset password success! \n")
|
err = service.AllService.UserService.UpdatePassword(u, pwd)
|
||||||
|
if err != nil {
|
||||||
|
global.Logger.Warn("reset password fail! ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
global.Logger.Info("reset password success!")
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,19 +105,16 @@ func init() {
|
|||||||
}
|
}
|
||||||
func main() {
|
func main() {
|
||||||
if err := rootCmd.Execute(); err != nil {
|
if err := rootCmd.Execute(); err != nil {
|
||||||
fmt.Println(err)
|
global.Logger.Error(err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitGlobal() {
|
func InitGlobal() {
|
||||||
//配置解析
|
// config parsing
|
||||||
global.Viper = config.Init(&global.Config, global.ConfigPath)
|
global.Viper = config.Init(&global.Config, global.ConfigPath)
|
||||||
|
|
||||||
//从配置文件中加载密钥
|
// logging
|
||||||
config.LoadKeyFile(&global.Config.Rustdesk)
|
|
||||||
|
|
||||||
//日志
|
|
||||||
global.Logger = logger.New(&logger.Config{
|
global.Logger = logger.New(&logger.Config{
|
||||||
Path: global.Config.Logger.Path,
|
Path: global.Config.Logger.Path,
|
||||||
Level: global.Config.Logger.Level,
|
Level: global.Config.Logger.Level,
|
||||||
@@ -133,20 +144,42 @@ func InitGlobal() {
|
|||||||
}
|
}
|
||||||
//gorm
|
//gorm
|
||||||
if global.Config.Gorm.Type == config.TypeMysql {
|
if global.Config.Gorm.Type == config.TypeMysql {
|
||||||
dns := global.Config.Mysql.Username + ":" + global.Config.Mysql.Password + "@(" + global.Config.Mysql.Addr + ")/" + global.Config.Mysql.Dbname + "?charset=utf8mb4&parseTime=True&loc=Local"
|
|
||||||
|
dsn := fmt.Sprintf("%s:%s@(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local&tls=%s",
|
||||||
|
global.Config.Mysql.Username,
|
||||||
|
global.Config.Mysql.Password,
|
||||||
|
global.Config.Mysql.Addr,
|
||||||
|
global.Config.Mysql.Dbname,
|
||||||
|
global.Config.Mysql.Tls,
|
||||||
|
)
|
||||||
|
|
||||||
global.DB = orm.NewMysql(&orm.MysqlConfig{
|
global.DB = orm.NewMysql(&orm.MysqlConfig{
|
||||||
Dns: dns,
|
Dsn: dsn,
|
||||||
MaxIdleConns: global.Config.Gorm.MaxIdleConns,
|
MaxIdleConns: global.Config.Gorm.MaxIdleConns,
|
||||||
MaxOpenConns: global.Config.Gorm.MaxOpenConns,
|
MaxOpenConns: global.Config.Gorm.MaxOpenConns,
|
||||||
})
|
}, global.Logger)
|
||||||
|
} else if global.Config.Gorm.Type == config.TypePostgresql {
|
||||||
|
dsn := fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=%s TimeZone=%s",
|
||||||
|
global.Config.Postgresql.Host,
|
||||||
|
global.Config.Postgresql.Port,
|
||||||
|
global.Config.Postgresql.User,
|
||||||
|
global.Config.Postgresql.Password,
|
||||||
|
global.Config.Postgresql.Dbname,
|
||||||
|
global.Config.Postgresql.Sslmode,
|
||||||
|
global.Config.Postgresql.TimeZone,
|
||||||
|
)
|
||||||
|
global.DB = orm.NewPostgresql(&orm.PostgresqlConfig{
|
||||||
|
Dsn: dsn,
|
||||||
|
MaxIdleConns: global.Config.Gorm.MaxIdleConns,
|
||||||
|
MaxOpenConns: global.Config.Gorm.MaxOpenConns,
|
||||||
|
}, global.Logger)
|
||||||
} else {
|
} else {
|
||||||
//sqlite
|
//sqlite
|
||||||
global.DB = orm.NewSqlite(&orm.SqliteConfig{
|
global.DB = orm.NewSqlite(&orm.SqliteConfig{
|
||||||
MaxIdleConns: global.Config.Gorm.MaxIdleConns,
|
MaxIdleConns: global.Config.Gorm.MaxIdleConns,
|
||||||
MaxOpenConns: global.Config.Gorm.MaxOpenConns,
|
MaxOpenConns: global.Config.Gorm.MaxOpenConns,
|
||||||
})
|
}, global.Logger)
|
||||||
}
|
}
|
||||||
DatabaseAutoUpdate()
|
|
||||||
|
|
||||||
//validator
|
//validator
|
||||||
global.ApiInitValidator()
|
global.ApiInitValidator()
|
||||||
@@ -163,43 +196,60 @@ func InitGlobal() {
|
|||||||
|
|
||||||
//jwt
|
//jwt
|
||||||
//fmt.Println(global.Config.Jwt.PrivateKey)
|
//fmt.Println(global.Config.Jwt.PrivateKey)
|
||||||
//global.Jwt = jwt.NewJwt(global.Config.Jwt.PrivateKey, global.Config.Jwt.ExpireDuration*time.Second)
|
global.Jwt = jwt.NewJwt(global.Config.Jwt.Key, global.Config.Jwt.ExpireDuration)
|
||||||
|
|
||||||
//locker
|
//locker
|
||||||
global.Lock = lock.NewLocal()
|
global.Lock = lock.NewLocal()
|
||||||
|
|
||||||
|
//service
|
||||||
|
service.New(&global.Config, global.DB, global.Logger, global.Jwt, global.Lock)
|
||||||
|
|
||||||
|
global.LoginLimiter = utils.NewLoginLimiter(utils.SecurityPolicy{
|
||||||
|
CaptchaThreshold: global.Config.App.CaptchaThreshold,
|
||||||
|
BanThreshold: global.Config.App.BanThreshold,
|
||||||
|
AttemptsWindow: 10 * time.Minute,
|
||||||
|
BanDuration: 30 * time.Minute,
|
||||||
|
})
|
||||||
|
global.LoginLimiter.RegisterProvider(utils.B64StringCaptchaProvider{})
|
||||||
|
DatabaseAutoUpdate()
|
||||||
}
|
}
|
||||||
|
|
||||||
func DatabaseAutoUpdate() {
|
func DatabaseAutoUpdate() {
|
||||||
version := 246
|
version := DatabaseVersion
|
||||||
|
|
||||||
db := global.DB
|
db := global.DB
|
||||||
|
|
||||||
if global.Config.Gorm.Type == config.TypeMysql {
|
if global.Config.Gorm.Type == config.TypeMysql {
|
||||||
//检查存不存在数据库,不存在则创建
|
// check whether the database exists; create it if not
|
||||||
dbName := db.Migrator().CurrentDatabase()
|
dbName := db.Migrator().CurrentDatabase()
|
||||||
fmt.Println("dbName", dbName)
|
|
||||||
if dbName == "" {
|
if dbName == "" {
|
||||||
dbName = global.Config.Mysql.Dbname
|
dbName = global.Config.Mysql.Dbname
|
||||||
// 移除 DSN 中的数据库名称,以便初始连接时不指定数据库
|
// remove the database name from the DSN so the initial connection does not specify a database
|
||||||
dsnWithoutDB := global.Config.Mysql.Username + ":" + global.Config.Mysql.Password + "@(" + global.Config.Mysql.Addr + ")/?charset=utf8mb4&parseTime=True&loc=Local"
|
dsnWithoutDB := fmt.Sprintf("%s:%s@(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",
|
||||||
//新链接
|
global.Config.Mysql.Username,
|
||||||
|
global.Config.Mysql.Password,
|
||||||
|
global.Config.Mysql.Addr,
|
||||||
|
"",
|
||||||
|
)
|
||||||
|
|
||||||
|
// new connection
|
||||||
dbWithoutDB := orm.NewMysql(&orm.MysqlConfig{
|
dbWithoutDB := orm.NewMysql(&orm.MysqlConfig{
|
||||||
Dns: dsnWithoutDB,
|
Dsn: dsnWithoutDB,
|
||||||
})
|
}, global.Logger)
|
||||||
// 获取底层的 *sql.DB 对象,并确保在程序退出时关闭连接
|
// get the underlying *sql.DB object and ensure the connection is closed when the program exits
|
||||||
sqlDBWithoutDB, err := dbWithoutDB.DB()
|
sqlDBWithoutDB, err := dbWithoutDB.DB()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("获取底层 *sql.DB 对象失败: %v\n", err)
|
global.Logger.Errorf("failed to get underlying *sql.DB object: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := sqlDBWithoutDB.Close(); err != nil {
|
if err := sqlDBWithoutDB.Close(); err != nil {
|
||||||
fmt.Printf("关闭连接失败: %v\n", err)
|
global.Logger.Errorf("failed to close connection: %v", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
err = dbWithoutDB.Exec("CREATE DATABASE IF NOT EXISTS " + dbName + " DEFAULT CHARSET utf8mb4").Error
|
err = dbWithoutDB.Exec("CREATE DATABASE IF NOT EXISTS " + dbName + " DEFAULT CHARSET utf8mb4").Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
global.Logger.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -208,19 +258,20 @@ func DatabaseAutoUpdate() {
|
|||||||
if !db.Migrator().HasTable(&model.Version{}) {
|
if !db.Migrator().HasTable(&model.Version{}) {
|
||||||
Migrate(uint(version))
|
Migrate(uint(version))
|
||||||
} else {
|
} else {
|
||||||
//查找最后一个version
|
// find the last version
|
||||||
var v model.Version
|
var v model.Version
|
||||||
db.Last(&v)
|
db.Last(&v)
|
||||||
if v.Version < uint(version) {
|
if v.Version < uint(version) {
|
||||||
Migrate(uint(version))
|
Migrate(uint(version))
|
||||||
}
|
}
|
||||||
// 245迁移
|
|
||||||
|
// 245 migration
|
||||||
if v.Version < 245 {
|
if v.Version < 245 {
|
||||||
//oauths 表的 oauth_type 字段设置为 op同样的值
|
// set the oauths table's oauth_type field to the same value as op
|
||||||
db.Exec("update oauths set oauth_type = op")
|
db.Exec("update oauths set oauth_type = op")
|
||||||
db.Exec("update oauths set issuer = 'https://accounts.google.com' where op = 'google'")
|
db.Exec("update oauths set issuer = 'https://accounts.google.com' where op = 'google'")
|
||||||
db.Exec("update user_thirds set oauth_type = third_type, op = third_type")
|
db.Exec("update user_thirds set oauth_type = third_type, op = third_type")
|
||||||
//通过email迁移旧的google授权
|
// migrate old google authorizations by email
|
||||||
uts := make([]model.UserThird, 0)
|
uts := make([]model.UserThird, 0)
|
||||||
db.Where("oauth_type = ?", "google").Find(&uts)
|
db.Where("oauth_type = ?", "google").Find(&uts)
|
||||||
for _, ut := range uts {
|
for _, ut := range uts {
|
||||||
@@ -236,7 +287,7 @@ func DatabaseAutoUpdate() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
func Migrate(version uint) {
|
func Migrate(version uint) {
|
||||||
fmt.Println("migrating....", version)
|
global.Logger.Info("Migrating....", version)
|
||||||
err := global.DB.AutoMigrate(
|
err := global.DB.AutoMigrate(
|
||||||
&model.Version{},
|
&model.Version{},
|
||||||
&model.User{},
|
&model.User{},
|
||||||
@@ -253,12 +304,14 @@ func Migrate(version uint) {
|
|||||||
&model.AuditFile{},
|
&model.AuditFile{},
|
||||||
&model.AddressBookCollection{},
|
&model.AddressBookCollection{},
|
||||||
&model.AddressBookCollectionRule{},
|
&model.AddressBookCollectionRule{},
|
||||||
|
&model.ServerCmd{},
|
||||||
|
&model.DeviceGroup{},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("migrate err :=>", err)
|
global.Logger.Error("migrate err :=>", err)
|
||||||
}
|
}
|
||||||
global.DB.Create(&model.Version{Version: version})
|
global.DB.Create(&model.Version{Version: version})
|
||||||
//如果是初次则创建一个默认用户
|
// if this is the first run, create a default user
|
||||||
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 {
|
||||||
@@ -280,7 +333,7 @@ func Migrate(version uint) {
|
|||||||
Type: model.GroupTypeShare,
|
Type: model.GroupTypeShare,
|
||||||
}
|
}
|
||||||
service.AllService.GroupService.Create(groupShare)
|
service.AllService.GroupService.Create(groupShare)
|
||||||
//是true
|
// is true
|
||||||
is_admin := true
|
is_admin := true
|
||||||
admin := &model.User{
|
admin := &model.User{
|
||||||
Username: "admin",
|
Username: "admin",
|
||||||
@@ -289,7 +342,15 @@ func Migrate(version uint) {
|
|||||||
IsAdmin: &is_admin,
|
IsAdmin: &is_admin,
|
||||||
GroupId: 1,
|
GroupId: 1,
|
||||||
}
|
}
|
||||||
admin.Password = service.AllService.UserService.EncryptPassword("admin")
|
|
||||||
|
// generate a random password
|
||||||
|
pwd := utils.RandomString(8)
|
||||||
|
global.Logger.Info("Admin Password Is: ", pwd)
|
||||||
|
var err error
|
||||||
|
admin.Password, err = utils.EncryptPassword(pwd)
|
||||||
|
if err != nil {
|
||||||
|
global.Logger.Fatalf("failed to generate admin password: %v", err)
|
||||||
|
}
|
||||||
global.DB.Create(admin)
|
global.DB.Create(admin)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
👏👏👏 你好 <strong>{{username}}</strong>, 欢迎使用 <a href='https://github.com/lejianwen/rustdesk-api' target='_blank'>RustDesk Api Admin</a>
|
|
||||||
@@ -1,15 +1,26 @@
|
|||||||
lang: "zh-CN"
|
lang: "en"
|
||||||
app:
|
app:
|
||||||
web-client: 1 # 1:启用 0:禁用
|
web-client: 1 # 1:enable 0:disable
|
||||||
register: false #是否开启注册
|
register: false #whether registration is enabled
|
||||||
|
register-status: 1 # default status for registered users 1:enable 2:disable
|
||||||
|
captcha-threshold: 3 # <0:disabled, 0 always, >0:enabled
|
||||||
|
ban-threshold: 0 # 0:disabled, >0:enabled
|
||||||
|
show-swagger: 0 # 1:enable 0:disable
|
||||||
|
token-expire: 168h
|
||||||
|
web-sso: true #web auth sso
|
||||||
|
disable-pwd-login: false #disable password login
|
||||||
|
|
||||||
admin:
|
admin:
|
||||||
title: "RustDesk Api Admin"
|
title: "RustDesk API Admin"
|
||||||
hello-file: "./conf/admin/hello.html" #优先使用file
|
hello-file: "./conf/admin/hello.html" #prefer to use a file for the welcome message
|
||||||
hello: ""
|
hello: ""
|
||||||
|
# ID Server and Relay Server ports https://github.com/lejianwen/rustdesk-api/issues/257
|
||||||
|
id-server-port: 21116 # ID Server port (for server cmd)
|
||||||
|
relay-server-port: 21117 # ID Server port (for server cmd)
|
||||||
gin:
|
gin:
|
||||||
api-addr: "0.0.0.0:21114"
|
api-addr: "0.0.0.0:21114"
|
||||||
mode: "release" #release,debug,test
|
mode: "release" #release,debug,test
|
||||||
resources-path: 'resources' #对外静态文件目录
|
resources-path: 'resources' #public static file directory
|
||||||
trust-proxy: ""
|
trust-proxy: ""
|
||||||
gorm:
|
gorm:
|
||||||
type: "sqlite"
|
type: "sqlite"
|
||||||
@@ -20,37 +31,54 @@ mysql:
|
|||||||
password: ""
|
password: ""
|
||||||
addr: ""
|
addr: ""
|
||||||
dbname: ""
|
dbname: ""
|
||||||
|
tls: "false" # true / false / skip-verify / custom
|
||||||
|
|
||||||
|
postgresql:
|
||||||
|
host: "127.0.0.1"
|
||||||
|
port: "5432"
|
||||||
|
user: ""
|
||||||
|
password: ""
|
||||||
|
dbname: "postgres"
|
||||||
|
sslmode: "disable" # disable, require, verify-ca, verify-full
|
||||||
|
time-zone: "Asia/Shanghai" # Time zone for PostgreSQL connection
|
||||||
|
|
||||||
rustdesk:
|
rustdesk:
|
||||||
id-server: "192.168.1.66:21116"
|
id-server: "192.168.1.66:21116"
|
||||||
relay-server: "192.168.1.66:21117"
|
relay-server: "192.168.1.66:21117"
|
||||||
api-server: "http://127.0.0.1:21114"
|
api-server: "http://127.0.0.1:21114"
|
||||||
key: ""
|
key: ""
|
||||||
key-file: "./conf/data/id_ed25519.pub"
|
key-file: "/data/id_ed25519.pub"
|
||||||
personal: 1
|
personal: 1
|
||||||
|
webclient-magic-queryonline: 0
|
||||||
|
ws-host: "" #eg: wss://192.168.1.3:4443
|
||||||
logger:
|
logger:
|
||||||
path: "./runtime/log.txt"
|
path: "./runtime/log.txt"
|
||||||
level: "warn" #trace,debug,info,warn,error,fatal
|
level: "info" #trace,debug,info,warn,error,fatal
|
||||||
report-caller: true
|
report-caller: true
|
||||||
proxy:
|
proxy:
|
||||||
enable: false
|
enable: false
|
||||||
host: "http://127.0.0.1:1080"
|
host: "http://127.0.0.1:1080"
|
||||||
redis:
|
|
||||||
addr: "127.0.0.1:6379"
|
|
||||||
password: ""
|
|
||||||
db: 0
|
|
||||||
cache:
|
|
||||||
type: "file"
|
|
||||||
file-dir: "./runtime/cache"
|
|
||||||
redis-addr: "127.0.0.1:6379"
|
|
||||||
redis-pwd: ""
|
|
||||||
redis-db: 0
|
|
||||||
oss:
|
|
||||||
access-key-id: ""
|
|
||||||
access-key-secret: ""
|
|
||||||
host: ""
|
|
||||||
callback-url: ""
|
|
||||||
expire-time: 30
|
|
||||||
max-byte: 10240
|
|
||||||
jwt:
|
jwt:
|
||||||
private-key: "./conf/jwt_pri.pem"
|
key: ""
|
||||||
expire-duration: 360000
|
expire-duration: 168h
|
||||||
|
ldap:
|
||||||
|
enable: false
|
||||||
|
url: "ldap://ldap.example.com:389"
|
||||||
|
tls-ca-file: ""
|
||||||
|
tls-verify: false
|
||||||
|
base-dn: "dc=example,dc=com"
|
||||||
|
bind-dn: "cn=admin,dc=example,dc=com"
|
||||||
|
bind-password: "password"
|
||||||
|
|
||||||
|
user:
|
||||||
|
base-dn: "ou=users,dc=example,dc=com"
|
||||||
|
enable-attr: "" #The attribute name of the user for enabling, in AD it is "userAccountControl", empty means no enable attribute, all users are enabled
|
||||||
|
enable-attr-value: "" # The value of the enable attribute when the user is enabled. If you are using AD, just set random value, it will be ignored.
|
||||||
|
filter: "(cn=*)"
|
||||||
|
username: "uid" # The attribute name of the user for usernamem if you are using AD, it should be "sAMAccountName"
|
||||||
|
email: "mail"
|
||||||
|
first-name: "givenName"
|
||||||
|
last-name: "sn"
|
||||||
|
sync: false # If true, the user will be synchronized to the database when the user logs in. If false, the user will be synchronized to the database when the user be created.
|
||||||
|
admin-group: "cn=admin,dc=example,dc=com" # The group name of the admin group, if the user is in this group, the user will be an admin.
|
||||||
|
allow-group: "cn=users,dc=example,dc=com" # The group name of the users group, if the user is in this group, the user will be an login.
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ package config
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/fsnotify/fsnotify"
|
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -16,11 +16,20 @@ const (
|
|||||||
type App struct {
|
type App struct {
|
||||||
WebClient int `mapstructure:"web-client"`
|
WebClient int `mapstructure:"web-client"`
|
||||||
Register bool `mapstructure:"register"`
|
Register bool `mapstructure:"register"`
|
||||||
|
RegisterStatus int `mapstructure:"register-status"`
|
||||||
|
ShowSwagger int `mapstructure:"show-swagger"`
|
||||||
|
TokenExpire time.Duration `mapstructure:"token-expire"`
|
||||||
|
WebSso bool `mapstructure:"web-sso"`
|
||||||
|
DisablePwdLogin bool `mapstructure:"disable-pwd-login"`
|
||||||
|
CaptchaThreshold int `mapstructure:"captcha-threshold"`
|
||||||
|
BanThreshold int `mapstructure:"ban-threshold"`
|
||||||
}
|
}
|
||||||
type Admin struct {
|
type Admin struct {
|
||||||
Title string `mapstructure:"title"`
|
Title string `mapstructure:"title"`
|
||||||
Hello string `mapstructure:"hello"`
|
Hello string `mapstructure:"hello"`
|
||||||
HelloFile string `mapstructure:"hello-file"`
|
HelloFile string `mapstructure:"hello-file"`
|
||||||
|
IdServerPort int `mapstructure:"id-server-port"`
|
||||||
|
RelayServerPort int `mapstructure:"relay-server-port"`
|
||||||
}
|
}
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Lang string `mapstructure:"lang"`
|
Lang string `mapstructure:"lang"`
|
||||||
@@ -28,6 +37,7 @@ type Config struct {
|
|||||||
Admin Admin
|
Admin Admin
|
||||||
Gorm Gorm
|
Gorm Gorm
|
||||||
Mysql Mysql
|
Mysql Mysql
|
||||||
|
Postgresql Postgresql
|
||||||
Gin Gin
|
Gin Gin
|
||||||
Logger Logger
|
Logger Logger
|
||||||
Redis Redis
|
Redis Redis
|
||||||
@@ -36,10 +46,20 @@ type Config struct {
|
|||||||
Jwt Jwt
|
Jwt Jwt
|
||||||
Rustdesk Rustdesk
|
Rustdesk Rustdesk
|
||||||
Proxy Proxy
|
Proxy Proxy
|
||||||
|
Ldap Ldap
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init 初始化配置
|
func (a *Admin) Init() {
|
||||||
func Init(rowVal interface{}, path string) *viper.Viper {
|
if a.IdServerPort == 0 {
|
||||||
|
a.IdServerPort = DefaultIdServerPort
|
||||||
|
}
|
||||||
|
if a.RelayServerPort == 0 {
|
||||||
|
a.RelayServerPort = DefaultRelayServerPort
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init initializes the configuration
|
||||||
|
func Init(rowVal *Config, path string) *viper.Viper {
|
||||||
if path == "" {
|
if path == "" {
|
||||||
path = DefaultConfig
|
path = DefaultConfig
|
||||||
}
|
}
|
||||||
@@ -53,22 +73,30 @@ func Init(rowVal interface{}, path string) *viper.Viper {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Errorf("Fatal error config file: %s \n", err))
|
panic(fmt.Errorf("Fatal error config file: %s \n", err))
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
v.WatchConfig()
|
v.WatchConfig()
|
||||||
|
|
||||||
|
|
||||||
|
// watching for config changes is not really necessary
|
||||||
v.OnConfigChange(func(e fsnotify.Event) {
|
v.OnConfigChange(func(e fsnotify.Event) {
|
||||||
//配置文件修改监听
|
// watch for config file changes
|
||||||
fmt.Println("config file changed:", e.Name)
|
fmt.Println("config file changed:", e.Name)
|
||||||
if err2 := v.Unmarshal(rowVal); err2 != nil {
|
if err2 := v.Unmarshal(rowVal); err2 != nil {
|
||||||
fmt.Println(err2)
|
fmt.Println(err2)
|
||||||
}
|
}
|
||||||
|
rowVal.Rustdesk.LoadKeyFile()
|
||||||
|
rowVal.Rustdesk.ParsePort()
|
||||||
})
|
})
|
||||||
|
*/
|
||||||
if err := v.Unmarshal(rowVal); err != nil {
|
if err := v.Unmarshal(rowVal); err != nil {
|
||||||
fmt.Println(err)
|
panic(fmt.Errorf("Fatal error config: %s \n", err))
|
||||||
}
|
}
|
||||||
|
rowVal.Rustdesk.LoadKeyFile()
|
||||||
|
rowVal.Admin.Init()
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadEnv 读取环境变量
|
// ReadEnv reads environment variables
|
||||||
func ReadEnv(rowVal interface{}) *viper.Viper {
|
func ReadEnv(rowVal interface{}) *viper.Viper {
|
||||||
v := viper.New()
|
v := viper.New()
|
||||||
v.AutomaticEnv()
|
v.AutomaticEnv()
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package config
|
|||||||
const (
|
const (
|
||||||
TypeSqlite = "sqlite"
|
TypeSqlite = "sqlite"
|
||||||
TypeMysql = "mysql"
|
TypeMysql = "mysql"
|
||||||
|
TypePostgresql = "postgresql"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Gorm struct {
|
type Gorm struct {
|
||||||
@@ -16,4 +17,15 @@ type Mysql struct {
|
|||||||
Username string `mapstructure:"username"`
|
Username string `mapstructure:"username"`
|
||||||
Password string `mapstructure:"password"`
|
Password string `mapstructure:"password"`
|
||||||
Dbname string `mapstructure:"dbname"`
|
Dbname string `mapstructure:"dbname"`
|
||||||
|
Tls string `mapstructure:"tls"` // true / false / skip-verify / custom
|
||||||
|
}
|
||||||
|
|
||||||
|
type Postgresql struct {
|
||||||
|
Host string `mapstructure:"host"`
|
||||||
|
Port string `mapstructure:"port"`
|
||||||
|
User string `mapstructure:"user"`
|
||||||
|
Password string `mapstructure:"password"`
|
||||||
|
Dbname string `mapstructure:"dbname"`
|
||||||
|
Sslmode string `mapstructure:"sslmode"` // "disable", "require", "verify-ca", "verify-full"
|
||||||
|
TimeZone string `mapstructure:"time-zone"` // e.g., "Asia/Shanghai"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,6 @@ package config
|
|||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
type Jwt struct {
|
type Jwt struct {
|
||||||
PrivateKey string `mapstructure:"private-key"`
|
Key string `mapstructure:"key"`
|
||||||
ExpireDuration time.Duration `mapstructure:"expire-duration"`
|
ExpireDuration time.Duration `mapstructure:"expire-duration"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
type LdapUser struct {
|
||||||
|
BaseDn string `mapstructure:"base-dn"` // The base DN of the user for searching
|
||||||
|
EnableAttr string `mapstructure:"enable-attr"` // The attribute name of the user for enabling, in AD it is "userAccountControl", empty means no enable attribute, all users are enabled
|
||||||
|
EnableAttrValue string `mapstructure:"enable-attr-value"` // The value of the enable attribute when the user is enabled. If you are using AD, just leave it random str, it will be ignored.
|
||||||
|
Filter string `mapstructure:"filter"`
|
||||||
|
Username string `mapstructure:"username"`
|
||||||
|
Email string `mapstructure:"email"`
|
||||||
|
FirstName string `mapstructure:"first-name"`
|
||||||
|
LastName string `mapstructure:"last-name"`
|
||||||
|
Sync bool `mapstructure:"sync"` // Will sync the user's information to the internal database
|
||||||
|
AdminGroup string `mapstructure:"admin-group"` // Which group is the admin group
|
||||||
|
AllowGroup string `mapstructure:"allow-group"` // Which group is allowed to login
|
||||||
|
}
|
||||||
|
|
||||||
|
// type LdapGroup struct {
|
||||||
|
// BaseDn string `mapstructure:"base-dn"` // The base DN of the group for searching
|
||||||
|
// Name string `mapstructure:"name"` // The attribute name of the group
|
||||||
|
// Filter string `mapstructure:"filter"`
|
||||||
|
// Admin string `mapstructure:"admin"` // Which group is the admin group
|
||||||
|
// Member string `mapstructure:"member"` // How to get the member of the group: member, uniqueMember, or memberOf (default: member)
|
||||||
|
// Mode string `mapstructure:"mode"`
|
||||||
|
// Map map[string]string `mapstructure:"map"` // If mode is "map", map the LDAP group to the internal group
|
||||||
|
// }
|
||||||
|
|
||||||
|
type Ldap struct {
|
||||||
|
Enable bool `mapstructure:"enable"`
|
||||||
|
Url string `mapstructure:"url"`
|
||||||
|
TlsCaFile string `mapstructure:"tls-ca-file"`
|
||||||
|
TlsVerify bool `mapstructure:"tls-verify"`
|
||||||
|
BaseDn string `mapstructure:"base-dn"`
|
||||||
|
BindDn string `mapstructure:"bind-dn"`
|
||||||
|
BindPassword string `mapstructure:"bind-password"`
|
||||||
|
User LdapUser `mapstructure:"user"`
|
||||||
|
// Group LdapGroup `mapstructure:"group"`
|
||||||
|
}
|
||||||
@@ -3,18 +3,20 @@ package config
|
|||||||
type GithubOauth struct {
|
type GithubOauth struct {
|
||||||
ClientId string `mapstructure:"client-id"`
|
ClientId string `mapstructure:"client-id"`
|
||||||
ClientSecret string `mapstructure:"client-secret"`
|
ClientSecret string `mapstructure:"client-secret"`
|
||||||
RedirectUrl string `mapstructure:"redirect-url"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type GoogleOauth struct {
|
type GoogleOauth struct {
|
||||||
ClientId string `mapstructure:"client-id"`
|
ClientId string `mapstructure:"client-id"`
|
||||||
ClientSecret string `mapstructure:"client-secret"`
|
ClientSecret string `mapstructure:"client-secret"`
|
||||||
RedirectUrl string `mapstructure:"redirect-url"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type OidcOauth struct {
|
type OidcOauth struct {
|
||||||
Issuer string `mapstructure:"issuer"`
|
Issuer string `mapstructure:"issuer"`
|
||||||
ClientId string `mapstructure:"client-id"`
|
ClientId string `mapstructure:"client-id"`
|
||||||
ClientSecret string `mapstructure:"client-secret"`
|
ClientSecret string `mapstructure:"client-secret"`
|
||||||
RedirectUrl string `mapstructure:"redirect-url"`
|
}
|
||||||
|
|
||||||
|
type LinuxdoOauth struct {
|
||||||
|
ClientId string `mapstructure:"client-id"`
|
||||||
|
ClientSecret string `mapstructure:"client-secret"`
|
||||||
}
|
}
|
||||||
@@ -4,27 +4,37 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DefaultIdServerPort = 21116
|
||||||
|
DefaultRelayServerPort = 21117
|
||||||
|
)
|
||||||
|
|
||||||
type Rustdesk struct {
|
type Rustdesk struct {
|
||||||
IdServer string `mapstructure:"id-server"`
|
IdServer string `mapstructure:"id-server"`
|
||||||
|
IdServerPort int `mapstructure:"-"`
|
||||||
RelayServer string `mapstructure:"relay-server"`
|
RelayServer string `mapstructure:"relay-server"`
|
||||||
|
RelayServerPort int `mapstructure:"-"`
|
||||||
ApiServer string `mapstructure:"api-server"`
|
ApiServer string `mapstructure:"api-server"`
|
||||||
Key string `mapstructure:"key"`
|
Key string `mapstructure:"key"`
|
||||||
KeyFile string `mapstructure:"key-file"`
|
KeyFile string `mapstructure:"key-file"`
|
||||||
Personal int `mapstructure:"personal"`
|
Personal int `mapstructure:"personal"`
|
||||||
|
//webclient-magic-queryonline
|
||||||
|
WebclientMagicQueryonline int `mapstructure:"webclient-magic-queryonline"`
|
||||||
|
WsHost string `mapstructure:"ws-host"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoadKeyFile(rustdesk *Rustdesk) {
|
func (rd *Rustdesk) LoadKeyFile() {
|
||||||
// Load key file
|
// Load key file
|
||||||
if rustdesk.Key != "" {
|
if rd.Key != "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if rustdesk.KeyFile != "" {
|
if rd.KeyFile != "" {
|
||||||
// Load key from file
|
// Load key from file
|
||||||
b, err := os.ReadFile(rustdesk.KeyFile)
|
b, err := os.ReadFile(rd.KeyFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
rustdesk.Key = string(b)
|
rd.Key = string(b)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
rustdesk-api-server (1.3.6) UNRELEASED; urgency=medium
|
||||||
|
|
||||||
|
* Update the version to 1.3.6 to match the client.
|
||||||
|
|
||||||
|
-- rustdesk-api <ymwlpoolc@qq.com> Tue, 24 Dec 2024 13:48:34 +0800
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
10
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
Source: rustdesk-api-server
|
||||||
|
Section: net
|
||||||
|
Priority: optional
|
||||||
|
Maintainer: ymwl <ymwlpoolc@qq.com>
|
||||||
|
Build-Depends: debhelper (>= 10), pkg-config
|
||||||
|
Standards-Version: 4.5.0
|
||||||
|
Homepage: https://github.com/lejianwen/rustdesk-api/
|
||||||
|
|
||||||
|
Package: rustdesk-api-server
|
||||||
|
Architecture: {{ ARCH }}
|
||||||
|
Depends: systemd ${misc:Depends}
|
||||||
|
Description: RustDesk api server
|
||||||
|
RustDesk api server, it is free and open source.
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2024-present Lejianwen and contributors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#!/usr/bin/make -f
|
||||||
|
%:
|
||||||
|
dh $@
|
||||||
|
|
||||||
|
override_dh_builddeb:
|
||||||
|
dh_builddeb -- -Zgzip
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
bin/rustdesk-api usr/bin
|
||||||
|
systemd/rustdesk-api.service lib/systemd/system
|
||||||
|
conf var/lib/rustdesk-api
|
||||||
|
data var/lib/rustdesk-api
|
||||||
|
resources var/lib/rustdesk-api
|
||||||
|
runtime var/lib/rustdesk-api
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
SERVICE=rustdesk-api.service
|
||||||
|
|
||||||
|
if [ "$1" = "configure" ]; then
|
||||||
|
mkdir -p /var/log/rustdesk-api
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
configure|abort-upgrade|abort-deconfigure|abort-remove)
|
||||||
|
mkdir -p /var/lib/rustdesk-api/
|
||||||
|
deb-systemd-helper unmask "${SERVICE}" >/dev/null || true
|
||||||
|
if deb-systemd-helper --quiet was-enabled "${SERVICE}"; then
|
||||||
|
deb-systemd-invoke enable "${SERVICE}" >/dev/null || true
|
||||||
|
else
|
||||||
|
deb-systemd-invoke update-state "${SERVICE}" >/dev/null || true
|
||||||
|
fi
|
||||||
|
systemctl --system daemon-reload >/dev/null || true
|
||||||
|
if [ -n "$2" ]; then
|
||||||
|
deb-systemd-invoke restart "${SERVICE}" >/dev/null || true
|
||||||
|
else
|
||||||
|
deb-systemd-invoke start "${SERVICE}" >/dev/null || true
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
exit 0
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
SERVICE=rustdesk-api.service
|
||||||
|
|
||||||
|
systemctl --system daemon-reload >/dev/null || true
|
||||||
|
|
||||||
|
if [ "$1" = "purge" ]; then
|
||||||
|
rm -rf /var/log/rustdesk-api/rustdesk-api.*
|
||||||
|
deb-systemd-helper purge "${SERVICE}" >/dev/null || true
|
||||||
|
deb-systemd-helper unmask "${SERVICE}" >/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$1" = "remove" ]; then
|
||||||
|
deb-systemd-helper mask "${SERVICE}" >/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
SERVICE=rustdesk-api.service
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
remove|deconfigure)
|
||||||
|
deb-systemd-invoke stop "${SERVICE}" >/dev/null || true
|
||||||
|
deb-systemd-invoke disable "${SERVICE}" >/dev/null || true
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
exit 0
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
3.0 (native)
|
||||||
@@ -5,7 +5,7 @@ services:
|
|||||||
dockerfile: Dockerfile.dev
|
dockerfile: Dockerfile.dev
|
||||||
args:
|
args:
|
||||||
COUNTRY: CN
|
COUNTRY: CN
|
||||||
FREONTEND_GIT_REPO: https://github.com/lejianwen/rustdesk-api-web.git
|
FRONTEND_GIT_REPO: https://github.com/lejianwen/rustdesk-api-web.git
|
||||||
FRONTEND_GIT_BRANCH: master
|
FRONTEND_GIT_BRANCH: master
|
||||||
# image: lejianwen/rustdesk-api
|
# image: lejianwen/rustdesk-api
|
||||||
container_name: rustdesk-api
|
container_name: rustdesk-api
|
||||||
@@ -18,7 +18,7 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- 21114:21114
|
- 21114:21114
|
||||||
volumes:
|
volumes:
|
||||||
- ./data/rustdesk/api:/app/data #将数据库挂载出来方便备份
|
- ./data/rustdesk/api:/app/data #mount the database out for easy backup
|
||||||
- ./conf:/app/conf # config
|
- ./conf:/app/conf # config
|
||||||
# - ./resources:/app/resources # 静态资源
|
# - ./resources:/app/resources # static resources
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
@@ -13,5 +13,5 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- ./data/rustdesk/api:/app/data # database
|
- ./data/rustdesk/api:/app/data # database
|
||||||
# - ./conf:/app/conf # config
|
# - ./conf:/app/conf # config
|
||||||
# - ./resources:/app/resources # 静态资源
|
# - ./resources:/app/resources # static resources
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
# RustDesk full stack (server + relay + API/Web Admin) — self-contained example.
|
||||||
|
#
|
||||||
|
# Copy to docker-compose.yml and adjust the public IP / keys / secrets:
|
||||||
|
# cp docker-compose.yml.example docker-compose.yml
|
||||||
|
#
|
||||||
|
# Everything is inline (no .env). The Ed25519 key below is an EXAMPLE — generate
|
||||||
|
# your own for production. The two keys belong together:
|
||||||
|
# - hbbs/hbbr get the SECRET key via -k
|
||||||
|
# - rustdesk-api gets the matching PUBLIC key via RUSTDESK_API_RUSTDESK_KEY
|
||||||
|
# (the public key is also what clients see as their "Key").
|
||||||
|
|
||||||
|
services:
|
||||||
|
hbbs:
|
||||||
|
container_name: hbbs
|
||||||
|
image: rustdesk/rustdesk-server:latest
|
||||||
|
command: hbbs -r 194.164.204.114:21117 -k 1jqLELJaIjaRtt1Tcj6BhqJ7DhT9WszBH/XUHrqJdhdg4K98HmANQFOpUx/vPZFRWnHPTYYHyIB8uH3Xxr8PTw==
|
||||||
|
environment:
|
||||||
|
- TZ=Europe/Berlin
|
||||||
|
- ENCRYPTED_ONLY=1
|
||||||
|
- MUST_LOGIN=Y
|
||||||
|
volumes:
|
||||||
|
- ./data/server:/root
|
||||||
|
ports:
|
||||||
|
- "21115:21115"
|
||||||
|
- "21116:21116"
|
||||||
|
- "21116:21116/udp"
|
||||||
|
- "21118:21118"
|
||||||
|
depends_on:
|
||||||
|
- hbbr
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
hbbr:
|
||||||
|
container_name: hbbr
|
||||||
|
image: rustdesk/rustdesk-server:latest
|
||||||
|
command: hbbr -k 1jqLELJaIjaRtt1Tcj6BhqJ7DhT9WszBH/XUHrqJdhdg4K98HmANQFOpUx/vPZFRWnHPTYYHyIB8uH3Xxr8PTw==
|
||||||
|
environment:
|
||||||
|
- TZ=Europe/Berlin
|
||||||
|
volumes:
|
||||||
|
- ./data/server:/root
|
||||||
|
ports:
|
||||||
|
- "21117:21117"
|
||||||
|
- "21119:21119"
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
rustdesk-api:
|
||||||
|
container_name: rustdesk-api
|
||||||
|
image: git.hackner.dev/thomas/rustdesk-api:latest
|
||||||
|
command: ["./apimain"]
|
||||||
|
environment:
|
||||||
|
- TZ=Europe/Berlin
|
||||||
|
- RUSTDESK_API_LANG=en
|
||||||
|
- RUSTDESK_API_RUSTDESK_ID_SERVER=194.164.204.114:21116
|
||||||
|
- RUSTDESK_API_RUSTDESK_RELAY_SERVER=194.164.204.114:21117
|
||||||
|
- RUSTDESK_API_RUSTDESK_API_SERVER=http://194.164.204.114:21114
|
||||||
|
- RUSTDESK_API_RUSTDESK_KEY=YOCvfB5gDUBTqVMf7z2RUVpxz02GB8iAfLh918a/D08=
|
||||||
|
- RUSTDESK_API_JWT_KEY=z5rt4z465rtzdh5sudtuzrutd66zz6
|
||||||
|
ports:
|
||||||
|
- "21114:21114"
|
||||||
|
volumes:
|
||||||
|
- ./api:/app/data
|
||||||
|
depends_on:
|
||||||
|
- hbbs
|
||||||
|
- hbbr
|
||||||
|
restart: unless-stopped
|
||||||
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 97 KiB |
@@ -17,7 +17,7 @@ const docTemplateapi = `{
|
|||||||
"paths": {
|
"paths": {
|
||||||
"/": {
|
"/": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "首页",
|
"description": "home",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -25,9 +25,9 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"首页"
|
"home"
|
||||||
],
|
],
|
||||||
"summary": "首页",
|
"summary": "home",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
@@ -51,7 +51,7 @@ const docTemplateapi = `{
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "地址列表",
|
"description": "address list",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -59,9 +59,9 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"地址"
|
"address"
|
||||||
],
|
],
|
||||||
"summary": "地址列表",
|
"summary": "address list",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
@@ -83,7 +83,7 @@ const docTemplateapi = `{
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "地址更新",
|
"description": "address update",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -91,12 +91,12 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"地址"
|
"address"
|
||||||
],
|
],
|
||||||
"summary": "地址更新",
|
"summary": "address update",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"description": "地址表单",
|
"description": "address form",
|
||||||
"name": "body",
|
"name": "body",
|
||||||
"in": "body",
|
"in": "body",
|
||||||
"required": true,
|
"required": true,
|
||||||
@@ -128,7 +128,7 @@ const docTemplateapi = `{
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "添加地址",
|
"description": "add address",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -136,9 +136,9 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"地址[Personal]"
|
"address[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "添加地址",
|
"summary": "add address",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -169,7 +169,7 @@ const docTemplateapi = `{
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "删除地址",
|
"description": "delete address",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -177,9 +177,9 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"地址[Personal]"
|
"address[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "删除地址",
|
"summary": "delete address",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -212,7 +212,7 @@ const docTemplateapi = `{
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "更新地址",
|
"description": "update address",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -220,9 +220,9 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"地址[Personal]"
|
"address[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "更新地址",
|
"summary": "update address",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -255,7 +255,7 @@ const docTemplateapi = `{
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "地址",
|
"description": "address",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -263,19 +263,19 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"地址[Personal]"
|
"address[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "地址列表",
|
"summary": "address list",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "页码",
|
"description": "page number",
|
||||||
"name": "current",
|
"name": "current",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "每页数量",
|
"description": "items per page",
|
||||||
"name": "pageSize",
|
"name": "pageSize",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
@@ -309,7 +309,7 @@ const docTemplateapi = `{
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "个人地址",
|
"description": "personal address",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -317,9 +317,9 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"地址[Personal]"
|
"address[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "个人地址",
|
"summary": "personal address",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"description": "string valid",
|
"description": "string valid",
|
||||||
@@ -353,7 +353,7 @@ const docTemplateapi = `{
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "设置",
|
"description": "settings",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -361,9 +361,9 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"地址[Personal]"
|
"address[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "设置",
|
"summary": "settings",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"description": "string valid",
|
"description": "string valid",
|
||||||
@@ -397,7 +397,7 @@ const docTemplateapi = `{
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "共享",
|
"description": "shared",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -405,19 +405,19 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"地址[Personal]"
|
"address[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "共享地址簿",
|
"summary": "shared address book",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "页码",
|
"description": "page number",
|
||||||
"name": "current",
|
"name": "current",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "每页数量",
|
"description": "items per page",
|
||||||
"name": "pageSize",
|
"name": "pageSize",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
}
|
}
|
||||||
@@ -445,7 +445,7 @@ const docTemplateapi = `{
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "标签",
|
"description": "tag",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -453,9 +453,9 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"地址[Personal]"
|
"address[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "标签添加",
|
"summary": "add tag",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -488,7 +488,7 @@ const docTemplateapi = `{
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "标签",
|
"description": "tag",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -496,9 +496,9 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"地址[Personal]"
|
"address[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "标签重命名",
|
"summary": "rename tag",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -531,7 +531,7 @@ const docTemplateapi = `{
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "标签",
|
"description": "tag",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -539,9 +539,9 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"地址[Personal]"
|
"address[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "标签修改颜色",
|
"summary": "change tag color",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -574,7 +574,7 @@ const docTemplateapi = `{
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "标签",
|
"description": "tag",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -582,9 +582,9 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"地址[Personal]"
|
"address[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "标签删除",
|
"summary": "delete tag",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -617,7 +617,7 @@ const docTemplateapi = `{
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "标签",
|
"description": "tag",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -625,9 +625,9 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"地址[Personal]"
|
"address[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "标签",
|
"summary": "tag",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -653,43 +653,9 @@ const docTemplateapi = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/api": {
|
|
||||||
"get": {
|
|
||||||
"security": [
|
|
||||||
{
|
|
||||||
"token": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "用户信息",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"用户"
|
|
||||||
],
|
|
||||||
"summary": "用户信息",
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/api.UserPayload"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"500": {
|
|
||||||
"description": "Internal Server Error",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/response.Response"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/audit/conn": {
|
"/audit/conn": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "审计连接",
|
"description": "audit connection",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -697,12 +663,12 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"审计"
|
"audit"
|
||||||
],
|
],
|
||||||
"summary": "审计连接",
|
"summary": "audit connection",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"description": "审计连接",
|
"description": "audit connection",
|
||||||
"name": "body",
|
"name": "body",
|
||||||
"in": "body",
|
"in": "body",
|
||||||
"required": true,
|
"required": true,
|
||||||
@@ -729,7 +695,7 @@ const docTemplateapi = `{
|
|||||||
},
|
},
|
||||||
"/audit/file": {
|
"/audit/file": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "审计文件",
|
"description": "audit file",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -737,12 +703,12 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"审计"
|
"audit"
|
||||||
],
|
],
|
||||||
"summary": "审计文件",
|
"summary": "audit file",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"description": "审计文件",
|
"description": "audit file",
|
||||||
"name": "body",
|
"name": "body",
|
||||||
"in": "body",
|
"in": "body",
|
||||||
"required": true,
|
"required": true,
|
||||||
@@ -767,9 +733,14 @@ const docTemplateapi = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/heartbeat": {
|
"/currentUser": {
|
||||||
"post": {
|
"get": {
|
||||||
"description": "心跳",
|
"security": [
|
||||||
|
{
|
||||||
|
"token": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "user info",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -777,9 +748,98 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"首页"
|
"user"
|
||||||
],
|
],
|
||||||
"summary": "心跳",
|
"summary": "user info",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/api.UserPayload"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.Response"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/device-group/accessible": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"BearerAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "machine",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"group"
|
||||||
|
],
|
||||||
|
"summary": "device",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "page number",
|
||||||
|
"name": "page",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "items per page",
|
||||||
|
"name": "pageSize",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "status",
|
||||||
|
"name": "status",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "accessible",
|
||||||
|
"name": "accessible",
|
||||||
|
"in": "query"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.DataResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.Response"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/heartbeat": {
|
||||||
|
"post": {
|
||||||
|
"description": "heartbeat",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"home"
|
||||||
|
],
|
||||||
|
"summary": "heartbeat",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK"
|
"description": "OK"
|
||||||
@@ -795,7 +855,7 @@ const docTemplateapi = `{
|
|||||||
},
|
},
|
||||||
"/login": {
|
"/login": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "登录",
|
"description": "login",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -803,12 +863,12 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"登录"
|
"login"
|
||||||
],
|
],
|
||||||
"summary": "登录",
|
"summary": "login",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"description": "登录表单",
|
"description": "login form",
|
||||||
"name": "body",
|
"name": "body",
|
||||||
"in": "body",
|
"in": "body",
|
||||||
"required": true,
|
"required": true,
|
||||||
@@ -835,7 +895,7 @@ const docTemplateapi = `{
|
|||||||
},
|
},
|
||||||
"/login-options": {
|
"/login-options": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "登录选项",
|
"description": "login options",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -843,9 +903,9 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"登录"
|
"login"
|
||||||
],
|
],
|
||||||
"summary": "登录选项",
|
"summary": "login options",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
@@ -867,7 +927,7 @@ const docTemplateapi = `{
|
|||||||
},
|
},
|
||||||
"/logout": {
|
"/logout": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "登出",
|
"description": "logout",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -875,9 +935,9 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"登录"
|
"login"
|
||||||
],
|
],
|
||||||
"summary": "登出",
|
"summary": "logout",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
@@ -894,35 +954,6 @@ const docTemplateapi = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/oauth/callback": {
|
|
||||||
"get": {
|
|
||||||
"description": "OauthCallback",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"Oauth"
|
|
||||||
],
|
|
||||||
"summary": "OauthCallback",
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/api.LoginRes"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"500": {
|
|
||||||
"description": "Internal Server Error",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/response.ErrorResponse"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/oidc/auth": {
|
"/oidc/auth": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "OidcAuth",
|
"description": "OidcAuth",
|
||||||
@@ -981,14 +1012,9 @@ const docTemplateapi = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/peers": {
|
"/oidc/callback": {
|
||||||
"get": {
|
"get": {
|
||||||
"security": [
|
"description": "OauthCallback",
|
||||||
{
|
|
||||||
"BearerAuth": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "机器",
|
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -996,25 +1022,59 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"群组"
|
"Oauth"
|
||||||
],
|
],
|
||||||
"summary": "机器",
|
"summary": "OauthCallback",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/api.LoginRes"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.ErrorResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/peers": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"BearerAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "machine",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"group"
|
||||||
|
],
|
||||||
|
"summary": "machine",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "页码",
|
"description": "page number",
|
||||||
"name": "page",
|
"name": "page",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "每页数量",
|
"description": "items per page",
|
||||||
"name": "pageSize",
|
"name": "pageSize",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "状态",
|
"description": "status",
|
||||||
"name": "status",
|
"name": "status",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
@@ -1048,7 +1108,41 @@ const docTemplateapi = `{
|
|||||||
"token": []
|
"token": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "服务配置,给webclient提供api-server",
|
"description": "service config, provides an api-server for the webclient",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"WEBCLIENT"
|
||||||
|
],
|
||||||
|
"summary": "service config",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.Response"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.Response"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/server-config-v2": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"token": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "service config, provides an api-server for the webclient",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -1058,7 +1152,7 @@ const docTemplateapi = `{
|
|||||||
"tags": [
|
"tags": [
|
||||||
"WEBCLIENT_V2"
|
"WEBCLIENT_V2"
|
||||||
],
|
],
|
||||||
"summary": "服务配置",
|
"summary": "service config",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
@@ -1077,7 +1171,7 @@ const docTemplateapi = `{
|
|||||||
},
|
},
|
||||||
"/shared-peer": {
|
"/shared-peer": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "分享的peer",
|
"description": "shared peer",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -1087,7 +1181,7 @@ const docTemplateapi = `{
|
|||||||
"tags": [
|
"tags": [
|
||||||
"WEBCLIENT"
|
"WEBCLIENT"
|
||||||
],
|
],
|
||||||
"summary": "分享的peer",
|
"summary": "shared peer",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
@@ -1106,7 +1200,7 @@ const docTemplateapi = `{
|
|||||||
},
|
},
|
||||||
"/sysinfo": {
|
"/sysinfo": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "提交系统信息",
|
"description": "submit system info",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -1114,12 +1208,12 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"地址"
|
"System"
|
||||||
],
|
],
|
||||||
"summary": "提交系统信息",
|
"summary": "submit system info",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"description": "系统信息表单",
|
"description": "system info form",
|
||||||
"name": "body",
|
"name": "body",
|
||||||
"in": "body",
|
"in": "body",
|
||||||
"required": true,
|
"required": true,
|
||||||
@@ -1144,14 +1238,9 @@ const docTemplateapi = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/tags": {
|
"/sysinfo_ver": {
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"description": "get system version info",
|
||||||
{
|
|
||||||
"BearerAuth": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "标签",
|
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -1159,17 +1248,14 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"地址"
|
"System"
|
||||||
],
|
],
|
||||||
"summary": "标签",
|
"summary": "get system version info",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
"schema": {
|
"schema": {
|
||||||
"type": "array",
|
"type": "string"
|
||||||
"items": {
|
|
||||||
"$ref": "#/definitions/model.Tag"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"500": {
|
"500": {
|
||||||
@@ -1188,7 +1274,7 @@ const docTemplateapi = `{
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "用户列表",
|
"description": "user list",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -1196,25 +1282,25 @@ const docTemplateapi = `{
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"群组"
|
"group"
|
||||||
],
|
],
|
||||||
"summary": "用户列表",
|
"summary": "user list",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "页码",
|
"description": "page number",
|
||||||
"name": "page",
|
"name": "page",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "每页数量",
|
"description": "items per page",
|
||||||
"name": "pageSize",
|
"name": "pageSize",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "状态",
|
"description": "status",
|
||||||
"name": "status",
|
"name": "status",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
@@ -1255,6 +1341,35 @@ const docTemplateapi = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"/version": {
|
||||||
|
"get": {
|
||||||
|
"description": "version",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"home"
|
||||||
|
],
|
||||||
|
"summary": "version",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.Response"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.Response"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"definitions": {
|
"definitions": {
|
||||||
@@ -1356,7 +1471,7 @@ const docTemplateapi = `{
|
|||||||
},
|
},
|
||||||
"password": {
|
"password": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"maxLength": 20,
|
"maxLength": 32,
|
||||||
"minLength": 4
|
"minLength": 4
|
||||||
},
|
},
|
||||||
"type": {
|
"type": {
|
||||||
@@ -1364,7 +1479,7 @@ const docTemplateapi = `{
|
|||||||
},
|
},
|
||||||
"username": {
|
"username": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"maxLength": 10,
|
"maxLength": 32,
|
||||||
"minLength": 2
|
"minLength": 2
|
||||||
},
|
},
|
||||||
"uuid": {
|
"uuid": {
|
||||||
@@ -1478,7 +1593,7 @@ const docTemplateapi = `{
|
|||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
"color": {
|
"color": {
|
||||||
"description": "color 是flutter的颜色值,从0x00000000 到 0xFFFFFFFF; 前两位表示透明度,后面6位表示颜色, 可以转成rgba",
|
"description": "color is flutter's color value,from 0x00000000 to 0xFFFFFFFF; the first two digits represent transparency, the following 6 digits represent the color, can be converted to rgba",
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
@@ -1568,8 +1683,8 @@ var SwaggerInfoapi = &swag.Spec{
|
|||||||
Host: "",
|
Host: "",
|
||||||
BasePath: "/api",
|
BasePath: "/api",
|
||||||
Schemes: []string{},
|
Schemes: []string{},
|
||||||
Title: "管理系统API",
|
Title: "management systemAPI",
|
||||||
Description: "接口",
|
Description: "API",
|
||||||
InfoInstanceName: "api",
|
InfoInstanceName: "api",
|
||||||
SwaggerTemplate: docTemplateapi,
|
SwaggerTemplate: docTemplateapi,
|
||||||
LeftDelim: "{{",
|
LeftDelim: "{{",
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"swagger": "2.0",
|
"swagger": "2.0",
|
||||||
"info": {
|
"info": {
|
||||||
"description": "接口",
|
"description": "API",
|
||||||
"title": "管理系统API",
|
"title": "management systemAPI",
|
||||||
"contact": {},
|
"contact": {},
|
||||||
"version": "1.0"
|
"version": "1.0"
|
||||||
},
|
},
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
"paths": {
|
"paths": {
|
||||||
"/": {
|
"/": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "首页",
|
"description": "home",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -18,9 +18,9 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"首页"
|
"home"
|
||||||
],
|
],
|
||||||
"summary": "首页",
|
"summary": "home",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "地址列表",
|
"description": "address list",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -52,9 +52,9 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"地址"
|
"address"
|
||||||
],
|
],
|
||||||
"summary": "地址列表",
|
"summary": "address list",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
@@ -76,7 +76,7 @@
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "地址更新",
|
"description": "address update",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -84,12 +84,12 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"地址"
|
"address"
|
||||||
],
|
],
|
||||||
"summary": "地址更新",
|
"summary": "address update",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"description": "地址表单",
|
"description": "address form",
|
||||||
"name": "body",
|
"name": "body",
|
||||||
"in": "body",
|
"in": "body",
|
||||||
"required": true,
|
"required": true,
|
||||||
@@ -121,7 +121,7 @@
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "添加地址",
|
"description": "add address",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -129,9 +129,9 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"地址[Personal]"
|
"address[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "添加地址",
|
"summary": "add address",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -162,7 +162,7 @@
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "删除地址",
|
"description": "delete address",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -170,9 +170,9 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"地址[Personal]"
|
"address[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "删除地址",
|
"summary": "delete address",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -205,7 +205,7 @@
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "更新地址",
|
"description": "update address",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -213,9 +213,9 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"地址[Personal]"
|
"address[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "更新地址",
|
"summary": "update address",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -248,7 +248,7 @@
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "地址",
|
"description": "address",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -256,19 +256,19 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"地址[Personal]"
|
"address[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "地址列表",
|
"summary": "address list",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "页码",
|
"description": "page number",
|
||||||
"name": "current",
|
"name": "current",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "每页数量",
|
"description": "items per page",
|
||||||
"name": "pageSize",
|
"name": "pageSize",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
@@ -302,7 +302,7 @@
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "个人地址",
|
"description": "personal address",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -310,9 +310,9 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"地址[Personal]"
|
"address[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "个人地址",
|
"summary": "personal address",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"description": "string valid",
|
"description": "string valid",
|
||||||
@@ -346,7 +346,7 @@
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "设置",
|
"description": "settings",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -354,9 +354,9 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"地址[Personal]"
|
"address[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "设置",
|
"summary": "settings",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"description": "string valid",
|
"description": "string valid",
|
||||||
@@ -390,7 +390,7 @@
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "共享",
|
"description": "shared",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -398,19 +398,19 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"地址[Personal]"
|
"address[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "共享地址簿",
|
"summary": "shared address book",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "页码",
|
"description": "page number",
|
||||||
"name": "current",
|
"name": "current",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "每页数量",
|
"description": "items per page",
|
||||||
"name": "pageSize",
|
"name": "pageSize",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
}
|
}
|
||||||
@@ -438,7 +438,7 @@
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "标签",
|
"description": "tag",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -446,9 +446,9 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"地址[Personal]"
|
"address[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "标签添加",
|
"summary": "add tag",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -481,7 +481,7 @@
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "标签",
|
"description": "tag",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -489,9 +489,9 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"地址[Personal]"
|
"address[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "标签重命名",
|
"summary": "rename tag",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -524,7 +524,7 @@
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "标签",
|
"description": "tag",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -532,9 +532,9 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"地址[Personal]"
|
"address[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "标签修改颜色",
|
"summary": "change tag color",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -567,7 +567,7 @@
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "标签",
|
"description": "tag",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -575,9 +575,9 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"地址[Personal]"
|
"address[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "标签删除",
|
"summary": "delete tag",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -610,7 +610,7 @@
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "标签",
|
"description": "tag",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -618,9 +618,9 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"地址[Personal]"
|
"address[Personal]"
|
||||||
],
|
],
|
||||||
"summary": "标签",
|
"summary": "tag",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -646,43 +646,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/api": {
|
|
||||||
"get": {
|
|
||||||
"security": [
|
|
||||||
{
|
|
||||||
"token": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "用户信息",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"用户"
|
|
||||||
],
|
|
||||||
"summary": "用户信息",
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/api.UserPayload"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"500": {
|
|
||||||
"description": "Internal Server Error",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/response.Response"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/audit/conn": {
|
"/audit/conn": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "审计连接",
|
"description": "audit connection",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -690,12 +656,12 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"审计"
|
"audit"
|
||||||
],
|
],
|
||||||
"summary": "审计连接",
|
"summary": "audit connection",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"description": "审计连接",
|
"description": "audit connection",
|
||||||
"name": "body",
|
"name": "body",
|
||||||
"in": "body",
|
"in": "body",
|
||||||
"required": true,
|
"required": true,
|
||||||
@@ -722,7 +688,7 @@
|
|||||||
},
|
},
|
||||||
"/audit/file": {
|
"/audit/file": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "审计文件",
|
"description": "audit file",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -730,12 +696,12 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"审计"
|
"audit"
|
||||||
],
|
],
|
||||||
"summary": "审计文件",
|
"summary": "audit file",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"description": "审计文件",
|
"description": "audit file",
|
||||||
"name": "body",
|
"name": "body",
|
||||||
"in": "body",
|
"in": "body",
|
||||||
"required": true,
|
"required": true,
|
||||||
@@ -760,9 +726,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/heartbeat": {
|
"/currentUser": {
|
||||||
"post": {
|
"get": {
|
||||||
"description": "心跳",
|
"security": [
|
||||||
|
{
|
||||||
|
"token": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "user info",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -770,9 +741,98 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"首页"
|
"user"
|
||||||
],
|
],
|
||||||
"summary": "心跳",
|
"summary": "user info",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/api.UserPayload"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.Response"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/device-group/accessible": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"BearerAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "machine",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"group"
|
||||||
|
],
|
||||||
|
"summary": "device",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "page number",
|
||||||
|
"name": "page",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "items per page",
|
||||||
|
"name": "pageSize",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "status",
|
||||||
|
"name": "status",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "accessible",
|
||||||
|
"name": "accessible",
|
||||||
|
"in": "query"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.DataResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.Response"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/heartbeat": {
|
||||||
|
"post": {
|
||||||
|
"description": "heartbeat",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"home"
|
||||||
|
],
|
||||||
|
"summary": "heartbeat",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK"
|
"description": "OK"
|
||||||
@@ -788,7 +848,7 @@
|
|||||||
},
|
},
|
||||||
"/login": {
|
"/login": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "登录",
|
"description": "login",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -796,12 +856,12 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"登录"
|
"login"
|
||||||
],
|
],
|
||||||
"summary": "登录",
|
"summary": "login",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"description": "登录表单",
|
"description": "login form",
|
||||||
"name": "body",
|
"name": "body",
|
||||||
"in": "body",
|
"in": "body",
|
||||||
"required": true,
|
"required": true,
|
||||||
@@ -828,7 +888,7 @@
|
|||||||
},
|
},
|
||||||
"/login-options": {
|
"/login-options": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "登录选项",
|
"description": "login options",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -836,9 +896,9 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"登录"
|
"login"
|
||||||
],
|
],
|
||||||
"summary": "登录选项",
|
"summary": "login options",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
@@ -860,7 +920,7 @@
|
|||||||
},
|
},
|
||||||
"/logout": {
|
"/logout": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "登出",
|
"description": "logout",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -868,9 +928,9 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"登录"
|
"login"
|
||||||
],
|
],
|
||||||
"summary": "登出",
|
"summary": "logout",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
@@ -887,35 +947,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/oauth/callback": {
|
|
||||||
"get": {
|
|
||||||
"description": "OauthCallback",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"Oauth"
|
|
||||||
],
|
|
||||||
"summary": "OauthCallback",
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/api.LoginRes"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"500": {
|
|
||||||
"description": "Internal Server Error",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/response.ErrorResponse"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/oidc/auth": {
|
"/oidc/auth": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "OidcAuth",
|
"description": "OidcAuth",
|
||||||
@@ -974,14 +1005,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/peers": {
|
"/oidc/callback": {
|
||||||
"get": {
|
"get": {
|
||||||
"security": [
|
"description": "OauthCallback",
|
||||||
{
|
|
||||||
"BearerAuth": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "机器",
|
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -989,25 +1015,59 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"群组"
|
"Oauth"
|
||||||
],
|
],
|
||||||
"summary": "机器",
|
"summary": "OauthCallback",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/api.LoginRes"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.ErrorResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/peers": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"BearerAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "machine",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"group"
|
||||||
|
],
|
||||||
|
"summary": "machine",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "页码",
|
"description": "page number",
|
||||||
"name": "page",
|
"name": "page",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "每页数量",
|
"description": "items per page",
|
||||||
"name": "pageSize",
|
"name": "pageSize",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "状态",
|
"description": "status",
|
||||||
"name": "status",
|
"name": "status",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
@@ -1041,7 +1101,41 @@
|
|||||||
"token": []
|
"token": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "服务配置,给webclient提供api-server",
|
"description": "service config, provides an api-server for the webclient",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"WEBCLIENT"
|
||||||
|
],
|
||||||
|
"summary": "service config",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.Response"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.Response"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/server-config-v2": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"token": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "service config, provides an api-server for the webclient",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -1051,7 +1145,7 @@
|
|||||||
"tags": [
|
"tags": [
|
||||||
"WEBCLIENT_V2"
|
"WEBCLIENT_V2"
|
||||||
],
|
],
|
||||||
"summary": "服务配置",
|
"summary": "service config",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
@@ -1070,7 +1164,7 @@
|
|||||||
},
|
},
|
||||||
"/shared-peer": {
|
"/shared-peer": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "分享的peer",
|
"description": "shared peer",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -1080,7 +1174,7 @@
|
|||||||
"tags": [
|
"tags": [
|
||||||
"WEBCLIENT"
|
"WEBCLIENT"
|
||||||
],
|
],
|
||||||
"summary": "分享的peer",
|
"summary": "shared peer",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
@@ -1099,7 +1193,7 @@
|
|||||||
},
|
},
|
||||||
"/sysinfo": {
|
"/sysinfo": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "提交系统信息",
|
"description": "submit system info",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -1107,12 +1201,12 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"地址"
|
"System"
|
||||||
],
|
],
|
||||||
"summary": "提交系统信息",
|
"summary": "submit system info",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"description": "系统信息表单",
|
"description": "system info form",
|
||||||
"name": "body",
|
"name": "body",
|
||||||
"in": "body",
|
"in": "body",
|
||||||
"required": true,
|
"required": true,
|
||||||
@@ -1137,14 +1231,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/tags": {
|
"/sysinfo_ver": {
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"description": "get system version info",
|
||||||
{
|
|
||||||
"BearerAuth": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "标签",
|
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -1152,17 +1241,14 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"地址"
|
"System"
|
||||||
],
|
],
|
||||||
"summary": "标签",
|
"summary": "get system version info",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
"schema": {
|
"schema": {
|
||||||
"type": "array",
|
"type": "string"
|
||||||
"items": {
|
|
||||||
"$ref": "#/definitions/model.Tag"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"500": {
|
"500": {
|
||||||
@@ -1181,7 +1267,7 @@
|
|||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "用户列表",
|
"description": "user list",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@@ -1189,25 +1275,25 @@
|
|||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"群组"
|
"group"
|
||||||
],
|
],
|
||||||
"summary": "用户列表",
|
"summary": "user list",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "页码",
|
"description": "page number",
|
||||||
"name": "page",
|
"name": "page",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "每页数量",
|
"description": "items per page",
|
||||||
"name": "pageSize",
|
"name": "pageSize",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "状态",
|
"description": "status",
|
||||||
"name": "status",
|
"name": "status",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
@@ -1248,6 +1334,35 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"/version": {
|
||||||
|
"get": {
|
||||||
|
"description": "version",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"home"
|
||||||
|
],
|
||||||
|
"summary": "version",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.Response"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.Response"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"definitions": {
|
"definitions": {
|
||||||
@@ -1349,7 +1464,7 @@
|
|||||||
},
|
},
|
||||||
"password": {
|
"password": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"maxLength": 20,
|
"maxLength": 32,
|
||||||
"minLength": 4
|
"minLength": 4
|
||||||
},
|
},
|
||||||
"type": {
|
"type": {
|
||||||
@@ -1357,7 +1472,7 @@
|
|||||||
},
|
},
|
||||||
"username": {
|
"username": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"maxLength": 10,
|
"maxLength": 32,
|
||||||
"minLength": 2
|
"minLength": 2
|
||||||
},
|
},
|
||||||
"uuid": {
|
"uuid": {
|
||||||
@@ -1471,7 +1586,7 @@
|
|||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
"color": {
|
"color": {
|
||||||
"description": "color 是flutter的颜色值,从0x00000000 到 0xFFFFFFFF; 前两位表示透明度,后面6位表示颜色, 可以转成rgba",
|
"description": "color is flutter's color value,from 0x00000000 to 0xFFFFFFFF; the first two digits represent transparency, the following 6 digits represent the color, can be converted to rgba",
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
|
|||||||
@@ -62,13 +62,13 @@ definitions:
|
|||||||
id:
|
id:
|
||||||
type: string
|
type: string
|
||||||
password:
|
password:
|
||||||
maxLength: 20
|
maxLength: 32
|
||||||
minLength: 4
|
minLength: 4
|
||||||
type: string
|
type: string
|
||||||
type:
|
type:
|
||||||
type: string
|
type: string
|
||||||
username:
|
username:
|
||||||
maxLength: 10
|
maxLength: 32
|
||||||
minLength: 2
|
minLength: 2
|
||||||
type: string
|
type: string
|
||||||
uuid:
|
uuid:
|
||||||
@@ -146,8 +146,8 @@ definitions:
|
|||||||
collection_id:
|
collection_id:
|
||||||
type: integer
|
type: integer
|
||||||
color:
|
color:
|
||||||
description: color 是flutter的颜色值,从0x00000000 到 0xFFFFFFFF; 前两位表示透明度,后面6位表示颜色,
|
description: color is flutter's color value,from 0x00000000 to 0xFFFFFFFF; the first two digits represent transparency, the following 6 digits represent the color,
|
||||||
可以转成rgba
|
can be converted to rgba
|
||||||
type: integer
|
type: integer
|
||||||
created_at:
|
created_at:
|
||||||
type: string
|
type: string
|
||||||
@@ -194,15 +194,15 @@ definitions:
|
|||||||
type: object
|
type: object
|
||||||
info:
|
info:
|
||||||
contact: {}
|
contact: {}
|
||||||
description: 接口
|
description: API
|
||||||
title: 管理系统API
|
title: management systemAPI
|
||||||
version: "1.0"
|
version: "1.0"
|
||||||
paths:
|
paths:
|
||||||
/:
|
/:
|
||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: 首页
|
description: home
|
||||||
produces:
|
produces:
|
||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
@@ -214,14 +214,14 @@ paths:
|
|||||||
description: Internal Server Error
|
description: Internal Server Error
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/response.Response'
|
$ref: '#/definitions/response.Response'
|
||||||
summary: 首页
|
summary: home
|
||||||
tags:
|
tags:
|
||||||
- 首页
|
- home
|
||||||
/ab:
|
/ab:
|
||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: 地址列表
|
description: address list
|
||||||
produces:
|
produces:
|
||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
@@ -235,15 +235,15 @@ paths:
|
|||||||
$ref: '#/definitions/response.ErrorResponse'
|
$ref: '#/definitions/response.ErrorResponse'
|
||||||
security:
|
security:
|
||||||
- BearerAuth: []
|
- BearerAuth: []
|
||||||
summary: 地址列表
|
summary: address list
|
||||||
tags:
|
tags:
|
||||||
- 地址
|
- address
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: 地址更新
|
description: address update
|
||||||
parameters:
|
parameters:
|
||||||
- description: 地址表单
|
- description: address form
|
||||||
in: body
|
in: body
|
||||||
name: body
|
name: body
|
||||||
required: true
|
required: true
|
||||||
@@ -262,14 +262,14 @@ paths:
|
|||||||
$ref: '#/definitions/response.ErrorResponse'
|
$ref: '#/definitions/response.ErrorResponse'
|
||||||
security:
|
security:
|
||||||
- BearerAuth: []
|
- BearerAuth: []
|
||||||
summary: 地址更新
|
summary: address update
|
||||||
tags:
|
tags:
|
||||||
- 地址
|
- address
|
||||||
/ab/peer/add/{guid}:
|
/ab/peer/add/{guid}:
|
||||||
delete:
|
delete:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: 删除地址
|
description: delete address
|
||||||
parameters:
|
parameters:
|
||||||
- description: guid
|
- description: guid
|
||||||
in: path
|
in: path
|
||||||
@@ -289,13 +289,13 @@ paths:
|
|||||||
$ref: '#/definitions/response.ErrorResponse'
|
$ref: '#/definitions/response.ErrorResponse'
|
||||||
security:
|
security:
|
||||||
- BearerAuth: []
|
- BearerAuth: []
|
||||||
summary: 删除地址
|
summary: delete address
|
||||||
tags:
|
tags:
|
||||||
- 地址[Personal]
|
- address[Personal]
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: 添加地址
|
description: add address
|
||||||
parameters:
|
parameters:
|
||||||
- description: guid
|
- description: guid
|
||||||
in: path
|
in: path
|
||||||
@@ -315,14 +315,14 @@ paths:
|
|||||||
$ref: '#/definitions/response.ErrorResponse'
|
$ref: '#/definitions/response.ErrorResponse'
|
||||||
security:
|
security:
|
||||||
- BearerAuth: []
|
- BearerAuth: []
|
||||||
summary: 添加地址
|
summary: add address
|
||||||
tags:
|
tags:
|
||||||
- 地址[Personal]
|
- address[Personal]
|
||||||
/ab/peer/update/{guid}:
|
/ab/peer/update/{guid}:
|
||||||
put:
|
put:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: 更新地址
|
description: update address
|
||||||
parameters:
|
parameters:
|
||||||
- description: guid
|
- description: guid
|
||||||
in: path
|
in: path
|
||||||
@@ -342,20 +342,20 @@ paths:
|
|||||||
$ref: '#/definitions/response.ErrorResponse'
|
$ref: '#/definitions/response.ErrorResponse'
|
||||||
security:
|
security:
|
||||||
- BearerAuth: []
|
- BearerAuth: []
|
||||||
summary: 更新地址
|
summary: update address
|
||||||
tags:
|
tags:
|
||||||
- 地址[Personal]
|
- address[Personal]
|
||||||
/ab/peers:
|
/ab/peers:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: 地址
|
description: address
|
||||||
parameters:
|
parameters:
|
||||||
- description: 页码
|
- description: page number
|
||||||
in: query
|
in: query
|
||||||
name: current
|
name: current
|
||||||
type: integer
|
type: integer
|
||||||
- description: 每页数量
|
- description: items per page
|
||||||
in: query
|
in: query
|
||||||
name: pageSize
|
name: pageSize
|
||||||
type: integer
|
type: integer
|
||||||
@@ -376,14 +376,14 @@ paths:
|
|||||||
$ref: '#/definitions/response.Response'
|
$ref: '#/definitions/response.Response'
|
||||||
security:
|
security:
|
||||||
- BearerAuth: []
|
- BearerAuth: []
|
||||||
summary: 地址列表
|
summary: address list
|
||||||
tags:
|
tags:
|
||||||
- 地址[Personal]
|
- address[Personal]
|
||||||
/ab/personal:
|
/ab/personal:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: 个人地址
|
description: personal address
|
||||||
parameters:
|
parameters:
|
||||||
- description: string valid
|
- description: string valid
|
||||||
in: body
|
in: body
|
||||||
@@ -403,14 +403,14 @@ paths:
|
|||||||
$ref: '#/definitions/response.Response'
|
$ref: '#/definitions/response.Response'
|
||||||
security:
|
security:
|
||||||
- BearerAuth: []
|
- BearerAuth: []
|
||||||
summary: 个人地址
|
summary: personal address
|
||||||
tags:
|
tags:
|
||||||
- 地址[Personal]
|
- address[Personal]
|
||||||
/ab/settings:
|
/ab/settings:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: 设置
|
description: settings
|
||||||
parameters:
|
parameters:
|
||||||
- description: string valid
|
- description: string valid
|
||||||
in: body
|
in: body
|
||||||
@@ -430,20 +430,20 @@ paths:
|
|||||||
$ref: '#/definitions/response.Response'
|
$ref: '#/definitions/response.Response'
|
||||||
security:
|
security:
|
||||||
- BearerAuth: []
|
- BearerAuth: []
|
||||||
summary: 设置
|
summary: settings
|
||||||
tags:
|
tags:
|
||||||
- 地址[Personal]
|
- address[Personal]
|
||||||
/ab/shared/profiles:
|
/ab/shared/profiles:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: 共享
|
description: shared
|
||||||
parameters:
|
parameters:
|
||||||
- description: 页码
|
- description: page number
|
||||||
in: query
|
in: query
|
||||||
name: current
|
name: current
|
||||||
type: integer
|
type: integer
|
||||||
- description: 每页数量
|
- description: items per page
|
||||||
in: query
|
in: query
|
||||||
name: pageSize
|
name: pageSize
|
||||||
type: integer
|
type: integer
|
||||||
@@ -460,14 +460,14 @@ paths:
|
|||||||
$ref: '#/definitions/response.Response'
|
$ref: '#/definitions/response.Response'
|
||||||
security:
|
security:
|
||||||
- BearerAuth: []
|
- BearerAuth: []
|
||||||
summary: 共享地址簿
|
summary: shared address book
|
||||||
tags:
|
tags:
|
||||||
- 地址[Personal]
|
- address[Personal]
|
||||||
/ab/tag/{guid}:
|
/ab/tag/{guid}:
|
||||||
delete:
|
delete:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: 标签
|
description: tag
|
||||||
parameters:
|
parameters:
|
||||||
- description: guid
|
- description: guid
|
||||||
in: path
|
in: path
|
||||||
@@ -487,14 +487,14 @@ paths:
|
|||||||
$ref: '#/definitions/response.ErrorResponse'
|
$ref: '#/definitions/response.ErrorResponse'
|
||||||
security:
|
security:
|
||||||
- BearerAuth: []
|
- BearerAuth: []
|
||||||
summary: 标签删除
|
summary: delete tag
|
||||||
tags:
|
tags:
|
||||||
- 地址[Personal]
|
- address[Personal]
|
||||||
/ab/tag/add/{guid}:
|
/ab/tag/add/{guid}:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: 标签
|
description: tag
|
||||||
parameters:
|
parameters:
|
||||||
- description: guid
|
- description: guid
|
||||||
in: path
|
in: path
|
||||||
@@ -514,14 +514,14 @@ paths:
|
|||||||
$ref: '#/definitions/response.ErrorResponse'
|
$ref: '#/definitions/response.ErrorResponse'
|
||||||
security:
|
security:
|
||||||
- BearerAuth: []
|
- BearerAuth: []
|
||||||
summary: 标签添加
|
summary: add tag
|
||||||
tags:
|
tags:
|
||||||
- 地址[Personal]
|
- address[Personal]
|
||||||
/ab/tag/rename/{guid}:
|
/ab/tag/rename/{guid}:
|
||||||
put:
|
put:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: 标签
|
description: tag
|
||||||
parameters:
|
parameters:
|
||||||
- description: guid
|
- description: guid
|
||||||
in: path
|
in: path
|
||||||
@@ -541,14 +541,14 @@ paths:
|
|||||||
$ref: '#/definitions/response.ErrorResponse'
|
$ref: '#/definitions/response.ErrorResponse'
|
||||||
security:
|
security:
|
||||||
- BearerAuth: []
|
- BearerAuth: []
|
||||||
summary: 标签重命名
|
summary: rename tag
|
||||||
tags:
|
tags:
|
||||||
- 地址[Personal]
|
- address[Personal]
|
||||||
/ab/tag/update/{guid}:
|
/ab/tag/update/{guid}:
|
||||||
put:
|
put:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: 标签
|
description: tag
|
||||||
parameters:
|
parameters:
|
||||||
- description: guid
|
- description: guid
|
||||||
in: path
|
in: path
|
||||||
@@ -568,14 +568,14 @@ paths:
|
|||||||
$ref: '#/definitions/response.ErrorResponse'
|
$ref: '#/definitions/response.ErrorResponse'
|
||||||
security:
|
security:
|
||||||
- BearerAuth: []
|
- BearerAuth: []
|
||||||
summary: 标签修改颜色
|
summary: change tag color
|
||||||
tags:
|
tags:
|
||||||
- 地址[Personal]
|
- address[Personal]
|
||||||
/ab/tags/{guid}:
|
/ab/tags/{guid}:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: 标签
|
description: tag
|
||||||
parameters:
|
parameters:
|
||||||
- description: guid
|
- description: guid
|
||||||
in: path
|
in: path
|
||||||
@@ -595,37 +595,16 @@ paths:
|
|||||||
$ref: '#/definitions/response.ErrorResponse'
|
$ref: '#/definitions/response.ErrorResponse'
|
||||||
security:
|
security:
|
||||||
- BearerAuth: []
|
- BearerAuth: []
|
||||||
summary: 标签
|
summary: tag
|
||||||
tags:
|
tags:
|
||||||
- 地址[Personal]
|
- address[Personal]
|
||||||
/api:
|
|
||||||
get:
|
|
||||||
consumes:
|
|
||||||
- application/json
|
|
||||||
description: 用户信息
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: OK
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/api.UserPayload'
|
|
||||||
"500":
|
|
||||||
description: Internal Server Error
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/response.Response'
|
|
||||||
security:
|
|
||||||
- token: []
|
|
||||||
summary: 用户信息
|
|
||||||
tags:
|
|
||||||
- 用户
|
|
||||||
/audit/conn:
|
/audit/conn:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: 审计连接
|
description: audit connection
|
||||||
parameters:
|
parameters:
|
||||||
- description: 审计连接
|
- description: audit connection
|
||||||
in: body
|
in: body
|
||||||
name: body
|
name: body
|
||||||
required: true
|
required: true
|
||||||
@@ -642,16 +621,16 @@ paths:
|
|||||||
description: Internal Server Error
|
description: Internal Server Error
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/response.Response'
|
$ref: '#/definitions/response.Response'
|
||||||
summary: 审计连接
|
summary: audit connection
|
||||||
tags:
|
tags:
|
||||||
- 审计
|
- audit
|
||||||
/audit/file:
|
/audit/file:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: 审计文件
|
description: audit file
|
||||||
parameters:
|
parameters:
|
||||||
- description: 审计文件
|
- description: audit file
|
||||||
in: body
|
in: body
|
||||||
name: body
|
name: body
|
||||||
required: true
|
required: true
|
||||||
@@ -668,14 +647,73 @@ paths:
|
|||||||
description: Internal Server Error
|
description: Internal Server Error
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/response.Response'
|
$ref: '#/definitions/response.Response'
|
||||||
summary: 审计文件
|
summary: audit file
|
||||||
tags:
|
tags:
|
||||||
- 审计
|
- audit
|
||||||
|
/currentUser:
|
||||||
|
get:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: user info
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/api.UserPayload'
|
||||||
|
"500":
|
||||||
|
description: Internal Server Error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/response.Response'
|
||||||
|
security:
|
||||||
|
- token: []
|
||||||
|
summary: user info
|
||||||
|
tags:
|
||||||
|
- user
|
||||||
|
/device-group/accessible:
|
||||||
|
get:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: machine
|
||||||
|
parameters:
|
||||||
|
- description: page number
|
||||||
|
in: query
|
||||||
|
name: page
|
||||||
|
type: integer
|
||||||
|
- description: items per page
|
||||||
|
in: query
|
||||||
|
name: pageSize
|
||||||
|
type: integer
|
||||||
|
- description: status
|
||||||
|
in: query
|
||||||
|
name: status
|
||||||
|
type: integer
|
||||||
|
- description: accessible
|
||||||
|
in: query
|
||||||
|
name: accessible
|
||||||
|
type: string
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/response.DataResponse'
|
||||||
|
"500":
|
||||||
|
description: Internal Server Error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/response.Response'
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
|
summary: device
|
||||||
|
tags:
|
||||||
|
- group
|
||||||
/heartbeat:
|
/heartbeat:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: 心跳
|
description: heartbeat
|
||||||
produces:
|
produces:
|
||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
@@ -685,16 +723,16 @@ paths:
|
|||||||
description: Internal Server Error
|
description: Internal Server Error
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/response.Response'
|
$ref: '#/definitions/response.Response'
|
||||||
summary: 心跳
|
summary: heartbeat
|
||||||
tags:
|
tags:
|
||||||
- 首页
|
- home
|
||||||
/login:
|
/login:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: 登录
|
description: login
|
||||||
parameters:
|
parameters:
|
||||||
- description: 登录表单
|
- description: login form
|
||||||
in: body
|
in: body
|
||||||
name: body
|
name: body
|
||||||
required: true
|
required: true
|
||||||
@@ -711,14 +749,14 @@ paths:
|
|||||||
description: Internal Server Error
|
description: Internal Server Error
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/response.ErrorResponse'
|
$ref: '#/definitions/response.ErrorResponse'
|
||||||
summary: 登录
|
summary: login
|
||||||
tags:
|
tags:
|
||||||
- 登录
|
- login
|
||||||
/login-options:
|
/login-options:
|
||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: 登录选项
|
description: login options
|
||||||
produces:
|
produces:
|
||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
@@ -732,14 +770,14 @@ paths:
|
|||||||
description: Internal Server Error
|
description: Internal Server Error
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/response.ErrorResponse'
|
$ref: '#/definitions/response.ErrorResponse'
|
||||||
summary: 登录选项
|
summary: login options
|
||||||
tags:
|
tags:
|
||||||
- 登录
|
- login
|
||||||
/logout:
|
/logout:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: 登出
|
description: logout
|
||||||
produces:
|
produces:
|
||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
@@ -751,28 +789,9 @@ paths:
|
|||||||
description: Internal Server Error
|
description: Internal Server Error
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/response.ErrorResponse'
|
$ref: '#/definitions/response.ErrorResponse'
|
||||||
summary: 登出
|
summary: logout
|
||||||
tags:
|
tags:
|
||||||
- 登录
|
- login
|
||||||
/oauth/callback:
|
|
||||||
get:
|
|
||||||
consumes:
|
|
||||||
- application/json
|
|
||||||
description: OauthCallback
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: OK
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/api.LoginRes'
|
|
||||||
"500":
|
|
||||||
description: Internal Server Error
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/response.ErrorResponse'
|
|
||||||
summary: OauthCallback
|
|
||||||
tags:
|
|
||||||
- Oauth
|
|
||||||
/oidc/auth:
|
/oidc/auth:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
@@ -811,21 +830,40 @@ paths:
|
|||||||
summary: OidcAuthQuery
|
summary: OidcAuthQuery
|
||||||
tags:
|
tags:
|
||||||
- Oauth
|
- Oauth
|
||||||
|
/oidc/callback:
|
||||||
|
get:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: OauthCallback
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/api.LoginRes'
|
||||||
|
"500":
|
||||||
|
description: Internal Server Error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/response.ErrorResponse'
|
||||||
|
summary: OauthCallback
|
||||||
|
tags:
|
||||||
|
- Oauth
|
||||||
/peers:
|
/peers:
|
||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: 机器
|
description: machine
|
||||||
parameters:
|
parameters:
|
||||||
- description: 页码
|
- description: page number
|
||||||
in: query
|
in: query
|
||||||
name: page
|
name: page
|
||||||
type: integer
|
type: integer
|
||||||
- description: 每页数量
|
- description: items per page
|
||||||
in: query
|
in: query
|
||||||
name: pageSize
|
name: pageSize
|
||||||
type: integer
|
type: integer
|
||||||
- description: 状态
|
- description: status
|
||||||
in: query
|
in: query
|
||||||
name: status
|
name: status
|
||||||
type: integer
|
type: integer
|
||||||
@@ -846,14 +884,14 @@ paths:
|
|||||||
$ref: '#/definitions/response.Response'
|
$ref: '#/definitions/response.Response'
|
||||||
security:
|
security:
|
||||||
- BearerAuth: []
|
- BearerAuth: []
|
||||||
summary: 机器
|
summary: machine
|
||||||
tags:
|
tags:
|
||||||
- 群组
|
- group
|
||||||
/server-config:
|
/server-config:
|
||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: 服务配置,给webclient提供api-server
|
description: service config, provides an api-server for the webclient
|
||||||
produces:
|
produces:
|
||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
@@ -867,14 +905,14 @@ paths:
|
|||||||
$ref: '#/definitions/response.Response'
|
$ref: '#/definitions/response.Response'
|
||||||
security:
|
security:
|
||||||
- token: []
|
- token: []
|
||||||
summary: 服务配置
|
summary: service config
|
||||||
tags:
|
tags:
|
||||||
- WEBCLIENT_V2
|
- WEBCLIENT
|
||||||
/shared-peer:
|
/server-config-v2:
|
||||||
post:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: 分享的peer
|
description: service config, provides an api-server for the webclient
|
||||||
produces:
|
produces:
|
||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
@@ -886,16 +924,37 @@ paths:
|
|||||||
description: Internal Server Error
|
description: Internal Server Error
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/response.Response'
|
$ref: '#/definitions/response.Response'
|
||||||
summary: 分享的peer
|
security:
|
||||||
|
- token: []
|
||||||
|
summary: service config
|
||||||
|
tags:
|
||||||
|
- WEBCLIENT_V2
|
||||||
|
/shared-peer:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: shared peer
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/response.Response'
|
||||||
|
"500":
|
||||||
|
description: Internal Server Error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/response.Response'
|
||||||
|
summary: shared peer
|
||||||
tags:
|
tags:
|
||||||
- WEBCLIENT
|
- WEBCLIENT
|
||||||
/sysinfo:
|
/sysinfo:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: 提交系统信息
|
description: submit system info
|
||||||
parameters:
|
parameters:
|
||||||
- description: 系统信息表单
|
- description: system info form
|
||||||
in: body
|
in: body
|
||||||
name: body
|
name: body
|
||||||
required: true
|
required: true
|
||||||
@@ -912,47 +971,43 @@ paths:
|
|||||||
description: Internal Server Error
|
description: Internal Server Error
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/response.ErrorResponse'
|
$ref: '#/definitions/response.ErrorResponse'
|
||||||
summary: 提交系统信息
|
summary: submit system info
|
||||||
tags:
|
tags:
|
||||||
- 地址
|
- System
|
||||||
/tags:
|
/sysinfo_ver:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: 标签
|
description: get system version info
|
||||||
produces:
|
produces:
|
||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: OK
|
description: OK
|
||||||
schema:
|
schema:
|
||||||
items:
|
type: string
|
||||||
$ref: '#/definitions/model.Tag'
|
|
||||||
type: array
|
|
||||||
"500":
|
"500":
|
||||||
description: Internal Server Error
|
description: Internal Server Error
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/response.ErrorResponse'
|
$ref: '#/definitions/response.ErrorResponse'
|
||||||
security:
|
summary: get system version info
|
||||||
- BearerAuth: []
|
|
||||||
summary: 标签
|
|
||||||
tags:
|
tags:
|
||||||
- 地址
|
- System
|
||||||
/users:
|
/users:
|
||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: 用户列表
|
description: user list
|
||||||
parameters:
|
parameters:
|
||||||
- description: 页码
|
- description: page number
|
||||||
in: query
|
in: query
|
||||||
name: page
|
name: page
|
||||||
type: integer
|
type: integer
|
||||||
- description: 每页数量
|
- description: items per page
|
||||||
in: query
|
in: query
|
||||||
name: pageSize
|
name: pageSize
|
||||||
type: integer
|
type: integer
|
||||||
- description: 状态
|
- description: status
|
||||||
in: query
|
in: query
|
||||||
name: status
|
name: status
|
||||||
type: integer
|
type: integer
|
||||||
@@ -980,9 +1035,28 @@ paths:
|
|||||||
$ref: '#/definitions/response.ErrorResponse'
|
$ref: '#/definitions/response.ErrorResponse'
|
||||||
security:
|
security:
|
||||||
- BearerAuth: []
|
- BearerAuth: []
|
||||||
summary: 用户列表
|
summary: user list
|
||||||
tags:
|
tags:
|
||||||
- 群组
|
- group
|
||||||
|
/version:
|
||||||
|
get:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: version
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/response.Response'
|
||||||
|
"500":
|
||||||
|
description: Internal Server Error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/response.Response'
|
||||||
|
summary: version
|
||||||
|
tags:
|
||||||
|
- home
|
||||||
securityDefinitions:
|
securityDefinitions:
|
||||||
BearerAuth:
|
BearerAuth:
|
||||||
in: header
|
in: header
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 97 KiB |
|
After Width: | Height: | Size: 99 KiB |
|
After Width: | Height: | Size: 67 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 99 KiB |
|
After Width: | Height: | Size: 67 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 13 KiB |
@@ -1,4 +1,4 @@
|
|||||||
package Gwen
|
package main
|
||||||
|
|
||||||
//go:generate swag init -g cmd/apimain.go --output docs/api --instanceName api --exclude http/controller/admin
|
//go:generate swag init -g cmd/apimain.go --output docs/api --instanceName api --exclude http/controller/admin
|
||||||
//go:generate swag init -g cmd/apimain.go --output docs/admin --instanceName admin --exclude http/controller/api
|
//go:generate swag init -g cmd/apimain.go --output docs/admin --instanceName admin --exclude http/controller/api
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
package Gwen
|
package main
|
||||||
|
|
||||||
//go:generate go run cmd/apimain.go
|
//go:generate go run cmd/apimain.go
|
||||||
|
|||||||
@@ -3,33 +3,45 @@ package global
|
|||||||
import (
|
import (
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/go-playground/locales/en"
|
"github.com/go-playground/locales/en"
|
||||||
|
"github.com/go-playground/locales/es"
|
||||||
|
"github.com/go-playground/locales/fr"
|
||||||
"github.com/go-playground/locales/ko"
|
"github.com/go-playground/locales/ko"
|
||||||
"github.com/go-playground/locales/ru"
|
"github.com/go-playground/locales/ru"
|
||||||
"github.com/go-playground/locales/zh_Hans_CN"
|
"github.com/go-playground/locales/zh_Hans_CN"
|
||||||
|
"github.com/go-playground/locales/zh_Hant"
|
||||||
ut "github.com/go-playground/universal-translator"
|
ut "github.com/go-playground/universal-translator"
|
||||||
"github.com/go-playground/validator/v10"
|
"github.com/go-playground/validator/v10"
|
||||||
en_translations "github.com/go-playground/validator/v10/translations/en"
|
en_translations "github.com/go-playground/validator/v10/translations/en"
|
||||||
|
es_translations "github.com/go-playground/validator/v10/translations/es"
|
||||||
|
fr_translations "github.com/go-playground/validator/v10/translations/fr"
|
||||||
|
ko_translations "github.com/go-playground/validator/v10/translations/ko"
|
||||||
ru_translations "github.com/go-playground/validator/v10/translations/ru"
|
ru_translations "github.com/go-playground/validator/v10/translations/ru"
|
||||||
zh_translations "github.com/go-playground/validator/v10/translations/zh"
|
zh_translations "github.com/go-playground/validator/v10/translations/zh"
|
||||||
|
zh_tw_translations "github.com/go-playground/validator/v10/translations/zh_tw"
|
||||||
"reflect"
|
"reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ApiInitValidator() {
|
func ApiInitValidator() {
|
||||||
validate := validator.New()
|
validate := validator.New()
|
||||||
|
|
||||||
// 定义不同的语言翻译
|
// define translations for different languages
|
||||||
enT := en.New()
|
enT := en.New()
|
||||||
cn := zh_Hans_CN.New()
|
cn := zh_Hans_CN.New()
|
||||||
koT := ko.New()
|
koT := ko.New()
|
||||||
ruT := ru.New()
|
ruT := ru.New()
|
||||||
|
esT := es.New()
|
||||||
|
frT := fr.New()
|
||||||
|
zhTwT := zh_Hant.New()
|
||||||
|
|
||||||
uni := ut.New(enT, cn, koT, ruT)
|
uni := ut.New(enT, cn, koT, ruT, esT, frT, zhTwT)
|
||||||
|
|
||||||
enTrans, _ := uni.GetTranslator("en")
|
enTrans, _ := uni.GetTranslator("en")
|
||||||
zhTrans, _ := uni.GetTranslator("zh_Hans_CN")
|
zhTrans, _ := uni.GetTranslator("zh_Hans_CN")
|
||||||
koTrans, _ := uni.GetTranslator("ko")
|
koTrans, _ := uni.GetTranslator("ko")
|
||||||
ruTrans, _ := uni.GetTranslator("ru")
|
ruTrans, _ := uni.GetTranslator("ru")
|
||||||
|
esTrans, _ := uni.GetTranslator("es")
|
||||||
|
frTrans, _ := uni.GetTranslator("fr")
|
||||||
|
zhTwTrans, _ := uni.GetTranslator("zh_Hant")
|
||||||
|
|
||||||
err := zh_translations.RegisterDefaultTranslations(validate, zhTrans)
|
err := zh_translations.RegisterDefaultTranslations(validate, zhTrans)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -40,8 +52,7 @@ func ApiInitValidator() {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
//validate没有ko的翻译,使用zh的翻译
|
err = ko_translations.RegisterDefaultTranslations(validate, koTrans)
|
||||||
err = zh_translations.RegisterDefaultTranslations(validate, koTrans)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -49,6 +60,18 @@ func ApiInitValidator() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
err = es_translations.RegisterDefaultTranslations(validate, esTrans)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
err = fr_translations.RegisterDefaultTranslations(validate, frTrans)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
err = zh_tw_translations.RegisterDefaultTranslations(validate, zhTwTrans)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
validate.RegisterTagNameFunc(func(field reflect.StructField) string {
|
validate.RegisterTagNameFunc(func(field reflect.StructField) string {
|
||||||
label := field.Tag.Get("label")
|
label := field.Tag.Get("label")
|
||||||
@@ -58,7 +81,7 @@ func ApiInitValidator() {
|
|||||||
return label
|
return label
|
||||||
})
|
})
|
||||||
Validator.Validate = validate
|
Validator.Validate = validate
|
||||||
Validator.UT = uni // 存储 Universal Translator
|
Validator.UT = uni // store the Universal Translator
|
||||||
Validator.VTrans = zhTrans
|
Validator.VTrans = zhTrans
|
||||||
|
|
||||||
Validator.ValidStruct = func(ctx *gin.Context, i interface{}) []string {
|
Validator.ValidStruct = func(ctx *gin.Context, i interface{}) []string {
|
||||||
@@ -109,12 +132,25 @@ func getTranslatorForLang(lang string) ut.Translator {
|
|||||||
case "zh":
|
case "zh":
|
||||||
trans, _ := Validator.UT.GetTranslator("zh_Hans_CN")
|
trans, _ := Validator.UT.GetTranslator("zh_Hans_CN")
|
||||||
return trans
|
return trans
|
||||||
|
case "zh_TW":
|
||||||
|
fallthrough
|
||||||
|
case "zh-TW":
|
||||||
|
fallthrough
|
||||||
|
case "zh-tw":
|
||||||
|
trans, _ := Validator.UT.GetTranslator("zh_Hant")
|
||||||
|
return trans
|
||||||
case "ko":
|
case "ko":
|
||||||
trans, _ := Validator.UT.GetTranslator("ko")
|
trans, _ := Validator.UT.GetTranslator("ko")
|
||||||
return trans
|
return trans
|
||||||
case "ru":
|
case "ru":
|
||||||
trans, _ := Validator.UT.GetTranslator("ru")
|
trans, _ := Validator.UT.GetTranslator("ru")
|
||||||
return trans
|
return trans
|
||||||
|
case "es":
|
||||||
|
trans, _ := Validator.UT.GetTranslator("es")
|
||||||
|
return trans
|
||||||
|
case "fr":
|
||||||
|
trans, _ := Validator.UT.GetTranslator("fr")
|
||||||
|
return trans
|
||||||
case "en":
|
case "en":
|
||||||
fallthrough
|
fallthrough
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
package global
|
package global
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"Gwen/config"
|
|
||||||
"Gwen/lib/cache"
|
|
||||||
"Gwen/lib/jwt"
|
|
||||||
"Gwen/lib/lock"
|
|
||||||
"Gwen/lib/upload"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
ut "github.com/go-playground/universal-translator"
|
ut "github.com/go-playground/universal-translator"
|
||||||
"github.com/go-playground/validator/v10"
|
"github.com/go-playground/validator/v10"
|
||||||
"github.com/go-redis/redis/v8"
|
"github.com/go-redis/redis/v8"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/config"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/lib/cache"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/lib/jwt"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/lib/lock"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/lib/upload"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/utils"
|
||||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
@@ -35,4 +36,5 @@ var (
|
|||||||
Jwt *jwt.Jwt
|
Jwt *jwt.Jwt
|
||||||
Lock lock.Locker
|
Lock lock.Locker
|
||||||
Localizer func(lang string) *i18n.Localizer
|
Localizer func(lang string) *i18n.Localizer
|
||||||
|
LoginLimiter *utils.LoginLimiter
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -10,15 +10,14 @@ import (
|
|||||||
func InitI18n() {
|
func InitI18n() {
|
||||||
bundle := i18n.NewBundle(language.English)
|
bundle := i18n.NewBundle(language.English)
|
||||||
bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal)
|
bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal)
|
||||||
//读取global.Config.Gin.ResourcesPath下的所有语言文件
|
// read all language files under global.Config.Gin.ResourcesPath
|
||||||
dir := Config.Gin.ResourcesPath + "/i18n"
|
dir := Config.Gin.ResourcesPath + "/i18n"
|
||||||
fileInfos, err := os.ReadDir(dir)
|
fileInfos, err := os.ReadDir(dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
for _, fileInfo := range fileInfos {
|
for _, fileInfo := range fileInfos {
|
||||||
//如果文件名不是.toml结尾
|
// if the file name does not end with .toml
|
||||||
if fileInfo.IsDir() || fileInfo.Name()[len(fileInfo.Name())-5:] != ".toml" {
|
if fileInfo.IsDir() || fileInfo.Name()[len(fileInfo.Name())-5:] != ".toml" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,23 @@
|
|||||||
module Gwen
|
module github.com/lejianwen/rustdesk-api/v2
|
||||||
|
|
||||||
go 1.22
|
go 1.23
|
||||||
|
|
||||||
|
toolchain go1.23.10
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/BurntSushi/toml v1.3.2
|
github.com/BurntSushi/toml v1.3.2
|
||||||
github.com/antonfisher/nested-logrus-formatter v1.3.1
|
github.com/antonfisher/nested-logrus-formatter v1.3.1
|
||||||
github.com/fsnotify/fsnotify v1.5.1
|
github.com/coreos/go-oidc/v3 v3.12.0
|
||||||
github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6
|
github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6
|
||||||
github.com/gin-gonic/gin v1.9.0
|
github.com/gin-gonic/gin v1.9.0
|
||||||
|
github.com/go-ldap/ldap/v3 v3.4.10
|
||||||
github.com/go-playground/locales v0.14.1
|
github.com/go-playground/locales v0.14.1
|
||||||
github.com/go-playground/universal-translator v0.18.1
|
github.com/go-playground/universal-translator v0.18.1
|
||||||
github.com/go-playground/validator/v10 v10.11.2
|
github.com/go-playground/validator/v10 v10.26.0
|
||||||
github.com/go-redis/redis/v8 v8.11.4
|
github.com/go-redis/redis/v8 v8.11.4
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.1
|
github.com/golang-jwt/jwt/v5 v5.2.1
|
||||||
github.com/google/uuid v1.1.2
|
github.com/google/uuid v1.6.0
|
||||||
|
github.com/mojocn/base64Captcha v1.3.6
|
||||||
github.com/nicksnyder/go-i18n/v2 v2.4.0
|
github.com/nicksnyder/go-i18n/v2 v2.4.0
|
||||||
github.com/sirupsen/logrus v1.8.1
|
github.com/sirupsen/logrus v1.8.1
|
||||||
github.com/spf13/cobra v1.8.1
|
github.com/spf13/cobra v1.8.1
|
||||||
@@ -21,14 +25,17 @@ require (
|
|||||||
github.com/swaggo/files v1.0.1
|
github.com/swaggo/files v1.0.1
|
||||||
github.com/swaggo/gin-swagger v1.6.0
|
github.com/swaggo/gin-swagger v1.6.0
|
||||||
github.com/swaggo/swag v1.16.3
|
github.com/swaggo/swag v1.16.3
|
||||||
|
golang.org/x/crypto v0.33.0
|
||||||
golang.org/x/oauth2 v0.23.0
|
golang.org/x/oauth2 v0.23.0
|
||||||
golang.org/x/text v0.18.0
|
golang.org/x/text v0.22.0
|
||||||
gorm.io/driver/mysql v1.5.7
|
gorm.io/driver/mysql v1.5.7
|
||||||
|
gorm.io/driver/postgres v1.6.0
|
||||||
gorm.io/driver/sqlite v1.5.6
|
gorm.io/driver/sqlite v1.5.6
|
||||||
gorm.io/gorm v1.25.7
|
gorm.io/gorm v1.25.10
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
|
||||||
github.com/KyleBanks/depth v1.2.1 // indirect
|
github.com/KyleBanks/depth v1.2.1 // indirect
|
||||||
github.com/PuerkitoBio/purell v1.1.1 // indirect
|
github.com/PuerkitoBio/purell v1.1.1 // indirect
|
||||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
|
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
|
||||||
@@ -36,21 +43,30 @@ require (
|
|||||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||||
|
github.com/fsnotify/fsnotify v1.5.1 // indirect
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
||||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||||
|
github.com/go-asn1-ber/asn1-ber v1.5.7 // indirect
|
||||||
|
github.com/go-jose/go-jose/v4 v4.0.2 // indirect
|
||||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||||
github.com/go-openapi/jsonreference v0.19.6 // indirect
|
github.com/go-openapi/jsonreference v0.19.6 // indirect
|
||||||
github.com/go-openapi/spec v0.20.4 // indirect
|
github.com/go-openapi/spec v0.20.4 // indirect
|
||||||
github.com/go-openapi/swag v0.19.15 // indirect
|
github.com/go-openapi/swag v0.19.15 // indirect
|
||||||
github.com/go-sql-driver/mysql v1.7.0 // indirect
|
github.com/go-sql-driver/mysql v1.7.0 // indirect
|
||||||
github.com/goccy/go-json v0.10.0 // indirect
|
github.com/goccy/go-json v0.10.0 // indirect
|
||||||
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
||||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
|
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||||
|
github.com/jackc/pgx/v5 v5.6.0 // indirect
|
||||||
|
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
||||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
github.com/jinzhu/now v1.1.5 // indirect
|
github.com/jinzhu/now v1.1.5 // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
|
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
|
||||||
github.com/leodido/go-urn v1.2.1 // indirect
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
github.com/magiconair/properties v1.8.5 // indirect
|
github.com/magiconair/properties v1.8.5 // indirect
|
||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.17 // indirect
|
github.com/mattn/go-isatty v0.0.17 // indirect
|
||||||
@@ -60,6 +76,7 @@ require (
|
|||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/pelletier/go-toml v1.9.4 // indirect
|
github.com/pelletier/go-toml v1.9.4 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
|
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
|
||||||
|
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
||||||
github.com/spf13/afero v1.6.0 // indirect
|
github.com/spf13/afero v1.6.0 // indirect
|
||||||
github.com/spf13/cast v1.4.1 // indirect
|
github.com/spf13/cast v1.4.1 // indirect
|
||||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||||
@@ -68,10 +85,11 @@ require (
|
|||||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
github.com/ugorji/go/codec v1.2.9 // indirect
|
github.com/ugorji/go/codec v1.2.9 // indirect
|
||||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect
|
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect
|
||||||
golang.org/x/crypto v0.23.0 // indirect
|
golang.org/x/image v0.13.0 // indirect
|
||||||
golang.org/x/net v0.25.0 // indirect
|
golang.org/x/net v0.34.0 // indirect
|
||||||
golang.org/x/sys v0.25.0 // indirect
|
golang.org/x/sync v0.11.0 // indirect
|
||||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
|
golang.org/x/sys v0.30.0 // indirect
|
||||||
|
golang.org/x/tools v0.26.0 // indirect
|
||||||
google.golang.org/protobuf v1.33.0 // indirect
|
google.golang.org/protobuf v1.33.0 // indirect
|
||||||
gopkg.in/ini.v1 v1.63.2 // indirect
|
gopkg.in/ini.v1 v1.63.2 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
package admin
|
package admin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"Gwen/global"
|
"encoding/json"
|
||||||
"Gwen/http/request/admin"
|
|
||||||
"Gwen/http/response"
|
|
||||||
"Gwen/model"
|
|
||||||
"Gwen/service"
|
|
||||||
_ "encoding/json"
|
_ "encoding/json"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
@@ -15,10 +15,10 @@ import (
|
|||||||
type AddressBook struct {
|
type AddressBook struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detail 地址簿
|
// Detail address book
|
||||||
// @Tags 地址簿
|
// @Tags address book
|
||||||
// @Summary 地址簿详情
|
// @Summary address book details
|
||||||
// @Description 地址簿详情
|
// @Description address book details
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param id path int true "ID"
|
// @Param id path int true "ID"
|
||||||
@@ -30,11 +30,6 @@ func (ct *AddressBook) Detail(c *gin.Context) {
|
|||||||
id := c.Param("id")
|
id := c.Param("id")
|
||||||
iid, _ := strconv.Atoi(id)
|
iid, _ := strconv.Atoi(id)
|
||||||
t := service.AllService.AddressBookService.InfoByRowId(uint(iid))
|
t := service.AllService.AddressBookService.InfoByRowId(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.RowId > 0 {
|
if t.RowId > 0 {
|
||||||
response.Success(c, t)
|
response.Success(c, t)
|
||||||
return
|
return
|
||||||
@@ -43,13 +38,13 @@ func (ct *AddressBook) Detail(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create 创建地址簿
|
// Create create address book
|
||||||
// @Tags 地址簿
|
// @Tags address book
|
||||||
// @Summary 创建地址簿
|
// @Summary create address book
|
||||||
// @Description 创建地址簿
|
// @Description create address book
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.AddressBookForm true "地址簿信息"
|
// @Param body body admin.AddressBookForm true "address book info"
|
||||||
// @Success 200 {object} response.Response{data=model.AddressBook}
|
// @Success 200 {object} response.Response{data=model.AddressBook}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/address_book/create [post]
|
// @Router /admin/address_book/create [post]
|
||||||
@@ -66,9 +61,9 @@ func (ct *AddressBook) Create(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
t := f.ToAddressBook()
|
t := f.ToAddressBook()
|
||||||
u := service.AllService.UserService.CurUser(c)
|
if t.UserId == 0 {
|
||||||
if !service.AllService.UserService.IsAdmin(u) || t.UserId == 0 {
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||||
t.UserId = u.Id
|
return
|
||||||
}
|
}
|
||||||
if t.CollectionId > 0 && !service.AllService.AddressBookService.CheckCollectionOwner(t.UserId, t.CollectionId) {
|
if t.CollectionId > 0 && !service.AllService.AddressBookService.CheckCollectionOwner(t.UserId, t.CollectionId) {
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||||
@@ -89,16 +84,16 @@ func (ct *AddressBook) Create(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// BatchCreate 批量创建地址簿
|
// BatchCreate batch create address books
|
||||||
// @Tags 地址簿
|
// @Tags address book
|
||||||
// @Summary 批量创建地址簿
|
// @Summary batch create address books
|
||||||
// @Description 批量创建地址簿
|
// @Description batch create address books
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.AddressBookForm true "地址簿信息"
|
// @Param body body admin.AddressBookForm true "address book info"
|
||||||
// @Success 200 {object} response.Response{data=model.AddressBook}
|
// @Success 200 {object} response.Response{data=model.AddressBook}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/address_book/create [post]
|
// @Router /admin/address_book/batchCreate [post]
|
||||||
// @Security token
|
// @Security token
|
||||||
func (ct *AddressBook) BatchCreate(c *gin.Context) {
|
func (ct *AddressBook) BatchCreate(c *gin.Context) {
|
||||||
f := &admin.AddressBookForm{}
|
f := &admin.AddressBookForm{}
|
||||||
@@ -111,9 +106,21 @@ func (ct *AddressBook) BatchCreate(c *gin.Context) {
|
|||||||
response.Fail(c, 101, errList[0])
|
response.Fail(c, 101, errList[0])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
ul := len(f.UserIds)
|
||||||
|
|
||||||
//创建标签
|
if ul == 0 {
|
||||||
for _, fu := range f.UserIds {
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ul > 1 {
|
||||||
|
//clear tags in multi-user mode
|
||||||
|
f.Tags = []string{}
|
||||||
|
//in multi-user mode, can only create in the default address book
|
||||||
|
f.CollectionId = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
//create tag
|
||||||
|
/*for _, fu := range f.UserIds {
|
||||||
if fu == 0 {
|
if fu == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -126,13 +133,13 @@ func (ct *AddressBook) BatchCreate(c *gin.Context) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
ts := f.ToAddressBooks()
|
ts := f.ToAddressBooks()
|
||||||
for _, t := range ts {
|
for _, t := range ts {
|
||||||
if t.UserId == 0 {
|
if t.UserId == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
ex := service.AllService.AddressBookService.InfoByUserIdAndId(t.UserId, t.Id)
|
ex := service.AllService.AddressBookService.InfoByUserIdAndIdAndCid(t.UserId, t.Id, t.CollectionId)
|
||||||
if ex.RowId == 0 {
|
if ex.RowId == 0 {
|
||||||
service.AllService.AddressBookService.Create(t)
|
service.AllService.AddressBookService.Create(t)
|
||||||
}
|
}
|
||||||
@@ -141,16 +148,16 @@ func (ct *AddressBook) BatchCreate(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// List 列表
|
// List list
|
||||||
// @Tags 地址簿
|
// @Tags address book
|
||||||
// @Summary 地址簿列表
|
// @Summary address book list
|
||||||
// @Description 地址簿列表
|
// @Description address book list
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param page query int false "页码"
|
// @Param page query int false "page number"
|
||||||
// @Param page_size query int false "页大小"
|
// @Param page_size query int false "page size"
|
||||||
// @Param user_id query int false "用户id"
|
// @Param user_id query int false "userid"
|
||||||
// @Param is_my query int false "是否是我的"
|
// @Param is_my query int false "whether it is mine"
|
||||||
// @Success 200 {object} response.Response{data=model.AddressBookList}
|
// @Success 200 {object} response.Response{data=model.AddressBookList}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/address_book/list [get]
|
// @Router /admin/address_book/list [get]
|
||||||
@@ -161,10 +168,6 @@ func (ct *AddressBook) List(c *gin.Context) {
|
|||||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
return
|
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.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 {
|
tx.Preload("Collection", func(txc *gorm.DB) *gorm.DB {
|
||||||
return txc.Select("id,name")
|
return txc.Select("id,name")
|
||||||
@@ -190,21 +193,16 @@ func (ct *AddressBook) List(c *gin.Context) {
|
|||||||
for _, ab := range res.AddressBooks {
|
for _, ab := range res.AddressBooks {
|
||||||
abCIds = append(abCIds, ab.CollectionId)
|
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update 编辑
|
// Update edit
|
||||||
// @Tags 地址簿
|
// @Tags address book
|
||||||
// @Summary 地址簿编辑
|
// @Summary edit address book
|
||||||
// @Description 地址簿编辑
|
// @Description edit address book
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.AddressBookForm true "地址簿信息"
|
// @Param body body admin.AddressBookForm true "address book info"
|
||||||
// @Success 200 {object} response.Response{data=model.AddressBook}
|
// @Success 200 {object} response.Response{data=model.AddressBook}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/address_book/update [post]
|
// @Router /admin/address_book/update [post]
|
||||||
@@ -221,15 +219,15 @@ func (ct *AddressBook) Update(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if f.RowId == 0 {
|
if f.RowId == 0 {
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ex := service.AllService.AddressBookService.InfoByRowId(f.RowId)
|
||||||
|
if ex.RowId == 0 {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
t := f.ToAddressBook()
|
t := f.ToAddressBook()
|
||||||
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.CollectionId > 0 && !service.AllService.AddressBookService.CheckCollectionOwner(t.UserId, t.CollectionId) {
|
if t.CollectionId > 0 && !service.AllService.AddressBookService.CheckCollectionOwner(t.UserId, t.CollectionId) {
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||||
return
|
return
|
||||||
@@ -242,13 +240,13 @@ func (ct *AddressBook) Update(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete 删除
|
// Delete delete
|
||||||
// @Tags 地址簿
|
// @Tags address book
|
||||||
// @Summary 地址簿删除
|
// @Summary delete address book
|
||||||
// @Description 地址簿删除
|
// @Description delete address book
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.AddressBookForm true "地址簿信息"
|
// @Param body body admin.AddressBookForm true "address book info"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/address_book/delete [post]
|
// @Router /admin/address_book/delete [post]
|
||||||
@@ -270,30 +268,21 @@ func (ct *AddressBook) Delete(c *gin.Context) {
|
|||||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
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.Delete(t)
|
err := service.AllService.AddressBookService.Delete(t)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
return
|
|
||||||
}
|
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ShareByWebClient
|
// ShareByWebClient
|
||||||
// @Tags 地址簿
|
// @Tags address book
|
||||||
// @Summary 地址簿分享
|
// @Summary share address book
|
||||||
// @Description 地址簿分享
|
// @Description share address book
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.ShareByWebClientForm true "地址簿信息"
|
// @Param body body admin.ShareByWebClientForm true "address book info"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/address_book/share [post]
|
// @Router /admin/address_book/share [post]
|
||||||
@@ -327,3 +316,47 @@ func (ct *AddressBook) ShareByWebClient(c *gin.Context) {
|
|||||||
"share_token": m.ShareToken,
|
"share_token": m.ShareToken,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ct *AddressBook) BatchCreateFromPeers(c *gin.Context) {
|
||||||
|
f := &admin.BatchCreateFromPeersForm{}
|
||||||
|
if err := c.ShouldBindJSON(f); err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if f.UserId == 0 {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if f.CollectionId != 0 {
|
||||||
|
collection := service.AllService.AddressBookService.CollectionInfoById(f.CollectionId)
|
||||||
|
if collection.Id == 0 {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pl := int64(len(f.PeerIds))
|
||||||
|
peers := service.AllService.PeerService.List(1, uint(pl), func(tx *gorm.DB) {
|
||||||
|
tx.Where("row_id in ?", f.PeerIds)
|
||||||
|
})
|
||||||
|
if peers.Total == 0 || pl != peers.Total {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tags, _ := json.Marshal(f.Tags)
|
||||||
|
for _, peer := range peers.Peers {
|
||||||
|
ab := service.AllService.AddressBookService.FromPeer(peer)
|
||||||
|
ab.Tags = tags
|
||||||
|
ab.CollectionId = f.CollectionId
|
||||||
|
ab.UserId = f.UserId
|
||||||
|
ex := service.AllService.AddressBookService.InfoByUserIdAndIdAndCid(f.UserId, ab.Id, ab.CollectionId)
|
||||||
|
if ex.RowId != 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
service.AllService.AddressBookService.Create(ab)
|
||||||
|
}
|
||||||
|
response.Success(c, nil)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
package admin
|
package admin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"Gwen/global"
|
|
||||||
"Gwen/http/request/admin"
|
|
||||||
"Gwen/http/response"
|
|
||||||
"Gwen/model"
|
|
||||||
"Gwen/service"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
@@ -14,10 +14,10 @@ import (
|
|||||||
type AddressBookCollection struct {
|
type AddressBookCollection struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detail 地址簿名称
|
// Detail address book name
|
||||||
// @Tags 地址簿名称
|
// @Tags address book name
|
||||||
// @Summary 地址簿名称详情
|
// @Summary address book name details
|
||||||
// @Description 地址簿名称详情
|
// @Description address book name details
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param id path int true "ID"
|
// @Param id path int true "ID"
|
||||||
@@ -29,11 +29,6 @@ func (abc *AddressBookCollection) Detail(c *gin.Context) {
|
|||||||
id := c.Param("id")
|
id := c.Param("id")
|
||||||
iid, _ := strconv.Atoi(id)
|
iid, _ := strconv.Atoi(id)
|
||||||
t := service.AllService.AddressBookService.CollectionInfoById(uint(iid))
|
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 {
|
if t.Id > 0 {
|
||||||
response.Success(c, t)
|
response.Success(c, t)
|
||||||
return
|
return
|
||||||
@@ -42,13 +37,13 @@ func (abc *AddressBookCollection) Detail(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create 创建地址簿名称
|
// Create create address book name
|
||||||
// @Tags 地址簿名称
|
// @Tags address book name
|
||||||
// @Summary 创建地址簿名称
|
// @Summary create address book name
|
||||||
// @Description 创建地址簿名称
|
// @Description create address book name
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body model.AddressBookCollection true "地址簿名称信息"
|
// @Param body body model.AddressBookCollection true "address book name info"
|
||||||
// @Success 200 {object} response.Response{data=model.AddressBookCollection}
|
// @Success 200 {object} response.Response{data=model.AddressBookCollection}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/address_book_collection/create [post]
|
// @Router /admin/address_book_collection/create [post]
|
||||||
@@ -64,12 +59,11 @@ func (abc *AddressBookCollection) Create(c *gin.Context) {
|
|||||||
response.Fail(c, 101, errList[0])
|
response.Fail(c, 101, errList[0])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//t := f.ToAddressBookCollection()
|
if f.UserId == 0 {
|
||||||
t := f
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||||
u := service.AllService.UserService.CurUser(c)
|
return
|
||||||
if !service.AllService.UserService.IsAdmin(u) || t.UserId == 0 {
|
|
||||||
t.UserId = u.Id
|
|
||||||
}
|
}
|
||||||
|
t := f
|
||||||
err := service.AllService.AddressBookService.CreateCollection(t)
|
err := service.AllService.AddressBookService.CreateCollection(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())
|
||||||
@@ -78,16 +72,16 @@ func (abc *AddressBookCollection) Create(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// List 列表
|
// List list
|
||||||
// @Tags 地址簿名称
|
// @Tags address book name
|
||||||
// @Summary 地址簿名称列表
|
// @Summary address book name list
|
||||||
// @Description 地址簿名称列表
|
// @Description address book name list
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param page query int false "页码"
|
// @Param page query int false "page number"
|
||||||
// @Param page_size query int false "页大小"
|
// @Param page_size query int false "page size"
|
||||||
// @Param is_my query int false "是否是我的"
|
// @Param is_my query int false "whether it is mine"
|
||||||
// @Param user_id query int false "用户id"
|
// @Param user_id query int false "userid"
|
||||||
// @Success 200 {object} response.Response{data=model.AddressBookCollectionList}
|
// @Success 200 {object} response.Response{data=model.AddressBookCollectionList}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/address_book_collection/list [get]
|
// @Router /admin/address_book_collection/list [get]
|
||||||
@@ -98,10 +92,6 @@ func (abc *AddressBookCollection) List(c *gin.Context) {
|
|||||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
return
|
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) {
|
res := service.AllService.AddressBookService.ListCollection(query.Page, query.PageSize, func(tx *gorm.DB) {
|
||||||
if query.UserId > 0 {
|
if query.UserId > 0 {
|
||||||
tx.Where("user_id = ?", query.UserId)
|
tx.Where("user_id = ?", query.UserId)
|
||||||
@@ -110,13 +100,13 @@ func (abc *AddressBookCollection) List(c *gin.Context) {
|
|||||||
response.Success(c, res)
|
response.Success(c, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update 编辑
|
// Update edit
|
||||||
// @Tags 地址簿名称
|
// @Tags address book name
|
||||||
// @Summary 地址簿名称编辑
|
// @Summary edit address book name
|
||||||
// @Description 地址簿名称编辑
|
// @Description edit address book name
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body model.AddressBookCollection true "地址簿名称信息"
|
// @Param body body model.AddressBookCollection true "address book name info"
|
||||||
// @Success 200 {object} response.Response{data=model.AddressBookCollection}
|
// @Success 200 {object} response.Response{data=model.AddressBookCollection}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/address_book_collection/update [post]
|
// @Router /admin/address_book_collection/update [post]
|
||||||
@@ -137,11 +127,6 @@ func (abc *AddressBookCollection) Update(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
t := f //f.ToAddressBookCollection()
|
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)
|
err := service.AllService.AddressBookService.UpdateCollection(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())
|
||||||
@@ -150,13 +135,13 @@ func (abc *AddressBookCollection) Update(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete 删除
|
// Delete delete
|
||||||
// @Tags 地址簿名称
|
// @Tags address book name
|
||||||
// @Summary 地址簿名称删除
|
// @Summary delete address book name
|
||||||
// @Description 地址簿名称删除
|
// @Description delete address book name
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body model.AddressBookCollection true "地址簿名称信息"
|
// @Param body body model.AddressBookCollection true "address book name info"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/address_book_collection/delete [post]
|
// @Router /admin/address_book_collection/delete [post]
|
||||||
@@ -173,20 +158,15 @@ func (abc *AddressBookCollection) Delete(c *gin.Context) {
|
|||||||
response.Fail(c, 101, errList[0])
|
response.Fail(c, 101, errList[0])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
t := service.AllService.AddressBookService.CollectionInfoById(f.Id)
|
ex := service.AllService.AddressBookService.CollectionInfoById(f.Id)
|
||||||
u := service.AllService.UserService.CurUser(c)
|
if ex.Id == 0 {
|
||||||
if !service.AllService.UserService.IsAdmin(u) && t.UserId != u.Id {
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "NoAccess"))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if u.Id > 0 {
|
err := service.AllService.AddressBookService.DeleteCollection(ex)
|
||||||
err := service.AllService.AddressBookService.DeleteCollection(t)
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
response.Fail(c, 101, err.Error())
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
return
|
|
||||||
}
|
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
package admin
|
package admin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"Gwen/global"
|
|
||||||
"Gwen/http/request/admin"
|
|
||||||
"Gwen/http/response"
|
|
||||||
"Gwen/model"
|
|
||||||
"Gwen/service"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
@@ -14,17 +14,17 @@ import (
|
|||||||
type AddressBookCollectionRule struct {
|
type AddressBookCollectionRule struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// List 列表
|
// List list
|
||||||
// @Tags 地址簿规则
|
// @Tags address book rules
|
||||||
// @Summary 地址簿规则列表
|
// @Summary address book rule list
|
||||||
// @Description 地址簿规则列表
|
// @Description address book rule list
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param page query int false "页码"
|
// @Param page query int false "page number"
|
||||||
// @Param page_size query int false "页大小"
|
// @Param page_size query int false "page size"
|
||||||
// @Param is_my query int false "是否是我的"
|
// @Param is_my query int false "whether it is mine"
|
||||||
// @Param user_id query int false "用户id"
|
// @Param user_id query int false "userid"
|
||||||
// @Param collection_id query int false "地址簿集合id"
|
// @Param collection_id query int false "address book collectionid"
|
||||||
// @Success 200 {object} response.Response{data=model.AddressBookCollectionList}
|
// @Success 200 {object} response.Response{data=model.AddressBookCollectionList}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/address_book_collection_rule/list [get]
|
// @Router /admin/address_book_collection_rule/list [get]
|
||||||
@@ -35,10 +35,6 @@ func (abcr *AddressBookCollectionRule) List(c *gin.Context) {
|
|||||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
return
|
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) {
|
res := service.AllService.AddressBookService.ListRules(query.Page, query.PageSize, func(tx *gorm.DB) {
|
||||||
if query.UserId > 0 {
|
if query.UserId > 0 {
|
||||||
@@ -51,10 +47,10 @@ func (abcr *AddressBookCollectionRule) List(c *gin.Context) {
|
|||||||
response.Success(c, res)
|
response.Success(c, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detail 地址簿规则
|
// Detail address book rules
|
||||||
// @Tags 地址簿规则
|
// @Tags address book rules
|
||||||
// @Summary 地址簿规则详情
|
// @Summary address book rule details
|
||||||
// @Description 地址簿规则详情
|
// @Description address book rule details
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param id path int true "ID"
|
// @Param id path int true "ID"
|
||||||
@@ -66,26 +62,20 @@ func (abcr *AddressBookCollectionRule) Detail(c *gin.Context) {
|
|||||||
id := c.Param("id")
|
id := c.Param("id")
|
||||||
iid, _ := strconv.Atoi(id)
|
iid, _ := strconv.Atoi(id)
|
||||||
t := service.AllService.AddressBookService.RuleInfoById(uint(iid))
|
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 {
|
if t.Id > 0 {
|
||||||
response.Success(c, t)
|
response.Success(c, t)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create 创建地址簿规则
|
// Create create address book rule
|
||||||
// @Tags 地址簿规则
|
// @Tags address book rules
|
||||||
// @Summary 创建地址簿规则
|
// @Summary create address book rule
|
||||||
// @Description 创建地址簿规则
|
// @Description create address book rule
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body model.AddressBookCollectionRule true "地址簿规则信息"
|
// @Param body body model.AddressBookCollectionRule true "address book rule info"
|
||||||
// @Success 200 {object} response.Response{data=model.AddressBookCollection}
|
// @Success 200 {object} response.Response{data=model.AddressBookCollection}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/address_book_collection_rule/create [post]
|
// @Router /admin/address_book_collection_rule/create [post]
|
||||||
@@ -105,13 +95,8 @@ func (abcr *AddressBookCollectionRule) Create(c *gin.Context) {
|
|||||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//t := f.ToAddressBookCollection()
|
|
||||||
t := f
|
t := f
|
||||||
u := service.AllService.UserService.CurUser(c)
|
msg, res := abcr.CheckForm(t)
|
||||||
if t.UserId == 0 {
|
|
||||||
t.UserId = u.Id
|
|
||||||
}
|
|
||||||
msg, res := abcr.CheckForm(u, t)
|
|
||||||
if !res {
|
if !res {
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, msg))
|
response.Fail(c, 101, response.TranslateMsg(c, msg))
|
||||||
return
|
return
|
||||||
@@ -124,9 +109,9 @@ func (abcr *AddressBookCollectionRule) Create(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (abcr *AddressBookCollectionRule) CheckForm(u *model.User, t *model.AddressBookCollectionRule) (string, bool) {
|
func (abcr *AddressBookCollectionRule) CheckForm(t *model.AddressBookCollectionRule) (string, bool) {
|
||||||
if !service.AllService.UserService.IsAdmin(u) && t.UserId != u.Id {
|
if t.UserId == 0 {
|
||||||
return "NoAccess", false
|
return "ParamsError", false
|
||||||
}
|
}
|
||||||
if t.CollectionId > 0 && !service.AllService.AddressBookService.CheckCollectionOwner(t.UserId, t.CollectionId) {
|
if t.CollectionId > 0 && !service.AllService.AddressBookService.CheckCollectionOwner(t.UserId, t.CollectionId) {
|
||||||
return "ParamsError", false
|
return "ParamsError", false
|
||||||
@@ -135,21 +120,13 @@ func (abcr *AddressBookCollectionRule) CheckForm(u *model.User, t *model.Address
|
|||||||
//check to_id
|
//check to_id
|
||||||
if t.Type == model.ShareAddressBookRuleTypePersonal {
|
if t.Type == model.ShareAddressBookRuleTypePersonal {
|
||||||
if t.ToId == t.UserId {
|
if t.ToId == t.UserId {
|
||||||
return "ParamsError", false
|
return "CannotShareToSelf", false
|
||||||
}
|
}
|
||||||
tou := service.AllService.UserService.InfoById(t.ToId)
|
tou := service.AllService.UserService.InfoById(t.ToId)
|
||||||
if tou.Id == 0 {
|
if tou.Id == 0 {
|
||||||
return "ItemNotFound", false
|
return "ItemNotFound", false
|
||||||
}
|
}
|
||||||
//非管理员不能分享给非本组织用户
|
|
||||||
if tou.GroupId != u.GroupId && !service.AllService.UserService.IsAdmin(u) {
|
|
||||||
return "NoAccess", false
|
|
||||||
}
|
|
||||||
} else if t.Type == model.ShareAddressBookRuleTypeGroup {
|
} 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)
|
tog := service.AllService.GroupService.InfoById(t.ToId)
|
||||||
if tog.Id == 0 {
|
if tog.Id == 0 {
|
||||||
return "ItemNotFound", false
|
return "ItemNotFound", false
|
||||||
@@ -157,8 +134,8 @@ func (abcr *AddressBookCollectionRule) CheckForm(u *model.User, t *model.Address
|
|||||||
} else {
|
} else {
|
||||||
return "ParamsError", false
|
return "ParamsError", false
|
||||||
}
|
}
|
||||||
// 重复检查
|
// duplicate check
|
||||||
ex := service.AllService.AddressBookService.RulePersonalInfoByToIdAndCid(t.ToId, t.CollectionId)
|
ex := service.AllService.AddressBookService.RuleInfoByToIdAndCid(t.Type, t.ToId, t.CollectionId)
|
||||||
if t.Id == 0 && ex.Id > 0 {
|
if t.Id == 0 && ex.Id > 0 {
|
||||||
return "ItemExists", false
|
return "ItemExists", false
|
||||||
}
|
}
|
||||||
@@ -168,13 +145,13 @@ func (abcr *AddressBookCollectionRule) CheckForm(u *model.User, t *model.Address
|
|||||||
return "", true
|
return "", true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update 编辑
|
// Update edit
|
||||||
// @Tags 地址簿规则
|
// @Tags address book rules
|
||||||
// @Summary 地址簿规则编辑
|
// @Summary edit address book rule
|
||||||
// @Description 地址簿规则编辑
|
// @Description edit address book rule
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body model.AddressBookCollectionRule true "地址簿规则信息"
|
// @Param body body model.AddressBookCollectionRule true "address book rule info"
|
||||||
// @Success 200 {object} response.Response{data=model.AddressBookCollection}
|
// @Success 200 {object} response.Response{data=model.AddressBookCollection}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/address_book_collection_rule/update [post]
|
// @Router /admin/address_book_collection_rule/update [post]
|
||||||
@@ -194,9 +171,8 @@ func (abcr *AddressBookCollectionRule) Update(c *gin.Context) {
|
|||||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
t := f //f.ToAddressBookCollection()
|
t := f
|
||||||
u := service.AllService.UserService.CurUser(c)
|
msg, res := abcr.CheckForm(t)
|
||||||
msg, res := abcr.CheckForm(u, t)
|
|
||||||
if !res {
|
if !res {
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, msg))
|
response.Fail(c, 101, response.TranslateMsg(c, msg))
|
||||||
return
|
return
|
||||||
@@ -209,13 +185,13 @@ func (abcr *AddressBookCollectionRule) Update(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete 删除
|
// Delete delete
|
||||||
// @Tags 地址簿规则
|
// @Tags address book rules
|
||||||
// @Summary 地址簿规则删除
|
// @Summary delete address book rule
|
||||||
// @Description 地址簿规则删除
|
// @Description delete address book rule
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body model.AddressBookCollectionRule true "地址簿规则信息"
|
// @Param body body model.AddressBookCollectionRule true "address book rule info"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/address_book_collection_rule/delete [post]
|
// @Router /admin/address_book_collection_rule/delete [post]
|
||||||
@@ -232,20 +208,15 @@ func (abcr *AddressBookCollectionRule) Delete(c *gin.Context) {
|
|||||||
response.Fail(c, 101, errList[0])
|
response.Fail(c, 101, errList[0])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
t := service.AllService.AddressBookService.RuleInfoById(f.Id)
|
ex := service.AllService.AddressBookService.RuleInfoById(f.Id)
|
||||||
u := service.AllService.UserService.CurUser(c)
|
if ex.Id == 0 {
|
||||||
if !service.AllService.UserService.IsAdmin(u) && t.UserId != u.Id {
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "NoAccess"))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if t.Id > 0 {
|
err := service.AllService.AddressBookService.DeleteRule(ex)
|
||||||
err := service.AllService.AddressBookService.DeleteRule(t)
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
response.Fail(c, 101, err.Error())
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
return
|
|
||||||
}
|
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,28 +1,28 @@
|
|||||||
package admin
|
package admin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"Gwen/global"
|
|
||||||
"Gwen/http/request/admin"
|
|
||||||
"Gwen/http/response"
|
|
||||||
"Gwen/model"
|
|
||||||
"Gwen/service"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Audit struct {
|
type Audit struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConnList 列表
|
// ConnList list
|
||||||
// @Tags 链接日志
|
// @Tags connection log
|
||||||
// @Summary 链接日志列表
|
// @Summary connection log list
|
||||||
// @Description 链接日志列表
|
// @Description connection log list
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param page query int false "页码"
|
// @Param page query int false "page number"
|
||||||
// @Param page_size query int false "页大小"
|
// @Param page_size query int false "page size"
|
||||||
// @Param peer_id query int false "目标设备"
|
// @Param peer_id query int false "target device"
|
||||||
// @Param from_peer query int false "来源设备"
|
// @Param from_peer query int false "source device"
|
||||||
// @Success 200 {object} response.Response{data=model.AuditConnList}
|
// @Success 200 {object} response.Response{data=model.AuditConnList}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/audit_conn/list [get]
|
// @Router /admin/audit_conn/list [get]
|
||||||
@@ -45,13 +45,13 @@ func (a *Audit) ConnList(c *gin.Context) {
|
|||||||
response.Success(c, res)
|
response.Success(c, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConnDelete 删除
|
// ConnDelete delete
|
||||||
// @Tags 链接日志
|
// @Tags connection log
|
||||||
// @Summary 链接日志删除
|
// @Summary delete connection log
|
||||||
// @Description 链接日志删除
|
// @Description delete connection log
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body model.AuditConn true "链接日志信息"
|
// @Param body body model.AuditConn true "connection log info"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/audit_conn/delete [post]
|
// @Router /admin/audit_conn/delete [post]
|
||||||
@@ -81,13 +81,13 @@ func (a *Audit) ConnDelete(c *gin.Context) {
|
|||||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// BatchConnDelete 删除
|
// BatchConnDelete delete
|
||||||
// @Tags 链接日志
|
// @Tags connection log
|
||||||
// @Summary 链接日志批量删除
|
// @Summary batch delete connection logs
|
||||||
// @Description 链接日志批量删除
|
// @Description batch delete connection logs
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.AuditConnLogIds true "链接日志"
|
// @Param body body admin.AuditConnLogIds true "connection log"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/audit_conn/batchDelete [post]
|
// @Router /admin/audit_conn/batchDelete [post]
|
||||||
@@ -112,16 +112,16 @@ func (a *Audit) BatchConnDelete(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// FileList 列表
|
// FileList list
|
||||||
// @Tags 文件日志
|
// @Tags file log
|
||||||
// @Summary 文件日志列表
|
// @Summary file log list
|
||||||
// @Description 文件日志列表
|
// @Description file log list
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param page query int false "页码"
|
// @Param page query int false "page number"
|
||||||
// @Param page_size query int false "页大小"
|
// @Param page_size query int false "page size"
|
||||||
// @Param peer_id query int false "目标设备"
|
// @Param peer_id query int false "target device"
|
||||||
// @Param from_peer query int false "来源设备"
|
// @Param from_peer query int false "source device"
|
||||||
// @Success 200 {object} response.Response{data=model.AuditFileList}
|
// @Success 200 {object} response.Response{data=model.AuditFileList}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/audit_file/list [get]
|
// @Router /admin/audit_file/list [get]
|
||||||
@@ -144,13 +144,13 @@ func (a *Audit) FileList(c *gin.Context) {
|
|||||||
response.Success(c, res)
|
response.Success(c, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FileDelete 删除
|
// FileDelete delete
|
||||||
// @Tags 文件日志
|
// @Tags file log
|
||||||
// @Summary 文件日志删除
|
// @Summary delete file log
|
||||||
// @Description 文件日志删除
|
// @Description delete file log
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body model.AuditFile true "文件日志信息"
|
// @Param body body model.AuditFile true "file log info"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/audit_file/delete [post]
|
// @Router /admin/audit_file/delete [post]
|
||||||
@@ -180,13 +180,13 @@ func (a *Audit) FileDelete(c *gin.Context) {
|
|||||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// BatchFileDelete 删除
|
// BatchFileDelete delete
|
||||||
// @Tags 文件日志
|
// @Tags file log
|
||||||
// @Summary 文件日志批量删除
|
// @Summary batch delete file logs
|
||||||
// @Description 文件日志批量删除
|
// @Description batch delete file logs
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.AuditFileLogIds true "文件日志"
|
// @Param body body admin.AuditFileLogIds true "file log"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/audit_file/batchDelete [post]
|
// @Router /admin/audit_file/batchDelete [post]
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
package admin
|
package admin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"Gwen/global"
|
|
||||||
"Gwen/http/response"
|
|
||||||
"Gwen/service"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@@ -12,10 +13,10 @@ import (
|
|||||||
type Config struct {
|
type Config struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServerConfig RUSTDESK服务配置
|
// ServerConfig RUSTDESKservice config
|
||||||
// @Tags ADMIN
|
// @Tags ADMIN
|
||||||
// @Summary RUSTDESK服务配置
|
// @Summary RUSTDESKservice config
|
||||||
// @Description 服务配置,给webclient提供api-server
|
// @Description service config, provides an api-server for the webclient
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
@@ -32,10 +33,10 @@ func (co *Config) ServerConfig(c *gin.Context) {
|
|||||||
response.Success(c, cf)
|
response.Success(c, cf)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AppConfig APP服务配置
|
// AppConfig APPservice config
|
||||||
// @Tags ADMIN
|
// @Tags ADMIN
|
||||||
// @Summary APP服务配置
|
// @Summary APPservice config
|
||||||
// @Description APP服务配置
|
// @Description APPservice config
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
@@ -48,10 +49,10 @@ func (co *Config) AppConfig(c *gin.Context) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// AdminConfig ADMIN服务配置
|
// AdminConfig ADMINservice config
|
||||||
// @Tags ADMIN
|
// @Tags ADMIN
|
||||||
// @Summary ADMIN服务配置
|
// @Summary ADMINservice config
|
||||||
// @Description ADMIN服务配置
|
// @Description ADMINservice config
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
@@ -60,8 +61,24 @@ func (co *Config) AppConfig(c *gin.Context) {
|
|||||||
// @Security token
|
// @Security token
|
||||||
func (co *Config) AdminConfig(c *gin.Context) {
|
func (co *Config) AdminConfig(c *gin.Context) {
|
||||||
|
|
||||||
u := service.AllService.UserService.CurUser(c)
|
u := &model.User{}
|
||||||
|
token := c.GetHeader("api-token")
|
||||||
|
if token != "" {
|
||||||
|
u, _ = service.AllService.UserService.InfoByAccessToken(token)
|
||||||
|
if !service.AllService.UserService.CheckUserEnable(u) {
|
||||||
|
u.Id = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if u.Id == 0 {
|
||||||
|
response.Success(c, &gin.H{
|
||||||
|
"title": global.Config.Admin.Title,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
hello := global.Config.Admin.Hello
|
hello := global.Config.Admin.Hello
|
||||||
|
if hello == "" {
|
||||||
helloFile := global.Config.Admin.HelloFile
|
helloFile := global.Config.Admin.HelloFile
|
||||||
if helloFile != "" {
|
if helloFile != "" {
|
||||||
b, err := os.ReadFile(helloFile)
|
b, err := os.ReadFile(helloFile)
|
||||||
@@ -69,6 +86,7 @@ func (co *Config) AdminConfig(c *gin.Context) {
|
|||||||
hello = string(b)
|
hello = string(b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//replace {{username}} to username
|
//replace {{username}} to username
|
||||||
hello = strings.Replace(hello, "{{username}}", u.Username, -1)
|
hello = strings.Replace(hello, "{{username}}", u.Username, -1)
|
||||||
|
|||||||
@@ -0,0 +1,160 @@
|
|||||||
|
package admin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DeviceGroup struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detail device group
|
||||||
|
// @Tags device group
|
||||||
|
// @Summary device group details
|
||||||
|
// @Description device group details
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path int true "ID"
|
||||||
|
// @Success 200 {object} response.Response{data=model.Group}
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/device_group/detail/{id} [get]
|
||||||
|
// @Security token
|
||||||
|
func (ct *DeviceGroup) Detail(c *gin.Context) {
|
||||||
|
id := c.Param("id")
|
||||||
|
iid, _ := strconv.Atoi(id)
|
||||||
|
u := service.AllService.GroupService.DeviceGroupInfoById(uint(iid))
|
||||||
|
if u.Id > 0 {
|
||||||
|
response.Success(c, u)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create create device group
|
||||||
|
// @Tags device group
|
||||||
|
// @Summary create device group
|
||||||
|
// @Description create device group
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param body body admin.DeviceGroupForm true "device group info"
|
||||||
|
// @Success 200 {object} response.Response{data=model.DeviceGroup}
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/device_group/create [post]
|
||||||
|
// @Security token
|
||||||
|
func (ct *DeviceGroup) Create(c *gin.Context) {
|
||||||
|
f := &admin.DeviceGroupForm{}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
u := f.ToDeviceGroup()
|
||||||
|
err := service.AllService.GroupService.DeviceGroupCreate(u)
|
||||||
|
if err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Success(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// List list
|
||||||
|
// @Tags group
|
||||||
|
// @Summary group list
|
||||||
|
// @Description group list
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param page query int false "page number"
|
||||||
|
// @Param page_size query int false "page size"
|
||||||
|
// @Success 200 {object} response.Response{data=model.GroupList}
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/device_group/list [get]
|
||||||
|
// @Security token
|
||||||
|
func (ct *DeviceGroup) List(c *gin.Context) {
|
||||||
|
query := &admin.PageQuery{}
|
||||||
|
if err := c.ShouldBindQuery(query); err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res := service.AllService.GroupService.DeviceGroupList(query.Page, query.PageSize, nil)
|
||||||
|
response.Success(c, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update edit
|
||||||
|
// @Tags device group
|
||||||
|
// @Summary edit device group
|
||||||
|
// @Description edit device group
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param body body admin.DeviceGroupForm true "group info"
|
||||||
|
// @Success 200 {object} response.Response{data=model.Group}
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/device_group/update [post]
|
||||||
|
// @Security token
|
||||||
|
func (ct *DeviceGroup) Update(c *gin.Context) {
|
||||||
|
f := &admin.DeviceGroupForm{}
|
||||||
|
if err := c.ShouldBindJSON(f); err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if f.Id == 0 {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
errList := global.Validator.ValidStruct(c, f)
|
||||||
|
if len(errList) > 0 {
|
||||||
|
response.Fail(c, 101, errList[0])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
u := f.ToDeviceGroup()
|
||||||
|
err := service.AllService.GroupService.DeviceGroupUpdate(u)
|
||||||
|
if err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Success(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete delete
|
||||||
|
// @Tags device group
|
||||||
|
// @Summary delete device group
|
||||||
|
// @Description delete device group
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param body body admin.DeviceGroupForm true "group info"
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/device_group/delete [post]
|
||||||
|
// @Security token
|
||||||
|
func (ct *DeviceGroup) Delete(c *gin.Context) {
|
||||||
|
f := &admin.DeviceGroupForm{}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
u := service.AllService.GroupService.DeviceGroupInfoById(f.Id)
|
||||||
|
if u.Id > 0 {
|
||||||
|
err := service.AllService.GroupService.DeviceGroupDelete(u)
|
||||||
|
if err == nil {
|
||||||
|
response.Success(c, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
package admin
|
package admin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"Gwen/global"
|
|
||||||
"Gwen/http/response"
|
|
||||||
"Gwen/lib/upload"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/lib/upload"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -13,10 +13,10 @@ import (
|
|||||||
type File struct {
|
type File struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// OssToken 文件
|
// OssToken file
|
||||||
// @Tags 文件
|
// @Tags file
|
||||||
// @Summary 获取ossToken
|
// @Summary getossToken
|
||||||
// @Description 获取ossToken
|
// @Description getossToken
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
@@ -33,12 +33,12 @@ type FileBack struct {
|
|||||||
Url string `json:"url"`
|
Url string `json:"url"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify 上传成功后回调
|
// Notify callback after successful upload
|
||||||
func (f *File) Notify(c *gin.Context) {
|
func (f *File) Notify(c *gin.Context) {
|
||||||
|
|
||||||
res := global.Oss.Verify(c.Request)
|
res := global.Oss.Verify(c.Request)
|
||||||
if !res {
|
if !res {
|
||||||
response.Fail(c, 101, "权限错误")
|
response.Fail(c, 101, response.TranslateMsg(c, "NoAccess"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fm := &FileBack{}
|
fm := &FileBack{}
|
||||||
@@ -50,13 +50,13 @@ func (f *File) Notify(c *gin.Context) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Upload 上传文件到本地
|
// Upload upload file to local
|
||||||
// @Tags 文件
|
// @Tags file
|
||||||
// @Summary 上传文件到本地
|
// @Summary upload file to local
|
||||||
// @Description 上传文件到本地
|
// @Description upload file to local
|
||||||
// @Accept multipart/form-data
|
// @Accept multipart/form-data
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param file formData file true "上传文件示例"
|
// @Param file formData file true "file upload example"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/file/upload [post]
|
// @Router /admin/file/upload [post]
|
||||||
@@ -71,12 +71,12 @@ func (f *File) Upload(c *gin.Context) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 上传文件至指定目录
|
// upload the file to the specified directory
|
||||||
err = c.SaveUploadedFile(file, dst)
|
err = c.SaveUploadedFile(file, dst)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 返回文件web地址
|
// return filewebaddress
|
||||||
response.Success(c, gin.H{
|
response.Success(c, gin.H{
|
||||||
"url": webPath + file.Filename,
|
"url": webPath + file.Filename,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
package admin
|
package admin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"Gwen/global"
|
|
||||||
"Gwen/http/request/admin"
|
|
||||||
"Gwen/http/response"
|
|
||||||
"Gwen/service"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Group struct {
|
type Group struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detail 群组
|
// Detail group
|
||||||
// @Tags 群组
|
// @Tags group
|
||||||
// @Summary 群组详情
|
// @Summary group details
|
||||||
// @Description 群组详情
|
// @Description group details
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param id path int true "ID"
|
// @Param id path int true "ID"
|
||||||
@@ -35,13 +35,13 @@ func (ct *Group) Detail(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create 创建群组
|
// Create create group
|
||||||
// @Tags 群组
|
// @Tags group
|
||||||
// @Summary 创建群组
|
// @Summary create group
|
||||||
// @Description 创建群组
|
// @Description create group
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.GroupForm true "群组信息"
|
// @Param body body admin.GroupForm true "group info"
|
||||||
// @Success 200 {object} response.Response{data=model.Group}
|
// @Success 200 {object} response.Response{data=model.Group}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/group/create [post]
|
// @Router /admin/group/create [post]
|
||||||
@@ -66,14 +66,14 @@ func (ct *Group) Create(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// List 列表
|
// List list
|
||||||
// @Tags 群组
|
// @Tags group
|
||||||
// @Summary 群组列表
|
// @Summary group list
|
||||||
// @Description 群组列表
|
// @Description group list
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param page query int false "页码"
|
// @Param page query int false "page number"
|
||||||
// @Param page_size query int false "页大小"
|
// @Param page_size query int false "page size"
|
||||||
// @Success 200 {object} response.Response{data=model.GroupList}
|
// @Success 200 {object} response.Response{data=model.GroupList}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/group/list [get]
|
// @Router /admin/group/list [get]
|
||||||
@@ -88,13 +88,13 @@ func (ct *Group) List(c *gin.Context) {
|
|||||||
response.Success(c, res)
|
response.Success(c, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update 编辑
|
// Update edit
|
||||||
// @Tags 群组
|
// @Tags group
|
||||||
// @Summary 群组编辑
|
// @Summary edit group
|
||||||
// @Description 群组编辑
|
// @Description edit group
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.GroupForm true "群组信息"
|
// @Param body body admin.GroupForm true "group info"
|
||||||
// @Success 200 {object} response.Response{data=model.Group}
|
// @Success 200 {object} response.Response{data=model.Group}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/group/update [post]
|
// @Router /admin/group/update [post]
|
||||||
@@ -123,13 +123,13 @@ func (ct *Group) Update(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete 删除
|
// Delete delete
|
||||||
// @Tags 群组
|
// @Tags group
|
||||||
// @Summary 群组删除
|
// @Summary delete group
|
||||||
// @Description 群组删除
|
// @Description delete group
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.GroupForm true "群组信息"
|
// @Param body body admin.GroupForm true "group info"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/group/delete [post]
|
// @Router /admin/group/delete [post]
|
||||||
|
|||||||
@@ -1,52 +1,88 @@
|
|||||||
package admin
|
package admin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"Gwen/global"
|
|
||||||
"Gwen/http/controller/api"
|
|
||||||
"Gwen/http/request/admin"
|
|
||||||
apiReq "Gwen/http/request/api"
|
|
||||||
"Gwen/http/response"
|
|
||||||
adResp "Gwen/http/response/admin"
|
|
||||||
"Gwen/model"
|
|
||||||
"Gwen/service"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/controller/api"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||||
|
apiReq "github.com/lejianwen/rustdesk-api/v2/http/request/api"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||||
|
adResp "github.com/lejianwen/rustdesk-api/v2/http/response/admin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Login struct {
|
type Login struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Login 登录
|
// Login login
|
||||||
// @Tags 登录
|
// @Tags login
|
||||||
// @Summary 登录
|
// @Summary login
|
||||||
// @Description 登录
|
// @Description login
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.Login true "登录信息"
|
// @Param body body admin.Login true "login info"
|
||||||
// @Success 200 {object} response.Response{data=adResp.LoginPayload}
|
// @Success 200 {object} response.Response{data=adResp.LoginPayload}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/login [post]
|
// @Router /admin/login [post]
|
||||||
// @Security token
|
// @Security token
|
||||||
func (ct *Login) Login(c *gin.Context) {
|
func (ct *Login) Login(c *gin.Context) {
|
||||||
|
if global.Config.App.DisablePwdLogin {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "PwdLoginDisabled"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// check login limit
|
||||||
|
loginLimiter := global.LoginLimiter
|
||||||
|
clientIp := c.ClientIP()
|
||||||
|
_, needCaptcha := loginLimiter.CheckSecurityStatus(clientIp)
|
||||||
|
|
||||||
f := &admin.Login{}
|
f := &admin.Login{}
|
||||||
err := c.ShouldBindJSON(f)
|
err := c.ShouldBindJSON(f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "ParamsError", c.RemoteIP(), c.ClientIP()))
|
loginLimiter.RecordFailedAttempt(clientIp)
|
||||||
|
global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "ParamsError", c.RemoteIP(), clientIp))
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
errList := global.Validator.ValidStruct(c, f)
|
errList := global.Validator.ValidStruct(c, f)
|
||||||
if len(errList) > 0 {
|
if len(errList) > 0 {
|
||||||
global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "ParamsError", c.RemoteIP(), c.ClientIP()))
|
loginLimiter.RecordFailedAttempt(clientIp)
|
||||||
|
global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "ParamsError", c.RemoteIP(), clientIp))
|
||||||
response.Fail(c, 101, errList[0])
|
response.Fail(c, 101, errList[0])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check whether a captcha is required
|
||||||
|
if needCaptcha {
|
||||||
|
if f.CaptchaId == "" || f.Captcha == "" || !loginLimiter.VerifyCaptcha(f.CaptchaId, f.Captcha) {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "CaptchaError"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
u := service.AllService.UserService.InfoByUsernamePassword(f.Username, f.Password)
|
u := service.AllService.UserService.InfoByUsernamePassword(f.Username, f.Password)
|
||||||
|
|
||||||
if u.Id == 0 {
|
if u.Id == 0 {
|
||||||
global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "UsernameOrPasswordError", c.RemoteIP(), c.ClientIP()))
|
global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "UsernameOrPasswordError", c.RemoteIP(), clientIp))
|
||||||
|
loginLimiter.RecordFailedAttempt(clientIp)
|
||||||
|
if _, needCaptcha = loginLimiter.CheckSecurityStatus(clientIp); needCaptcha {
|
||||||
|
response.Fail(c, 110, response.TranslateMsg(c, "UsernameOrPasswordError"))
|
||||||
|
} else {
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "UsernameOrPasswordError"))
|
response.Fail(c, 101, response.TranslateMsg(c, "UsernameOrPasswordError"))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !service.AllService.UserService.CheckUserEnable(u) {
|
||||||
|
if needCaptcha {
|
||||||
|
response.Fail(c, 110, response.TranslateMsg(c, "UserDisabled"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "UserDisabled"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,18 +90,49 @@ func (ct *Login) Login(c *gin.Context) {
|
|||||||
UserId: u.Id,
|
UserId: u.Id,
|
||||||
Client: model.LoginLogClientWebAdmin,
|
Client: model.LoginLogClientWebAdmin,
|
||||||
Uuid: "", //must be empty
|
Uuid: "", //must be empty
|
||||||
Ip: c.ClientIP(),
|
Ip: clientIp,
|
||||||
Type: model.LoginLogTypeAccount,
|
Type: model.LoginLogTypeAccount,
|
||||||
Platform: f.Platform,
|
Platform: f.Platform,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// login successful, clear the login limit
|
||||||
|
loginLimiter.RemoveAttempts(clientIp)
|
||||||
responseLoginSuccess(c, u, ut.Token)
|
responseLoginSuccess(c, u, ut.Token)
|
||||||
}
|
}
|
||||||
|
func (ct *Login) Captcha(c *gin.Context) {
|
||||||
|
loginLimiter := global.LoginLimiter
|
||||||
|
clientIp := c.ClientIP()
|
||||||
|
banned, needCaptcha := loginLimiter.CheckSecurityStatus(clientIp)
|
||||||
|
if banned {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "LoginBanned"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !needCaptcha {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "NoCaptchaRequired"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err, captcha := loginLimiter.RequireCaptcha()
|
||||||
|
if err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "CaptchaError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err, b64 := loginLimiter.DrawCaptcha(captcha.Content)
|
||||||
|
if err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "CaptchaError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Success(c, gin.H{
|
||||||
|
"captcha": gin.H{
|
||||||
|
"id": captcha.Id,
|
||||||
|
"b64": b64,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Logout 登出
|
// Logout logout
|
||||||
// @Tags 登录
|
// @Tags login
|
||||||
// @Summary 登出
|
// @Summary logout
|
||||||
// @Description 登出
|
// @Description logout
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
@@ -81,19 +148,29 @@ func (ct *Login) Logout(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// LoginOptions
|
// LoginOptions
|
||||||
// @Tags 登录
|
// @Tags login
|
||||||
// @Summary 登录选项
|
// @Summary login options
|
||||||
// @Description 登录选项
|
// @Description login options
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} []string
|
// @Success 200 {object} []string
|
||||||
// @Failure 500 {object} response.ErrorResponse
|
// @Failure 500 {object} response.ErrorResponse
|
||||||
// @Router /admin/login-options [post]
|
// @Router /admin/login-options [post]
|
||||||
func (ct *Login) LoginOptions(c *gin.Context) {
|
func (ct *Login) LoginOptions(c *gin.Context) {
|
||||||
|
loginLimiter := global.LoginLimiter
|
||||||
|
clientIp := c.ClientIP()
|
||||||
|
banned, needCaptcha := loginLimiter.CheckSecurityStatus(clientIp)
|
||||||
|
if banned {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "LoginBanned"))
|
||||||
|
return
|
||||||
|
}
|
||||||
ops := service.AllService.OauthService.GetOauthProviders()
|
ops := service.AllService.OauthService.GetOauthProviders()
|
||||||
response.Success(c, gin.H{
|
response.Success(c, gin.H{
|
||||||
"ops": ops,
|
"ops": ops,
|
||||||
"register": global.Config.App.Register,
|
"register": global.Config.App.Register,
|
||||||
|
"need_captcha": needCaptcha,
|
||||||
|
"disable_pwd": global.Config.App.DisablePwdLogin,
|
||||||
|
"auto_oidc": global.Config.App.DisablePwdLogin && len(ops) == 1,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,13 +191,13 @@ func (ct *Login) OidcAuth(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err, code, url := service.AllService.OauthService.BeginAuth(f.Op)
|
err, state, verifier, nonce, url := service.AllService.OauthService.BeginAuth(f.Op)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.Error(c, response.TranslateMsg(c, err.Error()))
|
response.Error(c, response.TranslateMsg(c, err.Error()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
service.AllService.OauthService.SetOauthCache(code, &service.OauthCacheItem{
|
service.AllService.OauthService.SetOauthCache(state, &service.OauthCacheItem{
|
||||||
Action: service.OauthActionTypeLogin,
|
Action: service.OauthActionTypeLogin,
|
||||||
Op: f.Op,
|
Op: f.Op,
|
||||||
Id: f.Id,
|
Id: f.Id,
|
||||||
@@ -128,10 +205,12 @@ func (ct *Login) OidcAuth(c *gin.Context) {
|
|||||||
// DeviceOs: ct.Platform(c),
|
// DeviceOs: ct.Platform(c),
|
||||||
DeviceOs: f.DeviceInfo.Os,
|
DeviceOs: f.DeviceInfo.Os,
|
||||||
Uuid: f.Uuid,
|
Uuid: f.Uuid,
|
||||||
|
Verifier: verifier,
|
||||||
|
Nonce: nonce,
|
||||||
}, 5*60)
|
}, 5*60)
|
||||||
|
|
||||||
response.Success(c, gin.H{
|
response.Success(c, gin.H{
|
||||||
"code": code,
|
"code": state,
|
||||||
"url": url,
|
"url": url,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -154,7 +233,6 @@ func (ct *Login) OidcAuthQuery(c *gin.Context) {
|
|||||||
responseLoginSuccess(c, u, ut.Token)
|
responseLoginSuccess(c, u, ut.Token)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func responseLoginSuccess(c *gin.Context, u *model.User, token string) {
|
func responseLoginSuccess(c *gin.Context, u *model.User, token string) {
|
||||||
lp := &adResp.LoginPayload{}
|
lp := &adResp.LoginPayload{}
|
||||||
lp.FromUser(u)
|
lp.FromUser(u)
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
package admin
|
package admin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"Gwen/global"
|
|
||||||
"Gwen/http/request/admin"
|
|
||||||
"Gwen/http/response"
|
|
||||||
"Gwen/model"
|
|
||||||
"Gwen/service"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
@@ -14,10 +14,10 @@ import (
|
|||||||
type LoginLog struct {
|
type LoginLog struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detail 登录日志
|
// Detail login log
|
||||||
// @Tags 登录日志
|
// @Tags login log
|
||||||
// @Summary 登录日志详情
|
// @Summary login log details
|
||||||
// @Description 登录日志详情
|
// @Description login log details
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param id path int true "ID"
|
// @Param id path int true "ID"
|
||||||
@@ -37,15 +37,15 @@ func (ct *LoginLog) Detail(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// List 列表
|
// List list
|
||||||
// @Tags 登录日志
|
// @Tags login log
|
||||||
// @Summary 登录日志列表
|
// @Summary login log list
|
||||||
// @Description 登录日志列表
|
// @Description login log list
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param page query int false "页码"
|
// @Param page query int false "page number"
|
||||||
// @Param page_size query int false "页大小"
|
// @Param page_size query int false "page size"
|
||||||
// @Param user_id query int false "用户ID"
|
// @Param user_id query int false "userID"
|
||||||
// @Success 200 {object} response.Response{data=model.LoginLogList}
|
// @Success 200 {object} response.Response{data=model.LoginLogList}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/login_log/list [get]
|
// @Router /admin/login_log/list [get]
|
||||||
@@ -56,10 +56,6 @@ func (ct *LoginLog) List(c *gin.Context) {
|
|||||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
u := service.AllService.UserService.CurUser(c)
|
|
||||||
if !service.AllService.UserService.IsAdmin(u) || query.IsMy == 1 {
|
|
||||||
query.UserId = int(u.Id)
|
|
||||||
}
|
|
||||||
res := service.AllService.LoginLogService.List(query.Page, query.PageSize, func(tx *gorm.DB) {
|
res := service.AllService.LoginLogService.List(query.Page, query.PageSize, func(tx *gorm.DB) {
|
||||||
if query.UserId > 0 {
|
if query.UserId > 0 {
|
||||||
tx.Where("user_id = ?", query.UserId)
|
tx.Where("user_id = ?", query.UserId)
|
||||||
@@ -69,13 +65,13 @@ func (ct *LoginLog) List(c *gin.Context) {
|
|||||||
response.Success(c, res)
|
response.Success(c, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete 删除
|
// Delete delete
|
||||||
// @Tags 登录日志
|
// @Tags login log
|
||||||
// @Summary 登录日志删除
|
// @Summary delete login log
|
||||||
// @Description 登录日志删除
|
// @Description delete login log
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body model.LoginLog true "登录日志信息"
|
// @Param body body model.LoginLog true "login log info"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/login_log/delete [post]
|
// @Router /admin/login_log/delete [post]
|
||||||
@@ -93,33 +89,28 @@ func (ct *LoginLog) Delete(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
l := service.AllService.LoginLogService.InfoById(f.Id)
|
l := service.AllService.LoginLogService.InfoById(f.Id)
|
||||||
u := service.AllService.UserService.CurUser(c)
|
if l.Id == 0 {
|
||||||
if !service.AllService.UserService.IsAdmin(u) && l.UserId != u.Id {
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "NoAccess"))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if l.Id > 0 {
|
|
||||||
err := service.AllService.LoginLogService.Delete(l)
|
err := service.AllService.LoginLogService.Delete(l)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
response.Fail(c, 101, err.Error())
|
response.Fail(c, 101, err.Error())
|
||||||
return
|
|
||||||
}
|
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// BatchDelete 删除
|
// BatchDelete delete
|
||||||
// @Tags 登录日志
|
// @Tags login log
|
||||||
// @Summary 登录日志批量删除
|
// @Summary batch delete login logs
|
||||||
// @Description 登录日志批量删除
|
// @Description batch delete login logs
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.LoginLogIds true "登录日志"
|
// @Param body body admin.LoginLogIds true "login log"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/login_log/delete [post]
|
// @Router /admin/login_log/batchDelete [post]
|
||||||
// @Security token
|
// @Security token
|
||||||
func (ct *LoginLog) BatchDelete(c *gin.Context) {
|
func (ct *LoginLog) BatchDelete(c *gin.Context) {
|
||||||
f := &admin.LoginLogIds{}
|
f := &admin.LoginLogIds{}
|
||||||
|
|||||||
@@ -0,0 +1,271 @@
|
|||||||
|
package my
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AddressBook struct{}
|
||||||
|
|
||||||
|
// List list
|
||||||
|
// @Tags my address book
|
||||||
|
// @Summary address book list
|
||||||
|
// @Description address book list
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param page query int false "page number"
|
||||||
|
// @Param page_size query int false "page size"
|
||||||
|
// @Param user_id query int false "userid"
|
||||||
|
// @Success 200 {object} response.Response{data=model.AddressBookList}
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/my/address_book/list [get]
|
||||||
|
// @Security token
|
||||||
|
func (ct *AddressBook) List(c *gin.Context) {
|
||||||
|
query := &admin.AddressBookQuery{}
|
||||||
|
if err := c.ShouldBindQuery(query); err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
query.UserId = int(u.Id)
|
||||||
|
res := service.AllService.AddressBookService.List(query.Page, query.PageSize, func(tx *gorm.DB) {
|
||||||
|
//preload address book name
|
||||||
|
tx.Preload("Collection", func(txc *gorm.DB) *gorm.DB {
|
||||||
|
return txc.Select("id,name")
|
||||||
|
})
|
||||||
|
if query.Id != "" {
|
||||||
|
tx.Where("id like ?", "%"+query.Id+"%")
|
||||||
|
}
|
||||||
|
tx.Where("user_id = ?", query.UserId)
|
||||||
|
if query.Username != "" {
|
||||||
|
tx.Where("username like ?", "%"+query.Username+"%")
|
||||||
|
}
|
||||||
|
if 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)
|
||||||
|
}
|
||||||
|
response.Success(c, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create create address book
|
||||||
|
// @Tags my address book
|
||||||
|
// @Summary create address book
|
||||||
|
// @Description create address book
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param body body admin.AddressBookForm true "address book info"
|
||||||
|
// @Success 200 {object} response.Response{data=model.AddressBook}
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/my/address_book/create [post]
|
||||||
|
// @Security token
|
||||||
|
func (ct *AddressBook) Create(c *gin.Context) {
|
||||||
|
f := &admin.AddressBookForm{}
|
||||||
|
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.ToAddressBook()
|
||||||
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
t.UserId = u.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 {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemExists"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := service.AllService.AddressBookService.Create(t)
|
||||||
|
if err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Success(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update edit
|
||||||
|
// @Tags my address book
|
||||||
|
// @Summary edit address book
|
||||||
|
// @Description edit address book
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param body body admin.AddressBookForm true "address book info"
|
||||||
|
// @Success 200 {object} response.Response{data=model.AddressBook}
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/my/address_book/update [post]
|
||||||
|
// @Security token
|
||||||
|
func (ct *AddressBook) Update(c *gin.Context) {
|
||||||
|
f := &admin.AddressBookForm{}
|
||||||
|
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.RowId == 0 {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
if f.UserId != u.Id {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "NoAccess"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ex := service.AllService.AddressBookService.InfoByRowId(f.RowId)
|
||||||
|
if ex.RowId == 0 {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ex.UserId != u.Id {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "NoAccess"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t := f.ToAddressBook()
|
||||||
|
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.UpdateAll(t)
|
||||||
|
if err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Success(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete delete
|
||||||
|
// @Tags my address book
|
||||||
|
// @Summary delete address book
|
||||||
|
// @Description delete address book
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param body body admin.AddressBookForm true "address book info"
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/my/address_book/delete [post]
|
||||||
|
// @Security token
|
||||||
|
func (ct *AddressBook) Delete(c *gin.Context) {
|
||||||
|
f := &admin.AddressBookForm{}
|
||||||
|
if err := c.ShouldBindJSON(f); err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
id := f.RowId
|
||||||
|
errList := global.Validator.ValidVar(c, id, "required,gt=0")
|
||||||
|
if len(errList) > 0 {
|
||||||
|
response.Fail(c, 101, errList[0])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ex := service.AllService.AddressBookService.InfoByRowId(f.RowId)
|
||||||
|
if ex.RowId == 0 {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
if ex.UserId != u.Id {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "NoAccess"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := service.AllService.AddressBookService.Delete(ex)
|
||||||
|
if err == nil {
|
||||||
|
response.Success(c, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (ct *AddressBook) BatchCreateFromPeers(c *gin.Context) {
|
||||||
|
f := &admin.BatchCreateFromPeersForm{}
|
||||||
|
if err := c.ShouldBindJSON(f); err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
|
||||||
|
if f.CollectionId != 0 {
|
||||||
|
collection := service.AllService.AddressBookService.CollectionInfoById(f.CollectionId)
|
||||||
|
if collection.Id == 0 {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if collection.UserId != u.Id {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "NoAccess"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(f.PeerIds) == 0 {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
pl := int64(len(f.PeerIds))
|
||||||
|
peers := service.AllService.PeerService.List(1, uint(pl), func(tx *gorm.DB) {
|
||||||
|
tx.Where("row_id in ?", f.PeerIds)
|
||||||
|
tx.Where("user_id = ?", u.Id)
|
||||||
|
})
|
||||||
|
if peers.Total == 0 || pl != peers.Total {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tags, _ := json.Marshal(f.Tags)
|
||||||
|
for _, peer := range peers.Peers {
|
||||||
|
ab := service.AllService.AddressBookService.FromPeer(peer)
|
||||||
|
ab.Tags = tags
|
||||||
|
ab.CollectionId = f.CollectionId
|
||||||
|
ex := service.AllService.AddressBookService.InfoByUserIdAndIdAndCid(u.Id, ab.Id, ab.CollectionId)
|
||||||
|
if ex.RowId != 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
service.AllService.AddressBookService.Create(ab)
|
||||||
|
}
|
||||||
|
response.Success(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ct *AddressBook) BatchUpdateTags(c *gin.Context) {
|
||||||
|
f := &admin.BatchUpdateTagsForm{}
|
||||||
|
if err := c.ShouldBindJSON(f); err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
|
||||||
|
abs := service.AllService.AddressBookService.List(1, 999, func(tx *gorm.DB) {
|
||||||
|
tx.Where("row_id in ?", f.RowIds)
|
||||||
|
tx.Where("user_id = ?", u.Id)
|
||||||
|
})
|
||||||
|
if abs.Total == 0 {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := service.AllService.AddressBookService.BatchUpdateTags(abs.AddressBooks, f.Tags)
|
||||||
|
if err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Success(c, nil)
|
||||||
|
}
|
||||||
@@ -0,0 +1,162 @@
|
|||||||
|
package my
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AddressBookCollection struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create create address book name
|
||||||
|
// @Tags my address book name
|
||||||
|
// @Summary create address book name
|
||||||
|
// @Description create address book name
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param body body model.AddressBookCollection true "address book name info"
|
||||||
|
// @Success 200 {object} response.Response{data=model.AddressBookCollection}
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/my/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
|
||||||
|
}
|
||||||
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
f.UserId = u.Id
|
||||||
|
err := service.AllService.AddressBookService.CreateCollection(f)
|
||||||
|
if err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Success(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// List list
|
||||||
|
// @Tags my address book name
|
||||||
|
// @Summary address book name list
|
||||||
|
// @Description address book name list
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param page query int false "page number"
|
||||||
|
// @Param page_size query int false "page size"
|
||||||
|
// @Success 200 {object} response.Response{data=model.AddressBookCollectionList}
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/my/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)
|
||||||
|
query.UserId = int(u.Id)
|
||||||
|
res := service.AllService.AddressBookService.ListCollection(query.Page, query.PageSize, func(tx *gorm.DB) {
|
||||||
|
tx.Where("user_id = ?", query.UserId)
|
||||||
|
})
|
||||||
|
response.Success(c, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update edit
|
||||||
|
// @Tags my address book name
|
||||||
|
// @Summary edit address book name
|
||||||
|
// @Description edit address book name
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param body body model.AddressBookCollection true "address book name info"
|
||||||
|
// @Success 200 {object} response.Response{data=model.AddressBookCollection}
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/my/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
|
||||||
|
}
|
||||||
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
//if f.UserId != u.Id {
|
||||||
|
// response.Fail(c, 101, response.TranslateMsg(c, "NoAccess"))
|
||||||
|
// return
|
||||||
|
//}
|
||||||
|
ex := service.AllService.AddressBookService.CollectionInfoById(f.Id)
|
||||||
|
if ex.Id == 0 {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ex.UserId != u.Id {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "NoAccess"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := service.AllService.AddressBookService.UpdateCollection(f)
|
||||||
|
if err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Success(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete delete
|
||||||
|
// @Tags my address book name
|
||||||
|
// @Summary delete address book name
|
||||||
|
// @Description delete address book name
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param body body model.AddressBookCollection true "address book name info"
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/my/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
|
||||||
|
}
|
||||||
|
ex := service.AllService.AddressBookService.CollectionInfoById(f.Id)
|
||||||
|
if ex.Id == 0 {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
if ex.UserId != u.Id {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "NoAccess"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := service.AllService.AddressBookService.DeleteCollection(ex)
|
||||||
|
if err == nil {
|
||||||
|
response.Success(c, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
|
}
|
||||||
@@ -0,0 +1,228 @@
|
|||||||
|
package my
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AddressBookCollectionRule struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// List list
|
||||||
|
// @Tags my address book rules
|
||||||
|
// @Summary address book rule list
|
||||||
|
// @Description address book rule list
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param page query int false "page number"
|
||||||
|
// @Param page_size query int false "page size"
|
||||||
|
// @Param is_my query int false "whether it is mine"
|
||||||
|
// @Param user_id query int false "userid"
|
||||||
|
// @Param collection_id query int false "address book collectionid"
|
||||||
|
// @Success 200 {object} response.Response{data=model.AddressBookCollectionList}
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/my/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)
|
||||||
|
query.UserId = int(u.Id)
|
||||||
|
|
||||||
|
res := service.AllService.AddressBookService.ListRules(query.Page, query.PageSize, func(tx *gorm.DB) {
|
||||||
|
tx.Where("user_id = ?", query.UserId)
|
||||||
|
if query.CollectionId > 0 {
|
||||||
|
tx.Where("collection_id = ?", query.CollectionId)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
response.Success(c, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create create address book rule
|
||||||
|
// @Tags my address book rules
|
||||||
|
// @Summary create address book rule
|
||||||
|
// @Description create address book rule
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param body body model.AddressBookCollectionRule true "address book rule info"
|
||||||
|
// @Success 200 {object} response.Response{data=model.AddressBookCollection}
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/my/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)
|
||||||
|
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 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 "CannotShareToSelf", false
|
||||||
|
}
|
||||||
|
tou := service.AllService.UserService.InfoById(t.ToId)
|
||||||
|
if tou.Id == 0 {
|
||||||
|
return "ItemNotFound", false
|
||||||
|
}
|
||||||
|
//non-admins cannot share with users outside their own organization
|
||||||
|
//if tou.GroupId != u.GroupId {
|
||||||
|
// return "NoAccess", false
|
||||||
|
//}
|
||||||
|
} else if t.Type == model.ShareAddressBookRuleTypeGroup {
|
||||||
|
//non-admins cannot share with other groups
|
||||||
|
//if t.ToId != u.GroupId {
|
||||||
|
// return "NoAccess", false
|
||||||
|
//}
|
||||||
|
|
||||||
|
tog := service.AllService.GroupService.InfoById(t.ToId)
|
||||||
|
if tog.Id == 0 {
|
||||||
|
return "ItemNotFound", false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return "ParamsError", false
|
||||||
|
}
|
||||||
|
// duplicate check
|
||||||
|
ex := service.AllService.AddressBookService.RuleInfoByToIdAndCid(t.Type, 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 edit
|
||||||
|
// @Tags my address book rules
|
||||||
|
// @Summary edit address book rule
|
||||||
|
// @Description edit address book rule
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param body body model.AddressBookCollectionRule true "address book rule info"
|
||||||
|
// @Success 200 {object} response.Response{data=model.AddressBookCollection}
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/my/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
|
||||||
|
}
|
||||||
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
|
||||||
|
ex := service.AllService.AddressBookService.RuleInfoById(f.Id)
|
||||||
|
if ex.Id == 0 {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ex.UserId != u.Id {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "NoAccess"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t := f
|
||||||
|
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 delete
|
||||||
|
// @Tags my address book rules
|
||||||
|
// @Summary delete address book rule
|
||||||
|
// @Description delete address book rule
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param body body model.AddressBookCollectionRule true "address book rule info"
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/my/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
|
||||||
|
}
|
||||||
|
ex := service.AllService.AddressBookService.RuleInfoById(f.Id)
|
||||||
|
if ex.Id == 0 {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
if ex.UserId != u.Id {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "NoAccess"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := service.AllService.AddressBookService.DeleteRule(ex)
|
||||||
|
if err == nil {
|
||||||
|
response.Success(c, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
|
}
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
package my
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LoginLog struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// List list
|
||||||
|
// @Tags my login logs
|
||||||
|
// @Summary login log list
|
||||||
|
// @Description login log list
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param page query int false "page number"
|
||||||
|
// @Param page_size query int false "page size"
|
||||||
|
// @Param user_id query int false "userID"
|
||||||
|
// @Success 200 {object} response.Response{data=model.LoginLogList}
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/my/login_log/list [get]
|
||||||
|
// @Security token
|
||||||
|
func (ct *LoginLog) List(c *gin.Context) {
|
||||||
|
query := &admin.LoginLogQuery{}
|
||||||
|
if err := c.ShouldBindQuery(query); err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
res := service.AllService.LoginLogService.List(query.Page, query.PageSize, func(tx *gorm.DB) {
|
||||||
|
tx.Where("user_id = ? and is_deleted = ?", u.Id, model.IsDeletedNo)
|
||||||
|
tx.Order("id desc")
|
||||||
|
})
|
||||||
|
response.Success(c, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete delete
|
||||||
|
// @Tags my login logs
|
||||||
|
// @Summary delete login log
|
||||||
|
// @Description delete login log
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param body body model.LoginLog true "login log info"
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/my/login_log/delete [post]
|
||||||
|
// @Security token
|
||||||
|
func (ct *LoginLog) Delete(c *gin.Context) {
|
||||||
|
f := &model.LoginLog{}
|
||||||
|
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.LoginLogService.InfoById(f.Id)
|
||||||
|
if l.Id == 0 || l.IsDeleted == model.IsDeletedYes {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
if l.UserId != u.Id {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := service.AllService.LoginLogService.SoftDelete(l)
|
||||||
|
if err == nil {
|
||||||
|
response.Success(c, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Fail(c, 101, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// BatchDelete delete
|
||||||
|
// @Tags my login logs
|
||||||
|
// @Summary batch delete login logs
|
||||||
|
// @Description batch delete login logs
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param body body admin.LoginLogIds true "login log"
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/my/login_log/batchDelete [post]
|
||||||
|
// @Security token
|
||||||
|
func (ct *LoginLog) BatchDelete(c *gin.Context) {
|
||||||
|
f := &admin.LoginLogIds{}
|
||||||
|
if err := c.ShouldBindJSON(f); err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(f.Ids) == 0 {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
err := service.AllService.LoginLogService.BatchSoftDelete(u.Id, f.Ids)
|
||||||
|
if err == nil {
|
||||||
|
response.Success(c, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Fail(c, 101, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package my
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Peer struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// List list
|
||||||
|
// @Tags my devices
|
||||||
|
// @Summary device list
|
||||||
|
// @Description device list
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param page query int false "page number"
|
||||||
|
// @Param page_size query int false "page size"
|
||||||
|
// @Param time_ago query int false "time"
|
||||||
|
// @Param id query string false "ID"
|
||||||
|
// @Param hostname query string false "hostname"
|
||||||
|
// @Param uuids query string false "uuids separated by commas"
|
||||||
|
// @Success 200 {object} response.Response{data=model.PeerList}
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/my/peer/list [get]
|
||||||
|
// @Security token
|
||||||
|
func (ct *Peer) List(c *gin.Context) {
|
||||||
|
query := &admin.PeerQuery{}
|
||||||
|
if err := c.ShouldBindQuery(query); err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
res := service.AllService.PeerService.List(query.Page, query.PageSize, func(tx *gorm.DB) {
|
||||||
|
tx.Where("user_id = ?", u.Id)
|
||||||
|
if query.TimeAgo > 0 {
|
||||||
|
lt := time.Now().Unix() - int64(query.TimeAgo)
|
||||||
|
tx.Where("last_online_time < ?", lt)
|
||||||
|
}
|
||||||
|
if query.TimeAgo < 0 {
|
||||||
|
lt := time.Now().Unix() + int64(query.TimeAgo)
|
||||||
|
tx.Where("last_online_time > ?", lt)
|
||||||
|
}
|
||||||
|
if query.Id != "" {
|
||||||
|
tx.Where("id like ?", "%"+query.Id+"%")
|
||||||
|
}
|
||||||
|
if query.Hostname != "" {
|
||||||
|
tx.Where("hostname like ?", "%"+query.Hostname+"%")
|
||||||
|
}
|
||||||
|
if query.Uuids != "" {
|
||||||
|
tx.Where("uuid in (?)", query.Uuids)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
response.Success(c, res)
|
||||||
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
package my
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ShareRecord struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// List share record list
|
||||||
|
// @Tags my share records
|
||||||
|
// @Summary share record list
|
||||||
|
// @Description share record list
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param page query int false "page number"
|
||||||
|
// @Param page_size query int false "page size"
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/my/share_record/list [get]
|
||||||
|
// @Security token
|
||||||
|
func (sr *ShareRecord) List(c *gin.Context) {
|
||||||
|
query := &admin.PageQuery{}
|
||||||
|
if err := c.ShouldBindQuery(query); err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
res := service.AllService.ShareRecordService.List(query.Page, query.PageSize, func(tx *gorm.DB) {
|
||||||
|
tx.Where("user_id = ?", u.Id)
|
||||||
|
})
|
||||||
|
response.Success(c, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete delete share record
|
||||||
|
// @Tags my share records
|
||||||
|
// @Summary delete share record
|
||||||
|
// @Description delete share record
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param body body admin.ShareRecordForm true "share record info"
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/my/share_record/delete [post]
|
||||||
|
// @Security token
|
||||||
|
func (sr *ShareRecord) Delete(c *gin.Context) {
|
||||||
|
f := &admin.ShareRecordForm{}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
i := service.AllService.ShareRecordService.InfoById(f.Id)
|
||||||
|
if i.UserId != u.Id {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if i.Id == 0 {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := service.AllService.ShareRecordService.Delete(i)
|
||||||
|
if err == nil {
|
||||||
|
response.Success(c, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// BatchDelete batch delete my share records
|
||||||
|
// @Tags my
|
||||||
|
// @Summary batch delete my share records
|
||||||
|
// @Description batch delete my share records
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param body body admin.PeerShareRecordBatchDeleteForm true "id"
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/my/share_record/batchDelete [post]
|
||||||
|
// @Security token
|
||||||
|
func (sr *ShareRecord) BatchDelete(c *gin.Context) {
|
||||||
|
f := &admin.PeerShareRecordBatchDeleteForm{}
|
||||||
|
if err := c.ShouldBindJSON(f); err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(f.Ids) == 0 {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
var l int64
|
||||||
|
l = int64(len(f.Ids))
|
||||||
|
res := service.AllService.ShareRecordService.List(1, uint(l), func(tx *gorm.DB) {
|
||||||
|
tx.Where("user_id = ?", u.Id)
|
||||||
|
tx.Where("id in ?", f.Ids)
|
||||||
|
})
|
||||||
|
if res.Total != l {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := service.AllService.ShareRecordService.BatchDelete(f.Ids)
|
||||||
|
if err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Success(c, nil)
|
||||||
|
}
|
||||||
@@ -0,0 +1,176 @@
|
|||||||
|
package my
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Tag struct{}
|
||||||
|
|
||||||
|
// List list
|
||||||
|
// @Tags my tags
|
||||||
|
// @Summary tag list
|
||||||
|
// @Description tag list
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param page query int false "page number"
|
||||||
|
// @Param page_size query int false "page size"
|
||||||
|
// @Param is_my query int false "whether it is mine"
|
||||||
|
// @Param user_id query int false "userid"
|
||||||
|
// @Success 200 {object} response.Response{data=model.TagList}
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/my/tag/list [get]
|
||||||
|
// @Security token
|
||||||
|
func (ct *Tag) List(c *gin.Context) {
|
||||||
|
query := &admin.TagQuery{}
|
||||||
|
if err := c.ShouldBindQuery(query); err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
query.UserId = int(u.Id)
|
||||||
|
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")
|
||||||
|
})
|
||||||
|
tx.Where("user_id = ?", query.UserId)
|
||||||
|
if query.CollectionId != nil && *query.CollectionId >= 0 {
|
||||||
|
tx.Where("collection_id = ?", query.CollectionId)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
response.Success(c, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create create tag
|
||||||
|
// @Tags my tags
|
||||||
|
// @Summary create tag
|
||||||
|
// @Description create tag
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param body body admin.TagForm true "tag info"
|
||||||
|
// @Success 200 {object} response.Response{data=model.Tag}
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/my/tag/create [post]
|
||||||
|
// @Security token
|
||||||
|
func (ct *Tag) Create(c *gin.Context) {
|
||||||
|
f := &admin.TagForm{}
|
||||||
|
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.ToTag()
|
||||||
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
t.UserId = u.Id
|
||||||
|
err := service.AllService.TagService.Create(t)
|
||||||
|
if err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Success(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update edit
|
||||||
|
// @Tags my tags
|
||||||
|
// @Summary edit tag
|
||||||
|
// @Description edit tag
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param body body admin.TagForm true "tag info"
|
||||||
|
// @Success 200 {object} response.Response{data=model.Tag}
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/my/tag/update [post]
|
||||||
|
// @Security token
|
||||||
|
func (ct *Tag) Update(c *gin.Context) {
|
||||||
|
f := &admin.TagForm{}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
if f.UserId != u.Id {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "NoAccess"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ex := service.AllService.TagService.InfoById(f.Id)
|
||||||
|
if ex.Id == 0 {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ex.UserId != u.Id {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "NoAccess"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t := f.ToTag()
|
||||||
|
if t.CollectionId > 0 && !service.AllService.AddressBookService.CheckCollectionOwner(t.UserId, t.CollectionId) {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := service.AllService.TagService.Update(t)
|
||||||
|
if err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Success(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete delete
|
||||||
|
// @Tags tag
|
||||||
|
// @Summary delete tag
|
||||||
|
// @Description delete tag
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param body body admin.TagForm true "tag info"
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/my/tag/delete [post]
|
||||||
|
// @Security token
|
||||||
|
func (ct *Tag) Delete(c *gin.Context) {
|
||||||
|
f := &admin.TagForm{}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
ex := service.AllService.TagService.InfoById(f.Id)
|
||||||
|
if ex.Id == 0 {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
if ex.UserId != u.Id {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "NoAccess"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := service.AllService.TagService.Delete(ex)
|
||||||
|
if err == nil {
|
||||||
|
response.Success(c, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Fail(c, 101, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -1,13 +1,14 @@
|
|||||||
package admin
|
package admin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"Gwen/global"
|
|
||||||
"Gwen/http/request/admin"
|
|
||||||
adminReq "Gwen/http/request/admin"
|
|
||||||
"Gwen/http/response"
|
|
||||||
"Gwen/service"
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||||
|
adminReq "github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Oauth struct {
|
type Oauth struct {
|
||||||
@@ -43,39 +44,41 @@ func (o *Oauth) ToBind(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err, code, url := service.AllService.OauthService.BeginAuth(f.Op)
|
err, state, verifier, nonce, url := service.AllService.OauthService.BeginAuth(f.Op)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.Error(c, response.TranslateMsg(c, err.Error()))
|
response.Error(c, response.TranslateMsg(c, err.Error()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
service.AllService.OauthService.SetOauthCache(code, &service.OauthCacheItem{
|
service.AllService.OauthService.SetOauthCache(state, &service.OauthCacheItem{
|
||||||
Action: service.OauthActionTypeBind,
|
Action: service.OauthActionTypeBind,
|
||||||
Op: f.Op,
|
Op: f.Op,
|
||||||
UserId: u.Id,
|
UserId: u.Id,
|
||||||
|
Verifier: verifier,
|
||||||
|
Nonce: nonce,
|
||||||
}, 5*60)
|
}, 5*60)
|
||||||
|
|
||||||
response.Success(c, gin.H{
|
response.Success(c, gin.H{
|
||||||
"code": code,
|
"code": state,
|
||||||
"url": url,
|
"url": url,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Confirm 确认授权登录
|
// Confirm confirm authorized login
|
||||||
func (o *Oauth) Confirm(c *gin.Context) {
|
func (o *Oauth) Confirm(c *gin.Context) {
|
||||||
j := &adminReq.OauthConfirmForm{}
|
j := &adminReq.OauthConfirmForm{}
|
||||||
err := c.ShouldBindJSON(j)
|
err := c.ShouldBindJSON(j)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.Fail(c, 101, "参数错误"+err.Error())
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if j.Code == "" {
|
if j.Code == "" {
|
||||||
response.Fail(c, 101, "参数错误: code 不存在")
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
v := service.AllService.OauthService.GetOauthCache(j.Code)
|
v := service.AllService.OauthService.GetOauthCache(j.Code)
|
||||||
if v == nil {
|
if v == nil {
|
||||||
response.Fail(c, 101, "授权已过期")
|
response.Fail(c, 101, response.TranslateMsg(c, "OauthExpired"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
u := service.AllService.UserService.CurUser(c)
|
u := service.AllService.UserService.CurUser(c)
|
||||||
@@ -137,8 +140,8 @@ func (o *Oauth) Unbind(c *gin.Context) {
|
|||||||
|
|
||||||
// Detail Oauth
|
// Detail Oauth
|
||||||
// @Tags Oauth
|
// @Tags Oauth
|
||||||
// @Summary Oauth详情
|
// @Summary Oauthdetails
|
||||||
// @Description Oauth详情
|
// @Description Oauthdetails
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param id path int true "ID"
|
// @Param id path int true "ID"
|
||||||
@@ -158,13 +161,13 @@ func (o *Oauth) Detail(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create 创建Oauth
|
// Create createOauth
|
||||||
// @Tags Oauth
|
// @Tags Oauth
|
||||||
// @Summary 创建Oauth
|
// @Summary createOauth
|
||||||
// @Description 创建Oauth
|
// @Description createOauth
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.OauthForm true "Oauth信息"
|
// @Param body body admin.OauthForm true "Oauthinfo"
|
||||||
// @Success 200 {object} response.Response{data=model.Oauth}
|
// @Success 200 {object} response.Response{data=model.Oauth}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/oauth/create [post]
|
// @Router /admin/oauth/create [post]
|
||||||
@@ -199,14 +202,14 @@ func (o *Oauth) Create(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// List 列表
|
// List list
|
||||||
// @Tags Oauth
|
// @Tags Oauth
|
||||||
// @Summary Oauth列表
|
// @Summary Oauthlist
|
||||||
// @Description Oauth列表
|
// @Description Oauthlist
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param page query int false "页码"
|
// @Param page query int false "page number"
|
||||||
// @Param page_size query int false "页大小"
|
// @Param page_size query int false "page size"
|
||||||
// @Success 200 {object} response.Response{data=model.OauthList}
|
// @Success 200 {object} response.Response{data=model.OauthList}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/oauth/list [get]
|
// @Router /admin/oauth/list [get]
|
||||||
@@ -221,13 +224,13 @@ func (o *Oauth) List(c *gin.Context) {
|
|||||||
response.Success(c, res)
|
response.Success(c, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update 编辑
|
// Update edit
|
||||||
// @Tags Oauth
|
// @Tags Oauth
|
||||||
// @Summary Oauth编辑
|
// @Summary Oauthedit
|
||||||
// @Description Oauth编辑
|
// @Description Oauthedit
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.OauthForm true "Oauth信息"
|
// @Param body body admin.OauthForm true "Oauthinfo"
|
||||||
// @Success 200 {object} response.Response{data=model.OauthList}
|
// @Success 200 {object} response.Response{data=model.OauthList}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/oauth/update [post]
|
// @Router /admin/oauth/update [post]
|
||||||
@@ -256,13 +259,13 @@ func (o *Oauth) Update(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete 删除
|
// Delete delete
|
||||||
// @Tags Oauth
|
// @Tags Oauth
|
||||||
// @Summary Oauth删除
|
// @Summary Oauthdelete
|
||||||
// @Description Oauth删除
|
// @Description Oauthdelete
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.OauthForm true "Oauth信息"
|
// @Param body body admin.OauthForm true "Oauthinfo"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/oauth/delete [post]
|
// @Router /admin/oauth/delete [post]
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
package admin
|
package admin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"Gwen/global"
|
|
||||||
"Gwen/http/request/admin"
|
|
||||||
"Gwen/http/response"
|
|
||||||
"Gwen/service"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
@@ -14,10 +14,10 @@ import (
|
|||||||
type Peer struct {
|
type Peer struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detail 设备
|
// Detail device
|
||||||
// @Tags 设备
|
// @Tags device
|
||||||
// @Summary 设备详情
|
// @Summary device details
|
||||||
// @Description 设备详情
|
// @Description device details
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param id path int true "ID"
|
// @Param id path int true "ID"
|
||||||
@@ -37,13 +37,13 @@ func (ct *Peer) Detail(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create 创建设备
|
// Create create device
|
||||||
// @Tags 设备
|
// @Tags device
|
||||||
// @Summary 创建设备
|
// @Summary create device
|
||||||
// @Description 创建设备
|
// @Description create device
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.PeerForm true "设备信息"
|
// @Param body body admin.PeerForm true "device info"
|
||||||
// @Success 200 {object} response.Response{data=model.Peer}
|
// @Success 200 {object} response.Response{data=model.Peer}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/peer/create [post]
|
// @Router /admin/peer/create [post]
|
||||||
@@ -68,18 +68,18 @@ func (ct *Peer) Create(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// List 列表
|
// List list
|
||||||
// @Tags 设备
|
// @Tags device
|
||||||
// @Summary 设备列表
|
// @Summary device list
|
||||||
// @Description 设备列表
|
// @Description device list
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param page query int false "页码"
|
// @Param page query int false "page number"
|
||||||
// @Param page_size query int false "页大小"
|
// @Param page_size query int false "page size"
|
||||||
// @Param time_ago query int false "时间"
|
// @Param time_ago query int false "time"
|
||||||
// @Param id query string false "ID"
|
// @Param id query string false "ID"
|
||||||
// @Param hostname query string false "主机名"
|
// @Param hostname query string false "hostname"
|
||||||
// @Param uuids query string false "uuids 用逗号分隔"
|
// @Param uuids query string false "uuids separated by commas"
|
||||||
// @Success 200 {object} response.Response{data=model.PeerList}
|
// @Success 200 {object} response.Response{data=model.PeerList}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/peer/list [get]
|
// @Router /admin/peer/list [get]
|
||||||
@@ -108,17 +108,26 @@ func (ct *Peer) List(c *gin.Context) {
|
|||||||
if query.Uuids != "" {
|
if query.Uuids != "" {
|
||||||
tx.Where("uuid in (?)", query.Uuids)
|
tx.Where("uuid in (?)", query.Uuids)
|
||||||
}
|
}
|
||||||
|
if query.Username != "" {
|
||||||
|
tx.Where("username like ?", "%"+query.Username+"%")
|
||||||
|
}
|
||||||
|
if query.Ip != "" {
|
||||||
|
tx.Where("last_online_ip like ?", "%"+query.Ip+"%")
|
||||||
|
}
|
||||||
|
if query.Alias != "" {
|
||||||
|
tx.Where("alias like ?", "%"+query.Alias+"%")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
response.Success(c, res)
|
response.Success(c, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update 编辑
|
// Update edit
|
||||||
// @Tags 设备
|
// @Tags device
|
||||||
// @Summary 设备编辑
|
// @Summary edit device
|
||||||
// @Description 设备编辑
|
// @Description edit device
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.PeerForm true "设备信息"
|
// @Param body body admin.PeerForm true "device info"
|
||||||
// @Success 200 {object} response.Response{data=model.Peer}
|
// @Success 200 {object} response.Response{data=model.Peer}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/peer/update [post]
|
// @Router /admin/peer/update [post]
|
||||||
@@ -147,13 +156,13 @@ func (ct *Peer) Update(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete 删除
|
// Delete delete
|
||||||
// @Tags 设备
|
// @Tags device
|
||||||
// @Summary 设备删除
|
// @Summary delete device
|
||||||
// @Description 设备删除
|
// @Description delete device
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.PeerForm true "设备信息"
|
// @Param body body admin.PeerForm true "device info"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/peer/delete [post]
|
// @Router /admin/peer/delete [post]
|
||||||
@@ -183,13 +192,13 @@ func (ct *Peer) Delete(c *gin.Context) {
|
|||||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// BatchDelete 批量删除
|
// BatchDelete batch delete
|
||||||
// @Tags 设备
|
// @Tags device
|
||||||
// @Summary 批量设备删除
|
// @Summary batch delete devices
|
||||||
// @Description 批量设备删除
|
// @Description batch delete devices
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.PeerBatchDeleteForm true "设备id"
|
// @Param body body admin.PeerBatchDeleteForm true "deviceid"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/peer/batchDelete [post]
|
// @Router /admin/peer/batchDelete [post]
|
||||||
@@ -223,7 +232,7 @@ func (ct *Peer) SimpleData(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
res := service.AllService.PeerService.List(1, 99999, func(tx *gorm.DB) {
|
res := service.AllService.PeerService.List(1, 99999, func(tx *gorm.DB) {
|
||||||
//可以公开的情报
|
//information that can be made public
|
||||||
tx.Select("id,version")
|
tx.Select("id,version")
|
||||||
tx.Where("id in (?)", f.Ids)
|
tx.Where("id in (?)", f.Ids)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,46 +1,137 @@
|
|||||||
package admin
|
package admin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"Gwen/global"
|
|
||||||
"Gwen/http/response"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Rustdesk struct {
|
type Rustdesk struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServerConfig RUSTDESK服务配置
|
type RustdeskCmd struct {
|
||||||
// @Tags ADMIN
|
Cmd string `json:"cmd"`
|
||||||
// @Summary RUSTDESK服务配置
|
Option string `json:"option"`
|
||||||
// @Description 服务配置,给webclient提供api-server
|
Target string `json:"target"`
|
||||||
// @Accept json
|
|
||||||
// @Produce json
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 500 {object} response.Response
|
|
||||||
// @Router /admin/server-config [get]
|
|
||||||
// @Security token
|
|
||||||
func (r *Rustdesk) ServerConfig(c *gin.Context) {
|
|
||||||
cf := &response.ServerConfigResponse{
|
|
||||||
IdServer: global.Config.Rustdesk.IdServer,
|
|
||||||
Key: global.Config.Rustdesk.Key,
|
|
||||||
RelayServer: global.Config.Rustdesk.RelayServer,
|
|
||||||
ApiServer: global.Config.Rustdesk.ApiServer,
|
|
||||||
}
|
|
||||||
response.Success(c, cf)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AppConfig APP服务配置
|
func (r *Rustdesk) CmdList(c *gin.Context) {
|
||||||
// @Tags ADMIN
|
q := &admin.PageQuery{}
|
||||||
// @Summary APP服务配置
|
if err := c.ShouldBindQuery(q); err != nil {
|
||||||
// @Description APP服务配置
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
// @Accept json
|
return
|
||||||
// @Produce json
|
}
|
||||||
// @Success 200 {object} response.Response
|
res := service.AllService.ServerCmdService.List(q.Page, 9999)
|
||||||
// @Failure 500 {object} response.Response
|
//add system commands before the list
|
||||||
// @Router /admin/app-config [get]
|
list := make([]*model.ServerCmd, 0)
|
||||||
// @Security token
|
list = append(list, model.SysIdServerCmds...)
|
||||||
func (r *Rustdesk) AppConfig(c *gin.Context) {
|
list = append(list, model.SysRelayServerCmds...)
|
||||||
response.Success(c, &gin.H{
|
list = append(list, res.ServerCmds...)
|
||||||
"web_client": global.Config.App.WebClient,
|
res.ServerCmds = list
|
||||||
})
|
response.Success(c, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Rustdesk) CmdDelete(c *gin.Context) {
|
||||||
|
f := &model.ServerCmd{}
|
||||||
|
if err := c.ShouldBindJSON(f); err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if f.Id == 0 {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ex := service.AllService.ServerCmdService.Info(f.Id)
|
||||||
|
if ex.Id == 0 {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := service.AllService.ServerCmdService.Delete(ex)
|
||||||
|
if err != nil {
|
||||||
|
response.Fail(c, 101, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Success(c, nil)
|
||||||
|
}
|
||||||
|
func (r *Rustdesk) CmdCreate(c *gin.Context) {
|
||||||
|
f := &model.ServerCmd{}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
err := service.AllService.ServerCmdService.Create(f)
|
||||||
|
if err != nil {
|
||||||
|
response.Fail(c, 101, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Success(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Rustdesk) CmdUpdate(c *gin.Context) {
|
||||||
|
f := &model.ServerCmd{}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
ex := service.AllService.ServerCmdService.Info(f.Id)
|
||||||
|
if ex.Id == 0 {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := service.AllService.ServerCmdService.Update(f)
|
||||||
|
if err != nil {
|
||||||
|
response.Fail(c, 101, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Success(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Rustdesk) SendCmd(c *gin.Context) {
|
||||||
|
rc := &RustdeskCmd{}
|
||||||
|
if err := c.ShouldBindJSON(rc); err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if rc.Cmd == "" {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if rc.Target == "" {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if rc.Target != model.ServerCmdTargetIdServer && rc.Target != model.ServerCmdTargetRelayServer {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
port := 0
|
||||||
|
switch rc.Target {
|
||||||
|
case model.ServerCmdTargetIdServer:
|
||||||
|
port = global.Config.Admin.IdServerPort - 1
|
||||||
|
case model.ServerCmdTargetRelayServer:
|
||||||
|
port = global.Config.Admin.RelayServerPort
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := service.AllService.ServerCmdService.SendCmd(port, rc.Cmd, rc.Option)
|
||||||
|
if err != nil {
|
||||||
|
response.Fail(c, 101, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Success(c, res)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,105 @@
|
|||||||
|
package admin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ShareRecord struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// List list
|
||||||
|
// @Tags share record
|
||||||
|
// @Summary share record list
|
||||||
|
// @Description share record list
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param user_id query int false "userID"
|
||||||
|
// @Param page query int false "page number"
|
||||||
|
// @Param page_size query int false "page size"
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/share_record/list [get]
|
||||||
|
// @Security token
|
||||||
|
func (sr *ShareRecord) List(c *gin.Context) {
|
||||||
|
query := &admin.ShareRecordQuery{}
|
||||||
|
if err := c.ShouldBindQuery(query); err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res := service.AllService.ShareRecordService.List(query.Page, query.PageSize, func(tx *gorm.DB) {
|
||||||
|
if query.UserId > 0 {
|
||||||
|
tx.Where("user_id = ?", query.UserId)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
response.Success(c, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete delete
|
||||||
|
// @Tags share record
|
||||||
|
// @Summary delete share record
|
||||||
|
// @Description delete share record
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param body body admin.ShareRecordForm true "share record info"
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/share_record/delete [post]
|
||||||
|
// @Security token
|
||||||
|
func (sr *ShareRecord) Delete(c *gin.Context) {
|
||||||
|
f := &admin.ShareRecordForm{}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
i := service.AllService.ShareRecordService.InfoById(f.Id)
|
||||||
|
if i.Id > 0 {
|
||||||
|
err := service.AllService.ShareRecordService.Delete(i)
|
||||||
|
if err == nil {
|
||||||
|
response.Success(c, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// BatchDelete batch delete
|
||||||
|
// @Tags share record
|
||||||
|
// @Summary batch share records
|
||||||
|
// @Description batch share records
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param body body admin.PeerShareRecordBatchDeleteForm true "id"
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/share_record/batchDelete [post]
|
||||||
|
// @Security token
|
||||||
|
func (sr *ShareRecord) BatchDelete(c *gin.Context) {
|
||||||
|
f := &admin.PeerShareRecordBatchDeleteForm{}
|
||||||
|
if err := c.ShouldBindJSON(f); err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(f.Ids) == 0 {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := service.AllService.ShareRecordService.BatchDelete(f.Ids)
|
||||||
|
if err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Success(c, nil)
|
||||||
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
package admin
|
package admin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"Gwen/global"
|
|
||||||
"Gwen/http/request/admin"
|
|
||||||
"Gwen/http/response"
|
|
||||||
"Gwen/service"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
@@ -13,10 +13,10 @@ import (
|
|||||||
type Tag struct {
|
type Tag struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detail 标签
|
// Detail tag
|
||||||
// @Tags 标签
|
// @Tags tag
|
||||||
// @Summary 标签详情
|
// @Summary tag details
|
||||||
// @Description 标签详情
|
// @Description tag details
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param id path int true "ID"
|
// @Param id path int true "ID"
|
||||||
@@ -41,13 +41,13 @@ func (ct *Tag) Detail(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create 创建标签
|
// Create create tag
|
||||||
// @Tags 标签
|
// @Tags tag
|
||||||
// @Summary 创建标签
|
// @Summary create tag
|
||||||
// @Description 创建标签
|
// @Description create tag
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.TagForm true "标签信息"
|
// @Param body body admin.TagForm true "tag info"
|
||||||
// @Success 200 {object} response.Response{data=model.Tag}
|
// @Success 200 {object} response.Response{data=model.Tag}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/tag/create [post]
|
// @Router /admin/tag/create [post]
|
||||||
@@ -64,9 +64,9 @@ func (ct *Tag) Create(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
t := f.ToTag()
|
t := f.ToTag()
|
||||||
u := service.AllService.UserService.CurUser(c)
|
if t.UserId == 0 {
|
||||||
if !service.AllService.UserService.IsAdmin(u) || t.UserId == 0 {
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||||
t.UserId = u.Id
|
return
|
||||||
}
|
}
|
||||||
err := service.AllService.TagService.Create(t)
|
err := service.AllService.TagService.Create(t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -76,16 +76,16 @@ func (ct *Tag) Create(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// List 列表
|
// List list
|
||||||
// @Tags 标签
|
// @Tags tag
|
||||||
// @Summary 标签列表
|
// @Summary tag list
|
||||||
// @Description 标签列表
|
// @Description tag list
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param page query int false "页码"
|
// @Param page query int false "page number"
|
||||||
// @Param page_size query int false "页大小"
|
// @Param page_size query int false "page size"
|
||||||
// @Param is_my query int false "是否是我的"
|
// @Param is_my query int false "whether it is mine"
|
||||||
// @Param user_id query int false "用户id"
|
// @Param user_id query int false "userid"
|
||||||
// @Success 200 {object} response.Response{data=model.TagList}
|
// @Success 200 {object} response.Response{data=model.TagList}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/tag/list [get]
|
// @Router /admin/tag/list [get]
|
||||||
@@ -96,10 +96,6 @@ func (ct *Tag) List(c *gin.Context) {
|
|||||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
u := service.AllService.UserService.CurUser(c)
|
|
||||||
if !service.AllService.UserService.IsAdmin(u) || query.IsMy == 1 {
|
|
||||||
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 {
|
tx.Preload("Collection", func(txc *gorm.DB) *gorm.DB {
|
||||||
return txc.Select("id,name")
|
return txc.Select("id,name")
|
||||||
@@ -114,13 +110,13 @@ func (ct *Tag) List(c *gin.Context) {
|
|||||||
response.Success(c, res)
|
response.Success(c, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update 编辑
|
// Update edit
|
||||||
// @Tags 标签
|
// @Tags tag
|
||||||
// @Summary 标签编辑
|
// @Summary edit tag
|
||||||
// @Description 标签编辑
|
// @Description edit tag
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.TagForm true "标签信息"
|
// @Param body body admin.TagForm true "tag info"
|
||||||
// @Success 200 {object} response.Response{data=model.Tag}
|
// @Success 200 {object} response.Response{data=model.Tag}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/tag/update [post]
|
// @Router /admin/tag/update [post]
|
||||||
@@ -140,12 +136,12 @@ func (ct *Tag) Update(c *gin.Context) {
|
|||||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
t := f.ToTag()
|
ex := service.AllService.TagService.InfoById(f.Id)
|
||||||
u := service.AllService.UserService.CurUser(c)
|
if ex.Id == 0 {
|
||||||
if !service.AllService.UserService.IsAdmin(u) && t.UserId != u.Id {
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "NoAccess"))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
t := f.ToTag()
|
||||||
err := service.AllService.TagService.Update(t)
|
err := service.AllService.TagService.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())
|
||||||
@@ -154,13 +150,13 @@ func (ct *Tag) Update(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete 删除
|
// Delete delete
|
||||||
// @Tags 标签
|
// @Tags tag
|
||||||
// @Summary 标签删除
|
// @Summary delete tag
|
||||||
// @Description 标签删除
|
// @Description delete tag
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.TagForm true "标签信息"
|
// @Param body body admin.TagForm true "tag info"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/tag/delete [post]
|
// @Router /admin/tag/delete [post]
|
||||||
@@ -177,20 +173,15 @@ func (ct *Tag) Delete(c *gin.Context) {
|
|||||||
response.Fail(c, 101, errList[0])
|
response.Fail(c, 101, errList[0])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
t := service.AllService.TagService.InfoById(f.Id)
|
ex := service.AllService.TagService.InfoById(f.Id)
|
||||||
u := service.AllService.UserService.CurUser(c)
|
if ex.Id == 0 {
|
||||||
if !service.AllService.UserService.IsAdmin(u) && t.UserId != u.Id {
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "NoAccess"))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if u.Id > 0 {
|
err := service.AllService.TagService.Delete(ex)
|
||||||
err := service.AllService.TagService.Delete(t)
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
response.Fail(c, 101, err.Error())
|
response.Fail(c, 101, err.Error())
|
||||||
return
|
|
||||||
}
|
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,25 @@
|
|||||||
package admin
|
package admin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"Gwen/global"
|
|
||||||
"Gwen/http/request/admin"
|
|
||||||
"Gwen/http/response"
|
|
||||||
adResp "Gwen/http/response/admin"
|
|
||||||
"Gwen/model"
|
|
||||||
"Gwen/service"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||||
|
adResp "github.com/lejianwen/rustdesk-api/v2/http/response/admin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/utils"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detail 管理员
|
// Detail administrator
|
||||||
// @Tags 用户
|
// @Tags user
|
||||||
// @Summary 管理员详情
|
// @Summary administrator details
|
||||||
// @Description 管理员详情
|
// @Description administrator details
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param id path int true "ID"
|
// @Param id path int true "ID"
|
||||||
@@ -39,13 +39,13 @@ func (ct *User) Detail(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create 管理员
|
// Create administrator
|
||||||
// @Tags 用户
|
// @Tags user
|
||||||
// @Summary 创建管理员
|
// @Summary create administrator
|
||||||
// @Description 创建管理员
|
// @Description create administrator
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.UserForm true "管理员信息"
|
// @Param body body admin.UserForm true "administrator info"
|
||||||
// @Success 200 {object} response.Response{data=model.User}
|
// @Success 200 {object} response.Response{data=model.User}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/user/create [post]
|
// @Router /admin/user/create [post]
|
||||||
@@ -70,15 +70,15 @@ func (ct *User) Create(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// List 列表
|
// List list
|
||||||
// @Tags 用户
|
// @Tags user
|
||||||
// @Summary 管理员列表
|
// @Summary administrator list
|
||||||
// @Description 管理员列表
|
// @Description administrator list
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param page query int false "页码"
|
// @Param page query int false "page number"
|
||||||
// @Param page_size query int false "页大小"
|
// @Param page_size query int false "page size"
|
||||||
// @Param username query int false "账户"
|
// @Param username query int false "account"
|
||||||
// @Success 200 {object} response.Response{data=model.UserList}
|
// @Success 200 {object} response.Response{data=model.UserList}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/user/list [get]
|
// @Router /admin/user/list [get]
|
||||||
@@ -97,13 +97,13 @@ func (ct *User) List(c *gin.Context) {
|
|||||||
response.Success(c, res)
|
response.Success(c, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update 编辑
|
// Update edit
|
||||||
// @Tags 用户
|
// @Tags user
|
||||||
// @Summary 管理员编辑
|
// @Summary edit administrator
|
||||||
// @Description 管理员编辑
|
// @Description edit administrator
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.UserForm true "用户信息"
|
// @Param body body admin.UserForm true "user info"
|
||||||
// @Success 200 {object} response.Response{data=model.User}
|
// @Success 200 {object} response.Response{data=model.User}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/user/update [post]
|
// @Router /admin/user/update [post]
|
||||||
@@ -132,13 +132,13 @@ func (ct *User) Update(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete 删除
|
// Delete delete
|
||||||
// @Tags 用户
|
// @Tags user
|
||||||
// @Summary 管理员删除
|
// @Summary delete administrator
|
||||||
// @Description 管理员编删除
|
// @Description delete administrator
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.UserForm true "用户信息"
|
// @Param body body admin.UserForm true "user info"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/user/delete [post]
|
// @Router /admin/user/delete [post]
|
||||||
@@ -168,13 +168,13 @@ func (ct *User) Delete(c *gin.Context) {
|
|||||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatePassword 修改密码
|
// UpdatePassword change password
|
||||||
// @Tags 用户
|
// @Tags user
|
||||||
// @Summary 修改密码
|
// @Summary change password
|
||||||
// @Description 修改密码
|
// @Description change password
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.UserPasswordForm true "用户信息"
|
// @Param body body admin.UserPasswordForm true "user info"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/user/updatePassword [post]
|
// @Router /admin/user/updatePassword [post]
|
||||||
@@ -203,10 +203,10 @@ func (ct *User) UpdatePassword(c *gin.Context) {
|
|||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Current 当前用户
|
// Current current user
|
||||||
// @Tags 用户
|
// @Tags user
|
||||||
// @Summary 当前用户
|
// @Summary current user
|
||||||
// @Description 当前用户
|
// @Description current user
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} response.Response{data=adResp.LoginPayload}
|
// @Success 200 {object} response.Response{data=adResp.LoginPayload}
|
||||||
@@ -220,13 +220,13 @@ func (ct *User) Current(c *gin.Context) {
|
|||||||
responseLoginSuccess(c, u, t)
|
responseLoginSuccess(c, u, t)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChangeCurPwd 修改当前用户密码
|
// ChangeCurPwd change the current user's password
|
||||||
// @Tags 用户
|
// @Tags user
|
||||||
// @Summary 修改当前用户密码
|
// @Summary change the current user's password
|
||||||
// @Description 修改当前用户密码
|
// @Description change the current user's password
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body admin.ChangeCurPasswordForm true "用户信息"
|
// @Param body body admin.ChangeCurPasswordForm true "user info"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/user/changeCurPwd [post]
|
// @Router /admin/user/changeCurPwd [post]
|
||||||
@@ -244,11 +244,10 @@ func (ct *User) ChangeCurPwd(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
u := service.AllService.UserService.CurUser(c)
|
u := service.AllService.UserService.CurUser(c)
|
||||||
// If the password is not empty, the old password is verified
|
// Verify the old password only when the account already has one set
|
||||||
// otherwise, the old password is not verified
|
|
||||||
if !service.AllService.UserService.IsPasswordEmptyByUser(u) {
|
if !service.AllService.UserService.IsPasswordEmptyByUser(u) {
|
||||||
oldPwd := service.AllService.UserService.EncryptPassword(f.OldPassword)
|
ok, _, err := utils.VerifyPassword(u.Password, f.OldPassword)
|
||||||
if u.Password != oldPwd {
|
if err != nil || !ok {
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "OldPasswordError"))
|
response.Fail(c, 101, response.TranslateMsg(c, "OldPasswordError"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -262,9 +261,9 @@ func (ct *User) ChangeCurPwd(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MyOauth
|
// MyOauth
|
||||||
// @Tags 用户
|
// @Tags user
|
||||||
// @Summary 我的授权
|
// @Summary my authorizations
|
||||||
// @Description 我的授权
|
// @Description my authorizations
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} response.Response{data=[]adResp.UserOauthItem}
|
// @Success 200 {object} response.Response{data=[]adResp.UserOauthItem}
|
||||||
@@ -295,79 +294,14 @@ func (ct *User) MyOauth(c *gin.Context) {
|
|||||||
response.Success(c, res)
|
response.Success(c, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MyPeer 列表
|
|
||||||
// @Tags 设备
|
|
||||||
// @Summary 我的设备列表
|
|
||||||
// @Description 我的设备列表
|
|
||||||
// @Accept json
|
|
||||||
// @Produce json
|
|
||||||
// @Param page query int false "页码"
|
|
||||||
// @Param page_size query int false "页大小"
|
|
||||||
// @Param time_ago query int false "时间"
|
|
||||||
// @Param id query string false "ID"
|
|
||||||
// @Param hostname query string false "主机名"
|
|
||||||
// @Param uuids query string false "uuids 用逗号分隔"
|
|
||||||
// @Success 200 {object} response.Response{data=model.PeerList}
|
|
||||||
// @Failure 500 {object} response.Response
|
|
||||||
// @Router /admin/user/myPeer [get]
|
|
||||||
// @Security token
|
|
||||||
func (ct *User) MyPeer(c *gin.Context) {
|
|
||||||
query := &admin.PeerQuery{}
|
|
||||||
if err := c.ShouldBindQuery(query); err != nil {
|
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
u := service.AllService.UserService.CurUser(c)
|
|
||||||
res := service.AllService.PeerService.ListFilterByUserId(query.Page, query.PageSize, func(tx *gorm.DB) {
|
|
||||||
if query.TimeAgo > 0 {
|
|
||||||
lt := time.Now().Unix() - int64(query.TimeAgo)
|
|
||||||
tx.Where("last_online_time < ?", lt)
|
|
||||||
}
|
|
||||||
if query.TimeAgo < 0 {
|
|
||||||
lt := time.Now().Unix() + int64(query.TimeAgo)
|
|
||||||
tx.Where("last_online_time > ?", lt)
|
|
||||||
}
|
|
||||||
if query.Id != "" {
|
|
||||||
tx.Where("id like ?", "%"+query.Id+"%")
|
|
||||||
}
|
|
||||||
if query.Hostname != "" {
|
|
||||||
tx.Where("hostname like ?", "%"+query.Hostname+"%")
|
|
||||||
}
|
|
||||||
if query.Uuids != "" {
|
|
||||||
tx.Where("uuid in (?)", query.Uuids)
|
|
||||||
}
|
|
||||||
}, u.Id)
|
|
||||||
response.Success(c, res)
|
|
||||||
}
|
|
||||||
|
|
||||||
// groupUsers
|
// groupUsers
|
||||||
func (ct *User) GroupUsers(c *gin.Context) {
|
func (ct *User) GroupUsers(c *gin.Context) {
|
||||||
q := &admin.GroupUsersQuery{}
|
aG := service.AllService.GroupService.List(1, 999, nil)
|
||||||
if err := c.ShouldBindJSON(q); err != nil {
|
aU := service.AllService.UserService.List(1, 9999, nil)
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
response.Success(c, gin.H{
|
||||||
return
|
"groups": aG.Groups,
|
||||||
}
|
"users": aU.Users,
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register
|
// Register
|
||||||
@@ -386,12 +320,23 @@ func (ct *User) Register(c *gin.Context) {
|
|||||||
response.Fail(c, 101, errList[0])
|
response.Fail(c, 101, errList[0])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
u := service.AllService.UserService.Register(f.Username, f.Email, f.Password)
|
regStatus := model.StatusCode(global.Config.App.RegisterStatus)
|
||||||
|
// the registration status may not be configured; enabled by default
|
||||||
|
if regStatus != model.COMMON_STATUS_DISABLED && regStatus != model.COMMON_STATUS_ENABLE {
|
||||||
|
regStatus = model.COMMON_STATUS_ENABLE
|
||||||
|
}
|
||||||
|
|
||||||
|
u := service.AllService.UserService.Register(f.Username, f.Email, f.Password, regStatus)
|
||||||
if u == nil || u.Id == 0 {
|
if u == nil || u.Id == 0 {
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed"))
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 注册成功后自动登录
|
if regStatus == model.COMMON_STATUS_DISABLED {
|
||||||
|
// requires administrator approval
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "RegisterSuccessWaitAdminConfirm"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// automatically log in after successful registration
|
||||||
ut := service.AllService.UserService.Login(u, &model.LoginLog{
|
ut := service.AllService.UserService.Login(u, &model.LoginLog{
|
||||||
UserId: u.Id,
|
UserId: u.Id,
|
||||||
Client: model.LoginLogClientWebAdmin,
|
Client: model.LoginLogClientWebAdmin,
|
||||||
|
|||||||
@@ -1,27 +1,27 @@
|
|||||||
package admin
|
package admin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"Gwen/global"
|
|
||||||
"Gwen/http/request/admin"
|
|
||||||
"Gwen/http/response"
|
|
||||||
"Gwen/model"
|
|
||||||
"Gwen/service"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/request/admin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
type UserToken struct {
|
type UserToken struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// List 列表
|
// List list
|
||||||
// @Tags 登录凭证
|
// @Tags login credential
|
||||||
// @Summary 登录凭证列表
|
// @Summary login credential list
|
||||||
// @Description 登录凭证列表
|
// @Description login credential list
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param page query int false "页码"
|
// @Param page query int false "page number"
|
||||||
// @Param page_size query int false "页大小"
|
// @Param page_size query int false "page size"
|
||||||
// @Param user_id query int false "用户ID"
|
// @Param user_id query int false "userID"
|
||||||
// @Success 200 {object} response.Response{data=model.UserTokenList}
|
// @Success 200 {object} response.Response{data=model.UserTokenList}
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/user_token/list [get]
|
// @Router /admin/user_token/list [get]
|
||||||
@@ -41,13 +41,13 @@ func (ct *UserToken) List(c *gin.Context) {
|
|||||||
response.Success(c, res)
|
response.Success(c, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete 删除
|
// Delete delete
|
||||||
// @Tags 登录凭证
|
// @Tags login credential
|
||||||
// @Summary 登录凭证删除
|
// @Summary delete login credential
|
||||||
// @Description 登录凭证删除
|
// @Description delete login credential
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body model.UserToken true "登录凭证信息"
|
// @Param body body model.UserToken true "login credential info"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /admin/user_token/delete [post]
|
// @Router /admin/user_token/delete [post]
|
||||||
@@ -81,3 +81,33 @@ func (ct *UserToken) Delete(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BatchDelete batch delete
|
||||||
|
// @Tags login credential
|
||||||
|
// @Summary batch delete login credentials
|
||||||
|
// @Description batch delete login credentials
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param body body admin.UserTokenBatchDeleteForm true "login credential info"
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/user_token/batchDelete [post]
|
||||||
|
// @Security token
|
||||||
|
func (ct *UserToken) BatchDelete(c *gin.Context) {
|
||||||
|
f := &admin.UserTokenBatchDeleteForm{}
|
||||||
|
if err := c.ShouldBindJSON(f); err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ids := f.Ids
|
||||||
|
if len(ids) == 0 {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := service.AllService.UserService.BatchDeleteUserToken(ids)
|
||||||
|
if err == nil {
|
||||||
|
response.Success(c, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Fail(c, 101, err.Error())
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"Gwen/global"
|
|
||||||
requstform "Gwen/http/request/api"
|
|
||||||
"Gwen/http/response"
|
|
||||||
"Gwen/http/response/api"
|
|
||||||
"Gwen/model"
|
|
||||||
"Gwen/service"
|
|
||||||
"Gwen/utils"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||||
|
requstform "github.com/lejianwen/rustdesk-api/v2/http/request/api"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/response/api"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/utils"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -20,9 +20,9 @@ type Ab struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Ab
|
// Ab
|
||||||
// @Tags 地址
|
// @Tags address
|
||||||
// @Summary 地址列表
|
// @Summary address list
|
||||||
// @Description 地址列表
|
// @Description address list
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
@@ -32,11 +32,11 @@ type Ab struct {
|
|||||||
func (a *Ab) Ab(c *gin.Context) {
|
func (a *Ab) Ab(c *gin.Context) {
|
||||||
user := service.AllService.UserService.CurUser(c)
|
user := service.AllService.UserService.CurUser(c)
|
||||||
|
|
||||||
al := service.AllService.AddressBookService.ListByUserId(user.Id, 1, 1000)
|
al := service.AllService.AddressBookService.ListByUserIdAndCollectionId(user.Id, 0, 1, 1000)
|
||||||
tags := service.AllService.TagService.ListByUserId(user.Id)
|
tags := service.AllService.TagService.ListByUserIdAndCollectionId(user.Id, 0)
|
||||||
|
|
||||||
tagColors := map[string]uint{}
|
tagColors := map[string]uint{}
|
||||||
//将tags中的name转成一个以逗号分割的字符串
|
// convert the name in tags into a comma-separated string
|
||||||
var tagNames []string
|
var tagNames []string
|
||||||
for _, tag := range tags.Tags {
|
for _, tag := range tags.Tags {
|
||||||
tagNames = append(tagNames, tag.Name)
|
tagNames = append(tagNames, tag.Name)
|
||||||
@@ -56,12 +56,12 @@ func (a *Ab) Ab(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UpAb
|
// UpAb
|
||||||
// @Tags 地址
|
// @Tags address
|
||||||
// @Summary 地址更新
|
// @Summary address update
|
||||||
// @Description 地址更新
|
// @Description address update
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body requstform.AddressBookForm true "地址表单"
|
// @Param body body requstform.AddressBookForm true "address form"
|
||||||
// @Success 200 {string} string "null"
|
// @Success 200 {string} string "null"
|
||||||
// @Failure 500 {object} response.ErrorResponse
|
// @Failure 500 {object} response.ErrorResponse
|
||||||
// @Router /ab [post]
|
// @Router /ab [post]
|
||||||
@@ -98,27 +98,10 @@ func (a *Ab) UpAb(c *gin.Context) {
|
|||||||
c.JSON(http.StatusOK, nil)
|
c.JSON(http.StatusOK, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tags
|
|
||||||
// @Tags 地址
|
|
||||||
// @Summary 标签
|
|
||||||
// @Description 标签
|
|
||||||
// @Accept json
|
|
||||||
// @Produce json
|
|
||||||
// @Success 200 {object} []model.Tag
|
|
||||||
// @Failure 500 {object} response.ErrorResponse
|
|
||||||
// @Router /tags [post]
|
|
||||||
// @Security BearerAuth
|
|
||||||
func (a *Ab) Tags(c *gin.Context) {
|
|
||||||
user := service.AllService.UserService.CurUser(c)
|
|
||||||
|
|
||||||
tags := service.AllService.TagService.ListByUserId(user.Id)
|
|
||||||
c.JSON(http.StatusOK, tags.Tags)
|
|
||||||
}
|
|
||||||
|
|
||||||
// PTags
|
// PTags
|
||||||
// @Tags 地址[Personal]
|
// @Tags address[Personal]
|
||||||
// @Summary 标签
|
// @Summary tag
|
||||||
// @Description 标签
|
// @Description tag
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param guid path string true "guid"
|
// @Param guid path string true "guid"
|
||||||
@@ -145,9 +128,9 @@ func (a *Ab) PTags(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TagAdd
|
// TagAdd
|
||||||
// @Tags 地址[Personal]
|
// @Tags address[Personal]
|
||||||
// @Summary 标签添加
|
// @Summary add tag
|
||||||
// @Description 标签
|
// @Description tag
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param guid path string true "guid"
|
// @Param guid path string true "guid"
|
||||||
@@ -194,9 +177,9 @@ func (a *Ab) TagAdd(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TagRename
|
// TagRename
|
||||||
// @Tags 地址[Personal]
|
// @Tags address[Personal]
|
||||||
// @Summary 标签重命名
|
// @Summary rename tag
|
||||||
// @Description 标签
|
// @Description tag
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param guid path string true "guid"
|
// @Param guid path string true "guid"
|
||||||
@@ -246,9 +229,9 @@ func (a *Ab) TagRename(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TagUpdate
|
// TagUpdate
|
||||||
// @Tags 地址[Personal]
|
// @Tags address[Personal]
|
||||||
// @Summary 标签修改颜色
|
// @Summary change tag color
|
||||||
// @Description 标签
|
// @Description tag
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param guid path string true "guid"
|
// @Param guid path string true "guid"
|
||||||
@@ -292,9 +275,9 @@ func (a *Ab) TagUpdate(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TagDel
|
// TagDel
|
||||||
// @Tags 地址[Personal]
|
// @Tags address[Personal]
|
||||||
// @Summary 标签删除
|
// @Summary delete tag
|
||||||
// @Description 标签
|
// @Description tag
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param guid path string true "guid"
|
// @Param guid path string true "guid"
|
||||||
@@ -341,9 +324,9 @@ func (a *Ab) TagDel(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Personal
|
// Personal
|
||||||
// @Tags 地址[Personal]
|
// @Tags address[Personal]
|
||||||
// @Summary 个人地址
|
// @Summary personal address
|
||||||
// @Description 个人地址
|
// @Description personal address
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param string body string false "string valid"
|
// @Param string body string false "string valid"
|
||||||
@@ -362,7 +345,7 @@ func (a *Ab) Personal(c *gin.Context) {
|
|||||||
*/
|
*/
|
||||||
if global.Config.Rustdesk.Personal == 1 {
|
if global.Config.Rustdesk.Personal == 1 {
|
||||||
guid := a.ComposeGuid(user.GroupId, user.Id, 0)
|
guid := a.ComposeGuid(user.GroupId, user.Id, 0)
|
||||||
//如果返回了guid,后面的请求会有变化
|
//if it returns guid, subsequent requests will change
|
||||||
c.JSON(http.StatusOK, gin.H{
|
c.JSON(http.StatusOK, gin.H{
|
||||||
"guid": guid,
|
"guid": guid,
|
||||||
"name": user.Username,
|
"name": user.Username,
|
||||||
@@ -375,9 +358,9 @@ func (a *Ab) Personal(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Settings
|
// Settings
|
||||||
// @Tags 地址[Personal]
|
// @Tags address[Personal]
|
||||||
// @Summary 设置
|
// @Summary settings
|
||||||
// @Description 设置
|
// @Description settings
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param string body string false "string valid"
|
// @Param string body string false "string valid"
|
||||||
@@ -387,18 +370,18 @@ func (a *Ab) Personal(c *gin.Context) {
|
|||||||
// @Security BearerAuth
|
// @Security BearerAuth
|
||||||
func (a *Ab) Settings(c *gin.Context) {
|
func (a *Ab) Settings(c *gin.Context) {
|
||||||
c.JSON(http.StatusOK, gin.H{
|
c.JSON(http.StatusOK, gin.H{
|
||||||
"max_peer_one_ab": 0, //最大peer数,0表示不限制
|
"max_peer_one_ab": 0, //max peer count, 0 means no limit
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// SharedProfiles
|
// SharedProfiles
|
||||||
// @Tags 地址[Personal]
|
// @Tags address[Personal]
|
||||||
// @Summary 共享地址簿
|
// @Summary shared address book
|
||||||
// @Description 共享
|
// @Description shared
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param current query int false "页码"
|
// @Param current query int false "page number"
|
||||||
// @Param pageSize query int false "每页数量"
|
// @Param pageSize query int false "items per page"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /ab/shared/profiles [post]
|
// @Router /ab/shared/profiles [post]
|
||||||
@@ -418,14 +401,14 @@ func (a *Ab) SharedProfiles(c *gin.Context) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
allAbIds := make(map[uint]int) //用map去重,并保留最大Rule
|
allAbIds := make(map[uint]int) //use map to deduplicate and keep the maximum Rule
|
||||||
allUserIds := make(map[uint]*model.User)
|
allUserIds := make(map[uint]*model.User)
|
||||||
rules := service.AllService.AddressBookService.CollectionReadRules(user)
|
rules := service.AllService.AddressBookService.CollectionReadRules(user)
|
||||||
for _, rule := range rules {
|
for _, rule := range rules {
|
||||||
//先判断是否存在
|
//first check whether it exists
|
||||||
r, ok := allAbIds[rule.CollectionId]
|
r, ok := allAbIds[rule.CollectionId]
|
||||||
if ok {
|
if ok {
|
||||||
//再判断权限大小
|
//then check the permission level
|
||||||
if r < rule.Rule {
|
if r < rule.Rule {
|
||||||
allAbIds[rule.CollectionId] = rule.Rule
|
allAbIds[rule.CollectionId] = rule.Rule
|
||||||
}
|
}
|
||||||
@@ -465,7 +448,7 @@ func (a *Ab) SharedProfiles(c *gin.Context) {
|
|||||||
|
|
||||||
// ParseGuid
|
// ParseGuid
|
||||||
func (a *Ab) ParseGuid(guid string) (gid, uid, cid uint) {
|
func (a *Ab) ParseGuid(guid string) (gid, uid, cid uint) {
|
||||||
//用-切割 guid
|
// split guid by -
|
||||||
guids := strings.Split(guid, "-")
|
guids := strings.Split(guid, "-")
|
||||||
if len(guids) < 2 {
|
if len(guids) < 2 {
|
||||||
return 0, 0, 0
|
return 0, 0, 0
|
||||||
@@ -538,13 +521,13 @@ func (a *Ab) CheckGuid(cu *model.User, guid string) (gid, uid, cid uint, err err
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Peers
|
// Peers
|
||||||
// @Tags 地址[Personal]
|
// @Tags address[Personal]
|
||||||
// @Summary 地址列表
|
// @Summary address list
|
||||||
// @Description 地址
|
// @Description address
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param current query int false "页码"
|
// @Param current query int false "page number"
|
||||||
// @Param pageSize query int false "每页数量"
|
// @Param pageSize query int false "items per page"
|
||||||
// @Param ab query string false "guid"
|
// @Param ab query string false "guid"
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
@@ -574,9 +557,9 @@ func (a *Ab) Peers(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PeerAdd
|
// PeerAdd
|
||||||
// @Tags 地址[Personal]
|
// @Tags address[Personal]
|
||||||
// @Summary 添加地址
|
// @Summary add address
|
||||||
// @Description 添加地址
|
// @Description add address
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param guid path string true "guid"
|
// @Param guid path string true "guid"
|
||||||
@@ -585,7 +568,7 @@ func (a *Ab) Peers(c *gin.Context) {
|
|||||||
// @Router /ab/peer/add/{guid} [post]
|
// @Router /ab/peer/add/{guid} [post]
|
||||||
// @Security BearerAuth
|
// @Security BearerAuth
|
||||||
func (a *Ab) PeerAdd(c *gin.Context) {
|
func (a *Ab) PeerAdd(c *gin.Context) {
|
||||||
// forceAlwaysRelay永远是字符串"false"
|
// forceAlwaysRelay is always the string "false"
|
||||||
//f := &gin.H{}
|
//f := &gin.H{}
|
||||||
f := &requstform.PersonalAddressBookForm{}
|
f := &requstform.PersonalAddressBookForm{}
|
||||||
err := c.ShouldBindJSON(f)
|
err := c.ShouldBindJSON(f)
|
||||||
@@ -630,9 +613,9 @@ func (a *Ab) PeerAdd(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PeerDel
|
// PeerDel
|
||||||
// @Tags 地址[Personal]
|
// @Tags address[Personal]
|
||||||
// @Summary 删除地址
|
// @Summary delete address
|
||||||
// @Description 删除地址
|
// @Description delete address
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param guid path string true "guid"
|
// @Param guid path string true "guid"
|
||||||
@@ -678,9 +661,9 @@ func (a *Ab) PeerDel(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PeerUpdate
|
// PeerUpdate
|
||||||
// @Tags 地址[Personal]
|
// @Tags address[Personal]
|
||||||
// @Summary 更新地址
|
// @Summary update address
|
||||||
// @Description 更新地址
|
// @Description update address
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param guid path string true "guid"
|
// @Param guid path string true "guid"
|
||||||
@@ -710,7 +693,7 @@ func (a *Ab) PeerUpdate(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
//fmt.Println(f)
|
//fmt.Println(f)
|
||||||
//判断f["Id"]是否存在
|
// determine whether f["Id"] exists
|
||||||
fid, ok := f["id"]
|
fid, ok := f["id"]
|
||||||
if !ok {
|
if !ok {
|
||||||
response.Error(c, response.TranslateMsg(c, "ParamsError"))
|
response.Error(c, response.TranslateMsg(c, "ParamsError"))
|
||||||
@@ -723,9 +706,9 @@ func (a *Ab) PeerUpdate(c *gin.Context) {
|
|||||||
response.Error(c, response.TranslateMsg(c, "ItemNotFound"))
|
response.Error(c, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//允许的字段
|
//allowed fields
|
||||||
allowUp := []string{"password", "hash", "tags", "alias"}
|
allowUp := []string{"password", "hash", "tags", "alias"}
|
||||||
//f中的字段如果不在allowUp中,就删除
|
// if a field in f is not in allowUp, delete it
|
||||||
for k := range f {
|
for k := range f {
|
||||||
if !utils.InArray(k, allowUp) {
|
if !utils.InArray(k, allowUp) {
|
||||||
delete(f, k)
|
delete(f, k)
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
request "Gwen/http/request/api"
|
|
||||||
"Gwen/http/response"
|
|
||||||
"Gwen/model"
|
|
||||||
"Gwen/service"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/gin-gonic/gin/binding"
|
"github.com/gin-gonic/gin/binding"
|
||||||
|
request "github.com/lejianwen/rustdesk-api/v2/http/request/api"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -14,12 +14,12 @@ type Audit struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AuditConn
|
// AuditConn
|
||||||
// @Tags 审计
|
// @Tags audit
|
||||||
// @Summary 审计连接
|
// @Summary audit connection
|
||||||
// @Description 审计连接
|
// @Description audit connection
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body request.AuditConnForm true "审计连接"
|
// @Param body body request.AuditConnForm true "audit connection"
|
||||||
// @Success 200 {string} string ""
|
// @Success 200 {string} string ""
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /audit/conn [post]
|
// @Router /audit/conn [post]
|
||||||
@@ -59,12 +59,12 @@ func (a *Audit) AuditConn(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AuditFile
|
// AuditFile
|
||||||
// @Tags 审计
|
// @Tags audit
|
||||||
// @Summary 审计文件
|
// @Summary audit file
|
||||||
// @Description 审计文件
|
// @Description audit file
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body request.AuditFileForm true "审计文件"
|
// @Param body body request.AuditFileForm true "audit file"
|
||||||
// @Success 200 {string} string ""
|
// @Success 200 {string} string ""
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /audit/file [post]
|
// @Router /audit/file [post]
|
||||||
|
|||||||
@@ -1,27 +1,27 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
apiReq "Gwen/http/request/api"
|
|
||||||
"Gwen/http/response"
|
|
||||||
apiResp "Gwen/http/response/api"
|
|
||||||
"Gwen/model"
|
|
||||||
"Gwen/service"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
apiReq "github.com/lejianwen/rustdesk-api/v2/http/request/api"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||||
|
apiResp "github.com/lejianwen/rustdesk-api/v2/http/response/api"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Group struct {
|
type Group struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Users 用户列表
|
// Users user list
|
||||||
// @Tags 群组
|
// @Tags group
|
||||||
// @Summary 用户列表
|
// @Summary user list
|
||||||
// @Description 用户列表
|
// @Description user list
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param page query int false "页码"
|
// @Param page query int false "page number"
|
||||||
// @Param pageSize query int false "每页数量"
|
// @Param pageSize query int false "items per page"
|
||||||
// @Param status query int false "状态"
|
// @Param status query int false "status"
|
||||||
// @Param accessible query string false "accessible"
|
// @Param accessible query string false "accessible"
|
||||||
// @Success 200 {object} response.DataResponse{data=[]apiResp.UserPayload}
|
// @Success 200 {object} response.DataResponse{data=[]apiResp.UserPayload}
|
||||||
// @Failure 500 {object} response.ErrorResponse
|
// @Failure 500 {object} response.ErrorResponse
|
||||||
@@ -38,14 +38,14 @@ func (g *Group) Users(c *gin.Context) {
|
|||||||
gr := service.AllService.GroupService.InfoById(u.GroupId)
|
gr := service.AllService.GroupService.InfoById(u.GroupId)
|
||||||
userList := &model.UserList{}
|
userList := &model.UserList{}
|
||||||
if !*u.IsAdmin && gr.Type != model.GroupTypeShare {
|
if !*u.IsAdmin && gr.Type != model.GroupTypeShare {
|
||||||
//仅能获取到自己
|
//can only retrieve one's own
|
||||||
userList.Users = append(userList.Users, u)
|
userList.Users = append(userList.Users, u)
|
||||||
userList.Total = 1
|
userList.Total = 1
|
||||||
} else {
|
} else {
|
||||||
userList = service.AllService.UserService.ListByGroupId(u.GroupId, q.Page, q.PageSize)
|
userList = service.AllService.UserService.ListByGroupId(u.GroupId, q.Page, q.PageSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
var data []*apiResp.UserPayload
|
data := make([]*apiResp.UserPayload, 0, len(userList.Users))
|
||||||
for _, user := range userList.Users {
|
for _, user := range userList.Users {
|
||||||
up := &apiResp.UserPayload{}
|
up := &apiResp.UserPayload{}
|
||||||
up.FromUser(user)
|
up.FromUser(user)
|
||||||
@@ -58,14 +58,14 @@ func (g *Group) Users(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Peers
|
// Peers
|
||||||
// @Tags 群组
|
// @Tags group
|
||||||
// @Summary 机器
|
// @Summary machine
|
||||||
// @Description 机器
|
// @Description machine
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param page query int false "页码"
|
// @Param page query int false "page number"
|
||||||
// @Param pageSize query int false "每页数量"
|
// @Param pageSize query int false "items per page"
|
||||||
// @Param status query int false "状态"
|
// @Param status query int false "status"
|
||||||
// @Param accessible query string false "accessible"
|
// @Param accessible query string false "accessible"
|
||||||
// @Success 200 {object} response.DataResponse
|
// @Success 200 {object} response.DataResponse
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
@@ -82,27 +82,36 @@ func (g *Group) Peers(c *gin.Context) {
|
|||||||
gr := service.AllService.GroupService.InfoById(u.GroupId)
|
gr := service.AllService.GroupService.InfoById(u.GroupId)
|
||||||
users := make([]*model.User, 0, 1)
|
users := make([]*model.User, 0, 1)
|
||||||
if !*u.IsAdmin && gr.Type != model.GroupTypeShare {
|
if !*u.IsAdmin && gr.Type != model.GroupTypeShare {
|
||||||
//仅能获取到自己
|
//can only retrieve one's own
|
||||||
users = append(users, u)
|
users = append(users, u)
|
||||||
} else {
|
} 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, len(users))
|
||||||
userIds := make([]uint, 0)
|
userIds := make([]uint, 0, len(users))
|
||||||
for _, user := range users {
|
for _, user := range users {
|
||||||
namesById[user.Id] = user.Username
|
namesById[user.Id] = user.Username
|
||||||
userIds = append(userIds, user.Id)
|
userIds = append(userIds, user.Id)
|
||||||
}
|
}
|
||||||
|
dGroupNameById := make(map[uint]string)
|
||||||
|
allGroup := service.AllService.GroupService.DeviceGroupList(1, 999, nil)
|
||||||
|
for _, group := range allGroup.DeviceGroups {
|
||||||
|
dGroupNameById[group.Id] = group.Name
|
||||||
|
}
|
||||||
peerList := service.AllService.PeerService.ListByUserIds(userIds, q.Page, q.PageSize)
|
peerList := service.AllService.PeerService.ListByUserIds(userIds, q.Page, q.PageSize)
|
||||||
var data []*apiResp.GroupPeerPayload
|
data := make([]*apiResp.GroupPeerPayload, 0, len(peerList.Peers))
|
||||||
for _, peer := range peerList.Peers {
|
for _, peer := range peerList.Peers {
|
||||||
uname, ok := namesById[peer.UserId]
|
uname, ok := namesById[peer.UserId]
|
||||||
if !ok {
|
if !ok {
|
||||||
uname = ""
|
uname = ""
|
||||||
}
|
}
|
||||||
|
dGroupName, ok2 := dGroupNameById[peer.GroupId]
|
||||||
|
if !ok2 {
|
||||||
|
dGroupName = ""
|
||||||
|
}
|
||||||
pp := &apiResp.GroupPeerPayload{}
|
pp := &apiResp.GroupPeerPayload{}
|
||||||
pp.FromPeer(peer, uname)
|
pp.FromPeer(peer, uname, dGroupName)
|
||||||
data = append(data, pp)
|
data = append(data, pp)
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -111,3 +120,31 @@ func (g *Group) Peers(c *gin.Context) {
|
|||||||
Data: data,
|
Data: data,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Device
|
||||||
|
// @Tags group
|
||||||
|
// @Summary device
|
||||||
|
// @Description machine
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param page query int false "page number"
|
||||||
|
// @Param pageSize query int false "items per page"
|
||||||
|
// @Param status query int false "status"
|
||||||
|
// @Param accessible query string false "accessible"
|
||||||
|
// @Success 200 {object} response.DataResponse
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /device-group/accessible [get]
|
||||||
|
// @Security BearerAuth
|
||||||
|
func (g *Group) Device(c *gin.Context) {
|
||||||
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
if !service.AllService.UserService.IsAdmin(u) {
|
||||||
|
response.Error(c, "Permission denied")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
allGroup := service.AllService.GroupService.DeviceGroupList(1, 999, nil)
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, response.DataResponse{
|
||||||
|
Total: 0,
|
||||||
|
Data: allGroup.DeviceGroups,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
requstform "Gwen/http/request/api"
|
|
||||||
"Gwen/http/response"
|
|
||||||
"Gwen/model"
|
|
||||||
"Gwen/service"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
requstform "github.com/lejianwen/rustdesk-api/v2/http/request/api"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -13,10 +13,10 @@ import (
|
|||||||
type Index struct {
|
type Index struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Index 首页
|
// Index home
|
||||||
// @Tags 首页
|
// @Tags home
|
||||||
// @Summary 首页
|
// @Summary home
|
||||||
// @Description 首页
|
// @Description home
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
@@ -29,10 +29,10 @@ func (i *Index) Index(c *gin.Context) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Heartbeat 心跳
|
// Heartbeat heartbeat
|
||||||
// @Tags 首页
|
// @Tags home
|
||||||
// @Summary 心跳
|
// @Summary heartbeat
|
||||||
// @Description 心跳
|
// @Description heartbeat
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} nil
|
// @Success 200 {object} nil
|
||||||
@@ -49,15 +49,33 @@ func (i *Index) Heartbeat(c *gin.Context) {
|
|||||||
c.JSON(http.StatusOK, gin.H{})
|
c.JSON(http.StatusOK, gin.H{})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
peer := service.AllService.PeerService.FindByUuid(info.Uuid)
|
peer := service.AllService.PeerService.FindById(info.Id)
|
||||||
if peer == nil || peer.RowId == 0 {
|
if peer == nil || peer.RowId == 0 {
|
||||||
c.JSON(http.StatusOK, gin.H{})
|
c.JSON(http.StatusOK, gin.H{})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//如果在40s以内则不更新
|
// do not update if within 40s
|
||||||
if time.Now().Unix()-peer.LastOnlineTime > 40 {
|
if time.Now().Unix()-peer.LastOnlineTime >= 30 {
|
||||||
upp := &model.Peer{RowId: peer.RowId, LastOnlineTime: time.Now().Unix(), LastOnlineIp: c.ClientIP()}
|
upp := &model.Peer{RowId: peer.RowId, LastOnlineTime: time.Now().Unix(), LastOnlineIp: c.ClientIP()}
|
||||||
service.AllService.PeerService.Update(upp)
|
service.AllService.PeerService.Update(upp)
|
||||||
}
|
}
|
||||||
c.JSON(http.StatusOK, gin.H{})
|
c.JSON(http.StatusOK, gin.H{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Version version
|
||||||
|
// @Tags home
|
||||||
|
// @Summary version
|
||||||
|
// @Description version
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /version [get]
|
||||||
|
func (i *Index) Version(c *gin.Context) {
|
||||||
|
// read the resources/version file
|
||||||
|
v := service.AllService.AppService.GetAppVersion()
|
||||||
|
response.Success(
|
||||||
|
c,
|
||||||
|
v,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,36 +1,46 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"Gwen/global"
|
|
||||||
"Gwen/http/request/api"
|
|
||||||
"Gwen/http/response"
|
|
||||||
apiResp "Gwen/http/response/api"
|
|
||||||
"Gwen/model"
|
|
||||||
"Gwen/service"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/request/api"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||||
|
apiResp "github.com/lejianwen/rustdesk-api/v2/http/response/api"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Login struct {
|
type Login struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Login 登录
|
// Login login
|
||||||
// @Tags 登录
|
// @Tags login
|
||||||
// @Summary 登录
|
// @Summary login
|
||||||
// @Description 登录
|
// @Description login
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body api.LoginForm true "登录表单"
|
// @Param body body api.LoginForm true "login form"
|
||||||
// @Success 200 {object} apiResp.LoginRes
|
// @Success 200 {object} apiResp.LoginRes
|
||||||
// @Failure 500 {object} response.ErrorResponse
|
// @Failure 500 {object} response.ErrorResponse
|
||||||
// @Router /login [post]
|
// @Router /login [post]
|
||||||
func (l *Login) Login(c *gin.Context) {
|
func (l *Login) Login(c *gin.Context) {
|
||||||
|
if global.Config.App.DisablePwdLogin {
|
||||||
|
response.Error(c, response.TranslateMsg(c, "PwdLoginDisabled"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// check login limit
|
||||||
|
loginLimiter := global.LoginLimiter
|
||||||
|
clientIp := c.ClientIP()
|
||||||
|
|
||||||
f := &api.LoginForm{}
|
f := &api.LoginForm{}
|
||||||
err := c.ShouldBindJSON(f)
|
err := c.ShouldBindJSON(f)
|
||||||
//fmt.Println(f)
|
//fmt.Println(f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
loginLimiter.RecordFailedAttempt(clientIp)
|
||||||
global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "ParamsError", c.RemoteIP(), c.ClientIP()))
|
global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "ParamsError", c.RemoteIP(), c.ClientIP()))
|
||||||
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
|
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
return
|
return
|
||||||
@@ -38,6 +48,7 @@ func (l *Login) Login(c *gin.Context) {
|
|||||||
|
|
||||||
errList := global.Validator.ValidStruct(c, f)
|
errList := global.Validator.ValidStruct(c, f)
|
||||||
if len(errList) > 0 {
|
if len(errList) > 0 {
|
||||||
|
loginLimiter.RecordFailedAttempt(clientIp)
|
||||||
global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "ParamsError", c.RemoteIP(), c.ClientIP()))
|
global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "ParamsError", c.RemoteIP(), c.ClientIP()))
|
||||||
response.Error(c, errList[0])
|
response.Error(c, errList[0])
|
||||||
return
|
return
|
||||||
@@ -46,12 +57,18 @@ func (l *Login) Login(c *gin.Context) {
|
|||||||
u := service.AllService.UserService.InfoByUsernamePassword(f.Username, f.Password)
|
u := service.AllService.UserService.InfoByUsernamePassword(f.Username, f.Password)
|
||||||
|
|
||||||
if u.Id == 0 {
|
if u.Id == 0 {
|
||||||
|
loginLimiter.RecordFailedAttempt(clientIp)
|
||||||
global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "UsernameOrPasswordError", c.RemoteIP(), c.ClientIP()))
|
global.Logger.Warn(fmt.Sprintf("Login Fail: %s %s %s", "UsernameOrPasswordError", c.RemoteIP(), c.ClientIP()))
|
||||||
response.Error(c, response.TranslateMsg(c, "UsernameOrPasswordError"))
|
response.Error(c, response.TranslateMsg(c, "UsernameOrPasswordError"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//根据refer判断是webclient还是app
|
if !service.AllService.UserService.CheckUserEnable(u) {
|
||||||
|
response.Error(c, response.TranslateMsg(c, "UserDisabled"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine whether it is webclient or app based on refer
|
||||||
ref := c.GetHeader("referer")
|
ref := c.GetHeader("referer")
|
||||||
if ref != "" {
|
if ref != "" {
|
||||||
f.DeviceInfo.Type = model.LoginLogClientWeb
|
f.DeviceInfo.Type = model.LoginLogClientWeb
|
||||||
@@ -75,9 +92,9 @@ func (l *Login) Login(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// LoginOptions
|
// LoginOptions
|
||||||
// @Tags 登录
|
// @Tags login
|
||||||
// @Summary 登录选项
|
// @Summary login options
|
||||||
// @Description 登录选项
|
// @Description login options
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} []string
|
// @Success 200 {object} []string
|
||||||
@@ -85,7 +102,9 @@ func (l *Login) Login(c *gin.Context) {
|
|||||||
// @Router /login-options [get]
|
// @Router /login-options [get]
|
||||||
func (l *Login) LoginOptions(c *gin.Context) {
|
func (l *Login) LoginOptions(c *gin.Context) {
|
||||||
ops := service.AllService.OauthService.GetOauthProviders()
|
ops := service.AllService.OauthService.GetOauthProviders()
|
||||||
|
if global.Config.App.WebSso {
|
||||||
ops = append(ops, model.OauthTypeWebauth)
|
ops = append(ops, model.OauthTypeWebauth)
|
||||||
|
}
|
||||||
var oidcItems []map[string]string
|
var oidcItems []map[string]string
|
||||||
for _, v := range ops {
|
for _, v := range ops {
|
||||||
oidcItems = append(oidcItems, map[string]string{"name": v})
|
oidcItems = append(oidcItems, map[string]string{"name": v})
|
||||||
@@ -104,9 +123,9 @@ func (l *Login) LoginOptions(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Logout
|
// Logout
|
||||||
// @Tags 登录
|
// @Tags login
|
||||||
// @Summary 登出
|
// @Summary logout
|
||||||
// @Description 登出
|
// @Description logout
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {string} string
|
// @Success 200 {string} string
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"Gwen/global"
|
|
||||||
"Gwen/http/request/api"
|
|
||||||
"Gwen/http/response"
|
|
||||||
apiResp "Gwen/http/response/api"
|
|
||||||
"Gwen/model"
|
|
||||||
"Gwen/service"
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/request/api"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||||
|
apiResp "github.com/lejianwen/rustdesk-api/v2/http/response/api"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/model"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/utils"
|
||||||
|
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Oauth struct {
|
type Oauth struct {
|
||||||
@@ -32,15 +35,14 @@ func (o *Oauth) OidcAuth(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
oauthService := service.AllService.OauthService
|
oauthService := service.AllService.OauthService
|
||||||
var code string
|
|
||||||
var url string
|
err, state, verifier, nonce, url := oauthService.BeginAuth(f.Op)
|
||||||
err, code, url = oauthService.BeginAuth(f.Op)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.Error(c, response.TranslateMsg(c, err.Error()))
|
response.Error(c, response.TranslateMsg(c, err.Error()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
service.AllService.OauthService.SetOauthCache(code, &service.OauthCacheItem{
|
service.AllService.OauthService.SetOauthCache(state, &service.OauthCacheItem{
|
||||||
Action: service.OauthActionTypeLogin,
|
Action: service.OauthActionTypeLogin,
|
||||||
Id: f.Id,
|
Id: f.Id,
|
||||||
Op: f.Op,
|
Op: f.Op,
|
||||||
@@ -48,10 +50,12 @@ func (o *Oauth) OidcAuth(c *gin.Context) {
|
|||||||
DeviceName: f.DeviceInfo.Name,
|
DeviceName: f.DeviceInfo.Name,
|
||||||
DeviceOs: f.DeviceInfo.Os,
|
DeviceOs: f.DeviceInfo.Os,
|
||||||
DeviceType: f.DeviceInfo.Type,
|
DeviceType: f.DeviceInfo.Type,
|
||||||
|
Verifier: verifier,
|
||||||
|
Nonce: nonce,
|
||||||
}, 5*60)
|
}, 5*60)
|
||||||
//fmt.Println("code url", code, url)
|
//fmt.Println("code url", code, url)
|
||||||
c.JSON(http.StatusOK, gin.H{
|
c.JSON(http.StatusOK, gin.H{
|
||||||
"code": code,
|
"code": state,
|
||||||
"url": url,
|
"url": url,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -61,36 +65,37 @@ func (o *Oauth) OidcAuthQueryPre(c *gin.Context) (*model.User, *model.UserToken)
|
|||||||
var ut *model.UserToken
|
var ut *model.UserToken
|
||||||
q := &api.OidcAuthQuery{}
|
q := &api.OidcAuthQuery{}
|
||||||
|
|
||||||
// 解析查询参数并处理错误
|
// parse query parameters and handle errors
|
||||||
if err := c.ShouldBindQuery(q); err != nil {
|
if err := c.ShouldBindQuery(q); err != nil {
|
||||||
response.Error(c, response.TranslateMsg(c, "ParamsError")+": "+err.Error())
|
response.Error(c, response.TranslateMsg(c, "ParamsError")+": "+err.Error())
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取 OAuth 缓存
|
// get OAuth cache
|
||||||
v := service.AllService.OauthService.GetOauthCache(q.Code)
|
v := service.AllService.OauthService.GetOauthCache(q.Code)
|
||||||
if v == nil {
|
if v == nil {
|
||||||
response.Error(c, response.TranslateMsg(c, "OauthExpired"))
|
response.Error(c, response.TranslateMsg(c, "OauthExpired"))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果 UserId 为 0,说明还在授权中
|
// if UserId is 0, authorization is still in progress
|
||||||
if v.UserId == 0 {
|
if v.UserId == 0 {
|
||||||
c.JSON(http.StatusOK, gin.H{"message": "Authorization in progress, please login and bind"})
|
//fix: 1.4.2 webclient oidc
|
||||||
|
c.JSON(http.StatusOK, gin.H{"message": "Authorization in progress, please login and bind", "error": "No authed oidc is found"})
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取用户信息
|
// get user info
|
||||||
u = service.AllService.UserService.InfoById(v.UserId)
|
u = service.AllService.UserService.InfoById(v.UserId)
|
||||||
if u == nil {
|
if u == nil {
|
||||||
response.Error(c, response.TranslateMsg(c, "UserNotFound"))
|
response.Error(c, response.TranslateMsg(c, "UserNotFound"))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除 OAuth 缓存
|
// delete OAuth cache
|
||||||
service.AllService.OauthService.DeleteOauthCache(q.Code)
|
service.AllService.OauthService.DeleteOauthCache(q.Code)
|
||||||
|
|
||||||
// 创建登录日志并生成用户令牌
|
// create a login log and generate a user token
|
||||||
ut = service.AllService.UserService.Login(u, &model.LoginLog{
|
ut = service.AllService.UserService.Login(u, &model.LoginLog{
|
||||||
UserId: u.Id,
|
UserId: u.Id,
|
||||||
Client: v.DeviceType,
|
Client: v.DeviceType,
|
||||||
@@ -106,7 +111,7 @@ func (o *Oauth) OidcAuthQueryPre(c *gin.Context) (*model.User, *model.UserToken)
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 返回用户令牌
|
// return user token
|
||||||
return u, ut
|
return u, ut
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,7 +136,7 @@ func (o *Oauth) OidcAuthQuery(c *gin.Context) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// OauthCallback 回调
|
// OauthCallback callback
|
||||||
// @Tags Oauth
|
// @Tags Oauth
|
||||||
// @Summary OauthCallback
|
// @Summary OauthCallback
|
||||||
// @Description OauthCallback
|
// @Description OauthCallback
|
||||||
@@ -139,29 +144,39 @@ func (o *Oauth) OidcAuthQuery(c *gin.Context) {
|
|||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} apiResp.LoginRes
|
// @Success 200 {object} apiResp.LoginRes
|
||||||
// @Failure 500 {object} response.ErrorResponse
|
// @Failure 500 {object} response.ErrorResponse
|
||||||
// @Router /oauth/callback [get]
|
// @Router /oidc/callback [get]
|
||||||
func (o *Oauth) OauthCallback(c *gin.Context) {
|
func (o *Oauth) OauthCallback(c *gin.Context) {
|
||||||
state := c.Query("state")
|
state := c.Query("state")
|
||||||
if state == "" {
|
if state == "" {
|
||||||
c.String(http.StatusInternalServerError, response.TranslateParamMsg(c, "ParamIsEmpty", "state"))
|
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
||||||
|
"message": "ParamIsEmpty",
|
||||||
|
"sub_message": "state",
|
||||||
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cacheKey := state
|
cacheKey := state
|
||||||
oauthService := service.AllService.OauthService
|
oauthService := service.AllService.OauthService
|
||||||
//从缓存中获取
|
//get from cache
|
||||||
oauthCache := oauthService.GetOauthCache(cacheKey)
|
oauthCache := oauthService.GetOauthCache(cacheKey)
|
||||||
if oauthCache == nil {
|
if oauthCache == nil {
|
||||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthExpired"))
|
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
||||||
|
"message": "OauthExpired",
|
||||||
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
nonce := oauthCache.Nonce
|
||||||
op := oauthCache.Op
|
op := oauthCache.Op
|
||||||
action := oauthCache.Action
|
action := oauthCache.Action
|
||||||
|
verifier := oauthCache.Verifier
|
||||||
var user *model.User
|
var user *model.User
|
||||||
// 获取用户信息
|
// get user info
|
||||||
code := c.Query("code")
|
code := c.Query("code")
|
||||||
err, oauthUser := oauthService.Callback(code, op)
|
err, oauthUser := oauthService.Callback(code, verifier, op, nonce)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthFailed")+response.TranslateMsg(c, err.Error()))
|
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
||||||
|
"message": "OauthFailed",
|
||||||
|
"sub_message": err.Error(),
|
||||||
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
userId := oauthCache.UserId
|
userId := oauthCache.UserId
|
||||||
@@ -169,54 +184,65 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
|
|||||||
if action == service.OauthActionTypeBind {
|
if action == service.OauthActionTypeBind {
|
||||||
|
|
||||||
//fmt.Println("bind", ty, userData)
|
//fmt.Println("bind", ty, userData)
|
||||||
// 检查此openid是否已经绑定过
|
// check whether this openid has already been bound
|
||||||
utr := oauthService.UserThirdInfo(op, openid)
|
utr := oauthService.UserThirdInfo(op, openid)
|
||||||
if utr.UserId > 0 {
|
if utr.UserId > 0 {
|
||||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBindOtherUser"))
|
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
||||||
|
"message": "OauthHasBindOtherUser",
|
||||||
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//绑定
|
//bind
|
||||||
user = service.AllService.UserService.InfoById(userId)
|
user = service.AllService.UserService.InfoById(userId)
|
||||||
if user == nil {
|
if user == nil {
|
||||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "ItemNotFound"))
|
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
||||||
|
"message": "ItemNotFound",
|
||||||
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//绑定
|
//bind
|
||||||
err := oauthService.BindOauthUser(userId, oauthUser, op)
|
err := oauthService.BindOauthUser(userId, oauthUser, op)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "BindFail"))
|
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
||||||
|
"message": "BindFail",
|
||||||
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.String(http.StatusOK, response.TranslateMsg(c, "BindSuccess"))
|
c.HTML(http.StatusOK, "oauth_success.html", gin.H{
|
||||||
|
"message": "BindSuccess",
|
||||||
|
})
|
||||||
return
|
return
|
||||||
|
|
||||||
} else if action == service.OauthActionTypeLogin {
|
} else if action == service.OauthActionTypeLogin {
|
||||||
//登录
|
//login
|
||||||
if userId != 0 {
|
if userId != 0 {
|
||||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBeenSuccess"))
|
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
||||||
|
"message": "OauthHasBeenSuccess",
|
||||||
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
user = service.AllService.UserService.InfoByOauthId(op, openid)
|
user = service.AllService.UserService.InfoByOauthId(op, openid)
|
||||||
if user == nil {
|
if user == nil {
|
||||||
oauthConfig := oauthService.InfoByOp(op)
|
oauthConfig := oauthService.InfoByOp(op)
|
||||||
if !*oauthConfig.AutoRegister {
|
if !*oauthConfig.AutoRegister {
|
||||||
//c.String(http.StatusInternalServerError, "还未绑定用户,请先绑定")
|
//c.String(http.StatusInternalServerError, "not yet bound to a user, please bind first")
|
||||||
oauthCache.UpdateFromOauthUser(oauthUser)
|
oauthCache.UpdateFromOauthUser(oauthUser)
|
||||||
url := global.Config.Rustdesk.ApiServer + "/_admin/#/oauth/bind/" + cacheKey
|
c.Redirect(http.StatusFound, "/_admin/#/oauth/bind/"+cacheKey)
|
||||||
c.Redirect(http.StatusFound, url)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//自动注册
|
//auto register
|
||||||
err, user = service.AllService.UserService.RegisterByOauth(oauthUser, op)
|
err, user = service.AllService.UserService.RegisterByOauth(oauthUser, op)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, err.Error()))
|
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
||||||
|
"message": err.Error(),
|
||||||
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
oauthCache.UserId = user.Id
|
oauthCache.UserId = user.Id
|
||||||
oauthService.SetOauthCache(cacheKey, oauthCache, 0)
|
oauthService.SetOauthCache(cacheKey, oauthCache, 0)
|
||||||
// 如果是webadmin,登录成功后跳转到webadmin
|
// if it is webadmin, after successful login redirect to webadmin
|
||||||
if oauthCache.DeviceType == model.LoginLogClientWebAdmin {
|
if oauthCache.DeviceType == model.LoginLogClientWebAdmin {
|
||||||
/*service.AllService.UserService.Login(u, &model.LoginLog{
|
/*service.AllService.UserService.Login(u, &model.LoginLog{
|
||||||
UserId: u.Id,
|
UserId: u.Id,
|
||||||
@@ -226,15 +252,54 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
|
|||||||
Type: model.LoginLogTypeOauth,
|
Type: model.LoginLogTypeOauth,
|
||||||
Platform: oauthService.DeviceOs,
|
Platform: oauthService.DeviceOs,
|
||||||
})*/
|
})*/
|
||||||
url := global.Config.Rustdesk.ApiServer + "/_admin/#/"
|
c.Redirect(http.StatusFound, "/_admin/#/")
|
||||||
c.Redirect(http.StatusFound, url)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.String(http.StatusOK, response.TranslateMsg(c, "OauthSuccess"))
|
c.HTML(http.StatusOK, "oauth_success.html", gin.H{
|
||||||
|
"message": "OauthSuccess",
|
||||||
|
})
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "ParamsError"))
|
c.HTML(http.StatusOK, "oauth_fail.html", gin.H{
|
||||||
|
"message": "ParamsError",
|
||||||
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MessageParams struct {
|
||||||
|
Lang string `json:"lang" form:"lang"`
|
||||||
|
Title string `json:"title" form:"title"`
|
||||||
|
Msg string `json:"msg" form:"msg"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Oauth) Message(c *gin.Context) {
|
||||||
|
mp := &MessageParams{}
|
||||||
|
if err := c.ShouldBindQuery(mp); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
localizer := global.Localizer(mp.Lang)
|
||||||
|
res := ""
|
||||||
|
if mp.Title != "" {
|
||||||
|
title, err := localizer.LocalizeMessage(&i18n.Message{
|
||||||
|
ID: mp.Title,
|
||||||
|
})
|
||||||
|
if err == nil {
|
||||||
|
res = utils.StringConcat(";title='", title, "';")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if mp.Msg != "" {
|
||||||
|
msg, err := localizer.LocalizeMessage(&i18n.Message{
|
||||||
|
ID: mp.Msg,
|
||||||
|
})
|
||||||
|
if err == nil {
|
||||||
|
res = utils.StringConcat(res, "msg = '", msg, "';")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//returnjscontent
|
||||||
|
c.Header("Content-Type", "application/javascript")
|
||||||
|
c.String(http.StatusOK, res)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
requstform "Gwen/http/request/api"
|
"fmt"
|
||||||
"Gwen/http/response"
|
|
||||||
"Gwen/service"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/gin-gonic/gin/binding"
|
"github.com/gin-gonic/gin/binding"
|
||||||
|
requstform "github.com/lejianwen/rustdesk-api/v2/http/request/api"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -13,12 +14,12 @@ type Peer struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SysInfo
|
// SysInfo
|
||||||
// @Tags 地址
|
// @Tags System
|
||||||
// @Summary 提交系统信息
|
// @Summary submit system info
|
||||||
// @Description 提交系统信息
|
// @Description submit system info
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body requstform.PeerForm true "系统信息表单"
|
// @Param body body requstform.PeerForm true "system info form"
|
||||||
// @Success 200 {string} string "SYSINFO_UPDATED,ID_NOT_FOUND"
|
// @Success 200 {string} string "SYSINFO_UPDATED,ID_NOT_FOUND"
|
||||||
// @Failure 500 {object} response.ErrorResponse
|
// @Failure 500 {object} response.ErrorResponse
|
||||||
// @Router /sysinfo [post]
|
// @Router /sysinfo [post]
|
||||||
@@ -33,7 +34,7 @@ func (p *Peer) SysInfo(c *gin.Context) {
|
|||||||
pe := service.AllService.PeerService.FindById(f.Id)
|
pe := service.AllService.PeerService.FindById(f.Id)
|
||||||
if pe.RowId == 0 {
|
if pe.RowId == 0 {
|
||||||
pe = f.ToPeer()
|
pe = f.ToPeer()
|
||||||
pe.UserId = service.AllService.UserService.FindLatestUserIdFromLoginLogByUuid(pe.Uuid)
|
pe.UserId = service.AllService.UserService.FindLatestUserIdFromLoginLogByUuid(pe.Uuid, pe.Id)
|
||||||
err = service.AllService.PeerService.Create(pe)
|
err = service.AllService.PeerService.Create(pe)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.Error(c, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
response.Error(c, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
@@ -41,7 +42,7 @@ func (p *Peer) SysInfo(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if pe.UserId == 0 {
|
if pe.UserId == 0 {
|
||||||
pe.UserId = service.AllService.UserService.FindLatestUserIdFromLoginLogByUuid(pe.Uuid)
|
pe.UserId = service.AllService.UserService.FindLatestUserIdFromLoginLogByUuid(pe.Uuid, pe.Id)
|
||||||
}
|
}
|
||||||
fpe.RowId = pe.RowId
|
fpe.RowId = pe.RowId
|
||||||
fpe.UserId = pe.UserId
|
fpe.UserId = pe.UserId
|
||||||
@@ -51,8 +52,25 @@ func (p *Peer) SysInfo(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//SYSINFO_UPDATED 上传成功
|
//SYSINFO_UPDATED upload successful
|
||||||
//ID_NOT_FOUND 下次心跳会上传
|
//ID_NOT_FOUND will be uploaded on the next heartbeat
|
||||||
//直接响应文本
|
//respond with text directly
|
||||||
c.String(http.StatusOK, "SYSINFO_UPDATED")
|
c.String(http.StatusOK, "SYSINFO_UPDATED")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SysInfoVer
|
||||||
|
// @Tags System
|
||||||
|
// @Summary get system version info
|
||||||
|
// @Description get system version info
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {string} string ""
|
||||||
|
// @Failure 500 {object} response.ErrorResponse
|
||||||
|
// @Router /sysinfo_ver [post]
|
||||||
|
func (p *Peer) SysInfoVer(c *gin.Context) {
|
||||||
|
// read the resources/version file
|
||||||
|
v := service.AllService.AppService.GetAppVersion()
|
||||||
|
// add the start time so the client can conveniently upload info
|
||||||
|
v = fmt.Sprintf("%s\n%s", v, service.AllService.AppService.GetStartTime())
|
||||||
|
c.String(http.StatusOK, v)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
apiResp "Gwen/http/response/api"
|
|
||||||
"Gwen/service"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
apiResp "github.com/lejianwen/rustdesk-api/v2/http/response/api"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// currentUser 当前用户
|
// currentUser current user
|
||||||
// @Tags 用户
|
// @Tags user
|
||||||
// @Summary 用户信息
|
// @Summary user info
|
||||||
// @Description 用户信息
|
// @Description user info
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} apiResp.UserPayload
|
// @Success 200 {object} apiResp.UserPayload
|
||||||
@@ -26,15 +26,15 @@ type User struct {
|
|||||||
// c.JSON(http.StatusOK, up)
|
// c.JSON(http.StatusOK, up)
|
||||||
//}
|
//}
|
||||||
|
|
||||||
// Info 用户信息
|
// Info user info
|
||||||
// @Tags 用户
|
// @Tags user
|
||||||
// @Summary 用户信息
|
// @Summary user info
|
||||||
// @Description 用户信息
|
// @Description user info
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} apiResp.UserPayload
|
// @Success 200 {object} apiResp.UserPayload
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /api [get]
|
// @Router /currentUser [get]
|
||||||
// @Security token
|
// @Security token
|
||||||
func (u *User) Info(c *gin.Context) {
|
func (u *User) Info(c *gin.Context) {
|
||||||
user := service.AllService.UserService.CurUser(c)
|
user := service.AllService.UserService.CurUser(c)
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"Gwen/global"
|
|
||||||
"Gwen/http/response"
|
|
||||||
"Gwen/http/response/api"
|
|
||||||
"Gwen/service"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/response/api"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type WebClient struct {
|
type WebClient struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServerConfig 服务配置
|
// ServerConfig service config
|
||||||
// @Tags WEBCLIENT
|
// @Tags WEBCLIENT
|
||||||
// @Summary 服务配置
|
// @Summary service config
|
||||||
// @Description 服务配置,给webclient提供api-server
|
// @Description service config, provides an api-server for the webclient
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
@@ -26,7 +26,7 @@ func (i *WebClient) ServerConfig(c *gin.Context) {
|
|||||||
u := service.AllService.UserService.CurUser(c)
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
|
||||||
peers := map[string]*api.WebClientPeerPayload{}
|
peers := map[string]*api.WebClientPeerPayload{}
|
||||||
abs := service.AllService.AddressBookService.ListByUserId(u.Id, 1, 100)
|
abs := service.AllService.AddressBookService.ListByUserIdAndCollectionId(u.Id, 0, 1, 100)
|
||||||
for _, ab := range abs.AddressBooks {
|
for _, ab := range abs.AddressBooks {
|
||||||
pp := &api.WebClientPeerPayload{}
|
pp := &api.WebClientPeerPayload{}
|
||||||
pp.FromAddressBook(ab)
|
pp.FromAddressBook(ab)
|
||||||
@@ -42,10 +42,10 @@ func (i *WebClient) ServerConfig(c *gin.Context) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SharedPeer 分享的peer
|
// SharedPeer shared peer
|
||||||
// @Tags WEBCLIENT
|
// @Tags WEBCLIENT
|
||||||
// @Summary 分享的peer
|
// @Summary shared peer
|
||||||
// @Description 分享的peer
|
// @Description shared peer
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
@@ -64,12 +64,15 @@ func (i *WebClient) SharedPeer(c *gin.Context) {
|
|||||||
response.Fail(c, 101, "share not found")
|
response.Fail(c, 101, "share not found")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//判断是否过期,created_at + expire > now
|
if sr.Expire != 0 {
|
||||||
|
//check whether expired,created_at + expire > now
|
||||||
ca := time.Time(sr.CreatedAt)
|
ca := time.Time(sr.CreatedAt)
|
||||||
if ca.Add(time.Second * time.Duration(sr.Expire)).Before(time.Now()) {
|
if ca.Add(time.Second * time.Duration(sr.Expire)).Before(time.Now()) {
|
||||||
response.Fail(c, 101, "share expired")
|
response.Fail(c, 101, "share expired")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ab := service.AllService.AddressBookService.InfoByUserIdAndId(sr.UserId, sr.PeerId)
|
ab := service.AllService.AddressBookService.InfoByUserIdAndId(sr.UserId, sr.PeerId)
|
||||||
if ab.RowId == 0 {
|
if ab.RowId == 0 {
|
||||||
response.Fail(c, 101, "peer not found")
|
response.Fail(c, 101, "peer not found")
|
||||||
@@ -86,15 +89,15 @@ func (i *WebClient) SharedPeer(c *gin.Context) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServerConfigV2 服务配置
|
// ServerConfigV2 service config
|
||||||
// @Tags WEBCLIENT_V2
|
// @Tags WEBCLIENT_V2
|
||||||
// @Summary 服务配置
|
// @Summary service config
|
||||||
// @Description 服务配置,给webclient提供api-server
|
// @Description service config, provides an api-server for the webclient
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} response.Response
|
// @Success 200 {object} response.Response
|
||||||
// @Failure 500 {object} response.Response
|
// @Failure 500 {object} response.Response
|
||||||
// @Router /server-config [get]
|
// @Router /server-config-v2 [get]
|
||||||
// @Security token
|
// @Security token
|
||||||
func (i *WebClient) ServerConfigV2(c *gin.Context) {
|
func (i *WebClient) ServerConfigV2(c *gin.Context) {
|
||||||
response.Success(
|
response.Success(
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
package web
|
package web
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"Gwen/global"
|
"fmt"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Index struct {
|
type Index struct {
|
||||||
@@ -14,11 +15,21 @@ func (i *Index) Index(c *gin.Context) {
|
|||||||
|
|
||||||
func (i *Index) ConfigJs(c *gin.Context) {
|
func (i *Index) ConfigJs(c *gin.Context) {
|
||||||
apiServer := global.Config.Rustdesk.ApiServer
|
apiServer := global.Config.Rustdesk.ApiServer
|
||||||
|
magicQueryonline := global.Config.Rustdesk.WebclientMagicQueryonline
|
||||||
|
tmp := fmt.Sprintf(`localStorage.setItem('api-server', '%v');
|
||||||
|
const ws2_prefix = 'wc-';
|
||||||
|
localStorage.setItem(ws2_prefix+'api-server', '%v');
|
||||||
|
|
||||||
tmp := `
|
window.webclient_magic_queryonline = %d;
|
||||||
localStorage.setItem('api-server', "` + apiServer + `")
|
window.ws_host = '%v';
|
||||||
const ws2_prefix = 'wc-'
|
`, apiServer, apiServer, magicQueryonline, global.Config.Rustdesk.WsHost)
|
||||||
localStorage.setItem(ws2_prefix+'api-server', "` + apiServer + `")
|
// tmp := `
|
||||||
`
|
//localStorage.setItem('api-server', "` + apiServer + `")
|
||||||
|
//const ws2_prefix = 'wc-'
|
||||||
|
//localStorage.setItem(ws2_prefix+'api-server', "` + apiServer + `")
|
||||||
|
//
|
||||||
|
//window.webclient_magic_queryonline = ` + magicQueryonline + ``
|
||||||
|
|
||||||
|
c.Header("Content-Type", "application/javascript")
|
||||||
c.String(200, tmp)
|
c.String(200, tmp)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package http
|
package http
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"Gwen/global"
|
|
||||||
"Gwen/http/middleware"
|
|
||||||
"Gwen/http/router"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/middleware"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/router"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -25,7 +25,7 @@ func ApiInit() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if global.Config.Gin.Mode == gin.ReleaseMode {
|
if global.Config.Gin.Mode == gin.ReleaseMode {
|
||||||
//修改gin Recovery日志 输出为logger的输出点
|
// redirect gin's Recovery log output to the logger's output
|
||||||
if global.Logger != nil {
|
if global.Logger != nil {
|
||||||
gin.DefaultErrorWriter = global.Logger.WriterLevel(logrus.ErrorLevel)
|
gin.DefaultErrorWriter = global.Logger.WriterLevel(logrus.ErrorLevel)
|
||||||
}
|
}
|
||||||
@@ -33,7 +33,7 @@ func ApiInit() {
|
|||||||
g.NoRoute(func(c *gin.Context) {
|
g.NoRoute(func(c *gin.Context) {
|
||||||
c.String(http.StatusNotFound, "404 not found")
|
c.String(http.StatusNotFound, "404 not found")
|
||||||
})
|
})
|
||||||
g.Use(middleware.Logger(), gin.Recovery())
|
g.Use(middleware.Logger(), middleware.Limiter(), gin.Recovery())
|
||||||
router.WebInit(g)
|
router.WebInit(g)
|
||||||
router.Init(g)
|
router.Init(g)
|
||||||
router.ApiInit(g)
|
router.ApiInit(g)
|
||||||
|
|||||||
@@ -1,32 +1,40 @@
|
|||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"Gwen/http/response"
|
|
||||||
"Gwen/service"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AdminAuth 后台权限验证中间件
|
// BackendUserAuth backend permission verification middleware
|
||||||
func AdminAuth() gin.HandlerFunc {
|
func BackendUserAuth() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
|
|
||||||
//测试先关闭
|
//disabled for testing
|
||||||
token := c.GetHeader("api-token")
|
token := c.GetHeader("api-token")
|
||||||
if token == "" {
|
if token == "" {
|
||||||
response.Fail(c, 403, "请先登录")
|
response.Fail(c, 403, response.TranslateMsg(c, "NeedLogin"))
|
||||||
c.Abort()
|
c.Abort()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
user, ut := service.AllService.UserService.InfoByAccessToken(token)
|
user, ut := service.AllService.UserService.InfoByAccessToken(token)
|
||||||
if user.Id == 0 {
|
if user.Id == 0 {
|
||||||
response.Fail(c, 403, "请先登录")
|
response.Fail(c, 403, response.TranslateMsg(c, "NeedLogin"))
|
||||||
|
c.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !service.AllService.UserService.CheckUserEnable(user) {
|
||||||
|
c.JSON(401, gin.H{
|
||||||
|
"error": "Unauthorized",
|
||||||
|
})
|
||||||
c.Abort()
|
c.Abort()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Set("curUser", user)
|
c.Set("curUser", user)
|
||||||
c.Set("token", token)
|
c.Set("token", token)
|
||||||
//如果时间小于1天,token自动续期
|
// if the remaining time is less than 1 day, the token is auto-renewed
|
||||||
service.AllService.UserService.AutoRefreshAccessToken(ut)
|
service.AllService.UserService.AutoRefreshAccessToken(ut)
|
||||||
|
|
||||||
c.Next()
|
c.Next()
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"Gwen/http/response"
|
|
||||||
"Gwen/service"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AdminPrivilege ...
|
// AdminPrivilege ...
|
||||||
@@ -12,7 +12,7 @@ func AdminPrivilege() gin.HandlerFunc {
|
|||||||
u := service.AllService.UserService.CurUser(c)
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
|
||||||
if !service.AllService.UserService.IsAdmin(u) {
|
if !service.AllService.UserService.IsAdmin(u) {
|
||||||
response.Fail(c, 403, "无权限")
|
response.Fail(c, 403, response.TranslateMsg(c, "NoAccess"))
|
||||||
c.Abort()
|
c.Abort()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Cors 跨域
|
// Cors CORS
|
||||||
func Cors() gin.HandlerFunc {
|
func Cors() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
origin := c.GetHeader("Origin")
|
origin := c.GetHeader("Origin")
|
||||||
|
|||||||
@@ -1,29 +1,29 @@
|
|||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"Gwen/global"
|
|
||||||
"Gwen/http/response"
|
|
||||||
"Gwen/service"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
func JwtAuth() gin.HandlerFunc {
|
func JwtAuth() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
//测试先关闭
|
//disabled for testing
|
||||||
token := c.GetHeader("api-token")
|
token := c.GetHeader("api-token")
|
||||||
if token == "" {
|
if token == "" {
|
||||||
response.Fail(c, 403, "请先登录")
|
response.Fail(c, 403, response.TranslateMsg(c, "NeedLogin"))
|
||||||
c.Abort()
|
c.Abort()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
uid, err := global.Jwt.ParseToken(token)
|
uid, err := global.Jwt.ParseToken(token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.Fail(c, 403, "请先登录")
|
response.Fail(c, 403, response.TranslateMsg(c, "NeedLogin"))
|
||||||
c.Abort()
|
c.Abort()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if uid == 0 {
|
if uid == 0 {
|
||||||
response.Fail(c, 403, "请先登录")
|
response.Fail(c, 403, response.TranslateMsg(c, "NeedLogin"))
|
||||||
c.Abort()
|
c.Abort()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -31,15 +31,15 @@ func JwtAuth() gin.HandlerFunc {
|
|||||||
user := service.AllService.UserService.InfoById(uid)
|
user := service.AllService.UserService.InfoById(uid)
|
||||||
//user := &model.User{
|
//user := &model.User{
|
||||||
// Id: uid,
|
// Id: uid,
|
||||||
// Username: "测试用户",
|
// Username: "test user",
|
||||||
//}
|
//}
|
||||||
if user.Id == 0 {
|
if user.Id == 0 {
|
||||||
response.Fail(c, 403, "请先登录")
|
response.Fail(c, 403, response.TranslateMsg(c, "NeedLogin"))
|
||||||
c.Abort()
|
c.Abort()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !service.AllService.UserService.CheckUserEnable(user) {
|
if !service.AllService.UserService.CheckUserEnable(user) {
|
||||||
response.Fail(c, 101, "你已被禁用")
|
response.Fail(c, 101, response.TranslateMsg(c, "Banned"))
|
||||||
c.Abort()
|
c.Abort()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/global"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/http/response"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Limiter() gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
loginLimiter := global.LoginLimiter
|
||||||
|
clientIp := c.ClientIP()
|
||||||
|
banned, _ := loginLimiter.CheckSecurityStatus(clientIp)
|
||||||
|
if banned {
|
||||||
|
response.Fail(c, http.StatusLocked, response.TranslateMsg(c, "Banned"))
|
||||||
|
c.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.Next()
|
||||||
|
}
|
||||||
|
}
|
||||||