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 | ||
|
|
3addc12f45 | ||
|
|
1e3403e3c5 | ||
|
|
ae4672174a | ||
|
|
f935fed5f7 | ||
|
|
989990c869 | ||
|
|
8b8a44e46b | ||
|
|
2ed2884118 | ||
|
|
03bd34cadd | ||
|
|
1c3f87fecb | ||
|
|
d45e85d29b | ||
|
|
a4b413dadb | ||
|
|
ebd1feb8d1 | ||
|
|
815ec0f75d | ||
|
|
4c7919e6b7 | ||
|
|
f3218d481c | ||
|
|
5e6e90788b | ||
|
|
579a6400ca | ||
|
|
db4ad69d8f | ||
|
|
b1293189ad | ||
|
|
c8b3d41d9d | ||
|
|
fefb679cfc | ||
|
|
352941a20f | ||
|
|
3006f5bd7c | ||
|
|
d9ed2127da | ||
|
|
f2ee00d49e | ||
|
|
c827a4e335 |
@@ -0,0 +1,29 @@
|
|||||||
|
# Ignore Docker Compose configuration files
|
||||||
|
docker-compose.yaml
|
||||||
|
docker-compose-dev.yaml
|
||||||
|
|
||||||
|
# Ignore development Dockerfile
|
||||||
|
Dockerfile
|
||||||
|
Dockerfile.dev
|
||||||
|
docker-dev.sh
|
||||||
|
|
||||||
|
# Ignore the data directory
|
||||||
|
data/
|
||||||
|
|
||||||
|
# Ignore version control system directories
|
||||||
|
.git/
|
||||||
|
|
||||||
|
# Ignore log and temporary files
|
||||||
|
*.log
|
||||||
|
*.tmp
|
||||||
|
*.swp
|
||||||
|
|
||||||
|
# Ignore editor/IDE configuration files
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# Ignore binaries and build cache
|
||||||
|
release/
|
||||||
|
bin/
|
||||||
|
*.exe
|
||||||
|
*.out
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
resources/web/**/* linguist-vendored
|
||||||
|
resources/web2/**/* linguist-vendored
|
||||||
@@ -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,9 +1,8 @@
|
|||||||
.idea
|
.idea
|
||||||
runtime/*
|
runtime/*
|
||||||
!runtime/cache/.gitignore
|
!runtime
|
||||||
|
!runtime/cache/.gitkeep
|
||||||
go.sum
|
go.sum
|
||||||
resources/*
|
resources/admin
|
||||||
!resources/public/upload/.gitignore
|
|
||||||
!resources/web
|
|
||||||
release
|
release
|
||||||
data
|
data/rustdeskapi.db
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
FROM alpine
|
||||||
|
|
||||||
|
ARG BUILDARCH
|
||||||
|
WORKDIR /app
|
||||||
|
RUN apk add --no-cache tzdata
|
||||||
|
COPY ./${BUILDARCH}/release /app/
|
||||||
|
VOLUME /app/data
|
||||||
|
|
||||||
|
EXPOSE 21114
|
||||||
|
CMD ["./apimain"]
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
# Use build arguments for Go version and architecture
|
||||||
|
ARG GO_VERSION=1.22
|
||||||
|
ARG BUILDARCH=amd64
|
||||||
|
|
||||||
|
# Stage 1: Builder Stage
|
||||||
|
# FROM golang:${GO_VERSION}-alpine AS builder
|
||||||
|
FROM crazymax/xgo:${GO_VERSION} AS builder-backend
|
||||||
|
|
||||||
|
# Set up working directory
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Step 1: Copy the source code
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# use --mount=type=cache,target=/go/pkg/mod to cache the go mod
|
||||||
|
# Step 2: Download dependencies
|
||||||
|
RUN --mount=type=cache,target=/go/pkg/mod \
|
||||||
|
go mod tidy && go mod download && go install github.com/swaggo/swag/cmd/swag@latest
|
||||||
|
|
||||||
|
# Step 3: Run swag build script
|
||||||
|
RUN --mount=type=cache,target=/go/pkg/mod \
|
||||||
|
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
|
||||||
|
|
||||||
|
# Step 4: Build the Go application with CGO enabled and specified ldflags
|
||||||
|
RUN --mount=type=cache,target=/go/pkg/mod \
|
||||||
|
CGO_ENABLED=1 GOOS=linux go build -a \
|
||||||
|
-ldflags "-s -w --extldflags '-static -fpic'" \
|
||||||
|
-installsuffix cgo -o release/apimain cmd/apimain.go
|
||||||
|
|
||||||
|
# Stage 2: Frontend Build Stage (builder2)
|
||||||
|
FROM node:18-alpine AS builder-admin-frontend
|
||||||
|
|
||||||
|
# Set working directory
|
||||||
|
WORKDIR /frontend
|
||||||
|
|
||||||
|
ARG COUNTRY
|
||||||
|
# Install required tools without caching index to minimize image size
|
||||||
|
RUN if [ "$COUNTRY" = "CN" ] ; then \
|
||||||
|
echo "It is in China, updating the repositories"; \
|
||||||
|
sed -i 's#https\?://dl-cdn.alpinelinux.org/alpine#https://mirrors.tuna.tsinghua.edu.cn/alpine#g' /etc/apk/repositories; \
|
||||||
|
fi && \
|
||||||
|
apk update && apk add --no-cache git
|
||||||
|
|
||||||
|
ARG FRONTEND_GIT_REPO=https://github.com/lejianwen/rustdesk-api-web.git
|
||||||
|
ARG FRONTEND_GIT_BRANCH=master
|
||||||
|
# Clone the frontend repository
|
||||||
|
|
||||||
|
RUN git clone -b $FRONTEND_GIT_BRANCH $FRONTEND_GIT_REPO .
|
||||||
|
|
||||||
|
# Install required tools without caching index to minimize image size
|
||||||
|
RUN if [ "$COUNTRY" = "CN" ] ; then \
|
||||||
|
echo "It is in China, updating NPM_CONFIG_REGISTRY"; \
|
||||||
|
export NPM_CONFIG_REGISTRY="https://mirrors.huaweicloud.com/repository/npm/"; \
|
||||||
|
fi && \
|
||||||
|
npm install && npm run build
|
||||||
|
|
||||||
|
|
||||||
|
# Stage 2: Final Image
|
||||||
|
FROM alpine:latest
|
||||||
|
|
||||||
|
# Set up working directory
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Install necessary runtime dependencies
|
||||||
|
# Install required tools without caching index to minimize image size
|
||||||
|
ARG COUNTRY
|
||||||
|
RUN if [ "$COUNTRY" = "CN" ] ; then \
|
||||||
|
echo "It is in China, updating the repositories"; \
|
||||||
|
sed -i 's#https\?://dl-cdn.alpinelinux.org/alpine#https://mirrors.tuna.tsinghua.edu.cn/alpine#g' /etc/apk/repositories; \
|
||||||
|
fi && \
|
||||||
|
apk update && apk add --no-cache tzdata file
|
||||||
|
|
||||||
|
# Copy the built application and resources from the builder stage
|
||||||
|
COPY --from=builder-backend /app/release /app/
|
||||||
|
COPY --from=builder-backend /app/conf /app/conf/
|
||||||
|
COPY --from=builder-backend /app/resources /app/resources/
|
||||||
|
COPY --from=builder-backend /app/docs /app/docs/
|
||||||
|
# Copy frontend build from builder2 stage
|
||||||
|
COPY --from=builder-admin-frontend /frontend/dist/ /app/resources/admin/
|
||||||
|
|
||||||
|
# Ensure the binary is correctly built and linked
|
||||||
|
RUN file /app/apimain && \
|
||||||
|
mkdir -p /app/data && \
|
||||||
|
mkdir -p /app/runtime
|
||||||
|
|
||||||
|
# Set up a volume for persistent data
|
||||||
|
VOLUME /app/data
|
||||||
|
|
||||||
|
# Expose the necessary port
|
||||||
|
EXPOSE 21114
|
||||||
|
|
||||||
|
# Define the command to run the application
|
||||||
|
CMD ["./apimain"]
|
||||||
@@ -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,118 +1,337 @@
|
|||||||
# RustDesk API
|
# RustDesk API
|
||||||
|
|
||||||
本项目使用 Go 实现了 RustDesk 的 API,并包含了 Web UI 和 Web 客户端。RustDesk 是一个远程桌面软件,提供了自托管的解决方案。
|
[中文文档](README_EN.md)
|
||||||
|
|
||||||
## 使用前准备
|
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.
|
||||||
|
|
||||||
### Rustdesk
|
<div align=center>
|
||||||
|
<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/gorm-v1.25.7-green"/>
|
||||||
|
<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"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
1. PC客户端使用的是 ***1.3.0***,经测试 ***1.2.6+*** 都可以
|
## Better used with [lejianwen/rustdesk-server].
|
||||||
2. server端必须指定key,不能用自带的生成的key,否则可能链接不上或者超时
|
> [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.
|
||||||
|
|
||||||
```bash
|
|
||||||
hbbs -r <relay-server-ip[:port]> -k 123456789
|
|
||||||
hbbr -k 123456789
|
|
||||||
```
|
|
||||||
|
|
||||||
## 功能
|
# Features
|
||||||
|
|
||||||
### **API 服务**: 基本实现了PC端基础的接口。
|
- PC API
|
||||||
|
- Personal API
|
||||||
|
- 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
|
||||||
|
- Web Admin
|
||||||
|
- User Management
|
||||||
|
- Device Management
|
||||||
|
- Address Book Management
|
||||||
|
- Tag Management
|
||||||
|
- Group Management
|
||||||
|
- OAuth Management
|
||||||
|
- LDAP Config by config file or ENV
|
||||||
|
- Login Logs
|
||||||
|
- Connection Logs
|
||||||
|
- File Transfer Logs
|
||||||
|
- Quick access to web client
|
||||||
|
- i18n
|
||||||
|
- Share to guest by web client
|
||||||
|
- Server control (some simple official commands [WIKI](https://github.com/lejianwen/rustdesk-api/wiki/Rustdesk-Command))
|
||||||
|
- Web Client
|
||||||
|
- Automatically obtain API server
|
||||||
|
- Automatically obtain ID server and KEY
|
||||||
|
- Automatically obtain address book
|
||||||
|
- Visitors are remotely to the device via a temporary sharing link
|
||||||
|
- CLI
|
||||||
|
- Reset admin password
|
||||||
|
|
||||||

|
## Overview
|
||||||

|
|
||||||
|
|
||||||
### **Web UI**: 使用前后端分离,提供用户友好的管理界面,主要用来管理和展示。
|
### 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.
|
||||||
|
|
||||||
***前端代码在[rustdesk-api-web](https://github.com/lejianwen/rustdesk-api-web)***
|
<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>
|
||||||
|
|
||||||
***初次安装管理员为用户名密码为admin admin,请即时更改密码***
|
### Web Admin
|
||||||
|
|
||||||
1. 管理员界面
|
* 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)
|
||||||
2. 普通用户界面
|
|
||||||

|
|
||||||
3. 更改密码在右上角
|
|
||||||
|
|
||||||

|
* 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).
|
||||||
|
|
||||||
4. 分组可以自定义,方便管理,暂时支持两种类型: `共享组` 和 `普通组`
|

|
||||||

|
|
||||||
|
|
||||||
### **Web 客户端**:
|
|
||||||
|
|
||||||
1. 如果已经登录了后台,web client将自动直接登录
|
1. Admin interface:
|
||||||
2. 如果没登录后台,点击右上角登录即可,api server已经自动配置好了
|

|
||||||
3. 登录后台后,会将地址簿自动保存到web client中,方便使用
|
2. Regular user interface:
|
||||||

|

|
||||||
|
|
||||||
### **自动化文档**: 使用 Swag 生成 API 文档,方便开发者理解和使用 API。
|
3. Each user can have multiple address books, which can also be shared with other users.
|
||||||
|
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`.
|
||||||
|
|
||||||
1. 后台文档 <youer server>/admin/swagger/index.html
|
7. Login logs
|
||||||
2. PC端文档 <youer server>/swagger/index.html
|
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 Client:
|
||||||
|
|
||||||
|
1. If you're already logged into the admin panel, the web client will log in automatically.
|
||||||
|
2. If you're not logged in, simply click the login button in the top right corner, and the API server will be
|
||||||
|
pre-configured.
|
||||||
|
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.
|
||||||
|
|
||||||
|
### Automated Documentation : API documentation is generated using Swag, making it easier for developers to understand and use the API.
|
||||||
|
|
||||||
|
1. Admin panel docs: `<your server[:port]>/admin/swagger/index.html`
|
||||||
|
2. PC client docs: `<your server[:port]>/swagger/index.html`
|
||||||

|

|
||||||
|
|
||||||
## 安装与运行
|
### CLI
|
||||||
|
```bash
|
||||||
### 相关配置
|
# help
|
||||||
|
./apimain -h
|
||||||
* 参考`conf/config.yaml`配置文件,修改相关配置。如果`gorm.type`是`sqlite`,则不需要配置mysql相关配置。
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
gin:
|
|
||||||
api-addr: "0.0.0.0:21114"
|
|
||||||
mode: "release"
|
|
||||||
resources-path: 'resources'
|
|
||||||
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"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 安装步骤
|
#### Reset admin password
|
||||||
|
```bash
|
||||||
|
./apimain reset-admin-pwd <pwd>
|
||||||
|
```
|
||||||
|
|
||||||
#### docker运行
|
## Installation and Setup
|
||||||
|
|
||||||
#### 下载release直接运行
|
### Configuration
|
||||||
|
|
||||||
#### 源码安装
|
* [Config File](./conf/config.yaml)
|
||||||
|
* Modify the configuration in `conf/config.yaml`.
|
||||||
|
* 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`.
|
||||||
|
|
||||||
1. 克隆仓库
|
|
||||||
|
### 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`.
|
||||||
|
|
||||||
|
| 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` |
|
||||||
|
|
||||||
|
### 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
|
||||||
|
docker run -d --name rustdesk-api -p 21114:21114 \
|
||||||
|
-v /data/rustdesk/api:/app/data \
|
||||||
|
-e RUSTDESK_API_LANG=en \
|
||||||
|
-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_API_SERVER=http://192.168.1.66:21114 \
|
||||||
|
-e RUSTDESK_API_RUSTDESK_KEY=abc123456 \
|
||||||
|
lejianwen/rustdesk-api
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Using `docker-compose`,look [WIKI](https://github.com/lejianwen/rustdesk-api/wiki)
|
||||||
|
|
||||||
|
#### Running from Release
|
||||||
|
|
||||||
|
Download the release from [release](https://github.com/lejianwen/rustdesk-api/releases).
|
||||||
|
|
||||||
|
#### 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. 安装依赖
|
|
||||||
|
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
|
||||||
git clone https://github.com/lejianwen/rustdesk-api-web
|
git clone https://github.com/lejianwen/rustdesk-api-web
|
||||||
cd rustdesk-api-web
|
cd rustdesk-api-web
|
||||||
npm install
|
npm install
|
||||||
npm run build
|
npm run build
|
||||||
cp -ar dist/* ../admin/
|
cp -ar dist/* ../admin/
|
||||||
```
|
```
|
||||||
4. 运行
|
|
||||||
```bash
|
|
||||||
#直接运行
|
|
||||||
go run cmd/apimain.go
|
|
||||||
#或者使用generate_api.go生成api并运行
|
|
||||||
go generate generate_api.go
|
|
||||||
```
|
|
||||||
5. 编译,如果想自己编译,先cd到项目根目录,然后windows下直接运行`build.bat`,linux下运行`build.sh`,编译后会在`release`
|
|
||||||
目录下生成对应的可执行文件。
|
|
||||||
|
|
||||||
|
4. Run:
|
||||||
|
```bash
|
||||||
|
# Run directly
|
||||||
|
go run cmd/apimain.go
|
||||||
|
# Or generate and run the API using generate_api.go
|
||||||
|
go generate generate_api.go
|
||||||
|
```
|
||||||
|
> **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
|
||||||
|
> ```
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
```
|
||||||
|
## Others
|
||||||
|
|
||||||
|
- [WIKI](https://github.com/lejianwen/rustdesk-api/wiki)
|
||||||
|
- [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
|
||||||
@@ -0,0 +1,335 @@
|
|||||||
|
# RustDesk API
|
||||||
|
|
||||||
|
[English Doc](README.md)
|
||||||
|
|
||||||
|
本项目使用 Go 实现了 RustDesk 的 API,并包含了 Web Admin 和 Web 客户端。
|
||||||
|
|
||||||
|
|
||||||
|
<div align=center>
|
||||||
|
<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/gorm-v1.25.7-green"/>
|
||||||
|
<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"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## 搭配[lejianwen/rustdesk-server]使用更佳。
|
||||||
|
> [lejianwen/rustdesk-server]fork自RustDesk Server官方仓库
|
||||||
|
> 1. 解决了使用API链接超时问题
|
||||||
|
> 2. 可以强制登录后才能发起链接
|
||||||
|
> 3. 支持客户端websocket
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# 特性
|
||||||
|
|
||||||
|
- PC端API
|
||||||
|
- 个人版API
|
||||||
|
- 登录
|
||||||
|
- 地址簿
|
||||||
|
- 群组
|
||||||
|
- 授权登录
|
||||||
|
- 支持`github`, `google` 和 `OIDC` 登录,
|
||||||
|
- 支持`web后台`授权登录
|
||||||
|
- 支持`LDAP`(AD和OpenLDAP已测试), 如果API Server配置了LDAP
|
||||||
|
- i18n
|
||||||
|
- Web Admin
|
||||||
|
- 用户管理
|
||||||
|
- 设备管理
|
||||||
|
- 地址簿管理
|
||||||
|
- 标签管理
|
||||||
|
- 群组管理
|
||||||
|
- Oauth 管理
|
||||||
|
- 配置LDAP, 配置文件或者环境变量
|
||||||
|
- 登录日志
|
||||||
|
- 链接日志
|
||||||
|
- 文件传输日志
|
||||||
|
- 快速使用web client
|
||||||
|
- i18n
|
||||||
|
- 通过 web client 分享给游客
|
||||||
|
- server控制(一些官方的简单的指令 [WIKI](https://github.com/lejianwen/rustdesk-api/wiki/Rustdesk-Command))
|
||||||
|
- Web Client
|
||||||
|
- 自动获取API server
|
||||||
|
- 自动获取ID服务器和KEY
|
||||||
|
- 自动获取地址簿
|
||||||
|
- 游客通过临时分享链接直接远程到设备
|
||||||
|
- CLI
|
||||||
|
- 重置管理员密码
|
||||||
|
|
||||||
|
## 功能
|
||||||
|
|
||||||
|
|
||||||
|
### API 服务
|
||||||
|
基本实现了PC端基础的接口。支持Personal版本接口,可以通过配置文件`rustdesk.personal`或环境变量`RUSTDESK_API_RUSTDESK_PERSONAL`来控制是否启用
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td width="50%" align="center" colspan="2"><b>登录</b></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="50%" align="center" colspan="2"><img src="docs/pc_login.png"></td>
|
||||||
|
</tr>
|
||||||
|
<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>
|
||||||
|
|
||||||
|
### Web Admin:
|
||||||
|
|
||||||
|
* 使用前后端分离,提供用户友好的管理界面,主要用来管理和展示。前端代码在[rustdesk-api-web](https://github.com/lejianwen/rustdesk-api-web)
|
||||||
|
|
||||||
|
* 后台访问地址是`http://<your server>[:port]/_admin/`
|
||||||
|
* 初次安装管理员为用户名为`admin`,密码将在控制台打印,可以通过[命令行](#CLI)更改密码
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
1. 管理员界面
|
||||||
|

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

|
||||||
|
|
||||||
|
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控制
|
||||||
|
|
||||||
|
- `简易模式`,已经界面化了一些简单的指令,可以直接在后台执行
|
||||||
|

|
||||||
|
|
||||||
|
- `高级模式`,直接在后台执行指令
|
||||||
|
* 可以官方指令
|
||||||
|
* 可以添加自定义指令
|
||||||
|
* 可以执行自定义指令
|
||||||
|
|
||||||
|
|
||||||
|
11. **LDAP 支持**, 当在API Server上设置了LDAP(已测试AD和LDAP),可以通过LDAP中的用户信息进行登录 https://github.com/lejianwen/rustdesk-api/issues/114 ,如果LDAP验证失败,返回本地用户
|
||||||
|
|
||||||
|
### Web Client:
|
||||||
|
|
||||||
|
1. 如果已经登录了后台,web client将自动直接登录
|
||||||
|
2. 如果没登录后台,点击右上角登录即可,api server已经自动配置好了
|
||||||
|
3. 登录后,会自动同步ID服务器和KEY
|
||||||
|
4. 登录后,会将地址簿自动保存到web client中,方便使用
|
||||||
|
|
||||||
|
|
||||||
|
### 自动化文档: 使用 Swag 生成 API 文档,方便开发者理解和使用 API。
|
||||||
|
|
||||||
|
1. 后台文档 `<youer server[:port]>/admin/swagger/index.html`
|
||||||
|
2. PC端文档 `<youer server[:port]>/swagger/index.html`
|
||||||
|

|
||||||
|
|
||||||
|
### CLI
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 查看帮助
|
||||||
|
./apimain -h
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 重置管理员密码
|
||||||
|
```bash
|
||||||
|
./apimain reset-admin-pwd <pwd>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 安装与运行
|
||||||
|
|
||||||
|
### 相关配置
|
||||||
|
|
||||||
|
* [配置文件](./conf/config.yaml)
|
||||||
|
* 参考`conf/config.yaml`配置文件,修改相关配置。
|
||||||
|
* 如果`gorm.type`是`sqlite`,则不需要配置mysql相关配置。
|
||||||
|
* 语言如果不设置默认为`zh-CN`
|
||||||
|
|
||||||
|
### 环境变量
|
||||||
|
环境变量和配置文件`conf/config.yaml`中的配置一一对应,变量名前缀是`RUSTDESK_API`
|
||||||
|
下面表格并未全部列出,可以参考`conf/config.yaml`中的配置。
|
||||||
|
|
||||||
|
| 变量名 | 说明 | 示例 |
|
||||||
|
|--------------------------------------------------------|--------------------------------------------------------------------------------|------------------------------|
|
||||||
|
| 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` |
|
||||||
|
| RUSTDESK_API_APP_SHOW_SWAGGER | 是否可见swagger文档;`1`显示,`0`不显示,默认`0`不显示 | `1` |
|
||||||
|
| RUSTDESK_API_APP_TOKEN_EXPIRE | token有效时长 | `168h` |
|
||||||
|
| RUSTDESK_API_APP_DISABLE_PWD_LOGIN | 是否禁用密码登录; `true`, `false` 默认`false` | `false` |
|
||||||
|
| RUSTDESK_API_APP_REGISTER_STATUS | 注册用户默认状态; 1 启用,2 禁用, 默认 1 | `1` |
|
||||||
|
| RUSTDESK_API_APP_CAPTCHA_THRESHOLD | 验证码触发次数; -1 不启用, 0 一直启用, >0 登录错误次数后启用 ;默认 `3` | `3` |
|
||||||
|
| RUSTDESK_API_APP_BAN_THRESHOLD | 封禁IP触发次数; 0 不启用, >0 登录错误次数后封禁IP; 默认 `0` | `0` |
|
||||||
|
| -----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_API_MYSQL_TLS | 是否启用TLS, 可选值: `true`, `false`, `skip-verify`, `custom` | `false` |
|
||||||
|
| -----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_WEBCLIENT<br/>_MAGIC_QUERYONLINE | Web client v2 中是否启用新的在线状态查询方法; `1`:启用,`0`:不启用,默认不启用 | `0` |
|
||||||
|
| RUSTDESK_API_RUSTDESK_WS_HOST | 自定义Websocket Host | `wss://192.168.1.123:1234` |
|
||||||
|
| ----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` |
|
||||||
|
|
||||||
|
|
||||||
|
### 运行
|
||||||
|
|
||||||
|
#### docker运行
|
||||||
|
|
||||||
|
1. 直接docker运行,配置可以通过挂载配置文件`/app/conf/config.yaml`来修改,或者通过环境变量覆盖配置文件中的配置
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -d --name rustdesk-api -p 21114:21114 \
|
||||||
|
-v /data/rustdesk/api:/app/data \
|
||||||
|
-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_RELAY_SERVER=192.168.1.66:21117 \
|
||||||
|
-e RUSTDESK_API_RUSTDESK_API_SERVER=http://192.168.1.66:21114 \
|
||||||
|
-e RUSTDESK_API_RUSTDESK_KEY=<key> \
|
||||||
|
lejianwen/rustdesk-api
|
||||||
|
```
|
||||||
|
|
||||||
|
2. 使用`docker compose`,参考[WIKI](https://github.com/lejianwen/rustdesk-api/wiki)
|
||||||
|
|
||||||
|
#### 下载release直接运行
|
||||||
|
|
||||||
|
[下载地址](https://github.com/lejianwen/rustdesk-api/releases)
|
||||||
|
|
||||||
|
#### 源码安装
|
||||||
|
|
||||||
|
1. 克隆仓库
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/lejianwen/rustdesk-api.git
|
||||||
|
cd rustdesk-api
|
||||||
|
```
|
||||||
|
|
||||||
|
2. 安装依赖
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go mod tidy
|
||||||
|
#安装swag,如果不需要生成文档,可以不安装
|
||||||
|
go install github.com/swaggo/swag/cmd/swag@latest
|
||||||
|
```
|
||||||
|
|
||||||
|
3. 编译后台前端,前端代码在[rustdesk-api-web](https://github.com/lejianwen/rustdesk-api-web)中
|
||||||
|
```bash
|
||||||
|
cd resources
|
||||||
|
mkdir -p admin
|
||||||
|
git clone https://github.com/lejianwen/rustdesk-api-web
|
||||||
|
cd rustdesk-api-web
|
||||||
|
npm install
|
||||||
|
npm run build
|
||||||
|
cp -ar dist/* ../admin/
|
||||||
|
```
|
||||||
|
4. 运行
|
||||||
|
```bash
|
||||||
|
#直接运行
|
||||||
|
go run cmd/apimain.go
|
||||||
|
#或者使用generate_api.go生成api并运行
|
||||||
|
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`
|
||||||
|
目录下生成对应的可执行文件。直接运行编译后的可执行文件即可。
|
||||||
|
|
||||||
|
6. 打开浏览器访问`http://<your server[:port]>/_admin/`,默认用户名密码为`admin`,请及时更改密码。
|
||||||
|
|
||||||
|
|
||||||
|
#### 使用`lejianwen/server-s6`镜像运行
|
||||||
|
|
||||||
|
- 已解决链接超时问题
|
||||||
|
- 可以强制登录后才能发起链接
|
||||||
|
- 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
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## 其他
|
||||||
|
|
||||||
|
- [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,4 +1,5 @@
|
|||||||
@echo off
|
@echo off
|
||||||
|
rmdir /s /q release
|
||||||
go env -w GO111MODULE=on
|
go env -w GO111MODULE=on
|
||||||
go env -w GOPROXY=https://goproxy.cn,direct
|
go env -w GOPROXY=https://goproxy.cn,direct
|
||||||
go env -w CGO_ENABLED=1
|
go env -w CGO_ENABLED=1
|
||||||
|
|||||||
@@ -1,15 +1,46 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
# Automatically get the current environment's GOARCH; if not defined, use the detected system architecture
|
||||||
|
GOARCH=${GOARCH:-$(go env GOARCH)}
|
||||||
|
DOCS="true"
|
||||||
|
# Safely remove the old release directory
|
||||||
|
rm -rf release
|
||||||
|
|
||||||
|
# Set Go environment variables
|
||||||
go env -w GO111MODULE=on
|
go env -w GO111MODULE=on
|
||||||
go env -w GOPROXY=https://goproxy.cn,direct
|
go env -w GOPROXY=https://goproxy.cn,direct
|
||||||
go env -w CGO_ENABLED=1
|
go env -w CGO_ENABLED=1
|
||||||
go env -w GOOS=linux
|
go env -w GOOS=linux
|
||||||
go env -w GOARCH=amd64
|
go env -w GOARCH=${GOARCH}
|
||||||
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
|
|
||||||
|
# Generate Swagger documentation if DOCS is not empty
|
||||||
|
if [ -n "${DOCS}" ]; then
|
||||||
|
# Check if swag is installed
|
||||||
|
if ! command -v swag &> /dev/null; then
|
||||||
|
echo "swag command not found. Please install it using:"
|
||||||
|
echo "go install github.com/swaggo/swag/cmd/swag@latest"
|
||||||
|
echo "Skipping Swagger documentation generation due to missing swag tool."
|
||||||
|
else
|
||||||
|
echo "Generating Swagger documentation..."
|
||||||
|
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
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Skipping Swagger documentation generation due to DOCS is empty."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Compile the Go code and output it to the release directory
|
||||||
go build -o release/apimain cmd/apimain.go
|
go build -o release/apimain cmd/apimain.go
|
||||||
|
|
||||||
|
# Copy resource files to the release directory
|
||||||
cp -ar resources release/
|
cp -ar resources release/
|
||||||
cp -ar docs release/
|
cp -ar docs release/
|
||||||
cp -ar conf release/
|
cp -ar conf release/
|
||||||
mkdir release/data
|
|
||||||
mkdir release/runtime
|
# Create necessary directory structures
|
||||||
|
mkdir -p release/data
|
||||||
|
mkdir -p release/runtime
|
||||||
|
|
||||||
|
echo "Build and setup completed successfully."
|
||||||
@@ -1,29 +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-playground/locales/en"
|
"os"
|
||||||
"github.com/go-playground/locales/zh_Hans_CN"
|
"strconv"
|
||||||
ut "github.com/go-playground/universal-translator"
|
"time"
|
||||||
"github.com/go-playground/validator/v10"
|
|
||||||
zh_translations "github.com/go-playground/validator/v10/translations/zh"
|
|
||||||
"github.com/go-redis/redis/v8"
|
"github.com/go-redis/redis/v8"
|
||||||
"reflect"
|
"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
|
||||||
@@ -31,19 +35,94 @@ import (
|
|||||||
// @securitydefinitions.apikey BearerAuth
|
// @securitydefinitions.apikey BearerAuth
|
||||||
// @in header
|
// @in header
|
||||||
// @name Authorization
|
// @name Authorization
|
||||||
func main() {
|
|
||||||
//配置解析
|
|
||||||
global.Viper = config.Init(&global.Config, func() {
|
|
||||||
fmt.Println(global.Config)
|
|
||||||
})
|
|
||||||
|
|
||||||
//日志
|
var rootCmd = &cobra.Command{
|
||||||
|
Use: "apimain",
|
||||||
|
Short: "RUSTDESK API SERVER",
|
||||||
|
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
||||||
|
InitGlobal()
|
||||||
|
},
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
global.Logger.Info("API SERVER START")
|
||||||
|
http.ApiInit()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var resetPwdCmd = &cobra.Command{
|
||||||
|
Use: "reset-admin-pwd [pwd]",
|
||||||
|
Example: "reset-admin-pwd 123456",
|
||||||
|
Short: "Reset Admin Password",
|
||||||
|
Args: cobra.ExactArgs(1),
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
pwd := args[0]
|
||||||
|
admin := service.AllService.UserService.InfoById(1)
|
||||||
|
if admin.Id == 0 {
|
||||||
|
global.Logger.Warn("user not found! ")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
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{
|
||||||
|
Use: "reset-pwd [userId] [pwd]",
|
||||||
|
Example: "reset-pwd 2 123456",
|
||||||
|
Short: "Reset User Password",
|
||||||
|
Args: cobra.ExactArgs(2),
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
userId := args[0]
|
||||||
|
pwd := args[1]
|
||||||
|
uid, err := strconv.Atoi(userId)
|
||||||
|
if err != nil {
|
||||||
|
global.Logger.Warn("userId must be int!")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if uid <= 0 {
|
||||||
|
global.Logger.Warn("userId must be greater than 0! ")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
u := service.AllService.UserService.InfoById(uint(uid))
|
||||||
|
if u.Id == 0 {
|
||||||
|
global.Logger.Warn("user not found! ")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = service.AllService.UserService.UpdatePassword(u, pwd)
|
||||||
|
if err != nil {
|
||||||
|
global.Logger.Warn("reset password fail! ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
global.Logger.Info("reset password success!")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rootCmd.PersistentFlags().StringVarP(&global.ConfigPath, "config", "c", "./conf/config.yaml", "choose config file")
|
||||||
|
rootCmd.AddCommand(resetPwdCmd, resetUserPwdCmd)
|
||||||
|
}
|
||||||
|
func main() {
|
||||||
|
if err := rootCmd.Execute(); err != nil {
|
||||||
|
global.Logger.Error(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitGlobal() {
|
||||||
|
// config parsing
|
||||||
|
global.Viper = config.Init(&global.Config, global.ConfigPath)
|
||||||
|
|
||||||
|
// logging
|
||||||
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,
|
||||||
ReportCaller: global.Config.Logger.ReportCaller,
|
ReportCaller: global.Config.Logger.ReportCaller,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
global.InitI18n()
|
||||||
|
|
||||||
//redis
|
//redis
|
||||||
global.Redis = redis.NewClient(&redis.Options{
|
global.Redis = redis.NewClient(&redis.Options{
|
||||||
Addr: global.Config.Redis.Addr,
|
Addr: global.Config.Redis.Addr,
|
||||||
@@ -65,23 +144,45 @@ func main() {
|
|||||||
}
|
}
|
||||||
//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
|
||||||
ApiInitValidator()
|
global.ApiInitValidator()
|
||||||
|
|
||||||
//oss
|
//oss
|
||||||
global.Oss = &upload.Oss{
|
global.Oss = &upload.Oss{
|
||||||
@@ -95,101 +196,60 @@ func main() {
|
|||||||
|
|
||||||
//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()
|
||||||
|
|
||||||
//gin
|
//service
|
||||||
http.ApiInit()
|
service.New(&global.Config, global.DB, global.Logger, global.Jwt, global.Lock)
|
||||||
|
|
||||||
}
|
global.LoginLimiter = utils.NewLoginLimiter(utils.SecurityPolicy{
|
||||||
|
CaptchaThreshold: global.Config.App.CaptchaThreshold,
|
||||||
func ApiInitValidator() {
|
BanThreshold: global.Config.App.BanThreshold,
|
||||||
validate := validator.New()
|
AttemptsWindow: 10 * time.Minute,
|
||||||
enT := en.New()
|
BanDuration: 30 * time.Minute,
|
||||||
cn := zh_Hans_CN.New()
|
|
||||||
uni := ut.New(enT, cn)
|
|
||||||
trans, _ := uni.GetTranslator("cn")
|
|
||||||
err := zh_translations.RegisterDefaultTranslations(validate, trans)
|
|
||||||
if err != nil {
|
|
||||||
//退出
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
validate.RegisterTagNameFunc(func(field reflect.StructField) string {
|
|
||||||
label := field.Tag.Get("label")
|
|
||||||
if label == "" {
|
|
||||||
return field.Name
|
|
||||||
}
|
|
||||||
return label
|
|
||||||
})
|
})
|
||||||
global.Validator.Validate = validate
|
global.LoginLimiter.RegisterProvider(utils.B64StringCaptchaProvider{})
|
||||||
global.Validator.VTrans = trans
|
DatabaseAutoUpdate()
|
||||||
|
|
||||||
global.Validator.ValidStruct = func(i interface{}) []string {
|
|
||||||
err := global.Validator.Validate.Struct(i)
|
|
||||||
errList := make([]string, 0, 10)
|
|
||||||
if err != nil {
|
|
||||||
if _, ok := err.(*validator.InvalidValidationError); ok {
|
|
||||||
errList = append(errList, err.Error())
|
|
||||||
return errList
|
|
||||||
}
|
|
||||||
for _, err2 := range err.(validator.ValidationErrors) {
|
|
||||||
errList = append(errList, err2.Translate(global.Validator.VTrans))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return errList
|
|
||||||
}
|
|
||||||
global.Validator.ValidVar = func(field interface{}, tag string) []string {
|
|
||||||
err := global.Validator.Validate.Var(field, tag)
|
|
||||||
fmt.Println(err)
|
|
||||||
errList := make([]string, 0, 10)
|
|
||||||
if err != nil {
|
|
||||||
if _, ok := err.(*validator.InvalidValidationError); ok {
|
|
||||||
errList = append(errList, err.Error())
|
|
||||||
return errList
|
|
||||||
}
|
|
||||||
for _, err2 := range err.(validator.ValidationErrors) {
|
|
||||||
errList = append(errList, err2.Translate(global.Validator.VTrans))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return errList
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func DatabaseAutoUpdate() {
|
func DatabaseAutoUpdate() {
|
||||||
version := 100
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -198,17 +258,36 @@ 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 migration
|
||||||
|
if v.Version < 245 {
|
||||||
|
// 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 issuer = 'https://accounts.google.com' where op = 'google'")
|
||||||
|
db.Exec("update user_thirds set oauth_type = third_type, op = third_type")
|
||||||
|
// migrate old google authorizations by email
|
||||||
|
uts := make([]model.UserThird, 0)
|
||||||
|
db.Where("oauth_type = ?", "google").Find(&uts)
|
||||||
|
for _, ut := range uts {
|
||||||
|
if ut.UserId > 0 {
|
||||||
|
db.Model(&model.User{}).Where("id = ?", ut.UserId).Update("email", ut.OpenId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if v.Version < 246 {
|
||||||
|
db.Exec("update oauths set issuer = 'https://accounts.google.com' where op = 'google' and issuer is null")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
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{},
|
||||||
@@ -217,35 +296,61 @@ func Migrate(version uint) {
|
|||||||
&model.AddressBook{},
|
&model.AddressBook{},
|
||||||
&model.Peer{},
|
&model.Peer{},
|
||||||
&model.Group{},
|
&model.Group{},
|
||||||
|
&model.UserThird{},
|
||||||
|
&model.Oauth{},
|
||||||
|
&model.LoginLog{},
|
||||||
|
&model.ShareRecord{},
|
||||||
|
&model.AuditConn{},
|
||||||
|
&model.AuditFile{},
|
||||||
|
&model.AddressBookCollection{},
|
||||||
|
&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 {
|
||||||
|
localizer := global.Localizer("")
|
||||||
|
defaultGroup, _ := localizer.LocalizeMessage(&i18n.Message{
|
||||||
|
ID: "DefaultGroup",
|
||||||
|
})
|
||||||
group := &model.Group{
|
group := &model.Group{
|
||||||
Name: "默认组",
|
Name: defaultGroup,
|
||||||
Type: model.GroupTypeDefault,
|
Type: model.GroupTypeDefault,
|
||||||
}
|
}
|
||||||
service.AllService.GroupService.Create(group)
|
service.AllService.GroupService.Create(group)
|
||||||
|
|
||||||
|
shareGroup, _ := localizer.LocalizeMessage(&i18n.Message{
|
||||||
|
ID: "ShareGroup",
|
||||||
|
})
|
||||||
groupShare := &model.Group{
|
groupShare := &model.Group{
|
||||||
Name: "共享组",
|
Name: shareGroup,
|
||||||
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",
|
||||||
Nickname: "管理员",
|
Nickname: "Admin",
|
||||||
Status: model.COMMON_STATUS_ENABLE,
|
Status: model.COMMON_STATUS_ENABLE,
|
||||||
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,42 +1,84 @@
|
|||||||
|
lang: "en"
|
||||||
|
app:
|
||||||
|
web-client: 1 # 1:enable 0:disable
|
||||||
|
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:
|
||||||
|
title: "RustDesk API Admin"
|
||||||
|
hello-file: "./conf/admin/hello.html" #prefer to use a file for the welcome message
|
||||||
|
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: ""
|
||||||
gorm:
|
gorm:
|
||||||
type: "sqlite"
|
type: "sqlite"
|
||||||
max-idle-conns: 10
|
max-idle-conns: 10
|
||||||
max-open-conns: 100
|
max-open-conns: 100
|
||||||
mysql:
|
mysql:
|
||||||
username: "root"
|
username: ""
|
||||||
password: "111111"
|
|
||||||
addr: "192.168.1.66:3308"
|
|
||||||
dbname: "rustdesk2"
|
|
||||||
rustdesk:
|
|
||||||
id-server: "124.220.134.240:21116"
|
|
||||||
relay-server: "124.220.134.240:21117"
|
|
||||||
api-server: "http://127.0.0.1:21114"
|
|
||||||
key: "ljw19891989"
|
|
||||||
redis:
|
|
||||||
addr: "127.0.0.1:6379"
|
|
||||||
password: ""
|
password: ""
|
||||||
db: 0
|
addr: ""
|
||||||
|
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:
|
||||||
|
id-server: "192.168.1.66:21116"
|
||||||
|
relay-server: "192.168.1.66:21117"
|
||||||
|
api-server: "http://127.0.0.1:21114"
|
||||||
|
key: ""
|
||||||
|
key-file: "/data/id_ed25519.pub"
|
||||||
|
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: "error" #trace,debug,info,warn,error,fatal
|
level: "info" #trace,debug,info,warn,error,fatal
|
||||||
report-caller: true
|
report-caller: true
|
||||||
cache:
|
proxy:
|
||||||
type: "file"
|
enable: false
|
||||||
file-dir: "./runtime/cache"
|
host: "http://127.0.0.1:1080"
|
||||||
redis-addr: "127.0.0.1:6379"
|
|
||||||
redis-pwd: "ljw19891989"
|
|
||||||
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.
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/fsnotify/fsnotify"
|
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -13,42 +13,93 @@ const (
|
|||||||
DefaultConfig = "conf/config.yaml"
|
DefaultConfig = "conf/config.yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type App struct {
|
||||||
|
WebClient int `mapstructure:"web-client"`
|
||||||
|
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 {
|
||||||
|
Title string `mapstructure:"title"`
|
||||||
|
Hello string `mapstructure:"hello"`
|
||||||
|
HelloFile string `mapstructure:"hello-file"`
|
||||||
|
IdServerPort int `mapstructure:"id-server-port"`
|
||||||
|
RelayServerPort int `mapstructure:"relay-server-port"`
|
||||||
|
}
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Gorm Gorm
|
Lang string `mapstructure:"lang"`
|
||||||
Mysql Mysql
|
App App
|
||||||
Gin Gin
|
Admin Admin
|
||||||
Logger Logger
|
Gorm Gorm
|
||||||
Redis Redis
|
Mysql Mysql
|
||||||
Cache Cache
|
Postgresql Postgresql
|
||||||
Oss Oss
|
Gin Gin
|
||||||
Jwt Jwt
|
Logger Logger
|
||||||
Rustdesk Rustdesk
|
Redis Redis
|
||||||
|
Cache Cache
|
||||||
|
Oss Oss
|
||||||
|
Jwt Jwt
|
||||||
|
Rustdesk Rustdesk
|
||||||
|
Proxy Proxy
|
||||||
|
Ldap Ldap
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init 初始化配置
|
func (a *Admin) Init() {
|
||||||
func Init(rowVal interface{}, cb func()) *viper.Viper {
|
if a.IdServerPort == 0 {
|
||||||
var config string
|
a.IdServerPort = DefaultIdServerPort
|
||||||
flag.StringVar(&config, "c", "", "choose config file.")
|
|
||||||
flag.Parse()
|
|
||||||
if config == "" { // 优先级: 命令行 > 默认值
|
|
||||||
config = DefaultConfig
|
|
||||||
}
|
}
|
||||||
v := viper.New()
|
if a.RelayServerPort == 0 {
|
||||||
v.SetConfigFile(config)
|
a.RelayServerPort = DefaultRelayServerPort
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init initializes the configuration
|
||||||
|
func Init(rowVal *Config, path string) *viper.Viper {
|
||||||
|
if path == "" {
|
||||||
|
path = DefaultConfig
|
||||||
|
}
|
||||||
|
v := viper.GetViper()
|
||||||
|
v.AutomaticEnv()
|
||||||
|
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_", "-", "_"))
|
||||||
|
v.SetEnvPrefix("RUSTDESK_API")
|
||||||
|
v.SetConfigFile(path)
|
||||||
v.SetConfigType("yaml")
|
v.SetConfigType("yaml")
|
||||||
err := v.ReadInConfig()
|
err := v.ReadInConfig()
|
||||||
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.OnConfigChange(func(e fsnotify.Event) {
|
v.WatchConfig()
|
||||||
//配置文件修改监听
|
|
||||||
fmt.Println("config file changed:", e.Name)
|
|
||||||
if err2 := v.Unmarshal(rowVal); err2 != nil {
|
// watching for config changes is not really necessary
|
||||||
fmt.Println(err2)
|
v.OnConfigChange(func(e fsnotify.Event) {
|
||||||
}
|
// watch for config file changes
|
||||||
cb()
|
fmt.Println("config file changed:", e.Name)
|
||||||
})
|
if err2 := v.Unmarshal(rowVal); err2 != nil {
|
||||||
|
fmt.Println(err2)
|
||||||
|
}
|
||||||
|
rowVal.Rustdesk.LoadKeyFile()
|
||||||
|
rowVal.Rustdesk.ParsePort()
|
||||||
|
})
|
||||||
|
*/
|
||||||
|
if err := v.Unmarshal(rowVal); err != nil {
|
||||||
|
panic(fmt.Errorf("Fatal error config: %s \n", err))
|
||||||
|
}
|
||||||
|
rowVal.Rustdesk.LoadKeyFile()
|
||||||
|
rowVal.Admin.Init()
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadEnv reads environment variables
|
||||||
|
func ReadEnv(rowVal interface{}) *viper.Viper {
|
||||||
|
v := viper.New()
|
||||||
|
v.AutomaticEnv()
|
||||||
if err := v.Unmarshal(rowVal); err != nil {
|
if err := v.Unmarshal(rowVal); err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,4 +5,5 @@ type Gin struct {
|
|||||||
AdminAddr string `mapstructure:"admin-addr"`
|
AdminAddr string `mapstructure:"admin-addr"`
|
||||||
Mode string
|
Mode string
|
||||||
ResourcesPath string `mapstructure:"resources-path"`
|
ResourcesPath string `mapstructure:"resources-path"`
|
||||||
|
TrustProxy string `mapstructure:"trust-proxy"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
package config
|
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"`
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
type GithubOauth struct {
|
||||||
|
ClientId string `mapstructure:"client-id"`
|
||||||
|
ClientSecret string `mapstructure:"client-secret"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GoogleOauth struct {
|
||||||
|
ClientId string `mapstructure:"client-id"`
|
||||||
|
ClientSecret string `mapstructure:"client-secret"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type OidcOauth struct {
|
||||||
|
Issuer string `mapstructure:"issuer"`
|
||||||
|
ClientId string `mapstructure:"client-id"`
|
||||||
|
ClientSecret string `mapstructure:"client-secret"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LinuxdoOauth struct {
|
||||||
|
ClientId string `mapstructure:"client-id"`
|
||||||
|
ClientSecret string `mapstructure:"client-secret"`
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
type Proxy struct {
|
||||||
|
Enable bool `mapstructure:"enable"`
|
||||||
|
Host string `mapstructure:"host"`
|
||||||
|
}
|
||||||
@@ -1,8 +1,40 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DefaultIdServerPort = 21116
|
||||||
|
DefaultRelayServerPort = 21117
|
||||||
|
)
|
||||||
|
|
||||||
type Rustdesk struct {
|
type Rustdesk struct {
|
||||||
IdServer string `mapstructure:"id-server"`
|
IdServer string `mapstructure:"id-server"`
|
||||||
RelayServer string `mapstructure:"relay-server"`
|
IdServerPort int `mapstructure:"-"`
|
||||||
ApiServer string `mapstructure:"api-server"`
|
RelayServer string `mapstructure:"relay-server"`
|
||||||
Key string `mapstructure:"key"`
|
RelayServerPort int `mapstructure:"-"`
|
||||||
|
ApiServer string `mapstructure:"api-server"`
|
||||||
|
Key string `mapstructure:"key"`
|
||||||
|
KeyFile string `mapstructure:"key-file"`
|
||||||
|
Personal int `mapstructure:"personal"`
|
||||||
|
//webclient-magic-queryonline
|
||||||
|
WebclientMagicQueryonline int `mapstructure:"webclient-magic-queryonline"`
|
||||||
|
WsHost string `mapstructure:"ws-host"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rd *Rustdesk) LoadKeyFile() {
|
||||||
|
// Load key file
|
||||||
|
if rd.Key != "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if rd.KeyFile != "" {
|
||||||
|
// Load key from file
|
||||||
|
b, err := os.ReadFile(rd.KeyFile)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rd.Key = string(b)
|
||||||
|
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)
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
services:
|
||||||
|
rustdesk-api:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile.dev
|
||||||
|
args:
|
||||||
|
COUNTRY: CN
|
||||||
|
FRONTEND_GIT_REPO: https://github.com/lejianwen/rustdesk-api-web.git
|
||||||
|
FRONTEND_GIT_BRANCH: master
|
||||||
|
# image: lejianwen/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://127.0.0.1:21114
|
||||||
|
- RUSTDESK_API_RUSTDESK_KEY=123456789
|
||||||
|
ports:
|
||||||
|
- 21114:21114
|
||||||
|
volumes:
|
||||||
|
- ./data/rustdesk/api:/app/data #mount the database out for easy backup
|
||||||
|
- ./conf:/app/conf # config
|
||||||
|
# - ./resources:/app/resources # static resources
|
||||||
|
restart: unless-stopped
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
services:
|
||||||
|
rustdesk-api:
|
||||||
|
image: lejianwen/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://127.0.0.1:21114
|
||||||
|
- RUSTDESK_API_RUSTDESK_KEY=123456789
|
||||||
|
ports:
|
||||||
|
- 21114:21114
|
||||||
|
volumes:
|
||||||
|
- ./data/rustdesk/api:/app/data # database
|
||||||
|
# - ./conf:/app/conf # config
|
||||||
|
# - ./resources:/app/resources # static resources
|
||||||
|
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
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Define Docker Compose file and cache option
|
||||||
|
COMPOSE_FILE_NAME="docker-compose-dev.yaml"
|
||||||
|
CACHE=""
|
||||||
|
# Uncomment the next line to enable no-cache option
|
||||||
|
# CACHE="--no-cache"
|
||||||
|
|
||||||
|
# Define the base Docker Compose command
|
||||||
|
DCS="docker compose -f ${COMPOSE_FILE_NAME}"
|
||||||
|
|
||||||
|
# Function to build and start services
|
||||||
|
build_and_run() {
|
||||||
|
echo "Building services..."
|
||||||
|
if ! $DCS build ${CACHE}; then
|
||||||
|
echo "Error: Failed to build services"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Starting services..."
|
||||||
|
if ! $DCS up -d; then
|
||||||
|
echo "Error: Failed to start services"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Services started successfully"
|
||||||
|
echo "If you want to stop the services, run"
|
||||||
|
echo "docker compose -f ${COMPOSE_FILE_NAME} down"
|
||||||
|
|
||||||
|
echo "If you want to see the logs, run"
|
||||||
|
echo "docker compose -f ${COMPOSE_FILE_NAME} logs -f"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Execute build and start function
|
||||||
|
build_and_run
|
||||||
|
After Width: | Height: | Size: 97 KiB |
|
After Width: | Height: | Size: 97 KiB |
|
After Width: | Height: | Size: 53 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 99 KiB |
|
After Width: | Height: | Size: 67 KiB |
|
After Width: | Height: | Size: 49 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 99 KiB |
|
After Width: | Height: | Size: 67 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 31 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
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
//go:generate go run cmd/apimain.go
|
||||||
@@ -0,0 +1,160 @@
|
|||||||
|
package global
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"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/ru"
|
||||||
|
"github.com/go-playground/locales/zh_Hans_CN"
|
||||||
|
"github.com/go-playground/locales/zh_Hant"
|
||||||
|
ut "github.com/go-playground/universal-translator"
|
||||||
|
"github.com/go-playground/validator/v10"
|
||||||
|
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"
|
||||||
|
zh_translations "github.com/go-playground/validator/v10/translations/zh"
|
||||||
|
zh_tw_translations "github.com/go-playground/validator/v10/translations/zh_tw"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ApiInitValidator() {
|
||||||
|
validate := validator.New()
|
||||||
|
|
||||||
|
// define translations for different languages
|
||||||
|
enT := en.New()
|
||||||
|
cn := zh_Hans_CN.New()
|
||||||
|
koT := ko.New()
|
||||||
|
ruT := ru.New()
|
||||||
|
esT := es.New()
|
||||||
|
frT := fr.New()
|
||||||
|
zhTwT := zh_Hant.New()
|
||||||
|
|
||||||
|
uni := ut.New(enT, cn, koT, ruT, esT, frT, zhTwT)
|
||||||
|
|
||||||
|
enTrans, _ := uni.GetTranslator("en")
|
||||||
|
zhTrans, _ := uni.GetTranslator("zh_Hans_CN")
|
||||||
|
koTrans, _ := uni.GetTranslator("ko")
|
||||||
|
ruTrans, _ := uni.GetTranslator("ru")
|
||||||
|
esTrans, _ := uni.GetTranslator("es")
|
||||||
|
frTrans, _ := uni.GetTranslator("fr")
|
||||||
|
zhTwTrans, _ := uni.GetTranslator("zh_Hant")
|
||||||
|
|
||||||
|
err := zh_translations.RegisterDefaultTranslations(validate, zhTrans)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
err = en_translations.RegisterDefaultTranslations(validate, enTrans)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ko_translations.RegisterDefaultTranslations(validate, koTrans)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
err = ru_translations.RegisterDefaultTranslations(validate, ruTrans)
|
||||||
|
if err != nil {
|
||||||
|
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 {
|
||||||
|
label := field.Tag.Get("label")
|
||||||
|
if label == "" {
|
||||||
|
return field.Name
|
||||||
|
}
|
||||||
|
return label
|
||||||
|
})
|
||||||
|
Validator.Validate = validate
|
||||||
|
Validator.UT = uni // store the Universal Translator
|
||||||
|
Validator.VTrans = zhTrans
|
||||||
|
|
||||||
|
Validator.ValidStruct = func(ctx *gin.Context, i interface{}) []string {
|
||||||
|
err := Validator.Validate.Struct(i)
|
||||||
|
lang := ctx.GetHeader("Accept-Language")
|
||||||
|
if lang == "" {
|
||||||
|
lang = Config.Lang
|
||||||
|
}
|
||||||
|
trans := getTranslatorForLang(lang)
|
||||||
|
errList := make([]string, 0, 10)
|
||||||
|
if err != nil {
|
||||||
|
if _, ok := err.(*validator.InvalidValidationError); ok {
|
||||||
|
errList = append(errList, err.Error())
|
||||||
|
return errList
|
||||||
|
}
|
||||||
|
for _, err2 := range err.(validator.ValidationErrors) {
|
||||||
|
errList = append(errList, err2.Translate(trans))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return errList
|
||||||
|
}
|
||||||
|
Validator.ValidVar = func(ctx *gin.Context, field interface{}, tag string) []string {
|
||||||
|
err := Validator.Validate.Var(field, tag)
|
||||||
|
lang := ctx.GetHeader("Accept-Language")
|
||||||
|
if lang == "" {
|
||||||
|
lang = Config.Lang
|
||||||
|
}
|
||||||
|
trans := getTranslatorForLang(lang)
|
||||||
|
errList := make([]string, 0, 10)
|
||||||
|
if err != nil {
|
||||||
|
if _, ok := err.(*validator.InvalidValidationError); ok {
|
||||||
|
errList = append(errList, err.Error())
|
||||||
|
return errList
|
||||||
|
}
|
||||||
|
for _, err2 := range err.(validator.ValidationErrors) {
|
||||||
|
errList = append(errList, err2.Translate(trans))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return errList
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func getTranslatorForLang(lang string) ut.Translator {
|
||||||
|
switch lang {
|
||||||
|
case "zh_CN":
|
||||||
|
fallthrough
|
||||||
|
case "zh-CN":
|
||||||
|
fallthrough
|
||||||
|
case "zh":
|
||||||
|
trans, _ := Validator.UT.GetTranslator("zh_Hans_CN")
|
||||||
|
return trans
|
||||||
|
case "zh_TW":
|
||||||
|
fallthrough
|
||||||
|
case "zh-TW":
|
||||||
|
fallthrough
|
||||||
|
case "zh-tw":
|
||||||
|
trans, _ := Validator.UT.GetTranslator("zh_Hant")
|
||||||
|
return trans
|
||||||
|
case "ko":
|
||||||
|
trans, _ := Validator.UT.GetTranslator("ko")
|
||||||
|
return trans
|
||||||
|
case "ru":
|
||||||
|
trans, _ := Validator.UT.GetTranslator("ru")
|
||||||
|
return trans
|
||||||
|
case "es":
|
||||||
|
trans, _ := Validator.UT.GetTranslator("es")
|
||||||
|
return trans
|
||||||
|
case "fr":
|
||||||
|
trans, _ := Validator.UT.GetTranslator("fr")
|
||||||
|
return trans
|
||||||
|
case "en":
|
||||||
|
fallthrough
|
||||||
|
default:
|
||||||
|
trans, _ := Validator.UT.GetTranslator("en")
|
||||||
|
return trans
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,33 +1,40 @@
|
|||||||
package global
|
package global
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"Gwen/config"
|
"github.com/gin-gonic/gin"
|
||||||
"Gwen/lib/cache"
|
|
||||||
"Gwen/lib/jwt"
|
|
||||||
"Gwen/lib/lock"
|
|
||||||
"Gwen/lib/upload"
|
|
||||||
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/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
DB *gorm.DB
|
DB *gorm.DB
|
||||||
Logger *logrus.Logger
|
Logger *logrus.Logger
|
||||||
Config config.Config
|
ConfigPath string = ""
|
||||||
Viper *viper.Viper
|
Config config.Config
|
||||||
Redis *redis.Client
|
Viper *viper.Viper
|
||||||
Cache cache.Handler
|
Redis *redis.Client
|
||||||
Validator struct {
|
Cache cache.Handler
|
||||||
|
Validator struct {
|
||||||
Validate *validator.Validate
|
Validate *validator.Validate
|
||||||
|
UT *ut.UniversalTranslator
|
||||||
VTrans ut.Translator
|
VTrans ut.Translator
|
||||||
ValidStruct func(interface{}) []string
|
ValidStruct func(*gin.Context, interface{}) []string
|
||||||
ValidVar func(field interface{}, tag string) []string
|
ValidVar func(ctx *gin.Context, field interface{}, tag string) []string
|
||||||
}
|
}
|
||||||
Oss *upload.Oss
|
Oss *upload.Oss
|
||||||
Jwt *jwt.Jwt
|
Jwt *jwt.Jwt
|
||||||
Lock lock.Locker
|
Lock lock.Locker
|
||||||
|
Localizer func(lang string) *i18n.Localizer
|
||||||
|
LoginLimiter *utils.LoginLimiter
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package global
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/BurntSushi/toml"
|
||||||
|
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||||
|
"golang.org/x/text/language"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func InitI18n() {
|
||||||
|
bundle := i18n.NewBundle(language.English)
|
||||||
|
bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal)
|
||||||
|
// read all language files under global.Config.Gin.ResourcesPath
|
||||||
|
dir := Config.Gin.ResourcesPath + "/i18n"
|
||||||
|
fileInfos, err := os.ReadDir(dir)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
for _, fileInfo := range fileInfos {
|
||||||
|
// if the file name does not end with .toml
|
||||||
|
if fileInfo.IsDir() || fileInfo.Name()[len(fileInfo.Name())-5:] != ".toml" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
bundle.LoadMessageFile(Config.Gin.ResourcesPath + "/i18n/" + fileInfo.Name())
|
||||||
|
}
|
||||||
|
Localizer = func(lang string) *i18n.Localizer {
|
||||||
|
if lang == "" {
|
||||||
|
lang = Config.Lang
|
||||||
|
}
|
||||||
|
if lang == "en" {
|
||||||
|
return i18n.NewLocalizer(bundle, "en")
|
||||||
|
} else {
|
||||||
|
return i18n.NewLocalizer(bundle, lang, "en")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//personUnreadEmails := localizer.MustLocalize(&i18n.LocalizeConfig{
|
||||||
|
// DefaultMessage: &i18n.Message{
|
||||||
|
// ID: "PersonUnreadEmails",
|
||||||
|
// },
|
||||||
|
// PluralCount: 6,
|
||||||
|
// TemplateData: map[string]interface{}{
|
||||||
|
// "Name": "LE",
|
||||||
|
// "PluralCount": 6,
|
||||||
|
// },
|
||||||
|
//})
|
||||||
|
//personUnreadEmails, err := global.Localizer.LocalizeMessage(&i18n.Message{
|
||||||
|
// ID: "ParamsError",
|
||||||
|
//})
|
||||||
|
//fmt.Println(err, personUnreadEmails)
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,28 +1,41 @@
|
|||||||
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/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.6.0
|
||||||
|
github.com/mojocn/base64Captcha v1.3.6
|
||||||
|
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/viper v1.9.0
|
github.com/spf13/viper v1.9.0
|
||||||
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/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
|
||||||
@@ -30,20 +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/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
|
||||||
@@ -53,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
|
||||||
@@ -61,12 +85,12 @@ 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.14.0 // indirect
|
golang.org/x/image v0.13.0 // indirect
|
||||||
golang.org/x/net v0.17.0 // indirect
|
golang.org/x/net v0.34.0 // indirect
|
||||||
golang.org/x/sys v0.13.0 // indirect
|
golang.org/x/sync v0.11.0 // indirect
|
||||||
golang.org/x/text v0.13.0 // indirect
|
golang.org/x/sys v0.30.0 // indirect
|
||||||
golang.org/x/tools v0.7.0 // indirect
|
golang.org/x/tools v0.26.0 // indirect
|
||||||
google.golang.org/protobuf v1.28.1 // 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
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
package admin
|
package admin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"Gwen/global"
|
"encoding/json"
|
||||||
"Gwen/http/request/admin"
|
|
||||||
"Gwen/http/response"
|
|
||||||
"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"
|
||||||
)
|
)
|
||||||
@@ -14,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"
|
||||||
@@ -29,26 +30,21 @@ 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, "无权限")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if t.RowId > 0 {
|
if t.RowId > 0 {
|
||||||
response.Success(c, t)
|
response.Success(c, t)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
response.Fail(c, 101, "信息不存在")
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
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]
|
||||||
@@ -56,37 +52,112 @@ func (ct *AddressBook) Detail(c *gin.Context) {
|
|||||||
func (ct *AddressBook) Create(c *gin.Context) {
|
func (ct *AddressBook) Create(c *gin.Context) {
|
||||||
f := &admin.AddressBookForm{}
|
f := &admin.AddressBookForm{}
|
||||||
if err := c.ShouldBindJSON(f); err != nil {
|
if err := c.ShouldBindJSON(f); err != nil {
|
||||||
response.Fail(c, 101, "参数错误")
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
errList := global.Validator.ValidStruct(f)
|
errList := global.Validator.ValidStruct(c, f)
|
||||||
if len(errList) > 0 {
|
if len(errList) > 0 {
|
||||||
response.Fail(c, 101, errList[0])
|
response.Fail(c, 101, errList[0])
|
||||||
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
|
|
||||||
}
|
|
||||||
err := service.AllService.AddressBookService.Create(t)
|
|
||||||
if err != nil {
|
|
||||||
response.Fail(c, 101, "创建失败")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
response.Success(c, u)
|
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
// List 列表
|
// 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 page query int false "页码"
|
// @Param body body admin.AddressBookForm true "address book info"
|
||||||
// @Param page_size query int false "页大小"
|
// @Success 200 {object} response.Response{data=model.AddressBook}
|
||||||
// @Param user_id query int false "用户id"
|
// @Failure 500 {object} response.Response
|
||||||
// @Param is_my query int false "是否是我的"
|
// @Router /admin/address_book/batchCreate [post]
|
||||||
|
// @Security token
|
||||||
|
func (ct *AddressBook) BatchCreate(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
|
||||||
|
}
|
||||||
|
ul := len(f.UserIds)
|
||||||
|
|
||||||
|
if ul == 0 {
|
||||||
|
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 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, ft := range f.Tags {
|
||||||
|
exTag := service.AllService.TagService.InfoByUserIdAndNameAndCollectionId(fu, ft, 0)
|
||||||
|
if exTag.Id == 0 {
|
||||||
|
service.AllService.TagService.Create(&model.Tag{
|
||||||
|
UserId: fu,
|
||||||
|
Name: ft,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
ts := f.ToAddressBooks()
|
||||||
|
for _, t := range ts {
|
||||||
|
if t.UserId == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ex := service.AllService.AddressBookService.InfoByUserIdAndIdAndCid(t.UserId, t.Id, t.CollectionId)
|
||||||
|
if ex.RowId == 0 {
|
||||||
|
service.AllService.AddressBookService.Create(t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
response.Success(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// List list
|
||||||
|
// @Tags 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"
|
||||||
|
// @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]
|
||||||
@@ -94,28 +165,44 @@ func (ct *AddressBook) Create(c *gin.Context) {
|
|||||||
func (ct *AddressBook) List(c *gin.Context) {
|
func (ct *AddressBook) List(c *gin.Context) {
|
||||||
query := &admin.AddressBookQuery{}
|
query := &admin.AddressBookQuery{}
|
||||||
if err := c.ShouldBindQuery(query); err != nil {
|
if err := c.ShouldBindQuery(query); err != nil {
|
||||||
response.Fail(c, 101, "参数错误")
|
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 {
|
||||||
|
return txc.Select("id,name")
|
||||||
|
})
|
||||||
|
if query.Id != "" {
|
||||||
|
tx.Where("id like ?", "%"+query.Id+"%")
|
||||||
|
}
|
||||||
if query.UserId > 0 {
|
if query.UserId > 0 {
|
||||||
tx.Where("user_id = ?", query.UserId)
|
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)
|
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]
|
||||||
@@ -123,39 +210,43 @@ func (ct *AddressBook) List(c *gin.Context) {
|
|||||||
func (ct *AddressBook) Update(c *gin.Context) {
|
func (ct *AddressBook) Update(c *gin.Context) {
|
||||||
f := &admin.AddressBookForm{}
|
f := &admin.AddressBookForm{}
|
||||||
if err := c.ShouldBindJSON(f); err != nil {
|
if err := c.ShouldBindJSON(f); err != nil {
|
||||||
response.Fail(c, 101, "参数错误")
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
errList := global.Validator.ValidStruct(f)
|
errList := global.Validator.ValidStruct(c, f)
|
||||||
if len(errList) > 0 {
|
if len(errList) > 0 {
|
||||||
response.Fail(c, 101, errList[0])
|
response.Fail(c, 101, errList[0])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if f.RowId == 0 {
|
if f.RowId == 0 {
|
||||||
response.Fail(c, 101, "参数错误")
|
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 t.CollectionId > 0 && !service.AllService.AddressBookService.CheckCollectionOwner(t.UserId, t.CollectionId) {
|
||||||
if !service.AllService.UserService.IsAdmin(u) && t.UserId != u.Id {
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||||
response.Fail(c, 101, "无权限")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err := service.AllService.AddressBookService.Update(t)
|
err := service.AllService.AddressBookService.UpdateAll(t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.Fail(c, 101, "更新失败")
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
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]
|
||||||
@@ -163,29 +254,109 @@ func (ct *AddressBook) Update(c *gin.Context) {
|
|||||||
func (ct *AddressBook) Delete(c *gin.Context) {
|
func (ct *AddressBook) Delete(c *gin.Context) {
|
||||||
f := &admin.AddressBookForm{}
|
f := &admin.AddressBookForm{}
|
||||||
if err := c.ShouldBindJSON(f); err != nil {
|
if err := c.ShouldBindJSON(f); err != nil {
|
||||||
response.Fail(c, 101, "系统错误")
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
id := f.RowId
|
id := f.RowId
|
||||||
errList := global.Validator.ValidVar(id, "required,gt=0")
|
errList := global.Validator.ValidVar(c, id, "required,gt=0")
|
||||||
if len(errList) > 0 {
|
if len(errList) > 0 {
|
||||||
response.Fail(c, 101, errList[0])
|
response.Fail(c, 101, errList[0])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
t := service.AllService.AddressBookService.InfoByRowId(f.RowId)
|
t := service.AllService.AddressBookService.InfoByRowId(f.RowId)
|
||||||
u := service.AllService.UserService.CurUser(c)
|
if t.RowId == 0 {
|
||||||
if !service.AllService.UserService.IsAdmin(u) && t.UserId != u.Id {
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
response.Fail(c, 101, "无权限")
|
|
||||||
return
|
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
|
||||||
|
}
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// ShareByWebClient
|
||||||
|
// @Tags address book
|
||||||
|
// @Summary share address book
|
||||||
|
// @Description share address book
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param body body admin.ShareByWebClientForm true "address book info"
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/address_book/share [post]
|
||||||
|
// @Security token
|
||||||
|
func (ct *AddressBook) ShareByWebClient(c *gin.Context) {
|
||||||
|
f := &admin.ShareByWebClientForm{}
|
||||||
|
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)
|
||||||
|
ab := service.AllService.AddressBookService.InfoByUserIdAndId(u.Id, f.Id)
|
||||||
|
if ab.RowId == 0 {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
m := f.ToShareRecord()
|
||||||
|
m.UserId = u.Id
|
||||||
|
err := service.AllService.AddressBookService.ShareByWebClient(m)
|
||||||
|
if err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Success(c, &gin.H{
|
||||||
|
"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
|
return
|
||||||
}
|
}
|
||||||
response.Fail(c, 101, err.Error())
|
}
|
||||||
|
|
||||||
|
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
|
return
|
||||||
}
|
}
|
||||||
response.Fail(c, 101, "信息不存在")
|
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,172 @@
|
|||||||
|
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/model"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AddressBookCollection struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detail address book name
|
||||||
|
// @Tags address book name
|
||||||
|
// @Summary address book name details
|
||||||
|
// @Description address book name details
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path int true "ID"
|
||||||
|
// @Success 200 {object} response.Response{data=model.AddressBookCollection}
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/address_book_collection/detail/{id} [get]
|
||||||
|
// @Security token
|
||||||
|
func (abc *AddressBookCollection) Detail(c *gin.Context) {
|
||||||
|
id := c.Param("id")
|
||||||
|
iid, _ := strconv.Atoi(id)
|
||||||
|
t := service.AllService.AddressBookService.CollectionInfoById(uint(iid))
|
||||||
|
if t.Id > 0 {
|
||||||
|
response.Success(c, t)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create create address book name
|
||||||
|
// @Tags 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/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
|
||||||
|
}
|
||||||
|
if f.UserId == 0 {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t := f
|
||||||
|
err := service.AllService.AddressBookService.CreateCollection(t)
|
||||||
|
if err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Success(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// List list
|
||||||
|
// @Tags 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"
|
||||||
|
// @Param is_my query int false "whether it is mine"
|
||||||
|
// @Param user_id query int false "userid"
|
||||||
|
// @Success 200 {object} response.Response{data=model.AddressBookCollectionList}
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/address_book_collection/list [get]
|
||||||
|
// @Security token
|
||||||
|
func (abc *AddressBookCollection) List(c *gin.Context) {
|
||||||
|
query := &admin.AddressBookCollectionQuery{}
|
||||||
|
if err := c.ShouldBindQuery(query); err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res := service.AllService.AddressBookService.ListCollection(query.Page, query.PageSize, func(tx *gorm.DB) {
|
||||||
|
if query.UserId > 0 {
|
||||||
|
tx.Where("user_id = ?", query.UserId)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
response.Success(c, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update edit
|
||||||
|
// @Tags 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/address_book_collection/update [post]
|
||||||
|
// @Security token
|
||||||
|
func (abc *AddressBookCollection) Update(c *gin.Context) {
|
||||||
|
f := &model.AddressBookCollection{}
|
||||||
|
if err := c.ShouldBindJSON(f); err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
errList := global.Validator.ValidStruct(c, f)
|
||||||
|
if len(errList) > 0 {
|
||||||
|
response.Fail(c, 101, errList[0])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if f.Id == 0 {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t := f //f.ToAddressBookCollection()
|
||||||
|
err := service.AllService.AddressBookService.UpdateCollection(t)
|
||||||
|
if err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Success(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete delete
|
||||||
|
// @Tags 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/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
|
||||||
|
}
|
||||||
|
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,222 @@
|
|||||||
|
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/model"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AddressBookCollectionRule struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// List list
|
||||||
|
// @Tags 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/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
|
||||||
|
}
|
||||||
|
|
||||||
|
res := service.AllService.AddressBookService.ListRules(query.Page, query.PageSize, func(tx *gorm.DB) {
|
||||||
|
if query.UserId > 0 {
|
||||||
|
tx.Where("user_id = ?", query.UserId)
|
||||||
|
}
|
||||||
|
if query.CollectionId > 0 {
|
||||||
|
tx.Where("collection_id = ?", query.CollectionId)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
response.Success(c, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detail address book rules
|
||||||
|
// @Tags address book rules
|
||||||
|
// @Summary address book rule details
|
||||||
|
// @Description address book rule details
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path int true "ID"
|
||||||
|
// @Success 200 {object} response.Response{data=model.AddressBookCollectionRule}
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/address_book_collection_rule/detail/{id} [get]
|
||||||
|
// @Security token
|
||||||
|
func (abcr *AddressBookCollectionRule) Detail(c *gin.Context) {
|
||||||
|
id := c.Param("id")
|
||||||
|
iid, _ := strconv.Atoi(id)
|
||||||
|
t := service.AllService.AddressBookService.RuleInfoById(uint(iid))
|
||||||
|
if t.Id > 0 {
|
||||||
|
response.Success(c, t)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create create address book rule
|
||||||
|
// @Tags 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/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
|
||||||
|
msg, res := abcr.CheckForm(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(t *model.AddressBookCollectionRule) (string, bool) {
|
||||||
|
if t.UserId == 0 {
|
||||||
|
return "ParamsError", 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
|
||||||
|
}
|
||||||
|
} else if t.Type == model.ShareAddressBookRuleTypeGroup {
|
||||||
|
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 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/address_book_collection_rule/update [post]
|
||||||
|
// @Security token
|
||||||
|
func (abcr *AddressBookCollectionRule) Update(c *gin.Context) {
|
||||||
|
f := &model.AddressBookCollectionRule{}
|
||||||
|
if err := c.ShouldBindJSON(f); err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
errList := global.Validator.ValidStruct(c, f)
|
||||||
|
if len(errList) > 0 {
|
||||||
|
response.Fail(c, 101, errList[0])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if f.Id == 0 {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t := f
|
||||||
|
msg, res := abcr.CheckForm(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 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/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
|
||||||
|
}
|
||||||
|
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,212 @@
|
|||||||
|
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/model"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Audit struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConnList list
|
||||||
|
// @Tags connection log
|
||||||
|
// @Summary connection log list
|
||||||
|
// @Description connection log list
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param page query int false "page number"
|
||||||
|
// @Param page_size query int false "page size"
|
||||||
|
// @Param peer_id query int false "target device"
|
||||||
|
// @Param from_peer query int false "source device"
|
||||||
|
// @Success 200 {object} response.Response{data=model.AuditConnList}
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/audit_conn/list [get]
|
||||||
|
// @Security token
|
||||||
|
func (a *Audit) ConnList(c *gin.Context) {
|
||||||
|
query := &admin.AuditQuery{}
|
||||||
|
if err := c.ShouldBindQuery(query); err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res := service.AllService.AuditService.AuditConnList(query.Page, query.PageSize, func(tx *gorm.DB) {
|
||||||
|
if query.PeerId != "" {
|
||||||
|
tx.Where("peer_id like ?", "%"+query.PeerId+"%")
|
||||||
|
}
|
||||||
|
if query.FromPeer != "" {
|
||||||
|
tx.Where("from_peer like ?", "%"+query.FromPeer+"%")
|
||||||
|
}
|
||||||
|
tx.Order("id desc")
|
||||||
|
})
|
||||||
|
response.Success(c, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConnDelete delete
|
||||||
|
// @Tags connection log
|
||||||
|
// @Summary delete connection log
|
||||||
|
// @Description delete connection log
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param body body model.AuditConn true "connection log info"
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/audit_conn/delete [post]
|
||||||
|
// @Security token
|
||||||
|
func (a *Audit) ConnDelete(c *gin.Context) {
|
||||||
|
f := &model.AuditConn{}
|
||||||
|
if err := c.ShouldBindJSON(f); err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
id := f.Id
|
||||||
|
errList := global.Validator.ValidVar(c, id, "required,gt=0")
|
||||||
|
if len(errList) > 0 {
|
||||||
|
response.Fail(c, 101, errList[0])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
l := service.AllService.AuditService.ConnInfoById(f.Id)
|
||||||
|
if l.Id > 0 {
|
||||||
|
err := service.AllService.AuditService.DeleteAuditConn(l)
|
||||||
|
if err == nil {
|
||||||
|
response.Success(c, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Fail(c, 101, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// BatchConnDelete delete
|
||||||
|
// @Tags connection log
|
||||||
|
// @Summary batch delete connection logs
|
||||||
|
// @Description batch delete connection logs
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param body body admin.AuditConnLogIds true "connection log"
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/audit_conn/batchDelete [post]
|
||||||
|
// @Security token
|
||||||
|
func (a *Audit) BatchConnDelete(c *gin.Context) {
|
||||||
|
f := &admin.AuditConnLogIds{}
|
||||||
|
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.AuditService.BatchDeleteAuditConn(f.Ids)
|
||||||
|
if err == nil {
|
||||||
|
response.Success(c, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Fail(c, 101, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// FileList list
|
||||||
|
// @Tags file log
|
||||||
|
// @Summary file log list
|
||||||
|
// @Description file log list
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param page query int false "page number"
|
||||||
|
// @Param page_size query int false "page size"
|
||||||
|
// @Param peer_id query int false "target device"
|
||||||
|
// @Param from_peer query int false "source device"
|
||||||
|
// @Success 200 {object} response.Response{data=model.AuditFileList}
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/audit_file/list [get]
|
||||||
|
// @Security token
|
||||||
|
func (a *Audit) FileList(c *gin.Context) {
|
||||||
|
query := &admin.AuditQuery{}
|
||||||
|
if err := c.ShouldBindQuery(query); err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res := service.AllService.AuditService.AuditFileList(query.Page, query.PageSize, func(tx *gorm.DB) {
|
||||||
|
if query.PeerId != "" {
|
||||||
|
tx.Where("peer_id like ?", "%"+query.PeerId+"%")
|
||||||
|
}
|
||||||
|
if query.FromPeer != "" {
|
||||||
|
tx.Where("from_peer like ?", "%"+query.FromPeer+"%")
|
||||||
|
}
|
||||||
|
tx.Order("id desc")
|
||||||
|
})
|
||||||
|
response.Success(c, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FileDelete delete
|
||||||
|
// @Tags file log
|
||||||
|
// @Summary delete file log
|
||||||
|
// @Description delete file log
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param body body model.AuditFile true "file log info"
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/audit_file/delete [post]
|
||||||
|
// @Security token
|
||||||
|
func (a *Audit) FileDelete(c *gin.Context) {
|
||||||
|
f := &model.AuditFile{}
|
||||||
|
if err := c.ShouldBindJSON(f); err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
id := f.Id
|
||||||
|
errList := global.Validator.ValidVar(c, id, "required,gt=0")
|
||||||
|
if len(errList) > 0 {
|
||||||
|
response.Fail(c, 101, errList[0])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
l := service.AllService.AuditService.FileInfoById(f.Id)
|
||||||
|
if l.Id > 0 {
|
||||||
|
err := service.AllService.AuditService.DeleteAuditFile(l)
|
||||||
|
if err == nil {
|
||||||
|
response.Success(c, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Fail(c, 101, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// BatchFileDelete delete
|
||||||
|
// @Tags file log
|
||||||
|
// @Summary batch delete file logs
|
||||||
|
// @Description batch delete file logs
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param body body admin.AuditFileLogIds true "file log"
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/audit_file/batchDelete [post]
|
||||||
|
// @Security token
|
||||||
|
func (a *Audit) BatchFileDelete(c *gin.Context) {
|
||||||
|
f := &admin.AuditFileLogIds{}
|
||||||
|
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.AuditService.BatchDeleteAuditFile(f.Ids)
|
||||||
|
if err == nil {
|
||||||
|
response.Success(c, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Fail(c, 101, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
package admin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"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"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServerConfig RUSTDESKservice config
|
||||||
|
// @Tags ADMIN
|
||||||
|
// @Summary RUSTDESKservice config
|
||||||
|
// @Description service config, provides an api-server for the webclient
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/config/server [get]
|
||||||
|
// @Security token
|
||||||
|
func (co *Config) 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 APPservice config
|
||||||
|
// @Tags ADMIN
|
||||||
|
// @Summary APPservice config
|
||||||
|
// @Description APPservice config
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/config/app [get]
|
||||||
|
// @Security token
|
||||||
|
func (co *Config) AppConfig(c *gin.Context) {
|
||||||
|
response.Success(c, &gin.H{
|
||||||
|
"web_client": global.Config.App.WebClient,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// AdminConfig ADMINservice config
|
||||||
|
// @Tags ADMIN
|
||||||
|
// @Summary ADMINservice config
|
||||||
|
// @Description ADMINservice config
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/config/admin [get]
|
||||||
|
// @Security token
|
||||||
|
func (co *Config) AdminConfig(c *gin.Context) {
|
||||||
|
|
||||||
|
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
|
||||||
|
if hello == "" {
|
||||||
|
helloFile := global.Config.Admin.HelloFile
|
||||||
|
if helloFile != "" {
|
||||||
|
b, err := os.ReadFile(helloFile)
|
||||||
|
if err == nil && len(b) > 0 {
|
||||||
|
hello = string(b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//replace {{username}} to username
|
||||||
|
hello = strings.Replace(hello, "{{username}}", u.Username, -1)
|
||||||
|
response.Success(c, &gin.H{
|
||||||
|
"title": global.Config.Admin.Title,
|
||||||
|
"hello": hello,
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -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"
|
||||||
@@ -31,17 +31,17 @@ func (ct *Group) Detail(c *gin.Context) {
|
|||||||
response.Success(c, u)
|
response.Success(c, u)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
response.Fail(c, 101, "信息不存在")
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
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]
|
||||||
@@ -49,10 +49,10 @@ func (ct *Group) Detail(c *gin.Context) {
|
|||||||
func (ct *Group) Create(c *gin.Context) {
|
func (ct *Group) Create(c *gin.Context) {
|
||||||
f := &admin.GroupForm{}
|
f := &admin.GroupForm{}
|
||||||
if err := c.ShouldBindJSON(f); err != nil {
|
if err := c.ShouldBindJSON(f); err != nil {
|
||||||
response.Fail(c, 101, "参数错误")
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
errList := global.Validator.ValidStruct(f)
|
errList := global.Validator.ValidStruct(c, f)
|
||||||
if len(errList) > 0 {
|
if len(errList) > 0 {
|
||||||
response.Fail(c, 101, errList[0])
|
response.Fail(c, 101, errList[0])
|
||||||
return
|
return
|
||||||
@@ -60,20 +60,20 @@ func (ct *Group) Create(c *gin.Context) {
|
|||||||
u := f.ToGroup()
|
u := f.ToGroup()
|
||||||
err := service.AllService.GroupService.Create(u)
|
err := service.AllService.GroupService.Create(u)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.Fail(c, 101, "创建失败")
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
response.Success(c, u)
|
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]
|
||||||
@@ -81,20 +81,20 @@ func (ct *Group) Create(c *gin.Context) {
|
|||||||
func (ct *Group) List(c *gin.Context) {
|
func (ct *Group) List(c *gin.Context) {
|
||||||
query := &admin.PageQuery{}
|
query := &admin.PageQuery{}
|
||||||
if err := c.ShouldBindQuery(query); err != nil {
|
if err := c.ShouldBindQuery(query); err != nil {
|
||||||
response.Fail(c, 101, "参数错误")
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
res := service.AllService.GroupService.List(query.Page, query.PageSize, nil)
|
res := service.AllService.GroupService.List(query.Page, query.PageSize, nil)
|
||||||
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]
|
||||||
@@ -102,14 +102,14 @@ func (ct *Group) List(c *gin.Context) {
|
|||||||
func (ct *Group) Update(c *gin.Context) {
|
func (ct *Group) Update(c *gin.Context) {
|
||||||
f := &admin.GroupForm{}
|
f := &admin.GroupForm{}
|
||||||
if err := c.ShouldBindJSON(f); err != nil {
|
if err := c.ShouldBindJSON(f); err != nil {
|
||||||
response.Fail(c, 101, "参数错误")
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if f.Id == 0 {
|
if f.Id == 0 {
|
||||||
response.Fail(c, 101, "参数错误")
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
errList := global.Validator.ValidStruct(f)
|
errList := global.Validator.ValidStruct(c, f)
|
||||||
if len(errList) > 0 {
|
if len(errList) > 0 {
|
||||||
response.Fail(c, 101, errList[0])
|
response.Fail(c, 101, errList[0])
|
||||||
return
|
return
|
||||||
@@ -117,19 +117,19 @@ func (ct *Group) Update(c *gin.Context) {
|
|||||||
u := f.ToGroup()
|
u := f.ToGroup()
|
||||||
err := service.AllService.GroupService.Update(u)
|
err := service.AllService.GroupService.Update(u)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.Fail(c, 101, "更新失败")
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
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]
|
||||||
@@ -137,11 +137,11 @@ func (ct *Group) Update(c *gin.Context) {
|
|||||||
func (ct *Group) Delete(c *gin.Context) {
|
func (ct *Group) Delete(c *gin.Context) {
|
||||||
f := &admin.GroupForm{}
|
f := &admin.GroupForm{}
|
||||||
if err := c.ShouldBindJSON(f); err != nil {
|
if err := c.ShouldBindJSON(f); err != nil {
|
||||||
response.Fail(c, 101, "系统错误")
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
id := f.Id
|
id := f.Id
|
||||||
errList := global.Validator.ValidVar(id, "required,gt=0")
|
errList := global.Validator.ValidVar(c, id, "required,gt=0")
|
||||||
if len(errList) > 0 {
|
if len(errList) > 0 {
|
||||||
response.Fail(c, 101, errList[0])
|
response.Fail(c, 101, errList[0])
|
||||||
return
|
return
|
||||||
@@ -153,8 +153,8 @@ func (ct *Group) Delete(c *gin.Context) {
|
|||||||
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
|
return
|
||||||
}
|
}
|
||||||
response.Fail(c, 101, "信息不存在")
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,64 +1,138 @@
|
|||||||
package admin
|
package admin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"Gwen/global"
|
|
||||||
"Gwen/http/request/admin"
|
|
||||||
"Gwen/http/response"
|
|
||||||
adResp "Gwen/http/response/admin"
|
|
||||||
"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) {
|
||||||
fmt.Println("login")
|
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 {
|
||||||
response.Fail(c, 101, "参数错误")
|
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())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
errList := global.Validator.ValidStruct(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(), 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 {
|
||||||
response.Fail(c, 101, "用户名或密码错误")
|
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"))
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ut := service.AllService.UserService.Login(u)
|
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
|
||||||
|
}
|
||||||
|
|
||||||
response.Success(c, &adResp.LoginPayload{
|
ut := service.AllService.UserService.Login(u, &model.LoginLog{
|
||||||
Token: ut.Token,
|
UserId: u.Id,
|
||||||
Username: u.Username,
|
Client: model.LoginLogClientWebAdmin,
|
||||||
RouteNames: service.AllService.UserService.RouteNames(u),
|
Uuid: "", //must be empty
|
||||||
Nickname: u.Nickname,
|
Ip: clientIp,
|
||||||
|
Type: model.LoginLogTypeAccount,
|
||||||
|
Platform: f.Platform,
|
||||||
|
})
|
||||||
|
|
||||||
|
// login successful, clear the login limit
|
||||||
|
loginLimiter.RemoveAttempts(clientIp)
|
||||||
|
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
|
||||||
@@ -72,3 +146,97 @@ func (ct *Login) Logout(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LoginOptions
|
||||||
|
// @Tags login
|
||||||
|
// @Summary login options
|
||||||
|
// @Description login options
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} []string
|
||||||
|
// @Failure 500 {object} response.ErrorResponse
|
||||||
|
// @Router /admin/login-options [post]
|
||||||
|
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()
|
||||||
|
response.Success(c, gin.H{
|
||||||
|
"ops": ops,
|
||||||
|
"register": global.Config.App.Register,
|
||||||
|
"need_captcha": needCaptcha,
|
||||||
|
"disable_pwd": global.Config.App.DisablePwdLogin,
|
||||||
|
"auto_oidc": global.Config.App.DisablePwdLogin && len(ops) == 1,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// OidcAuth
|
||||||
|
// @Tags Oauth
|
||||||
|
// @Summary OidcAuth
|
||||||
|
// @Description OidcAuth
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Router /admin/oidc/auth [post]
|
||||||
|
func (ct *Login) OidcAuth(c *gin.Context) {
|
||||||
|
// o := &api.Oauth{}
|
||||||
|
// o.OidcAuth(c)
|
||||||
|
f := &apiReq.OidcAuthRequest{}
|
||||||
|
err := c.ShouldBindJSON(f)
|
||||||
|
if err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err, state, verifier, nonce, url := service.AllService.OauthService.BeginAuth(f.Op)
|
||||||
|
if err != nil {
|
||||||
|
response.Error(c, response.TranslateMsg(c, err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
service.AllService.OauthService.SetOauthCache(state, &service.OauthCacheItem{
|
||||||
|
Action: service.OauthActionTypeLogin,
|
||||||
|
Op: f.Op,
|
||||||
|
Id: f.Id,
|
||||||
|
DeviceType: "webadmin",
|
||||||
|
// DeviceOs: ct.Platform(c),
|
||||||
|
DeviceOs: f.DeviceInfo.Os,
|
||||||
|
Uuid: f.Uuid,
|
||||||
|
Verifier: verifier,
|
||||||
|
Nonce: nonce,
|
||||||
|
}, 5*60)
|
||||||
|
|
||||||
|
response.Success(c, gin.H{
|
||||||
|
"code": state,
|
||||||
|
"url": url,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// OidcAuthQuery
|
||||||
|
// @Tags Oauth
|
||||||
|
// @Summary OidcAuthQuery
|
||||||
|
// @Description OidcAuthQuery
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} response.Response{data=adResp.LoginPayload}
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/oidc/auth-query [get]
|
||||||
|
func (ct *Login) OidcAuthQuery(c *gin.Context) {
|
||||||
|
o := &api.Oauth{}
|
||||||
|
u, ut := o.OidcAuthQueryPre(c)
|
||||||
|
if ut == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
responseLoginSuccess(c, u, ut.Token)
|
||||||
|
}
|
||||||
|
|
||||||
|
func responseLoginSuccess(c *gin.Context, u *model.User, token string) {
|
||||||
|
lp := &adResp.LoginPayload{}
|
||||||
|
lp.FromUser(u)
|
||||||
|
lp.Token = token
|
||||||
|
lp.RouteNames = service.AllService.UserService.RouteNames(u)
|
||||||
|
response.Success(c, lp)
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,133 @@
|
|||||||
|
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/model"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LoginLog struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detail login log
|
||||||
|
// @Tags login log
|
||||||
|
// @Summary login log details
|
||||||
|
// @Description login log details
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path int true "ID"
|
||||||
|
// @Success 200 {object} response.Response{data=model.LoginLog}
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/login_log/detail/{id} [get]
|
||||||
|
// @Security token
|
||||||
|
func (ct *LoginLog) Detail(c *gin.Context) {
|
||||||
|
id := c.Param("id")
|
||||||
|
iid, _ := strconv.Atoi(id)
|
||||||
|
u := service.AllService.LoginLogService.InfoById(uint(iid))
|
||||||
|
if u.Id > 0 {
|
||||||
|
response.Success(c, u)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// List list
|
||||||
|
// @Tags login log
|
||||||
|
// @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/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
|
||||||
|
}
|
||||||
|
res := service.AllService.LoginLogService.List(query.Page, query.PageSize, func(tx *gorm.DB) {
|
||||||
|
if query.UserId > 0 {
|
||||||
|
tx.Where("user_id = ?", query.UserId)
|
||||||
|
}
|
||||||
|
tx.Order("id desc")
|
||||||
|
})
|
||||||
|
response.Success(c, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete delete
|
||||||
|
// @Tags login log
|
||||||
|
// @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/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 {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := service.AllService.LoginLogService.Delete(l)
|
||||||
|
if err == nil {
|
||||||
|
response.Success(c, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Fail(c, 101, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// BatchDelete delete
|
||||||
|
// @Tags login log
|
||||||
|
// @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/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
|
||||||
|
}
|
||||||
|
|
||||||
|
err := service.AllService.LoginLogService.BatchDelete(f.Ids)
|
||||||
|
if err == nil {
|
||||||
|
response.Success(c, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Fail(c, 101, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -0,0 +1,296 @@
|
|||||||
|
package admin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"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 {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Info
|
||||||
|
func (o *Oauth) Info(c *gin.Context) {
|
||||||
|
code := c.Query("code")
|
||||||
|
if code == "" {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
v := service.AllService.OauthService.GetOauthCache(code)
|
||||||
|
if v == nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Success(c, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Oauth) ToBind(c *gin.Context) {
|
||||||
|
f := &adminReq.BindOauthForm{}
|
||||||
|
err := c.ShouldBindJSON(f)
|
||||||
|
if err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
|
||||||
|
utr := service.AllService.UserService.UserThirdInfo(u.Id, f.Op)
|
||||||
|
if utr.Id > 0 {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "OauthHasBindOtherUser"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err, state, verifier, nonce, url := service.AllService.OauthService.BeginAuth(f.Op)
|
||||||
|
if err != nil {
|
||||||
|
response.Error(c, response.TranslateMsg(c, err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
service.AllService.OauthService.SetOauthCache(state, &service.OauthCacheItem{
|
||||||
|
Action: service.OauthActionTypeBind,
|
||||||
|
Op: f.Op,
|
||||||
|
UserId: u.Id,
|
||||||
|
Verifier: verifier,
|
||||||
|
Nonce: nonce,
|
||||||
|
}, 5*60)
|
||||||
|
|
||||||
|
response.Success(c, gin.H{
|
||||||
|
"code": state,
|
||||||
|
"url": url,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Confirm confirm authorized login
|
||||||
|
func (o *Oauth) Confirm(c *gin.Context) {
|
||||||
|
j := &adminReq.OauthConfirmForm{}
|
||||||
|
err := c.ShouldBindJSON(j)
|
||||||
|
if err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if j.Code == "" {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
v := service.AllService.OauthService.GetOauthCache(j.Code)
|
||||||
|
if v == nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "OauthExpired"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
v.UserId = u.Id
|
||||||
|
service.AllService.OauthService.SetOauthCache(j.Code, v, 0)
|
||||||
|
response.Success(c, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Oauth) BindConfirm(c *gin.Context) {
|
||||||
|
j := &adminReq.OauthConfirmForm{}
|
||||||
|
err := c.ShouldBindJSON(j)
|
||||||
|
if err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if j.Code == "" {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
oauthService := service.AllService.OauthService
|
||||||
|
oauthCache := oauthService.GetOauthCache(j.Code)
|
||||||
|
if oauthCache == nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "OauthExpired"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
oauthUser := oauthCache.ToOauthUser()
|
||||||
|
user := service.AllService.UserService.CurUser(c)
|
||||||
|
err = oauthService.BindOauthUser(user.Id, oauthUser, oauthCache.Op)
|
||||||
|
if err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "BindFail"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
oauthCache.UserId = user.Id
|
||||||
|
oauthService.SetOauthCache(j.Code, oauthCache, 0)
|
||||||
|
response.Success(c, oauthCache)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Oauth) Unbind(c *gin.Context) {
|
||||||
|
f := &adminReq.UnBindOauthForm{}
|
||||||
|
err := c.ShouldBindJSON(f)
|
||||||
|
if err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
utr := service.AllService.UserService.UserThirdInfo(u.Id, f.Op)
|
||||||
|
if utr.Id == 0 {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = service.AllService.OauthService.UnBindOauthUser(u.Id, f.Op)
|
||||||
|
if err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Success(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detail Oauth
|
||||||
|
// @Tags Oauth
|
||||||
|
// @Summary Oauthdetails
|
||||||
|
// @Description Oauthdetails
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path int true "ID"
|
||||||
|
// @Success 200 {object} response.Response{data=model.Oauth}
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/oauth/detail/{id} [get]
|
||||||
|
// @Security token
|
||||||
|
func (o *Oauth) Detail(c *gin.Context) {
|
||||||
|
id := c.Param("id")
|
||||||
|
iid, _ := strconv.Atoi(id)
|
||||||
|
u := service.AllService.OauthService.InfoById(uint(iid))
|
||||||
|
if u.Id > 0 {
|
||||||
|
response.Success(c, u)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create createOauth
|
||||||
|
// @Tags Oauth
|
||||||
|
// @Summary createOauth
|
||||||
|
// @Description createOauth
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param body body admin.OauthForm true "Oauthinfo"
|
||||||
|
// @Success 200 {object} response.Response{data=model.Oauth}
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/oauth/create [post]
|
||||||
|
// @Security token
|
||||||
|
func (o *Oauth) Create(c *gin.Context) {
|
||||||
|
f := &admin.OauthForm{}
|
||||||
|
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.ToOauth()
|
||||||
|
err := u.FormatOauthInfo()
|
||||||
|
if err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ex := service.AllService.OauthService.InfoByOp(u.Op)
|
||||||
|
if ex.Id > 0 {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemExists"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = service.AllService.OauthService.Create(u)
|
||||||
|
if err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Success(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// List list
|
||||||
|
// @Tags Oauth
|
||||||
|
// @Summary Oauthlist
|
||||||
|
// @Description Oauthlist
|
||||||
|
// @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.OauthList}
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/oauth/list [get]
|
||||||
|
// @Security token
|
||||||
|
func (o *Oauth) 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.OauthService.List(query.Page, query.PageSize, nil)
|
||||||
|
response.Success(c, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update edit
|
||||||
|
// @Tags Oauth
|
||||||
|
// @Summary Oauthedit
|
||||||
|
// @Description Oauthedit
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param body body admin.OauthForm true "Oauthinfo"
|
||||||
|
// @Success 200 {object} response.Response{data=model.OauthList}
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/oauth/update [post]
|
||||||
|
// @Security token
|
||||||
|
func (o *Oauth) Update(c *gin.Context) {
|
||||||
|
f := &admin.OauthForm{}
|
||||||
|
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.ToOauth()
|
||||||
|
err := service.AllService.OauthService.Update(u)
|
||||||
|
if err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Success(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete delete
|
||||||
|
// @Tags Oauth
|
||||||
|
// @Summary Oauthdelete
|
||||||
|
// @Description Oauthdelete
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param body body admin.OauthForm true "Oauthinfo"
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/oauth/delete [post]
|
||||||
|
// @Security token
|
||||||
|
func (o *Oauth) Delete(c *gin.Context) {
|
||||||
|
f := &admin.OauthForm{}
|
||||||
|
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.OauthService.InfoById(f.Id)
|
||||||
|
if u.Id > 0 {
|
||||||
|
err := service.AllService.OauthService.Delete(u)
|
||||||
|
if err == nil {
|
||||||
|
response.Success(c, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Fail(c, 101, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
}
|
||||||
@@ -1,21 +1,23 @@
|
|||||||
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"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
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"
|
||||||
@@ -31,17 +33,17 @@ func (ct *Peer) Detail(c *gin.Context) {
|
|||||||
response.Success(c, u)
|
response.Success(c, u)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
response.Fail(c, 101, "信息不存在")
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
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]
|
||||||
@@ -49,52 +51,83 @@ func (ct *Peer) Detail(c *gin.Context) {
|
|||||||
func (ct *Peer) Create(c *gin.Context) {
|
func (ct *Peer) Create(c *gin.Context) {
|
||||||
f := &admin.PeerForm{}
|
f := &admin.PeerForm{}
|
||||||
if err := c.ShouldBindJSON(f); err != nil {
|
if err := c.ShouldBindJSON(f); err != nil {
|
||||||
response.Fail(c, 101, "参数错误")
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
errList := global.Validator.ValidStruct(f)
|
errList := global.Validator.ValidStruct(c, f)
|
||||||
if len(errList) > 0 {
|
if len(errList) > 0 {
|
||||||
response.Fail(c, 101, errList[0])
|
response.Fail(c, 101, errList[0])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
u := f.ToPeer()
|
p := f.ToPeer()
|
||||||
err := service.AllService.PeerService.Create(u)
|
err := service.AllService.PeerService.Create(p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.Fail(c, 101, "创建失败")
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
response.Success(c, u)
|
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 "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}
|
// @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]
|
||||||
// @Security token
|
// @Security token
|
||||||
func (ct *Peer) List(c *gin.Context) {
|
func (ct *Peer) List(c *gin.Context) {
|
||||||
query := &admin.PageQuery{}
|
query := &admin.PeerQuery{}
|
||||||
if err := c.ShouldBindQuery(query); err != nil {
|
if err := c.ShouldBindQuery(query); err != nil {
|
||||||
response.Fail(c, 101, "参数错误")
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
res := service.AllService.PeerService.List(query.Page, query.PageSize, nil)
|
res := service.AllService.PeerService.List(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)
|
||||||
|
}
|
||||||
|
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]
|
||||||
@@ -102,14 +135,14 @@ func (ct *Peer) List(c *gin.Context) {
|
|||||||
func (ct *Peer) Update(c *gin.Context) {
|
func (ct *Peer) Update(c *gin.Context) {
|
||||||
f := &admin.PeerForm{}
|
f := &admin.PeerForm{}
|
||||||
if err := c.ShouldBindJSON(f); err != nil {
|
if err := c.ShouldBindJSON(f); err != nil {
|
||||||
response.Fail(c, 101, "参数错误")
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if f.RowId == 0 {
|
if f.RowId == 0 {
|
||||||
response.Fail(c, 101, "参数错误")
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
errList := global.Validator.ValidStruct(f)
|
errList := global.Validator.ValidStruct(c, f)
|
||||||
if len(errList) > 0 {
|
if len(errList) > 0 {
|
||||||
response.Fail(c, 101, errList[0])
|
response.Fail(c, 101, errList[0])
|
||||||
return
|
return
|
||||||
@@ -117,19 +150,19 @@ func (ct *Peer) Update(c *gin.Context) {
|
|||||||
u := f.ToPeer()
|
u := f.ToPeer()
|
||||||
err := service.AllService.PeerService.Update(u)
|
err := service.AllService.PeerService.Update(u)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.Fail(c, 101, "更新失败")
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
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]
|
||||||
@@ -137,11 +170,11 @@ func (ct *Peer) Update(c *gin.Context) {
|
|||||||
func (ct *Peer) Delete(c *gin.Context) {
|
func (ct *Peer) Delete(c *gin.Context) {
|
||||||
f := &admin.PeerForm{}
|
f := &admin.PeerForm{}
|
||||||
if err := c.ShouldBindJSON(f); err != nil {
|
if err := c.ShouldBindJSON(f); err != nil {
|
||||||
response.Fail(c, 101, "系统错误")
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
id := f.RowId
|
id := f.RowId
|
||||||
errList := global.Validator.ValidVar(id, "required,gt=0")
|
errList := global.Validator.ValidVar(c, id, "required,gt=0")
|
||||||
if len(errList) > 0 {
|
if len(errList) > 0 {
|
||||||
response.Fail(c, 101, errList[0])
|
response.Fail(c, 101, errList[0])
|
||||||
return
|
return
|
||||||
@@ -153,8 +186,55 @@ func (ct *Peer) Delete(c *gin.Context) {
|
|||||||
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
|
return
|
||||||
}
|
}
|
||||||
response.Fail(c, 101, "信息不存在")
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// BatchDelete batch delete
|
||||||
|
// @Tags device
|
||||||
|
// @Summary batch delete devices
|
||||||
|
// @Description batch delete devices
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param body body admin.PeerBatchDeleteForm true "deviceid"
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/peer/batchDelete [post]
|
||||||
|
// @Security token
|
||||||
|
func (ct *Peer) BatchDelete(c *gin.Context) {
|
||||||
|
f := &admin.PeerBatchDeleteForm{}
|
||||||
|
if err := c.ShouldBindJSON(f); err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(f.RowIds) == 0 {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := service.AllService.PeerService.BatchDelete(f.RowIds)
|
||||||
|
if err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Success(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ct *Peer) SimpleData(c *gin.Context) {
|
||||||
|
f := &admin.SimpleDataQuery{}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
res := service.AllService.PeerService.List(1, 99999, func(tx *gorm.DB) {
|
||||||
|
//information that can be made public
|
||||||
|
tx.Select("id,version")
|
||||||
|
tx.Where("id in (?)", f.Ids)
|
||||||
|
})
|
||||||
|
response.Success(c, res)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,30 +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 服务配置
|
type RustdeskCmd struct {
|
||||||
// @Tags ADMIN
|
Cmd string `json:"cmd"`
|
||||||
// @Summary 服务配置
|
Option string `json:"option"`
|
||||||
// @Description 服务配置,给webclient提供api-server
|
Target string `json:"target"`
|
||||||
// @Accept json
|
}
|
||||||
// @Produce json
|
|
||||||
// @Success 200 {object} response.Response
|
func (r *Rustdesk) CmdList(c *gin.Context) {
|
||||||
// @Failure 500 {object} response.Response
|
q := &admin.PageQuery{}
|
||||||
// @Router /admin/server-config [get]
|
if err := c.ShouldBindQuery(q); err != nil {
|
||||||
// @Security token
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
func (r *Rustdesk) ServerConfig(c *gin.Context) {
|
return
|
||||||
cf := &response.ServerConfigResponse{
|
}
|
||||||
IdServer: global.Config.Rustdesk.IdServer,
|
res := service.AllService.ServerCmdService.List(q.Page, 9999)
|
||||||
Key: global.Config.Rustdesk.Key,
|
//add system commands before the list
|
||||||
RelayServer: global.Config.Rustdesk.RelayServer,
|
list := make([]*model.ServerCmd, 0)
|
||||||
ApiServer: global.Config.Rustdesk.ApiServer,
|
list = append(list, model.SysIdServerCmds...)
|
||||||
}
|
list = append(list, model.SysRelayServerCmds...)
|
||||||
response.Success(c, cf)
|
list = append(list, res.ServerCmds...)
|
||||||
|
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"
|
||||||
@@ -30,24 +30,24 @@ func (ct *Tag) Detail(c *gin.Context) {
|
|||||||
t := service.AllService.TagService.InfoById(uint(iid))
|
t := service.AllService.TagService.InfoById(uint(iid))
|
||||||
u := service.AllService.UserService.CurUser(c)
|
u := service.AllService.UserService.CurUser(c)
|
||||||
if !service.AllService.UserService.IsAdmin(u) && t.UserId != u.Id {
|
if !service.AllService.UserService.IsAdmin(u) && t.UserId != u.Id {
|
||||||
response.Fail(c, 101, "无权限")
|
response.Fail(c, 101, response.TranslateMsg(c, "NoAccess"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if t.Id > 0 {
|
if t.Id > 0 {
|
||||||
response.Success(c, t)
|
response.Success(c, t)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
response.Fail(c, 101, "信息不存在")
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
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]
|
||||||
@@ -55,37 +55,37 @@ func (ct *Tag) Detail(c *gin.Context) {
|
|||||||
func (ct *Tag) Create(c *gin.Context) {
|
func (ct *Tag) Create(c *gin.Context) {
|
||||||
f := &admin.TagForm{}
|
f := &admin.TagForm{}
|
||||||
if err := c.ShouldBindJSON(f); err != nil {
|
if err := c.ShouldBindJSON(f); err != nil {
|
||||||
response.Fail(c, 101, "参数错误")
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
errList := global.Validator.ValidStruct(f)
|
errList := global.Validator.ValidStruct(c, f)
|
||||||
if len(errList) > 0 {
|
if len(errList) > 0 {
|
||||||
response.Fail(c, 101, errList[0])
|
response.Fail(c, 101, errList[0])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
t := f.ToTag()
|
t := f.ToTag()
|
||||||
u := service.AllService.UserService.CurUser(c)
|
if t.UserId == 0 {
|
||||||
if !service.AllService.UserService.IsAdmin(u) {
|
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 {
|
||||||
response.Fail(c, 101, "创建失败")
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
response.Success(c, u)
|
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]
|
||||||
@@ -93,28 +93,30 @@ func (ct *Tag) Create(c *gin.Context) {
|
|||||||
func (ct *Tag) List(c *gin.Context) {
|
func (ct *Tag) List(c *gin.Context) {
|
||||||
query := &admin.TagQuery{}
|
query := &admin.TagQuery{}
|
||||||
if err := c.ShouldBindQuery(query); err != nil {
|
if err := c.ShouldBindQuery(query); err != nil {
|
||||||
response.Fail(c, 101, "参数错误")
|
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 {
|
||||||
|
return txc.Select("id,name")
|
||||||
|
})
|
||||||
if query.UserId > 0 {
|
if query.UserId > 0 {
|
||||||
tx.Where("user_id = ?", query.UserId)
|
tx.Where("user_id = ?", query.UserId)
|
||||||
}
|
}
|
||||||
|
if query.CollectionId != nil && *query.CollectionId >= 0 {
|
||||||
|
tx.Where("collection_id = ?", query.CollectionId)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
response.Success(c, res)
|
response.Success(c, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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]
|
||||||
@@ -122,39 +124,39 @@ func (ct *Tag) List(c *gin.Context) {
|
|||||||
func (ct *Tag) Update(c *gin.Context) {
|
func (ct *Tag) Update(c *gin.Context) {
|
||||||
f := &admin.TagForm{}
|
f := &admin.TagForm{}
|
||||||
if err := c.ShouldBindJSON(f); err != nil {
|
if err := c.ShouldBindJSON(f); err != nil {
|
||||||
response.Fail(c, 101, "参数错误")
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
errList := global.Validator.ValidStruct(f)
|
errList := global.Validator.ValidStruct(c, f)
|
||||||
if len(errList) > 0 {
|
if len(errList) > 0 {
|
||||||
response.Fail(c, 101, errList[0])
|
response.Fail(c, 101, errList[0])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if f.Id == 0 {
|
if f.Id == 0 {
|
||||||
response.Fail(c, 101, "参数错误")
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ex := service.AllService.TagService.InfoById(f.Id)
|
||||||
|
if ex.Id == 0 {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
t := f.ToTag()
|
t := f.ToTag()
|
||||||
u := service.AllService.UserService.CurUser(c)
|
|
||||||
if !service.AllService.UserService.IsAdmin(u) && t.UserId != u.Id {
|
|
||||||
response.Fail(c, 101, "无权限")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err := service.AllService.TagService.Update(t)
|
err := service.AllService.TagService.Update(t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.Fail(c, 101, "更新失败")
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
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]
|
||||||
@@ -162,29 +164,24 @@ func (ct *Tag) Update(c *gin.Context) {
|
|||||||
func (ct *Tag) Delete(c *gin.Context) {
|
func (ct *Tag) Delete(c *gin.Context) {
|
||||||
f := &admin.TagForm{}
|
f := &admin.TagForm{}
|
||||||
if err := c.ShouldBindJSON(f); err != nil {
|
if err := c.ShouldBindJSON(f); err != nil {
|
||||||
response.Fail(c, 101, "系统错误")
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
id := f.Id
|
id := f.Id
|
||||||
errList := global.Validator.ValidVar(id, "required,gt=0")
|
errList := global.Validator.ValidVar(c, id, "required,gt=0")
|
||||||
if len(errList) > 0 {
|
if len(errList) > 0 {
|
||||||
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, "无权限")
|
|
||||||
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
|
|
||||||
}
|
|
||||||
response.Fail(c, 101, err.Error())
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
response.Fail(c, 101, "信息不存在")
|
response.Fail(c, 101, err.Error())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
package admin
|
package admin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"Gwen/global"
|
|
||||||
"Gwen/http/request/admin"
|
|
||||||
"Gwen/http/response"
|
|
||||||
adResp "Gwen/http/response/admin"
|
|
||||||
"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"
|
||||||
)
|
)
|
||||||
@@ -14,10 +16,10 @@ import (
|
|||||||
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"
|
||||||
@@ -33,17 +35,17 @@ func (ct *User) Detail(c *gin.Context) {
|
|||||||
response.Success(c, u)
|
response.Success(c, u)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
response.Fail(c, 101, "信息不存在")
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
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]
|
||||||
@@ -51,10 +53,10 @@ func (ct *User) Detail(c *gin.Context) {
|
|||||||
func (ct *User) Create(c *gin.Context) {
|
func (ct *User) Create(c *gin.Context) {
|
||||||
f := &admin.UserForm{}
|
f := &admin.UserForm{}
|
||||||
if err := c.ShouldBindJSON(f); err != nil {
|
if err := c.ShouldBindJSON(f); err != nil {
|
||||||
response.Fail(c, 101, "参数错误")
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
errList := global.Validator.ValidStruct(f)
|
errList := global.Validator.ValidStruct(c, f)
|
||||||
if len(errList) > 0 {
|
if len(errList) > 0 {
|
||||||
response.Fail(c, 101, errList[0])
|
response.Fail(c, 101, errList[0])
|
||||||
return
|
return
|
||||||
@@ -62,21 +64,21 @@ func (ct *User) Create(c *gin.Context) {
|
|||||||
u := f.ToUser()
|
u := f.ToUser()
|
||||||
err := service.AllService.UserService.Create(u)
|
err := service.AllService.UserService.Create(u)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.Fail(c, 101, "创建失败")
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
response.Success(c, u)
|
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]
|
||||||
@@ -84,7 +86,7 @@ func (ct *User) Create(c *gin.Context) {
|
|||||||
func (ct *User) List(c *gin.Context) {
|
func (ct *User) List(c *gin.Context) {
|
||||||
query := &admin.UserQuery{}
|
query := &admin.UserQuery{}
|
||||||
if err := c.ShouldBindQuery(query); err != nil {
|
if err := c.ShouldBindQuery(query); err != nil {
|
||||||
response.Fail(c, 101, "参数错误")
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
res := service.AllService.UserService.List(query.Page, query.PageSize, func(tx *gorm.DB) {
|
res := service.AllService.UserService.List(query.Page, query.PageSize, func(tx *gorm.DB) {
|
||||||
@@ -95,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]
|
||||||
@@ -109,14 +111,14 @@ func (ct *User) List(c *gin.Context) {
|
|||||||
func (ct *User) Update(c *gin.Context) {
|
func (ct *User) Update(c *gin.Context) {
|
||||||
f := &admin.UserForm{}
|
f := &admin.UserForm{}
|
||||||
if err := c.ShouldBindJSON(f); err != nil {
|
if err := c.ShouldBindJSON(f); err != nil {
|
||||||
response.Fail(c, 101, "参数错误:"+err.Error())
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if f.Id == 0 {
|
if f.Id == 0 {
|
||||||
response.Fail(c, 101, "参数错误")
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
errList := global.Validator.ValidStruct(f)
|
errList := global.Validator.ValidStruct(c, f)
|
||||||
if len(errList) > 0 {
|
if len(errList) > 0 {
|
||||||
response.Fail(c, 101, errList[0])
|
response.Fail(c, 101, errList[0])
|
||||||
return
|
return
|
||||||
@@ -124,19 +126,19 @@ func (ct *User) Update(c *gin.Context) {
|
|||||||
u := f.ToUser()
|
u := f.ToUser()
|
||||||
err := service.AllService.UserService.Update(u)
|
err := service.AllService.UserService.Update(u)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.Fail(c, 101, "更新失败")
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
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]
|
||||||
@@ -144,11 +146,11 @@ func (ct *User) Update(c *gin.Context) {
|
|||||||
func (ct *User) Delete(c *gin.Context) {
|
func (ct *User) Delete(c *gin.Context) {
|
||||||
f := &admin.UserForm{}
|
f := &admin.UserForm{}
|
||||||
if err := c.ShouldBindJSON(f); err != nil {
|
if err := c.ShouldBindJSON(f); err != nil {
|
||||||
response.Fail(c, 101, "系统错误")
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
id := f.Id
|
id := f.Id
|
||||||
errList := global.Validator.ValidVar(id, "required,gt=0")
|
errList := global.Validator.ValidVar(c, id, "required,gt=0")
|
||||||
if len(errList) > 0 {
|
if len(errList) > 0 {
|
||||||
response.Fail(c, 101, errList[0])
|
response.Fail(c, 101, errList[0])
|
||||||
return
|
return
|
||||||
@@ -163,16 +165,16 @@ func (ct *User) Delete(c *gin.Context) {
|
|||||||
response.Fail(c, 101, err.Error())
|
response.Fail(c, 101, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
response.Fail(c, 101, "信息不存在")
|
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]
|
||||||
@@ -180,31 +182,31 @@ func (ct *User) Delete(c *gin.Context) {
|
|||||||
func (ct *User) UpdatePassword(c *gin.Context) {
|
func (ct *User) UpdatePassword(c *gin.Context) {
|
||||||
f := &admin.UserPasswordForm{}
|
f := &admin.UserPasswordForm{}
|
||||||
if err := c.ShouldBindJSON(f); err != nil {
|
if err := c.ShouldBindJSON(f); err != nil {
|
||||||
response.Fail(c, 101, "参数错误")
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
errList := global.Validator.ValidStruct(f)
|
errList := global.Validator.ValidStruct(c, f)
|
||||||
if len(errList) > 0 {
|
if len(errList) > 0 {
|
||||||
response.Fail(c, 101, errList[0])
|
response.Fail(c, 101, errList[0])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
u := service.AllService.UserService.InfoById(f.Id)
|
u := service.AllService.UserService.InfoById(f.Id)
|
||||||
if u.Id == 0 {
|
if u.Id == 0 {
|
||||||
response.Fail(c, 101, "信息不存在")
|
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err := service.AllService.UserService.UpdatePassword(u, f.Password)
|
err := service.AllService.UserService.UpdatePassword(u, f.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.Fail(c, 101, "更新失败")
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
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}
|
||||||
@@ -215,21 +217,16 @@ func (ct *User) Current(c *gin.Context) {
|
|||||||
u := service.AllService.UserService.CurUser(c)
|
u := service.AllService.UserService.CurUser(c)
|
||||||
token, _ := c.Get("token")
|
token, _ := c.Get("token")
|
||||||
t := token.(string)
|
t := token.(string)
|
||||||
response.Success(c, &adResp.LoginPayload{
|
responseLoginSuccess(c, u, t)
|
||||||
Token: t,
|
|
||||||
Username: u.Username,
|
|
||||||
RouteNames: service.AllService.UserService.RouteNames(u),
|
|
||||||
Nickname: u.Nickname,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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]
|
||||||
@@ -237,25 +234,115 @@ func (ct *User) Current(c *gin.Context) {
|
|||||||
func (ct *User) ChangeCurPwd(c *gin.Context) {
|
func (ct *User) ChangeCurPwd(c *gin.Context) {
|
||||||
f := &admin.ChangeCurPasswordForm{}
|
f := &admin.ChangeCurPasswordForm{}
|
||||||
if err := c.ShouldBindJSON(f); err != nil {
|
if err := c.ShouldBindJSON(f); err != nil {
|
||||||
response.Fail(c, 101, "参数错误")
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
errList := global.Validator.ValidStruct(f)
|
errList := global.Validator.ValidStruct(c, f)
|
||||||
if len(errList) > 0 {
|
if len(errList) > 0 {
|
||||||
response.Fail(c, 101, errList[0])
|
response.Fail(c, 101, errList[0])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
u := service.AllService.UserService.CurUser(c)
|
u := service.AllService.UserService.CurUser(c)
|
||||||
oldPwd := service.AllService.UserService.EncryptPassword(f.OldPassword)
|
// Verify the old password only when the account already has one set
|
||||||
if u.Password != oldPwd {
|
if !service.AllService.UserService.IsPasswordEmptyByUser(u) {
|
||||||
response.Fail(c, 101, "旧密码错误")
|
ok, _, err := utils.VerifyPassword(u.Password, f.OldPassword)
|
||||||
return
|
if err != nil || !ok {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "OldPasswordError"))
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
err := service.AllService.UserService.UpdatePassword(u, f.NewPassword)
|
err := service.AllService.UserService.UpdatePassword(u, f.NewPassword)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.Fail(c, 101, "更新失败")
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MyOauth
|
||||||
|
// @Tags user
|
||||||
|
// @Summary my authorizations
|
||||||
|
// @Description my authorizations
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} response.Response{data=[]adResp.UserOauthItem}
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/user/myOauth [get]
|
||||||
|
// @Security token
|
||||||
|
func (ct *User) MyOauth(c *gin.Context) {
|
||||||
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
oal := service.AllService.OauthService.List(1, 100, nil)
|
||||||
|
ops := make([]string, 0)
|
||||||
|
for _, oa := range oal.Oauths {
|
||||||
|
ops = append(ops, oa.Op)
|
||||||
|
}
|
||||||
|
uts := service.AllService.UserService.UserThirdsByUserId(u.Id)
|
||||||
|
var res []*adResp.UserOauthItem
|
||||||
|
for _, oa := range oal.Oauths {
|
||||||
|
item := &adResp.UserOauthItem{
|
||||||
|
Op: oa.Op,
|
||||||
|
}
|
||||||
|
for _, ut := range uts {
|
||||||
|
if ut.Op == oa.Op {
|
||||||
|
item.Status = 1
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res = append(res, item)
|
||||||
|
}
|
||||||
|
response.Success(c, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// groupUsers
|
||||||
|
func (ct *User) GroupUsers(c *gin.Context) {
|
||||||
|
aG := service.AllService.GroupService.List(1, 999, nil)
|
||||||
|
aU := service.AllService.UserService.List(1, 9999, nil)
|
||||||
|
response.Success(c, gin.H{
|
||||||
|
"groups": aG.Groups,
|
||||||
|
"users": aU.Users,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register
|
||||||
|
func (ct *User) Register(c *gin.Context) {
|
||||||
|
if !global.Config.App.Register {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "RegisterClosed"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
f := &admin.RegisterForm{}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
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 {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed"))
|
||||||
|
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{
|
||||||
|
UserId: u.Id,
|
||||||
|
Client: model.LoginLogClientWebAdmin,
|
||||||
|
Uuid: "",
|
||||||
|
Ip: c.ClientIP(),
|
||||||
|
Type: model.LoginLogTypeAccount,
|
||||||
|
})
|
||||||
|
responseLoginSuccess(c, u, ut.Token)
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,113 @@
|
|||||||
|
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/model"
|
||||||
|
"github.com/lejianwen/rustdesk-api/v2/service"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UserToken struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// List list
|
||||||
|
// @Tags login credential
|
||||||
|
// @Summary login credential list
|
||||||
|
// @Description login credential 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.UserTokenList}
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/user_token/list [get]
|
||||||
|
// @Security token
|
||||||
|
func (ct *UserToken) List(c *gin.Context) {
|
||||||
|
query := &admin.LoginTokenQuery{}
|
||||||
|
if err := c.ShouldBindQuery(query); err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res := service.AllService.UserService.TokenList(query.Page, query.PageSize, func(tx *gorm.DB) {
|
||||||
|
if query.UserId > 0 {
|
||||||
|
tx.Where("user_id = ?", query.UserId)
|
||||||
|
}
|
||||||
|
tx.Order("id desc")
|
||||||
|
})
|
||||||
|
response.Success(c, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete delete
|
||||||
|
// @Tags login credential
|
||||||
|
// @Summary delete login credential
|
||||||
|
// @Description delete login credential
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param body body model.UserToken true "login credential info"
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/user_token/delete [post]
|
||||||
|
// @Security token
|
||||||
|
func (ct *UserToken) Delete(c *gin.Context) {
|
||||||
|
f := &model.UserToken{}
|
||||||
|
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.UserService.TokenInfoById(f.Id)
|
||||||
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
if !service.AllService.UserService.IsAdmin(u) && l.UserId != u.Id {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "NoAccess"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if l.Id > 0 {
|
||||||
|
err := service.AllService.UserService.DeleteToken(l)
|
||||||
|
if err == nil {
|
||||||
|
response.Success(c, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.Fail(c, 101, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
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,24 +1,28 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
requstform "Gwen/http/request/api"
|
|
||||||
"Gwen/http/response"
|
|
||||||
"Gwen/http/response/api"
|
|
||||||
"Gwen/model"
|
|
||||||
"Gwen/service"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"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"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Ab struct {
|
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
|
||||||
@@ -28,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)
|
||||||
@@ -52,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]
|
||||||
@@ -66,85 +70,658 @@ func (a *Ab) UpAb(c *gin.Context) {
|
|||||||
abf := &requstform.AddressBookForm{}
|
abf := &requstform.AddressBookForm{}
|
||||||
err := c.ShouldBindJSON(&abf)
|
err := c.ShouldBindJSON(&abf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
response.Error(c, "参数错误")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
abd := &requstform.AddressBookFormData{}
|
abd := &requstform.AddressBookFormData{}
|
||||||
err = json.Unmarshal([]byte(abf.Data), abd)
|
err = json.Unmarshal([]byte(abf.Data), abd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.Error(c, "系统错误")
|
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tc := map[string]uint{}
|
||||||
|
err = json.Unmarshal([]byte(abd.TagColors), &tc)
|
||||||
|
if err != nil {
|
||||||
|
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//fmt.Println(abd)
|
|
||||||
//for _, peer := range abd.Peers {
|
|
||||||
// fmt.Println(peer)
|
|
||||||
//}
|
|
||||||
|
|
||||||
user := service.AllService.UserService.CurUser(c)
|
user := service.AllService.UserService.CurUser(c)
|
||||||
|
|
||||||
err = service.AllService.AddressBookService.UpdateAddressBook(abd.Peers, user.Id)
|
err = service.AllService.AddressBookService.UpdateAddressBook(abd.Peers, user.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Abort()
|
response.Error(c, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
tc := map[string]uint{}
|
service.AllService.TagService.UpdateTags(user.Id, tc)
|
||||||
err = json.Unmarshal([]byte(abd.TagColors), &tc)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
response.Error(c, "系统错误")
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
service.AllService.TagService.UpdateTags(user.Id, tc)
|
|
||||||
}
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, nil)
|
c.JSON(http.StatusOK, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tags
|
// PTags
|
||||||
// @Tags 地址
|
// @Tags address[Personal]
|
||||||
// @Summary 标签
|
// @Summary tag
|
||||||
// @Description 标签
|
// @Description tag
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} []model.Tag
|
// @Param guid path string true "guid"
|
||||||
|
// @Success 200 {object} model.TagList
|
||||||
// @Failure 500 {object} response.ErrorResponse
|
// @Failure 500 {object} response.ErrorResponse
|
||||||
// @Router /tags [post]
|
// @Router /ab/tags/{guid} [post]
|
||||||
// @Security BearerAuth
|
// @Security BearerAuth
|
||||||
func (a *Ab) Tags(c *gin.Context) {
|
func (a *Ab) PTags(c *gin.Context) {
|
||||||
user := service.AllService.UserService.CurUser(c)
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
guid := c.Param("guid")
|
||||||
|
_, uid, cid, err := a.CheckGuid(u, guid)
|
||||||
|
if err != nil {
|
||||||
|
response.Error(c, response.TranslateMsg(c, err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
tags := service.AllService.TagService.ListByUserId(user.Id)
|
//check privileges
|
||||||
|
if !service.AllService.AddressBookService.CheckUserReadPrivilege(u, uid, cid) {
|
||||||
|
response.Error(c, response.TranslateMsg(c, "NoAccess"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tags := service.AllService.TagService.ListByUserIdAndCollectionId(uid, cid)
|
||||||
c.JSON(http.StatusOK, tags.Tags)
|
c.JSON(http.StatusOK, tags.Tags)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TagAdd
|
// TagAdd
|
||||||
// @Tags 地址
|
// @Tags address[Personal]
|
||||||
// @Summary 标签添加
|
// @Summary add tag
|
||||||
// @Description 标签
|
// @Description tag
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
|
// @Param guid path string true "guid"
|
||||||
// @Success 200 {string} string
|
// @Success 200 {string} string
|
||||||
// @Failure 500 {object} response.ErrorResponse
|
// @Failure 500 {object} response.ErrorResponse
|
||||||
// @Router /ab/add [post]
|
// @Router /ab/tag/add/{guid} [post]
|
||||||
// @Security BearerAuth
|
// @Security BearerAuth
|
||||||
func (a *Ab) TagAdd(c *gin.Context) {
|
func (a *Ab) TagAdd(c *gin.Context) {
|
||||||
|
|
||||||
t := &model.Tag{}
|
t := &model.Tag{}
|
||||||
err := c.ShouldBindJSON(t)
|
err := c.ShouldBindJSON(t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
response.Error(c, "参数错误")
|
|
||||||
return
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
guid := c.Param("guid")
|
||||||
|
_, uid, cid, err := a.CheckGuid(u, guid)
|
||||||
|
if err != nil {
|
||||||
|
response.Error(c, response.TranslateMsg(c, err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//check privileges
|
||||||
|
if !service.AllService.AddressBookService.CheckUserWritePrivilege(u, uid, cid) {
|
||||||
|
response.Error(c, response.TranslateMsg(c, "NoAccess"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tag := service.AllService.TagService.InfoByUserIdAndNameAndCollectionId(uid, t.Name, cid)
|
||||||
|
if tag != nil && tag.Id != 0 {
|
||||||
|
response.Error(c, response.TranslateMsg(c, "ItemExists"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t.UserId = uid
|
||||||
|
t.CollectionId = cid
|
||||||
|
err = service.AllService.TagService.Create(t)
|
||||||
|
if err != nil {
|
||||||
|
response.Error(c, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.String(http.StatusOK, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TagRename
|
||||||
|
// @Tags address[Personal]
|
||||||
|
// @Summary rename tag
|
||||||
|
// @Description tag
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param guid path string true "guid"
|
||||||
|
// @Success 200 {string} string
|
||||||
|
// @Failure 500 {object} response.ErrorResponse
|
||||||
|
// @Router /ab/tag/rename/{guid} [put]
|
||||||
|
// @Security BearerAuth
|
||||||
|
func (a *Ab) TagRename(c *gin.Context) {
|
||||||
|
|
||||||
|
t := &requstform.TagRenameForm{}
|
||||||
|
err := c.ShouldBindJSON(t)
|
||||||
|
if err != nil {
|
||||||
|
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
guid := c.Param("guid")
|
||||||
|
_, uid, cid, err := a.CheckGuid(u, guid)
|
||||||
|
if err != nil {
|
||||||
|
response.Error(c, response.TranslateMsg(c, err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//check privileges
|
||||||
|
if !service.AllService.AddressBookService.CheckUserWritePrivilege(u, uid, cid) {
|
||||||
|
response.Error(c, response.TranslateMsg(c, "NoAccess"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tag := service.AllService.TagService.InfoByUserIdAndNameAndCollectionId(uid, t.Old, cid)
|
||||||
|
if tag == nil || tag.Id == 0 {
|
||||||
|
response.Error(c, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ntag := service.AllService.TagService.InfoByUserIdAndNameAndCollectionId(uid, t.New, cid)
|
||||||
|
if ntag != nil && ntag.Id != 0 {
|
||||||
|
response.Error(c, response.TranslateMsg(c, "ItemExists"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tag.Name = t.New
|
||||||
|
err = service.AllService.TagService.Update(tag)
|
||||||
|
if err != nil {
|
||||||
|
response.Error(c, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.String(http.StatusOK, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TagUpdate
|
||||||
|
// @Tags address[Personal]
|
||||||
|
// @Summary change tag color
|
||||||
|
// @Description tag
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param guid path string true "guid"
|
||||||
|
// @Success 200 {string} string
|
||||||
|
// @Failure 500 {object} response.ErrorResponse
|
||||||
|
// @Router /ab/tag/update/{guid} [put]
|
||||||
|
// @Security BearerAuth
|
||||||
|
func (a *Ab) TagUpdate(c *gin.Context) {
|
||||||
|
t := &requstform.TagColorForm{}
|
||||||
|
err := c.ShouldBindJSON(t)
|
||||||
|
if err != nil {
|
||||||
|
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
guid := c.Param("guid")
|
||||||
|
_, uid, cid, err := a.CheckGuid(u, guid)
|
||||||
|
if err != nil {
|
||||||
|
response.Error(c, response.TranslateMsg(c, err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//check privileges
|
||||||
|
if !service.AllService.AddressBookService.CheckUserWritePrivilege(u, uid, cid) {
|
||||||
|
response.Error(c, response.TranslateMsg(c, "NoAccess"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tag := service.AllService.TagService.InfoByUserIdAndNameAndCollectionId(uid, t.Name, cid)
|
||||||
|
if tag == nil || tag.Id == 0 {
|
||||||
|
response.Error(c, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tag.Color = t.Color
|
||||||
|
err = service.AllService.TagService.Update(tag)
|
||||||
|
if err != nil {
|
||||||
|
response.Error(c, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.String(http.StatusOK, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TagDel
|
||||||
|
// @Tags address[Personal]
|
||||||
|
// @Summary delete tag
|
||||||
|
// @Description tag
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param guid path string true "guid"
|
||||||
|
// @Success 200 {string} string
|
||||||
|
// @Failure 500 {object} response.ErrorResponse
|
||||||
|
// @Router /ab/tag/{guid} [delete]
|
||||||
|
// @Security BearerAuth
|
||||||
|
func (a *Ab) TagDel(c *gin.Context) {
|
||||||
|
|
||||||
|
t := &[]string{}
|
||||||
|
err := c.ShouldBind(t)
|
||||||
|
if err != nil {
|
||||||
|
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//fmt.Println(t)
|
||||||
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
guid := c.Param("guid")
|
||||||
|
_, uid, cid, err := a.CheckGuid(u, guid)
|
||||||
|
if err != nil {
|
||||||
|
response.Error(c, response.TranslateMsg(c, err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//check privileges
|
||||||
|
if !service.AllService.AddressBookService.CheckUserFullControlPrivilege(u, uid, cid) {
|
||||||
|
response.Error(c, response.TranslateMsg(c, "NoAccess"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, name := range *t {
|
||||||
|
tag := service.AllService.TagService.InfoByUserIdAndNameAndCollectionId(uid, name, cid)
|
||||||
|
if tag == nil || tag.Id == 0 {
|
||||||
|
response.Error(c, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = service.AllService.TagService.Delete(tag)
|
||||||
|
if err != nil {
|
||||||
|
response.Error(c, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.String(http.StatusOK, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Personal
|
||||||
|
// @Tags address[Personal]
|
||||||
|
// @Summary personal address
|
||||||
|
// @Description personal address
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param string body string false "string valid"
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /ab/personal [post]
|
||||||
|
// @Security BearerAuth
|
||||||
|
func (a *Ab) Personal(c *gin.Context) {
|
||||||
|
user := service.AllService.UserService.CurUser(c)
|
||||||
|
/**
|
||||||
|
guid = json['guid'] ?? '',
|
||||||
|
name = json['name'] ?? '',
|
||||||
|
owner = json['owner'] ?? '',
|
||||||
|
note = json['note'] ?? '',
|
||||||
|
rule = json['rule'] ?? 0;
|
||||||
|
*/
|
||||||
|
if global.Config.Rustdesk.Personal == 1 {
|
||||||
|
guid := a.ComposeGuid(user.GroupId, user.Id, 0)
|
||||||
|
//if it returns guid, subsequent requests will change
|
||||||
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"guid": guid,
|
||||||
|
"name": user.Username,
|
||||||
|
"rule": 3,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
c.JSON(http.StatusOK, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Settings
|
||||||
|
// @Tags address[Personal]
|
||||||
|
// @Summary settings
|
||||||
|
// @Description settings
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param string body string false "string valid"
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /ab/settings [post]
|
||||||
|
// @Security BearerAuth
|
||||||
|
func (a *Ab) Settings(c *gin.Context) {
|
||||||
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"max_peer_one_ab": 0, //max peer count, 0 means no limit
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// SharedProfiles
|
||||||
|
// @Tags address[Personal]
|
||||||
|
// @Summary shared address book
|
||||||
|
// @Description shared
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param current query int false "page number"
|
||||||
|
// @Param pageSize query int false "items per page"
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /ab/shared/profiles [post]
|
||||||
|
// @Security BearerAuth
|
||||||
|
func (a *Ab) SharedProfiles(c *gin.Context) {
|
||||||
|
|
||||||
|
var res []*api.SharedProfilesPayload
|
||||||
|
|
||||||
|
user := service.AllService.UserService.CurUser(c)
|
||||||
|
myAbCollectionList := service.AllService.AddressBookService.ListCollectionByUserId(user.Id)
|
||||||
|
for _, ab := range myAbCollectionList.AddressBookCollection {
|
||||||
|
res = append(res, &api.SharedProfilesPayload{
|
||||||
|
Guid: a.ComposeGuid(user.GroupId, user.Id, ab.Id),
|
||||||
|
Name: ab.Name,
|
||||||
|
Owner: user.Username,
|
||||||
|
Rule: model.ShareAddressBookRuleRuleFullControl,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
allAbIds := make(map[uint]int) //use map to deduplicate and keep the maximum Rule
|
||||||
|
allUserIds := make(map[uint]*model.User)
|
||||||
|
rules := service.AllService.AddressBookService.CollectionReadRules(user)
|
||||||
|
for _, rule := range rules {
|
||||||
|
//first check whether it exists
|
||||||
|
r, ok := allAbIds[rule.CollectionId]
|
||||||
|
if ok {
|
||||||
|
//then check the permission level
|
||||||
|
if r < rule.Rule {
|
||||||
|
allAbIds[rule.CollectionId] = rule.Rule
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
allAbIds[rule.CollectionId] = rule.Rule
|
||||||
|
allUserIds[rule.UserId] = nil
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
//u := service.AllService.UserService.CurUser(c)
|
abids := utils.Keys(allAbIds)
|
||||||
|
collections := service.AllService.AddressBookService.ListCollectionByIds(abids)
|
||||||
|
|
||||||
//err = service.AllService.TagService.UpdateTags(t.Name, t.Color, user.Id)
|
ids := utils.Keys(allUserIds)
|
||||||
//if err != nil {
|
allUsers := service.AllService.UserService.ListByIds(ids)
|
||||||
// response.Error(c, "操作失败")
|
for _, u := range allUsers {
|
||||||
// return
|
allUserIds[u.Id] = u
|
||||||
//}
|
}
|
||||||
c.JSON(http.StatusOK, "")
|
|
||||||
|
for _, collection := range collections {
|
||||||
|
_u, ok := allUserIds[collection.UserId]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
res = append(res, &api.SharedProfilesPayload{
|
||||||
|
Guid: a.ComposeGuid(_u.GroupId, _u.Id, collection.Id),
|
||||||
|
Name: collection.Name,
|
||||||
|
Owner: _u.Username,
|
||||||
|
Rule: allAbIds[collection.Id],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"total": 0, //len(res),
|
||||||
|
"data": res,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseGuid
|
||||||
|
func (a *Ab) ParseGuid(guid string) (gid, uid, cid uint) {
|
||||||
|
// split guid by -
|
||||||
|
guids := strings.Split(guid, "-")
|
||||||
|
if len(guids) < 2 {
|
||||||
|
return 0, 0, 0
|
||||||
|
}
|
||||||
|
if len(guids) != 3 {
|
||||||
|
cid = 0
|
||||||
|
} else {
|
||||||
|
s, err := strconv.Atoi(guids[2])
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, 0
|
||||||
|
}
|
||||||
|
cid = uint(s)
|
||||||
|
}
|
||||||
|
g, err := strconv.Atoi(guids[0])
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, 0
|
||||||
|
}
|
||||||
|
gid = uint(g)
|
||||||
|
u, err := strconv.Atoi(guids[1])
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, 0
|
||||||
|
}
|
||||||
|
uid = uint(u)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ComposeGuid
|
||||||
|
func (a *Ab) ComposeGuid(gid, uid, cid uint) string {
|
||||||
|
return strconv.Itoa(int(gid)) + "-" + strconv.Itoa(int(uid)) + "-" + strconv.Itoa(int(cid))
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckGuid
|
||||||
|
func (a *Ab) CheckGuid(cu *model.User, guid string) (gid, uid, cid uint, err error) {
|
||||||
|
gid, uid, cid = a.ParseGuid(guid)
|
||||||
|
err = nil
|
||||||
|
if gid == 0 || uid == 0 {
|
||||||
|
err = errors.New("ParamsError")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
u := &model.User{}
|
||||||
|
if cu.Id == uid {
|
||||||
|
u = cu
|
||||||
|
} else {
|
||||||
|
u = service.AllService.UserService.InfoById(uid)
|
||||||
|
}
|
||||||
|
if u == nil || u.Id == 0 {
|
||||||
|
err = errors.New("ParamsError")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if u.GroupId != gid {
|
||||||
|
err = errors.New("ParamsError")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if cid == 0 && cu.Id != uid {
|
||||||
|
err = errors.New("ParamsError")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if cid > 0 {
|
||||||
|
c := service.AllService.AddressBookService.CollectionInfoById(cid)
|
||||||
|
if c == nil || c.Id == 0 {
|
||||||
|
err = errors.New("ParamsError")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if c.UserId != uid {
|
||||||
|
err = errors.New("ParamsError")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Peers
|
||||||
|
// @Tags address[Personal]
|
||||||
|
// @Summary address list
|
||||||
|
// @Description address
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param current query int false "page number"
|
||||||
|
// @Param pageSize query int false "items per page"
|
||||||
|
// @Param ab query string false "guid"
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /ab/peers [post]
|
||||||
|
// @Security BearerAuth
|
||||||
|
func (a *Ab) Peers(c *gin.Context) {
|
||||||
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
guid := c.Query("ab")
|
||||||
|
_, uid, cid, err := a.CheckGuid(u, guid)
|
||||||
|
if err != nil {
|
||||||
|
response.Error(c, response.TranslateMsg(c, err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//check privileges
|
||||||
|
if !service.AllService.AddressBookService.CheckUserReadPrivilege(u, uid, cid) {
|
||||||
|
response.Error(c, response.TranslateMsg(c, "NoAccess"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
al := service.AllService.AddressBookService.ListByUserIdAndCollectionId(uid, cid, 1, 1000)
|
||||||
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"total": al.Total,
|
||||||
|
"data": al.AddressBooks,
|
||||||
|
"licensed_devices": 99999,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// PeerAdd
|
||||||
|
// @Tags address[Personal]
|
||||||
|
// @Summary add address
|
||||||
|
// @Description add address
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param guid path string true "guid"
|
||||||
|
// @Success 200 {string} string
|
||||||
|
// @Failure 500 {object} response.ErrorResponse
|
||||||
|
// @Router /ab/peer/add/{guid} [post]
|
||||||
|
// @Security BearerAuth
|
||||||
|
func (a *Ab) PeerAdd(c *gin.Context) {
|
||||||
|
// forceAlwaysRelay is always the string "false"
|
||||||
|
//f := &gin.H{}
|
||||||
|
f := &requstform.PersonalAddressBookForm{}
|
||||||
|
err := c.ShouldBindJSON(f)
|
||||||
|
if err != nil {
|
||||||
|
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
guid := c.Param("guid")
|
||||||
|
_, uid, cid, err := a.CheckGuid(u, guid)
|
||||||
|
if err != nil {
|
||||||
|
response.Error(c, response.TranslateMsg(c, err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//check privileges
|
||||||
|
if !service.AllService.AddressBookService.CheckUserWritePrivilege(u, uid, cid) {
|
||||||
|
response.Error(c, response.TranslateMsg(c, "NoAccess"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//fmt.Println(f)
|
||||||
|
f.UserId = uid
|
||||||
|
ab := f.ToAddressBook()
|
||||||
|
ab.CollectionId = cid
|
||||||
|
if ab.Platform == "" || ab.Username == "" || ab.Hostname == "" {
|
||||||
|
peer := service.AllService.PeerService.FindById(ab.Id)
|
||||||
|
if peer.RowId != 0 {
|
||||||
|
ab.Platform = service.AllService.AddressBookService.PlatformFromOs(peer.Os)
|
||||||
|
ab.Username = peer.Username
|
||||||
|
ab.Hostname = peer.Hostname
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = service.AllService.AddressBookService.AddAddressBook(ab)
|
||||||
|
if err != nil {
|
||||||
|
response.Error(c, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.String(http.StatusOK, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// PeerDel
|
||||||
|
// @Tags address[Personal]
|
||||||
|
// @Summary delete address
|
||||||
|
// @Description delete address
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param guid path string true "guid"
|
||||||
|
// @Success 200 {string} string
|
||||||
|
// @Failure 500 {object} response.ErrorResponse
|
||||||
|
// @Router /ab/peer/add/{guid} [delete]
|
||||||
|
// @Security BearerAuth
|
||||||
|
func (a *Ab) PeerDel(c *gin.Context) {
|
||||||
|
f := &[]string{}
|
||||||
|
err := c.ShouldBind(f)
|
||||||
|
if err != nil {
|
||||||
|
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
guid := c.Param("guid")
|
||||||
|
_, uid, cid, err := a.CheckGuid(u, guid)
|
||||||
|
if err != nil {
|
||||||
|
response.Error(c, response.TranslateMsg(c, err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//check privileges
|
||||||
|
if !service.AllService.AddressBookService.CheckUserFullControlPrivilege(u, uid, cid) {
|
||||||
|
response.Error(c, response.TranslateMsg(c, "NoAccess"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, id := range *f {
|
||||||
|
ab := service.AllService.AddressBookService.InfoByUserIdAndIdAndCid(uid, id, cid)
|
||||||
|
if ab == nil || ab.RowId == 0 {
|
||||||
|
response.Error(c, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = service.AllService.AddressBookService.Delete(ab)
|
||||||
|
if err != nil {
|
||||||
|
response.Error(c, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c.String(http.StatusOK, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// PeerUpdate
|
||||||
|
// @Tags address[Personal]
|
||||||
|
// @Summary update address
|
||||||
|
// @Description update address
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param guid path string true "guid"
|
||||||
|
// @Success 200 {string} string
|
||||||
|
// @Failure 500 {object} response.ErrorResponse
|
||||||
|
// @Router /ab/peer/update/{guid} [put]
|
||||||
|
// @Security BearerAuth
|
||||||
|
func (a *Ab) PeerUpdate(c *gin.Context) {
|
||||||
|
f := gin.H{}
|
||||||
|
//f := &requstform.PersonalAddressBookForm{}
|
||||||
|
err := c.ShouldBindJSON(&f)
|
||||||
|
if err != nil {
|
||||||
|
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
u := service.AllService.UserService.CurUser(c)
|
||||||
|
guid := c.Param("guid")
|
||||||
|
_, uid, cid, err := a.CheckGuid(u, guid)
|
||||||
|
if err != nil {
|
||||||
|
response.Error(c, response.TranslateMsg(c, err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//check privileges
|
||||||
|
if !service.AllService.AddressBookService.CheckUserWritePrivilege(u, uid, cid) {
|
||||||
|
response.Error(c, response.TranslateMsg(c, "NoAccess"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//fmt.Println(f)
|
||||||
|
// determine whether f["Id"] exists
|
||||||
|
fid, ok := f["id"]
|
||||||
|
if !ok {
|
||||||
|
response.Error(c, response.TranslateMsg(c, "ParamsError"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fidstr := fid.(string)
|
||||||
|
|
||||||
|
ab := service.AllService.AddressBookService.InfoByUserIdAndIdAndCid(uid, fidstr, cid)
|
||||||
|
if ab == nil || ab.RowId == 0 {
|
||||||
|
response.Error(c, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//allowed fields
|
||||||
|
allowUp := []string{"password", "hash", "tags", "alias"}
|
||||||
|
// if a field in f is not in allowUp, delete it
|
||||||
|
for k := range f {
|
||||||
|
if !utils.InArray(k, allowUp) {
|
||||||
|
delete(f, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//fmt.Println(f)
|
||||||
|
if tags, _ok := f["tags"]; _ok {
|
||||||
|
f["tags"], _ = json.Marshal(tags)
|
||||||
|
}
|
||||||
|
err = service.AllService.AddressBookService.UpdateByMap(ab, f)
|
||||||
|
if err != nil {
|
||||||
|
response.Error(c, response.TranslateMsg(c, "OperationFailed")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.String(http.StatusOK, "")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,84 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"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"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Audit struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuditConn
|
||||||
|
// @Tags audit
|
||||||
|
// @Summary audit connection
|
||||||
|
// @Description audit connection
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param body body request.AuditConnForm true "audit connection"
|
||||||
|
// @Success 200 {string} string ""
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /audit/conn [post]
|
||||||
|
func (a *Audit) AuditConn(c *gin.Context) {
|
||||||
|
af := &request.AuditConnForm{}
|
||||||
|
err := c.ShouldBindBodyWith(af, binding.JSON)
|
||||||
|
if err != nil {
|
||||||
|
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
/*ttt := &gin.H{}
|
||||||
|
c.ShouldBindBodyWith(ttt, binding.JSON)
|
||||||
|
fmt.Println(ttt)*/
|
||||||
|
ac := af.ToAuditConn()
|
||||||
|
if af.Action == model.AuditActionNew {
|
||||||
|
service.AllService.AuditService.CreateAuditConn(ac)
|
||||||
|
} else if af.Action == model.AuditActionClose {
|
||||||
|
ex := service.AllService.AuditService.InfoByPeerIdAndConnId(af.Id, af.ConnId)
|
||||||
|
if ex.Id != 0 {
|
||||||
|
ex.CloseTime = time.Now().Unix()
|
||||||
|
service.AllService.AuditService.UpdateAuditConn(ex)
|
||||||
|
}
|
||||||
|
} else if af.Action == "" {
|
||||||
|
ex := service.AllService.AuditService.InfoByPeerIdAndConnId(af.Id, af.ConnId)
|
||||||
|
if ex.Id != 0 {
|
||||||
|
up := &model.AuditConn{
|
||||||
|
IdModel: model.IdModel{Id: ex.Id},
|
||||||
|
FromPeer: ac.FromPeer,
|
||||||
|
FromName: ac.FromName,
|
||||||
|
SessionId: ac.SessionId,
|
||||||
|
Type: ac.Type,
|
||||||
|
}
|
||||||
|
service.AllService.AuditService.UpdateAuditConn(up)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
response.Success(c, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuditFile
|
||||||
|
// @Tags audit
|
||||||
|
// @Summary audit file
|
||||||
|
// @Description audit file
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param body body request.AuditFileForm true "audit file"
|
||||||
|
// @Success 200 {string} string ""
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /audit/file [post]
|
||||||
|
func (a *Audit) AuditFile(c *gin.Context) {
|
||||||
|
aff := &request.AuditFileForm{}
|
||||||
|
err := c.ShouldBindBodyWith(aff, binding.JSON)
|
||||||
|
if err != nil {
|
||||||
|
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//ttt := &gin.H{}
|
||||||
|
//c.ShouldBindBodyWith(ttt, binding.JSON)
|
||||||
|
//fmt.Println(ttt)
|
||||||
|
af := aff.ToAuditFile()
|
||||||
|
service.AllService.AuditService.CreateAuditFile(af)
|
||||||
|
response.Success(c, "")
|
||||||
|
}
|
||||||