first commit
This commit is contained in:
commit
91436ca88a
5
.devcontainer/.env
Normal file
5
.devcontainer/.env
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
POSTGRES_DB=ginadmin
|
||||||
|
POSTGRES_USER=postgres
|
||||||
|
POSTGRES_PASSWORD=123456
|
||||||
|
DATABASE_URL=postgres://postgres:123456@db:5432/ginadmin
|
||||||
13
.devcontainer/Dockerfile
Normal file
13
.devcontainer/Dockerfile
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
FROM mcr.microsoft.com/devcontainers/go:1.22-bookworm
|
||||||
|
|
||||||
|
ARG APP=hailinservice
|
||||||
|
|
||||||
|
# Set CGO_CFLAGS to enable large file support
|
||||||
|
ENV CGO_CFLAGS "-D_LARGEFILE64_SOURCE"
|
||||||
|
|
||||||
|
RUN go install github.com/google/wire/cmd/wire@latest \
|
||||||
|
&& go install github.com/swaggo/swag/cmd/swag@latest \
|
||||||
|
&& go install github.com/gin-admin/gin-admin-cli/v10@latest \
|
||||||
|
&& chown -R vscode /go
|
||||||
|
|
||||||
|
|
||||||
9
.devcontainer/devcontainer.json
Normal file
9
.devcontainer/devcontainer.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"name": "ginadmin",
|
||||||
|
"dockerComposeFile": "docker-compose.yml",
|
||||||
|
"service": "app",
|
||||||
|
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
|
||||||
|
"forwardPorts": [
|
||||||
|
8040
|
||||||
|
]
|
||||||
|
}
|
||||||
42
.devcontainer/docker-compose.yml
Normal file
42
.devcontainer/docker-compose.yml
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
version: "3"
|
||||||
|
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
command: sleep infinity
|
||||||
|
networks:
|
||||||
|
- db
|
||||||
|
- redis
|
||||||
|
volumes:
|
||||||
|
- ../..:/workspaces:cached
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
|
||||||
|
db:
|
||||||
|
image: postgres:15.3-alpine
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- 5432:5432
|
||||||
|
networks:
|
||||||
|
- db
|
||||||
|
volumes:
|
||||||
|
- postgres-data:/var/lib/postgresql/data
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: redis:latest
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- 6379:6379
|
||||||
|
networks:
|
||||||
|
- redis
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres-data:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
db:
|
||||||
|
redis:
|
||||||
33
.gitignore
vendored
Normal file
33
.gitignore
vendored
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# Binaries for programs and plugins
|
||||||
|
*.exe
|
||||||
|
*.exe~
|
||||||
|
*.dll
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
|
||||||
|
# Test binary, build with `go test -c`
|
||||||
|
*.test
|
||||||
|
|
||||||
|
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||||
|
*.out
|
||||||
|
|
||||||
|
*.DS_Store
|
||||||
|
/hailinservice
|
||||||
|
/hailinservice_linux_amd64
|
||||||
|
/hailinservice.lock
|
||||||
|
/release
|
||||||
|
/data
|
||||||
|
/uploads
|
||||||
|
/internal/test/data
|
||||||
|
tmp
|
||||||
|
/vendor
|
||||||
|
/configs/gen_rbac_policy.csv
|
||||||
|
/configs/gen_rbac_policy.csv.bak
|
||||||
|
/configs/rbac_policy.csv.bak
|
||||||
|
/test/data
|
||||||
|
/internal/swagger/v3/.openapi-generator
|
||||||
|
/internal/swagger/v3/.openapi-generator-ignore
|
||||||
|
|
||||||
|
# IDE configs
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
28
Dockerfile
Normal file
28
Dockerfile
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
FROM golang:alpine as builder
|
||||||
|
|
||||||
|
ARG APP=hailinservice
|
||||||
|
ARG VERSION=v1.0.0
|
||||||
|
ARG RELEASE_TAG=$(VERSION)
|
||||||
|
|
||||||
|
# Install the required packages
|
||||||
|
RUN apk add --no-cache gcc musl-dev sqlite-dev
|
||||||
|
|
||||||
|
# Set CGO_CFLAGS to enable large file support
|
||||||
|
ENV CGO_CFLAGS "-D_LARGEFILE64_SOURCE"
|
||||||
|
|
||||||
|
ENV GOPROXY="https://goproxy.cn"
|
||||||
|
|
||||||
|
WORKDIR /go/src/${APP}
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Build the application
|
||||||
|
RUN go build -ldflags "-w -s -X main.VERSION=${RELEASE_TAG}" -o ./${APP} .
|
||||||
|
|
||||||
|
FROM alpine
|
||||||
|
ARG APP=hailinservice
|
||||||
|
WORKDIR /go/src/${APP}
|
||||||
|
COPY --from=builder /go/src/${APP}/${APP} /usr/bin/
|
||||||
|
# COPY --from=builder /go/src/${APP}/configs /usr/bin/configs
|
||||||
|
# COPY --from=builder /go/src/${APP}/dist /usr/bin/dist
|
||||||
|
ENTRYPOINT ["hailinservice", "start", "-d", "/usr/bin/configs", "-c", "prod", "-s", "/usr/bin/dist"]
|
||||||
|
EXPOSE 8040
|
||||||
51
Makefile
Normal file
51
Makefile
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
.PHONY: start build
|
||||||
|
|
||||||
|
NOW = $(shell date -u '+%Y%m%d%I%M%S')
|
||||||
|
|
||||||
|
RELEASE_VERSION = v1.0.0
|
||||||
|
|
||||||
|
APP = hailinservice
|
||||||
|
SERVER_BIN = ${APP}
|
||||||
|
GIT_COUNT = $(shell git rev-list --all --count)
|
||||||
|
GIT_HASH = $(shell git rev-parse --short HEAD)
|
||||||
|
RELEASE_TAG = $(RELEASE_VERSION).$(GIT_COUNT).$(GIT_HASH)
|
||||||
|
|
||||||
|
CONFIG_DIR = ./configs
|
||||||
|
CONFIG_FILES = dev
|
||||||
|
STATIC_DIR = ./build/dist
|
||||||
|
START_ARGS = -d $(CONFIG_DIR) -c $(CONFIG_FILES) -s $(STATIC_DIR)
|
||||||
|
|
||||||
|
all: start
|
||||||
|
|
||||||
|
start:
|
||||||
|
@go run -ldflags "-X main.VERSION=$(RELEASE_TAG)" main.go start $(START_ARGS)
|
||||||
|
|
||||||
|
build:
|
||||||
|
@go build -ldflags "-w -s -X main.VERSION=$(RELEASE_TAG)" -o $(SERVER_BIN)
|
||||||
|
|
||||||
|
build-linux:
|
||||||
|
CGO_ENABLED=1 GOOS=linux GOARCH=amd64 CC="zig cc -target x86_64-linux-musl" CXX="zig c++ -target x86_64-linux-musl" CGO_CFLAGS="-D_LARGEFILE64_SOURCE" go build -ldflags "-w -s -X main.VERSION=$(RELEASE_TAG)" -o $(SERVER_BIN)_linux_amd64
|
||||||
|
|
||||||
|
# go install github.com/google/wire/cmd/wire@latest
|
||||||
|
wire:
|
||||||
|
@wire gen ./internal/wirex
|
||||||
|
|
||||||
|
# go install github.com/swaggo/swag/cmd/swag@latest
|
||||||
|
swagger:
|
||||||
|
@swag init --parseDependency --generalInfo ./main.go --output ./internal/swagger
|
||||||
|
|
||||||
|
# https://github.com/OpenAPITools/openapi-generator
|
||||||
|
openapi:
|
||||||
|
docker run --rm -v ${PWD}:/local openapitools/openapi-generator-cli generate -i /local/internal/swagger/swagger.yaml -g openapi -o /local/internal/swagger/v3
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf data $(SERVER_BIN)
|
||||||
|
|
||||||
|
serve: build
|
||||||
|
./$(SERVER_BIN) start $(START_ARGS)
|
||||||
|
|
||||||
|
serve-d: build
|
||||||
|
./$(SERVER_BIN) start $(START_ARGS) -d
|
||||||
|
|
||||||
|
stop:
|
||||||
|
./$(SERVER_BIN) stop
|
||||||
28
README.md
Normal file
28
README.md
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# hailinService
|
||||||
|
|
||||||
|
> Hailinservice API service
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make start
|
||||||
|
```
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make build
|
||||||
|
```
|
||||||
|
|
||||||
|
## Generate wire inject files
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make wire
|
||||||
|
```
|
||||||
|
|
||||||
|
## Generate swagger documents
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make swagger
|
||||||
|
```
|
||||||
|
|
||||||
250
README_EN.md
Normal file
250
README_EN.md
Normal file
@ -0,0 +1,250 @@
|
|||||||
|
# [Gin](https://github.com/gin-gonic/gin)-Admin
|
||||||
|
|
||||||
|
> A lightweight, flexible, elegant and full-featured RBAC scaffolding based on Golang + Gin + GORM 2.0 + Casbin 2.0 + Wire DI.
|
||||||
|
|
||||||
|
English | [中文](README.md)
|
||||||
|
|
||||||
|
[](https://github.com/LyricTian/gin-admin/blob/main/LICENSE)
|
||||||
|
[](https://golang.org/)
|
||||||
|
[](https://goreportcard.com/report/github.com/LyricTian/gin-admin)
|
||||||
|
[](https://github.com/LyricTian/gin-admin/releases)
|
||||||
|
[](https://github.com/LyricTian/gin-admin/releases)
|
||||||
|
[](https://godoc.org/github.com/LyricTian/gin-admin)
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- :scroll: Elegant implementation of `RESTful API`, using interface-based programming paradigm to make your API design more professional and standardized
|
||||||
|
- :house: Adopts clear and concise modular architecture, making code structure clear at a glance, maintenance and upgrades more effortless
|
||||||
|
- :rocket: Based on high-performance `GIN` framework, integrating rich and practical middleware (authentication, CORS, logging, rate limiting, tracing, permission control, fault tolerance, compression, etc.), helping you quickly build enterprise-level applications
|
||||||
|
- :closed_lock_with_key: Integrates industry-leading `Casbin` permission framework, flexible and precise RBAC permission control makes security protection rock solid
|
||||||
|
- :page_facing_up: Based on powerful `GORM 2.0` ORM framework, elegantly handles database operations, greatly improving development efficiency
|
||||||
|
- :electric_plug: Innovatively adopts `WIRE` dependency injection, revolutionarily simplifies module dependency relationships, making code more elegant and decoupled
|
||||||
|
- :memo: Based on high-performance `Zap` logging framework, coupled with Context tracing, making system running status clear and transparent, problem troubleshooting nowhere to hide
|
||||||
|
- :key: Integrates time-tested `JWT` authentication mechanism, making user identity verification more secure and reliable
|
||||||
|
- :microscope: Automatically integrates `Swagger` API documentation, real-time API documentation updates, making development and debugging easier - [Online Demo](https://demo.ginadmin.top/swagger/index.html)
|
||||||
|
- :wrench: Complete unit testing system, based on `testify` framework to ensure system quality, leaving no place for bugs to hide
|
||||||
|
- :100: Adopts stateless design, supports horizontal scaling, paired with Redis to implement dynamic permission management, letting your system easily handle high concurrency
|
||||||
|
- :hammer: Developer's blessing! Powerful scaffolding tool [gin-admin-cli](https://github.com/gin-admin/gin-admin-cli), making your development work twice as efficient
|
||||||
|
|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
## Frontend Projects
|
||||||
|
|
||||||
|
- [Frontend project based on Ant Design React](https://github.com/gin-admin/gin-admin-frontend)
|
||||||
|
- [Frontend project based on Vue.js](https://github.com/gin-admin/gin-admin-vue)
|
||||||
|
|
||||||
|
## Install Dependencies
|
||||||
|
|
||||||
|
- [Go](https://golang.org/) 1.19+
|
||||||
|
- [Wire](github.com/google/wire) `go install github.com/google/wire/cmd/wire@latest`
|
||||||
|
- [Swag](github.com/swaggo/swag) `go install github.com/swaggo/swag/cmd/swag@latest`
|
||||||
|
- [GIN-ADMIN-CLI](https://github.com/gin-admin/gin-admin-cli) `go install github.com/gin-admin/gin-admin-cli/v10@latest`
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### Create a New Project
|
||||||
|
|
||||||
|
> You can view detailed command instructions via `gin-admin-cli help new`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gin-admin-cli new -d ~/go/src --name testapp --desc 'A test API service based on golang.' --pkg 'github.com/xxx/testapp' --git-url https://gitee.com/lyric/gin-admin.git
|
||||||
|
```
|
||||||
|
|
||||||
|
### Start the Service
|
||||||
|
|
||||||
|
> You can switch to Chinese menu by changing `MenuFile = "menu_cn.json"` in the `configs/dev/server.toml` configuration file
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/go/src/testapp
|
||||||
|
|
||||||
|
make start
|
||||||
|
# or
|
||||||
|
go run main.go start
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compile the Service
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make build
|
||||||
|
# or
|
||||||
|
go build -ldflags "-w -s -X main.VERSION=v1.0.0" -o testapp
|
||||||
|
```
|
||||||
|
|
||||||
|
### Generate Docker Image
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker build -f ./Dockerfile -t testapp:v1.0.0 .
|
||||||
|
```
|
||||||
|
|
||||||
|
### Generate Codes
|
||||||
|
|
||||||
|
> You can view detailed command instructions via `gin-admin-cli help gen`
|
||||||
|
|
||||||
|
#### Prepare Configuration File `dictionary.yaml`
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: Dictionary
|
||||||
|
comment: Dictionary management
|
||||||
|
disable_pagination: true
|
||||||
|
fill_gorm_commit: true
|
||||||
|
fill_router_prefix: true
|
||||||
|
tpl_type: "tree"
|
||||||
|
fields:
|
||||||
|
- name: Code
|
||||||
|
type: string
|
||||||
|
comment: Code of dictionary (unique for same parent)
|
||||||
|
gorm_tag: "size:32;"
|
||||||
|
form:
|
||||||
|
binding_tag: "required,max=32"
|
||||||
|
- name: Name
|
||||||
|
type: string
|
||||||
|
comment: Display name of dictionary
|
||||||
|
gorm_tag: "size:128;index"
|
||||||
|
query:
|
||||||
|
name: LikeName
|
||||||
|
in_query: true
|
||||||
|
form_tag: name
|
||||||
|
op: LIKE
|
||||||
|
form:
|
||||||
|
binding_tag: "required,max=128"
|
||||||
|
- name: Description
|
||||||
|
type: string
|
||||||
|
comment: Details about dictionary
|
||||||
|
gorm_tag: "size:1024"
|
||||||
|
form: {}
|
||||||
|
- name: Sequence
|
||||||
|
type: int
|
||||||
|
comment: Sequence for sorting
|
||||||
|
gorm_tag: "index;"
|
||||||
|
order: DESC
|
||||||
|
form: {}
|
||||||
|
- name: Status
|
||||||
|
type: string
|
||||||
|
comment: Status of dictionary (disabled, enabled)
|
||||||
|
gorm_tag: "size:20;index"
|
||||||
|
query: {}
|
||||||
|
form:
|
||||||
|
binding_tag: "required,oneof=disabled enabled"
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gin-admin-cli gen -d . -m SYS -c dictionary.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
### Delete Function Module
|
||||||
|
|
||||||
|
> You can view detailed command instructions via `gin-admin-cli help remove`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gin-admin-cli rm -d . -m CMS --structs Article
|
||||||
|
```
|
||||||
|
|
||||||
|
### Generate Swagger Documentation
|
||||||
|
|
||||||
|
> You can generate Swagger documentation automatically via [Swag](github.com/swaggo/swag)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make swagger
|
||||||
|
# or
|
||||||
|
swag init --parseDependency --generalInfo ./main.go --output ./internal/swagger
|
||||||
|
```
|
||||||
|
|
||||||
|
### Generate Dependency Injection Code
|
||||||
|
|
||||||
|
> Dependency injection itself is used to solve the initial process of layer dependency among various modules, and you can generate dependency injection code automatically via [Wire](github.com/google/wire) to simplify the dependency injection process.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make wire
|
||||||
|
# or
|
||||||
|
wire gen ./internal/wirex
|
||||||
|
```
|
||||||
|
|
||||||
|
## Project Structure Overview
|
||||||
|
|
||||||
|
```text
|
||||||
|
├── cmd (Command line definition directory)
|
||||||
|
│ ├── start.go (Start command)
|
||||||
|
│ ├── stop.go (Stop command)
|
||||||
|
│ └── version.go (Version command)
|
||||||
|
├── configs
|
||||||
|
│ ├── dev
|
||||||
|
│ │ ├── logging.toml (Logging configuration file)
|
||||||
|
│ │ ├── middleware.toml (Middleware configuration file)
|
||||||
|
│ │ └── server.toml (Service configuration file)
|
||||||
|
│ ├── menu.json (Initialization menu file)
|
||||||
|
│ └── rbac_model.conf (Casbin RBAC model configuration file)
|
||||||
|
├── internal
|
||||||
|
│ ├── bootstrap (Initialization directory)
|
||||||
|
│ │ ├── bootstrap.go (Initialization)
|
||||||
|
│ │ ├── http.go (HTTP service)
|
||||||
|
│ │ └── logger.go (Logging service)
|
||||||
|
│ ├── config (Configuration file directory)
|
||||||
|
│ │ ├── config.go (Configuration file initialization)
|
||||||
|
│ │ ├── consts.go (Constant definition)
|
||||||
|
│ │ ├── middleware.go (Middleware configuration)
|
||||||
|
│ │ └── parse.go (Configuration file parsing)
|
||||||
|
│ ├── mods
|
||||||
|
│ │ ├── rbac (RBAC module)
|
||||||
|
│ │ │ ├── api (API layer)
|
||||||
|
│ │ │ ├── biz (Business logic layer)
|
||||||
|
│ │ │ ├── dal (Data access layer)
|
||||||
|
│ │ │ ├── schema (Data model layer)
|
||||||
|
│ │ │ ├── casbin.go (Casbin initialization)
|
||||||
|
│ │ │ ├── main.go (RBAC module entry)
|
||||||
|
│ │ │ └── wire.go (RBAC dependency injection initialization)
|
||||||
|
│ │ └── mods.go
|
||||||
|
│ ├── utility
|
||||||
|
│ │ └── prom
|
||||||
|
│ │ └── prom.go (Prometheus monitoring, used for integration with prometheus)
|
||||||
|
│ └── wirex (Dependency injection directory, contains the definition and initialization of dependency groups)
|
||||||
|
│ ├── injector.go
|
||||||
|
│ ├── wire.go
|
||||||
|
│ └── wire_gen.go
|
||||||
|
├── pkg (Public package directory)
|
||||||
|
│ ├── cachex (Cache package)
|
||||||
|
│ ├── crypto (Encryption package)
|
||||||
|
│ │ ├── aes (AES encryption)
|
||||||
|
│ │ ├── hash (Hash encryption)
|
||||||
|
│ │ └── rand (Random number)
|
||||||
|
│ ├── encoding (Encoding package)
|
||||||
|
│ │ ├── json (JSON encoding)
|
||||||
|
│ │ ├── toml (TOML encoding)
|
||||||
|
│ │ └── yaml (YAML encoding)
|
||||||
|
│ ├── errors (Error handling package)
|
||||||
|
│ ├── gormx (Gorm extension package)
|
||||||
|
│ ├── jwtx (JWT package)
|
||||||
|
│ ├── logging (Logging package)
|
||||||
|
│ ├── mail (Mail package)
|
||||||
|
│ ├── middleware (Middleware package)
|
||||||
|
│ ├── oss (Object storage package)
|
||||||
|
│ ├── promx (Prometheus package)
|
||||||
|
│ └── util (Utility package)
|
||||||
|
├── test (Unit test directory)
|
||||||
|
│ ├── menu_test.go
|
||||||
|
│ ├── role_test.go
|
||||||
|
│ ├── test.go
|
||||||
|
│ └── user_test.go
|
||||||
|
├── Dockerfile
|
||||||
|
├── Makefile
|
||||||
|
├── README.md
|
||||||
|
├── go.mod
|
||||||
|
├── go.sum
|
||||||
|
└── main.go (Entry file)
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Copyright (c) 2023 Lyric
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
105
cmd/start.go
Normal file
105
cmd/start.go
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/bootstrap"
|
||||||
|
"github.com/guxuan/hailin_service/internal/config"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// The function defines a CLI command to start a server with various flags and options, including the
|
||||||
|
// ability to run as a daemon.
|
||||||
|
func StartCmd() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
|
Name: "start",
|
||||||
|
Usage: "Start server",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "workdir",
|
||||||
|
Aliases: []string{"d"},
|
||||||
|
Usage: "Working directory",
|
||||||
|
DefaultText: "configs",
|
||||||
|
Value: "configs",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "config",
|
||||||
|
Aliases: []string{"c"},
|
||||||
|
Usage: "Runtime configuration files or directory (relative to workdir, multiple separated by commas)",
|
||||||
|
DefaultText: "dev",
|
||||||
|
Value: "dev",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "static",
|
||||||
|
Aliases: []string{"s"},
|
||||||
|
Usage: "Static files directory",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "daemon",
|
||||||
|
Usage: "Run as a daemon",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Action: func(c *cli.Context) error {
|
||||||
|
workDir := c.String("workdir")
|
||||||
|
staticDir := c.String("static")
|
||||||
|
configs := c.String("config")
|
||||||
|
|
||||||
|
if c.Bool("daemon") {
|
||||||
|
bin, err := filepath.Abs(os.Args[0])
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("failed to get absolute path for command: %s \n", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
args := []string{"start"}
|
||||||
|
args = append(args, "-d", workDir)
|
||||||
|
args = append(args, "-c", configs)
|
||||||
|
args = append(args, "-s", staticDir)
|
||||||
|
fmt.Printf("execute command: %s %s \n", bin, strings.Join(args, " "))
|
||||||
|
command := exec.Command(bin, args...)
|
||||||
|
|
||||||
|
// Redirect stdout and stderr to log file
|
||||||
|
stdLogFile := fmt.Sprintf("%s.log", c.App.Name)
|
||||||
|
file, err := os.OpenFile(stdLogFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("failed to open log file: %s \n", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
command.Stdout = file
|
||||||
|
command.Stderr = file
|
||||||
|
|
||||||
|
err = command.Start()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("failed to start daemon thread: %s \n", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't wait for the command to finish
|
||||||
|
// The main process will exit, allowing the daemon to run independently
|
||||||
|
fmt.Printf("Service %s daemon thread started successfully\n", config.C.General.AppName)
|
||||||
|
|
||||||
|
pid := command.Process.Pid
|
||||||
|
_ = os.WriteFile(fmt.Sprintf("%s.lock", c.App.Name), []byte(fmt.Sprintf("%d", pid)), 0666)
|
||||||
|
fmt.Printf("service %s daemon thread started with pid %d \n", config.C.General.AppName, pid)
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := bootstrap.Run(context.Background(), bootstrap.RunConfig{
|
||||||
|
WorkDir: workDir,
|
||||||
|
Configs: configs,
|
||||||
|
StaticDir: staticDir,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
40
cmd/stop.go
Normal file
40
cmd/stop.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// The function defines a CLI command to stop a server by reading a lock file, killing the process with
|
||||||
|
// the corresponding PID, and removing the lock file.
|
||||||
|
func StopCmd() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
|
Name: "stop",
|
||||||
|
Usage: "stop server",
|
||||||
|
Action: func(c *cli.Context) error {
|
||||||
|
appName := c.App.Name
|
||||||
|
lockFile := fmt.Sprintf("%s.lock", appName)
|
||||||
|
pid, err := os.ReadFile(lockFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
command := exec.Command("kill", string(pid))
|
||||||
|
err = command.Start()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.Remove(lockFile)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("can't remove %s.lock. %s", appName, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("service %s stopped \n", appName)
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
19
cmd/version.go
Normal file
19
cmd/version.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This function creates a CLI command that prints the version number.
|
||||||
|
func VersionCmd(v string) *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
|
Name: "version",
|
||||||
|
Usage: "Show version",
|
||||||
|
Action: func(_ *cli.Context) error {
|
||||||
|
fmt.Println(v)
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
26
configs/dev/logging.toml
Normal file
26
configs/dev/logging.toml
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
[Logger]
|
||||||
|
Debug = true
|
||||||
|
Level = "debug" # debug/info/warn/error/dpanic/panic/fatal
|
||||||
|
CallerSkip = 1
|
||||||
|
|
||||||
|
[Logger.File]
|
||||||
|
Enable = false
|
||||||
|
Path = "data/log/hailinservice.log"
|
||||||
|
MaxBackups = 20 # Files
|
||||||
|
MaxSize = 64 # MB
|
||||||
|
|
||||||
|
[[Logger.Hooks]]
|
||||||
|
Enable = true
|
||||||
|
Level = "info"
|
||||||
|
Type = "gorm" # gorm
|
||||||
|
MaxBuffer = 1024
|
||||||
|
MaxThread = 2
|
||||||
|
|
||||||
|
[Logger.Hooks.Options]
|
||||||
|
Debug = "false"
|
||||||
|
DBType = "sqlite3" # sqlite3/mysql/postgres
|
||||||
|
DSN = "data/hailinservice.db"
|
||||||
|
MaxOpenConns = "16"
|
||||||
|
MaxIdleConns = "4"
|
||||||
|
MaxLifetime = "86400"
|
||||||
|
MaxIdleTime = "7200"
|
||||||
76
configs/dev/middleware.toml
Normal file
76
configs/dev/middleware.toml
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
[Middleware]
|
||||||
|
|
||||||
|
[Middleware.Recovery]
|
||||||
|
Skip = 3
|
||||||
|
|
||||||
|
[Middleware.CORS]
|
||||||
|
Enable = true
|
||||||
|
AllowOrigins = ["*"]
|
||||||
|
AllowMethods = ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]
|
||||||
|
AllowHeaders = ["*"]
|
||||||
|
MaxAge = 86400
|
||||||
|
AllowWildcard = true
|
||||||
|
AllowWebSockets = true
|
||||||
|
AllowFiles = true
|
||||||
|
|
||||||
|
[Middleware.Trace]
|
||||||
|
RequestHeaderKey = "X-Request-Id"
|
||||||
|
ResponseTraceKey = "X-Trace-Id"
|
||||||
|
|
||||||
|
[Middleware.Logger]
|
||||||
|
MaxOutputRequestBodyLen = 4096 # bytes
|
||||||
|
MaxOutputResponseBodyLen = 4096 # bytes
|
||||||
|
|
||||||
|
[Middleware.CopyBody]
|
||||||
|
MaxContentLen = 134217728 # 128MB
|
||||||
|
|
||||||
|
[Middleware.Auth]
|
||||||
|
Disable = true
|
||||||
|
SkippedPathPrefixes = ["/api/v1/captcha/", "/api/v1/login", "/api/v1/web/articles", "/api/v1/web/jobs"]
|
||||||
|
SigningMethod = "HS512" # HS256/HS384/HS512
|
||||||
|
SigningKey = "XnEsT0S@" # Secret key
|
||||||
|
OldSigningKey = "" # Old secret key (For change secret key)
|
||||||
|
Expired = 86400 # seconds
|
||||||
|
|
||||||
|
[Middleware.Auth.Store]
|
||||||
|
Type = "badger" # memory/badger/redis
|
||||||
|
Delimiter = ":"
|
||||||
|
|
||||||
|
[Middleware.Auth.Store.Memory]
|
||||||
|
CleanupInterval = 60 # seconds
|
||||||
|
|
||||||
|
[Middleware.Auth.Store.Badger]
|
||||||
|
Path = "data/auth"
|
||||||
|
|
||||||
|
[Middleware.Auth.Store.Redis]
|
||||||
|
Addr = "" # If empty, then use the same configuration as Storage.Cache.Redis
|
||||||
|
Username = ""
|
||||||
|
Password = ""
|
||||||
|
DB = 2
|
||||||
|
|
||||||
|
[Middleware.RateLimiter]
|
||||||
|
Enable = false
|
||||||
|
Period = 10 # seconds
|
||||||
|
MaxRequestsPerIP = 1000
|
||||||
|
MaxRequestsPerUser = 500
|
||||||
|
|
||||||
|
[Middleware.RateLimiter.Store]
|
||||||
|
Type = "memory" # memory/redis
|
||||||
|
|
||||||
|
[Middleware.RateLimiter.Store.Memory]
|
||||||
|
Expiration = 3600
|
||||||
|
CleanupInterval = 60
|
||||||
|
|
||||||
|
[Middleware.RateLimiter.Store.Redis]
|
||||||
|
Addr = "" # If empty, then use the same configuration as Storage.Cache.Redis
|
||||||
|
Username = ""
|
||||||
|
Password = ""
|
||||||
|
DB = 10
|
||||||
|
|
||||||
|
[Middleware.Casbin]
|
||||||
|
Disable = true
|
||||||
|
SkippedPathPrefixes = ["/api/v1/captcha/", "/api/v1/login", "/api/v1/current/", "/api/v1/web/articles", "/api/v1/web/jobs"]
|
||||||
|
LoadThread = 2
|
||||||
|
AutoLoadInterval = 3 # seconds
|
||||||
|
ModelFile = "rbac_model.conf"
|
||||||
|
GenPolicyFile = "gen_rbac_policy.csv"
|
||||||
89
configs/dev/server.toml
Normal file
89
configs/dev/server.toml
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
[General]
|
||||||
|
AppName = "hailinservice"
|
||||||
|
Version = "v10.1.0"
|
||||||
|
Debug = true
|
||||||
|
PprofAddr = "" # Pprof monitor address, "localhost:6060"
|
||||||
|
DisableSwagger = false
|
||||||
|
DisablePrintConfig = false
|
||||||
|
DefaultLoginPwd = "6351623c8cef86fefabfa7da046fc619" # MD5("abc-123")
|
||||||
|
MenuFile = "menu.json" # Or use "menu_cn.json"
|
||||||
|
DenyOperateMenu = false
|
||||||
|
|
||||||
|
[General.HTTP]
|
||||||
|
Addr = ":8060"
|
||||||
|
ShutdownTimeout = 10
|
||||||
|
ReadTimeout = 60
|
||||||
|
WriteTimeout = 60
|
||||||
|
IdleTimeout = 10
|
||||||
|
CertFile = ""
|
||||||
|
KeyFile = ""
|
||||||
|
|
||||||
|
[General.Root] # Super Administrator Account
|
||||||
|
ID = "root"
|
||||||
|
Username = "admin"
|
||||||
|
Password = "6351623c8cef86fefabfa7da046fc619" # MD5("abc-123")
|
||||||
|
Name = "Admin"
|
||||||
|
|
||||||
|
[Storage]
|
||||||
|
|
||||||
|
[Storage.Cache]
|
||||||
|
Type = "memory" # memory/badger/redis
|
||||||
|
Delimiter = ":"
|
||||||
|
|
||||||
|
[Storage.Cache.Memory]
|
||||||
|
CleanupInterval = 60
|
||||||
|
|
||||||
|
[Storage.Cache.Badger]
|
||||||
|
Path = "data/cache"
|
||||||
|
|
||||||
|
[Storage.Cache.Redis]
|
||||||
|
Addr = "127.0.0.1:6379"
|
||||||
|
Username = ""
|
||||||
|
Password = ""
|
||||||
|
DB = 1
|
||||||
|
|
||||||
|
[Storage.DB]
|
||||||
|
Debug = true
|
||||||
|
Type = "mysql" # sqlite3/mysql/postgres
|
||||||
|
# SQLite3 DSN
|
||||||
|
#DSN = "data/hailinservice.db"
|
||||||
|
# MySQL DSN
|
||||||
|
DSN = "hailin:z2askDphamsxk5BH@tcp(115.239.217.220:3306)/hailin?charset=utf8mb4&parseTime=True&loc=Local"
|
||||||
|
# PostgreSQL DSN
|
||||||
|
# DSN = "host=db user=postgres password=123456 dbname=hailinservice port=5432 sslmode=disable TimeZone=Asia/Shanghai"
|
||||||
|
MaxLifetime = 86400
|
||||||
|
MaxIdleTime = 3600
|
||||||
|
MaxOpenConns = 100
|
||||||
|
MaxIdleConns = 50
|
||||||
|
TablePrefix = ""
|
||||||
|
AutoMigrate = true
|
||||||
|
|
||||||
|
[Util]
|
||||||
|
|
||||||
|
[Util.Captcha]
|
||||||
|
Length = 4
|
||||||
|
Width = 400
|
||||||
|
Height = 160
|
||||||
|
CacheType = "memory" # memory/redis
|
||||||
|
|
||||||
|
[Util.Captcha.Redis]
|
||||||
|
Addr = "" # If empty, then use the same configuration as Storage.Cache.Redis
|
||||||
|
Username = ""
|
||||||
|
Password = ""
|
||||||
|
DB = 1
|
||||||
|
KeyPrefix = "captcha:"
|
||||||
|
|
||||||
|
[Util.Prometheus]
|
||||||
|
Enable = false
|
||||||
|
Port = 9100
|
||||||
|
BasicUsername = "admin"
|
||||||
|
BasicPassword = "admin"
|
||||||
|
LogApis = [] # Log APIs, e.g. ["/api/v1/users"]
|
||||||
|
LogMethods = [] # Log HTTP methods, e.g. ["GET"]
|
||||||
|
DefaultCollect = true
|
||||||
|
|
||||||
|
[Dictionary]
|
||||||
|
UserCacheExp = 4 # hours
|
||||||
|
[FileConfig]
|
||||||
|
UploadDir = "./uploads"
|
||||||
|
StaticPrefix = "/static"
|
||||||
240
configs/menu.json
Normal file
240
configs/menu.json
Normal file
@ -0,0 +1,240 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"code": "home",
|
||||||
|
"name": "Home",
|
||||||
|
"sequence": 90,
|
||||||
|
"type": "page",
|
||||||
|
"path": "/home",
|
||||||
|
"status": "enabled"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "system",
|
||||||
|
"name": "System",
|
||||||
|
"sequence": 10,
|
||||||
|
"type": "page",
|
||||||
|
"path": "/system",
|
||||||
|
"status": "enabled",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"code": "menu",
|
||||||
|
"name": "Menu",
|
||||||
|
"sequence": 90,
|
||||||
|
"type": "page",
|
||||||
|
"path": "/system/menu",
|
||||||
|
"status": "enabled",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"code": "add",
|
||||||
|
"name": "Add",
|
||||||
|
"sequence": 9,
|
||||||
|
"type": "button",
|
||||||
|
"status": "enabled",
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"method": "POST",
|
||||||
|
"path": "/api/v1/menus"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "edit",
|
||||||
|
"name": "Edit",
|
||||||
|
"sequence": 8,
|
||||||
|
"type": "button",
|
||||||
|
"status": "enabled",
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"method": "PUT",
|
||||||
|
"path": "/api/v1/menus/{id}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "delete",
|
||||||
|
"name": "Delete",
|
||||||
|
"sequence": 7,
|
||||||
|
"type": "button",
|
||||||
|
"status": "enabled",
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"method": "DELETE",
|
||||||
|
"path": "/api/v1/menus/{id}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "search",
|
||||||
|
"name": "Search",
|
||||||
|
"sequence": 6,
|
||||||
|
"type": "button",
|
||||||
|
"status": "enabled"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"path": "/api/v1/menus"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"path": "/api/v1/menus/{id}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "role",
|
||||||
|
"name": "Role",
|
||||||
|
"sequence": 80,
|
||||||
|
"type": "page",
|
||||||
|
"path": "/system/role",
|
||||||
|
"status": "enabled",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"code": "add",
|
||||||
|
"name": "Add",
|
||||||
|
"sequence": 9,
|
||||||
|
"type": "button",
|
||||||
|
"status": "enabled",
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"method": "POST",
|
||||||
|
"path": "/api/v1/roles"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "edit",
|
||||||
|
"name": "Edit",
|
||||||
|
"sequence": 8,
|
||||||
|
"type": "button",
|
||||||
|
"status": "enabled",
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"method": "PUT",
|
||||||
|
"path": "/api/v1/roles/{id}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "delete",
|
||||||
|
"name": "Delete",
|
||||||
|
"sequence": 7,
|
||||||
|
"type": "button",
|
||||||
|
"status": "enabled",
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"method": "DELETE",
|
||||||
|
"path": "/api/v1/roles/{id}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "search",
|
||||||
|
"name": "Search",
|
||||||
|
"sequence": 6,
|
||||||
|
"type": "button",
|
||||||
|
"status": "enabled"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"path": "/api/v1/menus"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"path": "/api/v1/roles"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"path": "/api/v1/roles/{id}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "user",
|
||||||
|
"name": "User",
|
||||||
|
"sequence": 70,
|
||||||
|
"type": "page",
|
||||||
|
"path": "/system/user",
|
||||||
|
"status": "enabled",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"code": "add",
|
||||||
|
"name": "Add",
|
||||||
|
"sequence": 9,
|
||||||
|
"type": "button",
|
||||||
|
"status": "enabled",
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"method": "POST",
|
||||||
|
"path": "/api/v1/users"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "edit",
|
||||||
|
"name": "Edit",
|
||||||
|
"sequence": 8,
|
||||||
|
"type": "button",
|
||||||
|
"status": "enabled",
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"method": "PUT",
|
||||||
|
"path": "/api/v1/users/{id}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "delete",
|
||||||
|
"name": "Delete",
|
||||||
|
"sequence": 7,
|
||||||
|
"type": "button",
|
||||||
|
"status": "enabled",
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"method": "DELETE",
|
||||||
|
"path": "/api/v1/users/{id}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "search",
|
||||||
|
"name": "Search",
|
||||||
|
"sequence": 6,
|
||||||
|
"type": "button",
|
||||||
|
"status": "enabled"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"path": "/api/v1/roles"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"path": "/api/v1/users"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"path": "/api/v1/users/{id}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "logger",
|
||||||
|
"name": "Logger",
|
||||||
|
"sequence": 10,
|
||||||
|
"type": "page",
|
||||||
|
"path": "/system/logger",
|
||||||
|
"status": "enabled",
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"path": "/api/v1/loggers"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
240
configs/menu_cn.json
Normal file
240
configs/menu_cn.json
Normal file
@ -0,0 +1,240 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"code": "home",
|
||||||
|
"name": "首页",
|
||||||
|
"sequence": 90,
|
||||||
|
"type": "page",
|
||||||
|
"path": "/home",
|
||||||
|
"status": "enabled"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "system",
|
||||||
|
"name": "系统管理",
|
||||||
|
"sequence": 10,
|
||||||
|
"type": "page",
|
||||||
|
"path": "/system",
|
||||||
|
"status": "enabled",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"code": "menu",
|
||||||
|
"name": "菜单管理",
|
||||||
|
"sequence": 90,
|
||||||
|
"type": "page",
|
||||||
|
"path": "/system/menu",
|
||||||
|
"status": "enabled",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"code": "add",
|
||||||
|
"name": "增加",
|
||||||
|
"sequence": 9,
|
||||||
|
"type": "button",
|
||||||
|
"status": "enabled",
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"method": "POST",
|
||||||
|
"path": "/api/v1/menus"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "edit",
|
||||||
|
"name": "编辑",
|
||||||
|
"sequence": 8,
|
||||||
|
"type": "button",
|
||||||
|
"status": "enabled",
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"method": "PUT",
|
||||||
|
"path": "/api/v1/menus/{id}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "delete",
|
||||||
|
"name": "删除",
|
||||||
|
"sequence": 7,
|
||||||
|
"type": "button",
|
||||||
|
"status": "enabled",
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"method": "DELETE",
|
||||||
|
"path": "/api/v1/menus/{id}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "search",
|
||||||
|
"name": "查询",
|
||||||
|
"sequence": 6,
|
||||||
|
"type": "button",
|
||||||
|
"status": "enabled"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"path": "/api/v1/menus"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"path": "/api/v1/menus/{id}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "role",
|
||||||
|
"name": "角色管理",
|
||||||
|
"sequence": 80,
|
||||||
|
"type": "page",
|
||||||
|
"path": "/system/role",
|
||||||
|
"status": "enabled",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"code": "add",
|
||||||
|
"name": "增加",
|
||||||
|
"sequence": 9,
|
||||||
|
"type": "button",
|
||||||
|
"status": "enabled",
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"method": "POST",
|
||||||
|
"path": "/api/v1/roles"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "edit",
|
||||||
|
"name": "编辑",
|
||||||
|
"sequence": 8,
|
||||||
|
"type": "button",
|
||||||
|
"status": "enabled",
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"method": "PUT",
|
||||||
|
"path": "/api/v1/roles/{id}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "delete",
|
||||||
|
"name": "删除",
|
||||||
|
"sequence": 7,
|
||||||
|
"type": "button",
|
||||||
|
"status": "enabled",
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"method": "DELETE",
|
||||||
|
"path": "/api/v1/roles/{id}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "search",
|
||||||
|
"name": "查询",
|
||||||
|
"sequence": 6,
|
||||||
|
"type": "button",
|
||||||
|
"status": "enabled"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"path": "/api/v1/menus"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"path": "/api/v1/roles"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"path": "/api/v1/roles/{id}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "user",
|
||||||
|
"name": "用户管理",
|
||||||
|
"sequence": 70,
|
||||||
|
"type": "page",
|
||||||
|
"path": "/system/user",
|
||||||
|
"status": "enabled",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"code": "add",
|
||||||
|
"name": "增加",
|
||||||
|
"sequence": 9,
|
||||||
|
"type": "button",
|
||||||
|
"status": "enabled",
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"method": "POST",
|
||||||
|
"path": "/api/v1/users"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "edit",
|
||||||
|
"name": "编辑",
|
||||||
|
"sequence": 8,
|
||||||
|
"type": "button",
|
||||||
|
"status": "enabled",
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"method": "PUT",
|
||||||
|
"path": "/api/v1/users/{id}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "delete",
|
||||||
|
"name": "删除",
|
||||||
|
"sequence": 7,
|
||||||
|
"type": "button",
|
||||||
|
"status": "enabled",
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"method": "DELETE",
|
||||||
|
"path": "/api/v1/users/{id}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "search",
|
||||||
|
"name": "查询",
|
||||||
|
"sequence": 6,
|
||||||
|
"type": "button",
|
||||||
|
"status": "enabled"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"path": "/api/v1/roles"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"path": "/api/v1/users"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"path": "/api/v1/users/{id}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "logger",
|
||||||
|
"name": "日志查询",
|
||||||
|
"sequence": 10,
|
||||||
|
"type": "page",
|
||||||
|
"path": "/system/logger",
|
||||||
|
"status": "enabled",
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"path": "/api/v1/loggers"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
14
configs/rbac_model.conf
Normal file
14
configs/rbac_model.conf
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
[request_definition]
|
||||||
|
r = sub, obj, act
|
||||||
|
|
||||||
|
[policy_definition]
|
||||||
|
p = sub, obj, act
|
||||||
|
|
||||||
|
[policy_effect]
|
||||||
|
e = some(where (p.eft == allow)) # Passes auth if any of the policies allows
|
||||||
|
|
||||||
|
[role_definition]
|
||||||
|
g = _, _
|
||||||
|
|
||||||
|
[matchers]
|
||||||
|
m = g(r.sub, p.sub) && r.sub == p.sub && (keyMatch2(r.obj, p.obj) || keyMatch3(r.obj, p.obj)) && r.act == p.act
|
||||||
114
go.mod
Normal file
114
go.mod
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
module github.com/guxuan/hailin_service
|
||||||
|
|
||||||
|
go 1.19
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/BurntSushi/toml v1.2.1
|
||||||
|
github.com/LyricTian/captcha v1.2.0
|
||||||
|
github.com/aws/aws-sdk-go v1.44.300
|
||||||
|
github.com/casbin/casbin/v2 v2.68.0
|
||||||
|
github.com/creasty/defaults v1.7.0
|
||||||
|
github.com/dgraph-io/badger/v3 v3.2103.5
|
||||||
|
github.com/gin-contrib/cors v1.4.0
|
||||||
|
github.com/gin-gonic/gin v1.9.0
|
||||||
|
github.com/go-playground/validator/v10 v10.12.0
|
||||||
|
github.com/go-redis/redis/v8 v8.11.5
|
||||||
|
github.com/go-redis/redis_rate/v9 v9.1.2
|
||||||
|
github.com/go-sql-driver/mysql v1.7.0
|
||||||
|
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||||
|
github.com/google/uuid v1.3.0
|
||||||
|
github.com/google/wire v0.5.0
|
||||||
|
github.com/json-iterator/go v1.1.12
|
||||||
|
github.com/minio/minio-go/v7 v7.0.51
|
||||||
|
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||||
|
github.com/pelletier/go-toml v1.9.5
|
||||||
|
github.com/pkg/errors v0.9.1
|
||||||
|
github.com/prometheus/client_golang v1.14.0
|
||||||
|
github.com/redis/go-redis/v9 v9.0.4
|
||||||
|
github.com/rs/xid v1.4.0
|
||||||
|
github.com/spf13/cast v1.5.1
|
||||||
|
github.com/stretchr/testify v1.8.4
|
||||||
|
github.com/swaggo/files v1.0.1
|
||||||
|
github.com/swaggo/gin-swagger v1.6.0
|
||||||
|
github.com/swaggo/swag v1.16.2
|
||||||
|
github.com/urfave/cli/v2 v2.25.1
|
||||||
|
go.uber.org/zap v1.24.0
|
||||||
|
golang.org/x/crypto v0.8.0
|
||||||
|
golang.org/x/time v0.3.0
|
||||||
|
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
|
||||||
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||||
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
|
gorm.io/driver/mysql v1.4.7
|
||||||
|
gorm.io/driver/postgres v1.5.0
|
||||||
|
gorm.io/driver/sqlite v1.4.4
|
||||||
|
gorm.io/gorm v1.24.7-0.20230306060331-85eaf9eeda11
|
||||||
|
gorm.io/plugin/dbresolver v1.4.1
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible // indirect
|
||||||
|
github.com/KyleBanks/depth v1.2.1 // indirect
|
||||||
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
|
github.com/bytedance/sonic v1.8.7 // indirect
|
||||||
|
github.com/cespare/xxhash v1.1.0 // indirect
|
||||||
|
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||||
|
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||||
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
|
github.com/dgraph-io/ristretto v0.1.1 // indirect
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||||
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
|
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||||
|
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
||||||
|
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
||||||
|
github.com/go-openapi/spec v0.20.8 // indirect
|
||||||
|
github.com/go-openapi/swag v0.22.3 // indirect
|
||||||
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
|
github.com/goccy/go-json v0.10.2 // indirect
|
||||||
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
|
github.com/golang/glog v1.1.1 // indirect
|
||||||
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||||
|
github.com/golang/protobuf v1.5.3 // indirect
|
||||||
|
github.com/golang/snappy v0.0.4 // indirect
|
||||||
|
github.com/google/flatbuffers v23.3.3+incompatible // indirect
|
||||||
|
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
|
||||||
|
github.com/jackc/pgx/v5 v5.3.1 // indirect
|
||||||
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
|
github.com/jinzhu/now v1.1.5 // indirect
|
||||||
|
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||||
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
|
github.com/klauspost/compress v1.16.4 // indirect
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
|
||||||
|
github.com/leodido/go-urn v1.2.3 // indirect
|
||||||
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.18 // indirect
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.16 // indirect
|
||||||
|
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||||
|
github.com/minio/md5-simd v1.1.2 // indirect
|
||||||
|
github.com/minio/sha256-simd v1.0.0 // indirect
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
|
github.com/pelletier/go-toml/v2 v2.0.7 // indirect
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
|
github.com/prometheus/client_model v0.3.0 // indirect
|
||||||
|
github.com/prometheus/common v0.42.0 // indirect
|
||||||
|
github.com/prometheus/procfs v0.9.0 // indirect
|
||||||
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
|
github.com/sirupsen/logrus v1.9.0 // indirect
|
||||||
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
|
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||||
|
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||||
|
go.opencensus.io v0.24.0 // indirect
|
||||||
|
go.uber.org/atomic v1.10.0 // indirect
|
||||||
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
|
golang.org/x/arch v0.3.0 // indirect
|
||||||
|
golang.org/x/net v0.9.0 // indirect
|
||||||
|
golang.org/x/sys v0.7.0 // indirect
|
||||||
|
golang.org/x/text v0.9.0 // indirect
|
||||||
|
golang.org/x/tools v0.8.0 // indirect
|
||||||
|
google.golang.org/protobuf v1.30.0 // indirect
|
||||||
|
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||||
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
|
)
|
||||||
528
go.sum
Normal file
528
go.sum
Normal file
@ -0,0 +1,528 @@
|
|||||||
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
|
github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=
|
||||||
|
github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||||
|
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw=
|
||||||
|
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||||
|
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
|
||||||
|
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
|
||||||
|
github.com/LyricTian/captcha v1.2.0 h1:SXmXj9B1KHBTsVv9rXVVTsKdgNlHrSeb4Memlw+wks4=
|
||||||
|
github.com/LyricTian/captcha v1.2.0/go.mod h1:tpNDvMWf9XBnkfPB2Tyx7lxDWTgfZ9wA4o7Yl50FWs4=
|
||||||
|
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
|
||||||
|
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||||
|
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||||
|
github.com/aws/aws-sdk-go v1.44.300 h1:Zn+3lqgYahIf9yfrwZ+g+hq/c3KzUBaQ8wqY/ZXiAbY=
|
||||||
|
github.com/aws/aws-sdk-go v1.44.300/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
|
||||||
|
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||||
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
|
github.com/bsm/ginkgo/v2 v2.7.0 h1:ItPMPH90RbmZJt5GtkcNvIRuGEdwlBItdNVoyzaNQao=
|
||||||
|
github.com/bsm/gomega v1.26.0 h1:LhQm+AFcgV2M0WyKroMASzAzCAJVpAxQXv4SaI9a69Y=
|
||||||
|
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
||||||
|
github.com/bytedance/sonic v1.8.7 h1:d3sry5vGgVq/OpgozRUNP6xBsSo0mtNdwliApw+SAMQ=
|
||||||
|
github.com/bytedance/sonic v1.8.7/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
|
||||||
|
github.com/casbin/casbin/v2 v2.68.0 h1:7L4kwNJJw/pzdSEhl4SkeHz+1JzYn8guO+Q422sxzLM=
|
||||||
|
github.com/casbin/casbin/v2 v2.68.0/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg=
|
||||||
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
|
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||||
|
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||||
|
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
||||||
|
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
|
||||||
|
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
||||||
|
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||||
|
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||||
|
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||||
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
|
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||||
|
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||||
|
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
|
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||||
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
|
github.com/creasty/defaults v1.7.0 h1:eNdqZvc5B509z18lD8yc212CAqJNvfT1Jq6L8WowdBA=
|
||||||
|
github.com/creasty/defaults v1.7.0/go.mod h1:iGzKe6pbEHnpMPtfDXZEr0NVxWnPTjb1bbDy08fPzYM=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/dgraph-io/badger/v3 v3.2103.5 h1:ylPa6qzbjYRQMU6jokoj4wzcaweHylt//CH0AKt0akg=
|
||||||
|
github.com/dgraph-io/badger/v3 v3.2103.5/go.mod h1:4MPiseMeDQ3FNCYwRbbcBOGJLf5jsE0PPFzRiKjtcdw=
|
||||||
|
github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8=
|
||||||
|
github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA=
|
||||||
|
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=
|
||||||
|
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||||
|
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||||
|
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||||
|
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
|
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
|
github.com/gin-contrib/cors v1.4.0 h1:oJ6gwtUl3lqV0WEIwM/LxPF1QZ5qe2lGWdY2+bz7y0g=
|
||||||
|
github.com/gin-contrib/cors v1.4.0/go.mod h1:bs9pNM0x/UsmHPBWT2xZz9ROh8xYjYkiURUfmBoMlcs=
|
||||||
|
github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4=
|
||||||
|
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||||
|
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||||
|
github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
|
||||||
|
github.com/gin-gonic/gin v1.9.0 h1:OjyFBKICoexlu99ctXNR2gg+c5pKrKMuyjgARg9qeY8=
|
||||||
|
github.com/gin-gonic/gin v1.9.0/go.mod h1:W1Me9+hsUSyj3CePGrd1/QrKJMSJ1Tu/0hFEH89961k=
|
||||||
|
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||||
|
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||||
|
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
|
||||||
|
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
||||||
|
github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo=
|
||||||
|
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
|
||||||
|
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
|
||||||
|
github.com/go-openapi/spec v0.20.8 h1:ubHmXNY3FCIOinT8RNrrPfGc9t7I1qhPtdOGoG2AxRU=
|
||||||
|
github.com/go-openapi/spec v0.20.8/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA=
|
||||||
|
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||||
|
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||||
|
github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
|
||||||
|
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||||
|
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||||
|
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||||
|
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
|
||||||
|
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||||
|
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||||
|
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
|
||||||
|
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||||
|
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||||
|
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
|
||||||
|
github.com/go-playground/validator/v10 v10.12.0 h1:E4gtWgxWxp8YSxExrQFv5BpCahla0PVF2oTTEYaWQGI=
|
||||||
|
github.com/go-playground/validator/v10 v10.12.0/go.mod h1:hCAPuzYvKdP33pxWa+2+6AIKXEKqjIUyqsNCtbsSJrA=
|
||||||
|
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
|
||||||
|
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
|
||||||
|
github.com/go-redis/redis_rate/v9 v9.1.2 h1:H0l5VzoAtOE6ydd38j8MCq3ABlGLnvvbA1xDSVVCHgQ=
|
||||||
|
github.com/go-redis/redis_rate/v9 v9.1.2/go.mod h1:oam2de2apSgRG8aJzwJddXbNu91Iyz1m8IKJE2vpvlQ=
|
||||||
|
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||||
|
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
|
||||||
|
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||||
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||||
|
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||||
|
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||||
|
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||||
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
|
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
||||||
|
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||||
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
|
github.com/golang/glog v1.1.1 h1:jxpi2eWoU84wbX9iIEyAeeoac3FLuifZpY9tcNUD9kw=
|
||||||
|
github.com/golang/glog v1.1.1/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ=
|
||||||
|
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||||
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
|
||||||
|
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||||
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||||
|
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||||
|
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||||
|
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
|
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
|
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
|
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||||
|
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
|
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
|
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||||
|
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
|
github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
|
||||||
|
github.com/google/flatbuffers v23.3.3+incompatible h1:5PJI/WbJkaMTvpGxsHVKG/LurN/KnWXNyGpwSCDgen0=
|
||||||
|
github.com/google/flatbuffers v23.3.3+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
|
||||||
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||||
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
|
github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
||||||
|
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||||
|
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/google/wire v0.5.0 h1:I7ELFeVBr3yfPIcc8+MWvrjk+3VjbcSzoXm3JVa+jD8=
|
||||||
|
github.com/google/wire v0.5.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU=
|
||||||
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||||
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
|
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
|
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||||
|
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||||
|
github.com/jackc/pgx/v5 v5.3.0/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8=
|
||||||
|
github.com/jackc/pgx/v5 v5.3.1 h1:Fcr8QJ1ZeLi5zsPZqQeUZhNhxfkkKBOgJuYkJHoBOtU=
|
||||||
|
github.com/jackc/pgx/v5 v5.3.1/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8=
|
||||||
|
github.com/jackc/puddle/v2 v2.2.0/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||||
|
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||||
|
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||||
|
github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||||
|
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||||
|
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||||
|
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||||
|
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||||
|
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||||
|
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||||
|
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||||
|
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||||
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
|
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
|
github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
||||||
|
github.com/klauspost/compress v1.16.4 h1:91KN02FnsOYhuunwU4ssRe8lc2JosWmizWa91B5v1PU=
|
||||||
|
github.com/klauspost/compress v1.16.4/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
||||||
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
|
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||||
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
|
||||||
|
github.com/leodido/go-urn v1.2.3 h1:6BE2vPT0lqoz3fmOesHZiaiFh7889ssCo2GMvLCfiuA=
|
||||||
|
github.com/leodido/go-urn v1.2.3/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
|
||||||
|
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
|
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||||
|
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||||
|
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||||
|
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||||
|
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||||
|
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||||
|
github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
|
||||||
|
github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||||
|
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
||||||
|
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||||
|
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
|
||||||
|
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
|
||||||
|
github.com/minio/minio-go/v7 v7.0.51 h1:eSewrwc23TqUDEH8aw8Bwp4f+JDdozRrPWcKR7DZhmY=
|
||||||
|
github.com/minio/minio-go/v7 v7.0.51/go.mod h1:IbbodHyjUAguneyucUaahv+VMNs/EOTV9du7A7/Z3HU=
|
||||||
|
github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g=
|
||||||
|
github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM=
|
||||||
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||||
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
|
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||||
|
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||||
|
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||||
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||||
|
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||||
|
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||||
|
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||||
|
github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
|
||||||
|
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||||
|
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||||
|
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||||
|
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
|
||||||
|
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
|
||||||
|
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||||
|
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||||
|
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
|
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
|
||||||
|
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.0.7 h1:muncTPStnKRos5dpVKULv2FVd4bMOhNePj9CjgDb8Us=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.0.7/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
|
||||||
|
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw=
|
||||||
|
github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
|
||||||
|
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
|
||||||
|
github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
|
||||||
|
github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
|
||||||
|
github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI=
|
||||||
|
github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
|
||||||
|
github.com/redis/go-redis/v9 v9.0.4 h1:FC82T+CHJ/Q/PdyLW++GeCO+Ol59Y4T7R4jbgjvktgc=
|
||||||
|
github.com/redis/go-redis/v9 v9.0.4/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk=
|
||||||
|
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||||
|
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||||
|
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||||
|
github.com/rs/xid v1.4.0 h1:qd7wPTDkN6KQx2VmMBLrpHkiyQwgFXRnkOLacUiaSNY=
|
||||||
|
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||||
|
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||||
|
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||||
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||||
|
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
|
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
|
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
||||||
|
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
|
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||||
|
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
|
github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA=
|
||||||
|
github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48=
|
||||||
|
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||||
|
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||||
|
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
|
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
|
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
|
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||||
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
|
github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE=
|
||||||
|
github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg=
|
||||||
|
github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M=
|
||||||
|
github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo=
|
||||||
|
github.com/swaggo/swag v1.16.2 h1:28Pp+8DkQoV+HLzLx8RGJZXNGKbFqnuvSbAAtoxiY04=
|
||||||
|
github.com/swaggo/swag v1.16.2/go.mod h1:6YzXnDcpr0767iOejs318CwYkCQqyGer6BizOg03f+E=
|
||||||
|
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||||
|
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||||
|
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
|
||||||
|
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||||
|
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
|
||||||
|
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
|
||||||
|
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||||
|
github.com/urfave/cli/v2 v2.25.1 h1:zw8dSP7ghX0Gmm8vugrs6q9Ku0wzweqPyshy+syu9Gw=
|
||||||
|
github.com/urfave/cli/v2 v2.25.1/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc=
|
||||||
|
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||||
|
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
|
||||||
|
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
||||||
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
|
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||||
|
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||||
|
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||||
|
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
|
||||||
|
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||||
|
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
|
||||||
|
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||||
|
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
|
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
|
||||||
|
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
|
||||||
|
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||||
|
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
|
||||||
|
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||||
|
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
|
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||||
|
golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ=
|
||||||
|
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
|
||||||
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
|
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
|
||||||
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
|
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
|
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||||
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
|
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||||
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
|
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
|
golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
|
||||||
|
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
|
||||||
|
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
|
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
|
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||||
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
|
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||||
|
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190422233926-fe54fb35175b/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
|
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
|
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
|
golang.org/x/tools v0.8.0 h1:vSDcovVPld282ceKgDimkRSC8kpaH1dgyc9UMzlt84Y=
|
||||||
|
golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
|
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||||
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
|
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
|
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||||
|
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
|
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
|
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||||
|
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||||
|
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||||
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
|
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
|
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
||||||
|
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
|
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
|
||||||
|
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
|
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=
|
||||||
|
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
|
||||||
|
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||||
|
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
|
||||||
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
|
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gorm.io/driver/mysql v1.4.3/go.mod h1:sSIebwZAVPiT+27jK9HIwvsqOGKx3YMPmrA3mBJR10c=
|
||||||
|
gorm.io/driver/mysql v1.4.7 h1:rY46lkCspzGHn7+IYsNpSfEv9tA+SU4SkkB+GFX125Y=
|
||||||
|
gorm.io/driver/mysql v1.4.7/go.mod h1:SxzItlnT1cb6e1e4ZRpgJN2VYtcqJgqnHxWr4wsP8oc=
|
||||||
|
gorm.io/driver/postgres v1.5.0 h1:u2FXTy14l45qc3UeCJ7QaAXZmZfDDv0YrthvmRq1l0U=
|
||||||
|
gorm.io/driver/postgres v1.5.0/go.mod h1:FUZXzO+5Uqg5zzwzv4KK49R8lvGIyscBOqYrtI1Ce9A=
|
||||||
|
gorm.io/driver/sqlite v1.4.4 h1:gIufGoR0dQzjkyqDyYSCvsYR6fba1Gw5YKDqKeChxFc=
|
||||||
|
gorm.io/driver/sqlite v1.4.4/go.mod h1:0Aq3iPO+v9ZKbcdiz8gLWRw5VOPcBOPUQJFLq5e2ecI=
|
||||||
|
gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
|
||||||
|
gorm.io/gorm v1.24.0/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=
|
||||||
|
gorm.io/gorm v1.24.3/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=
|
||||||
|
gorm.io/gorm v1.24.7-0.20230306060331-85eaf9eeda11 h1:9qNbmu21nNThCNnF5i2R3kw2aL27U8ZwbzccNjOmW0g=
|
||||||
|
gorm.io/gorm v1.24.7-0.20230306060331-85eaf9eeda11/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
|
||||||
|
gorm.io/plugin/dbresolver v1.4.1 h1:Ug4LcoPhrvqq71UhxtF346f+skTYoCa/nEsdjvHwEzk=
|
||||||
|
gorm.io/plugin/dbresolver v1.4.1/go.mod h1:CTbCtMWhsjXSiJqiW2R8POvJ2cq18RVOl4WGyT5nhNc=
|
||||||
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||||
106
internal/bootstrap/bootstrap.go
Normal file
106
internal/bootstrap/bootstrap.go
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
package bootstrap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
_ "net/http/pprof" //nolint:gosec
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/config"
|
||||||
|
_ "github.com/guxuan/hailin_service/internal/swagger"
|
||||||
|
"github.com/guxuan/hailin_service/internal/utility/prom"
|
||||||
|
"github.com/guxuan/hailin_service/internal/wirex"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/logging"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RunConfig defines the config for run command.
|
||||||
|
type RunConfig struct {
|
||||||
|
WorkDir string // Working directory
|
||||||
|
Configs string // Directory or files (multiple separated by commas)
|
||||||
|
StaticDir string // Static files directory
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Run function initializes and starts a service with configuration and logging, and handles
|
||||||
|
// cleanup upon exit.
|
||||||
|
func Run(ctx context.Context, runCfg RunConfig) error {
|
||||||
|
defer func() {
|
||||||
|
if err := zap.L().Sync(); err != nil {
|
||||||
|
fmt.Printf("failed to sync zap logger: %s \n", err.Error())
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Load configuration.
|
||||||
|
workDir := runCfg.WorkDir
|
||||||
|
staticDir := runCfg.StaticDir
|
||||||
|
config.MustLoad(workDir, strings.Split(runCfg.Configs, ",")...)
|
||||||
|
config.C.General.WorkDir = workDir
|
||||||
|
config.C.Middleware.Static.Dir = staticDir
|
||||||
|
config.C.Print()
|
||||||
|
config.C.PreLoad()
|
||||||
|
|
||||||
|
// Initialize logger.
|
||||||
|
cleanLoggerFn, err := logging.InitWithConfig(ctx, &config.C.Logger, initLoggerHook)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ctx = logging.NewTag(ctx, logging.TagKeyMain)
|
||||||
|
|
||||||
|
logging.Context(ctx).Info("starting service ...",
|
||||||
|
zap.String("version", config.C.General.Version),
|
||||||
|
zap.Int("pid", os.Getpid()),
|
||||||
|
zap.String("workdir", workDir),
|
||||||
|
zap.String("config", runCfg.Configs),
|
||||||
|
zap.String("static", staticDir),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Start pprof server.
|
||||||
|
if addr := config.C.General.PprofAddr; addr != "" {
|
||||||
|
logging.Context(ctx).Info("pprof server is listening on " + addr)
|
||||||
|
go func() {
|
||||||
|
err := http.ListenAndServe(addr, nil)
|
||||||
|
if err != nil {
|
||||||
|
logging.Context(ctx).Error("failed to listen pprof server", zap.Error(err))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build injector.
|
||||||
|
injector, cleanInjectorFn, err := wirex.BuildInjector(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := injector.M.Init(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize global prometheus metrics.
|
||||||
|
prom.Init()
|
||||||
|
|
||||||
|
return util.Run(ctx, func(ctx context.Context) (func(), error) {
|
||||||
|
cleanHTTPServerFn, err := startHTTPServer(ctx, injector)
|
||||||
|
if err != nil {
|
||||||
|
return cleanInjectorFn, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return func() {
|
||||||
|
if err := injector.M.Release(ctx); err != nil {
|
||||||
|
logging.Context(ctx).Error("failed to release injector", zap.Error(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
if cleanHTTPServerFn != nil {
|
||||||
|
cleanHTTPServerFn()
|
||||||
|
}
|
||||||
|
if cleanInjectorFn != nil {
|
||||||
|
cleanInjectorFn()
|
||||||
|
}
|
||||||
|
if cleanLoggerFn != nil {
|
||||||
|
cleanLoggerFn()
|
||||||
|
}
|
||||||
|
}, nil
|
||||||
|
})
|
||||||
|
}
|
||||||
192
internal/bootstrap/http.go
Normal file
192
internal/bootstrap/http.go
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
package bootstrap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"path/filepath"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/config"
|
||||||
|
"github.com/guxuan/hailin_service/internal/utility/prom"
|
||||||
|
"github.com/guxuan/hailin_service/internal/wirex"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/errors"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/logging"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/middleware"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
"github.com/casbin/casbin/v2"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
swaggerFiles "github.com/swaggo/files"
|
||||||
|
ginSwagger "github.com/swaggo/gin-swagger"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
func startHTTPServer(ctx context.Context, injector *wirex.Injector) (func(), error) {
|
||||||
|
if config.C.IsDebug() {
|
||||||
|
gin.SetMode(gin.DebugMode)
|
||||||
|
} else {
|
||||||
|
gin.SetMode(gin.ReleaseMode)
|
||||||
|
}
|
||||||
|
|
||||||
|
e := gin.New()
|
||||||
|
e.GET("/health", func(c *gin.Context) {
|
||||||
|
util.ResOK(c)
|
||||||
|
})
|
||||||
|
e.Use(middleware.RecoveryWithConfig(middleware.RecoveryConfig{
|
||||||
|
Skip: config.C.Middleware.Recovery.Skip,
|
||||||
|
}))
|
||||||
|
e.NoMethod(func(c *gin.Context) {
|
||||||
|
util.ResError(c, errors.MethodNotAllowed("", "Method Not Allowed"))
|
||||||
|
})
|
||||||
|
e.NoRoute(func(c *gin.Context) {
|
||||||
|
util.ResError(c, errors.NotFound("", "Not Found"))
|
||||||
|
})
|
||||||
|
|
||||||
|
allowedPrefixes := injector.M.RouterPrefixes()
|
||||||
|
|
||||||
|
// Register middlewares
|
||||||
|
if err := useHTTPMiddlewares(ctx, e, injector, allowedPrefixes); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register routers
|
||||||
|
if err := injector.M.RegisterRouters(ctx, e); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register swagger
|
||||||
|
if !config.C.General.DisableSwagger {
|
||||||
|
e.StaticFile("/openapi.json", filepath.Join(config.C.General.WorkDir, "openapi.json"))
|
||||||
|
e.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
|
||||||
|
}
|
||||||
|
|
||||||
|
if dir := config.C.Middleware.Static.Dir; dir != "" {
|
||||||
|
e.Use(middleware.StaticWithConfig(middleware.StaticConfig{
|
||||||
|
Root: dir,
|
||||||
|
SkippedPathPrefixes: allowedPrefixes,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
addr := config.C.General.HTTP.Addr
|
||||||
|
logging.Context(ctx).Info(fmt.Sprintf("HTTP server is listening on %s", addr))
|
||||||
|
srv := &http.Server{
|
||||||
|
Addr: addr,
|
||||||
|
Handler: e,
|
||||||
|
ReadTimeout: time.Second * time.Duration(config.C.General.HTTP.ReadTimeout),
|
||||||
|
WriteTimeout: time.Second * time.Duration(config.C.General.HTTP.WriteTimeout),
|
||||||
|
IdleTimeout: time.Second * time.Duration(config.C.General.HTTP.IdleTimeout),
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
var err error
|
||||||
|
if config.C.General.HTTP.CertFile != "" && config.C.General.HTTP.KeyFile != "" {
|
||||||
|
srv.TLSConfig = &tls.Config{MinVersion: tls.VersionTLS12}
|
||||||
|
err = srv.ListenAndServeTLS(config.C.General.HTTP.CertFile, config.C.General.HTTP.KeyFile)
|
||||||
|
} else {
|
||||||
|
err = srv.ListenAndServe()
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil && err != http.ErrServerClosed {
|
||||||
|
logging.Context(ctx).Error("Failed to listen http server", zap.Error(err))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return func() {
|
||||||
|
ctx, cancel := context.WithTimeout(ctx, time.Second*time.Duration(config.C.General.HTTP.ShutdownTimeout))
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
srv.SetKeepAlivesEnabled(false)
|
||||||
|
if err := srv.Shutdown(ctx); err != nil {
|
||||||
|
logging.Context(ctx).Error("Failed to shutdown http server", zap.Error(err))
|
||||||
|
}
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func useHTTPMiddlewares(_ context.Context, e *gin.Engine, injector *wirex.Injector, allowedPrefixes []string) error {
|
||||||
|
e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
|
||||||
|
Enable: config.C.Middleware.CORS.Enable,
|
||||||
|
AllowAllOrigins: config.C.Middleware.CORS.AllowAllOrigins,
|
||||||
|
AllowOrigins: config.C.Middleware.CORS.AllowOrigins,
|
||||||
|
AllowMethods: config.C.Middleware.CORS.AllowMethods,
|
||||||
|
AllowHeaders: config.C.Middleware.CORS.AllowHeaders,
|
||||||
|
AllowCredentials: config.C.Middleware.CORS.AllowCredentials,
|
||||||
|
ExposeHeaders: config.C.Middleware.CORS.ExposeHeaders,
|
||||||
|
MaxAge: config.C.Middleware.CORS.MaxAge,
|
||||||
|
AllowWildcard: config.C.Middleware.CORS.AllowWildcard,
|
||||||
|
AllowBrowserExtensions: config.C.Middleware.CORS.AllowBrowserExtensions,
|
||||||
|
AllowWebSockets: config.C.Middleware.CORS.AllowWebSockets,
|
||||||
|
AllowFiles: config.C.Middleware.CORS.AllowFiles,
|
||||||
|
}))
|
||||||
|
|
||||||
|
e.Use(middleware.TraceWithConfig(middleware.TraceConfig{
|
||||||
|
AllowedPathPrefixes: allowedPrefixes,
|
||||||
|
SkippedPathPrefixes: config.C.Middleware.Trace.SkippedPathPrefixes,
|
||||||
|
RequestHeaderKey: config.C.Middleware.Trace.RequestHeaderKey,
|
||||||
|
ResponseTraceKey: config.C.Middleware.Trace.ResponseTraceKey,
|
||||||
|
}))
|
||||||
|
|
||||||
|
e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
|
||||||
|
AllowedPathPrefixes: allowedPrefixes,
|
||||||
|
SkippedPathPrefixes: config.C.Middleware.Logger.SkippedPathPrefixes,
|
||||||
|
MaxOutputRequestBodyLen: config.C.Middleware.Logger.MaxOutputRequestBodyLen,
|
||||||
|
MaxOutputResponseBodyLen: config.C.Middleware.Logger.MaxOutputResponseBodyLen,
|
||||||
|
}))
|
||||||
|
|
||||||
|
e.Use(middleware.CopyBodyWithConfig(middleware.CopyBodyConfig{
|
||||||
|
AllowedPathPrefixes: allowedPrefixes,
|
||||||
|
SkippedPathPrefixes: config.C.Middleware.CopyBody.SkippedPathPrefixes,
|
||||||
|
MaxContentLen: config.C.Middleware.CopyBody.MaxContentLen,
|
||||||
|
}))
|
||||||
|
|
||||||
|
e.Use(middleware.AuthWithConfig(middleware.AuthConfig{
|
||||||
|
AllowedPathPrefixes: allowedPrefixes,
|
||||||
|
SkippedPathPrefixes: config.C.Middleware.Auth.SkippedPathPrefixes,
|
||||||
|
ParseUserID: injector.M.RBAC.LoginAPI.LoginBIZ.ParseUserID,
|
||||||
|
RootID: config.C.General.Root.ID,
|
||||||
|
}))
|
||||||
|
|
||||||
|
e.Use(middleware.RateLimiterWithConfig(middleware.RateLimiterConfig{
|
||||||
|
Enable: config.C.Middleware.RateLimiter.Enable,
|
||||||
|
AllowedPathPrefixes: allowedPrefixes,
|
||||||
|
SkippedPathPrefixes: config.C.Middleware.RateLimiter.SkippedPathPrefixes,
|
||||||
|
Period: config.C.Middleware.RateLimiter.Period,
|
||||||
|
MaxRequestsPerIP: config.C.Middleware.RateLimiter.MaxRequestsPerIP,
|
||||||
|
MaxRequestsPerUser: config.C.Middleware.RateLimiter.MaxRequestsPerUser,
|
||||||
|
StoreType: config.C.Middleware.RateLimiter.Store.Type,
|
||||||
|
MemoryStoreConfig: middleware.RateLimiterMemoryConfig{
|
||||||
|
Expiration: time.Second * time.Duration(config.C.Middleware.RateLimiter.Store.Memory.Expiration),
|
||||||
|
CleanupInterval: time.Second * time.Duration(config.C.Middleware.RateLimiter.Store.Memory.CleanupInterval),
|
||||||
|
},
|
||||||
|
RedisStoreConfig: middleware.RateLimiterRedisConfig{
|
||||||
|
Addr: config.C.Middleware.RateLimiter.Store.Redis.Addr,
|
||||||
|
Password: config.C.Middleware.RateLimiter.Store.Redis.Password,
|
||||||
|
DB: config.C.Middleware.RateLimiter.Store.Redis.DB,
|
||||||
|
Username: config.C.Middleware.RateLimiter.Store.Redis.Username,
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
|
||||||
|
e.Use(middleware.CasbinWithConfig(middleware.CasbinConfig{
|
||||||
|
AllowedPathPrefixes: allowedPrefixes,
|
||||||
|
SkippedPathPrefixes: config.C.Middleware.Casbin.SkippedPathPrefixes,
|
||||||
|
Skipper: func(c *gin.Context) bool {
|
||||||
|
if config.C.Middleware.Casbin.Disable ||
|
||||||
|
util.FromIsRootUser(c.Request.Context()) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
GetEnforcer: func(c *gin.Context) *casbin.Enforcer {
|
||||||
|
return injector.M.RBAC.Casbinx.GetEnforcer()
|
||||||
|
},
|
||||||
|
GetSubjects: func(c *gin.Context) []string {
|
||||||
|
return util.FromUserCache(c.Request.Context()).RoleIDs
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
|
||||||
|
if config.C.Util.Prometheus.Enable {
|
||||||
|
e.Use(prom.GinMiddleware)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
43
internal/bootstrap/logger.go
Normal file
43
internal/bootstrap/logger.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package bootstrap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/config"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/gormx"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/logging"
|
||||||
|
"github.com/spf13/cast"
|
||||||
|
)
|
||||||
|
|
||||||
|
func initLoggerHook(_ context.Context, cfg *logging.HookConfig) (*logging.Hook, error) {
|
||||||
|
extra := cfg.Extra
|
||||||
|
if extra == nil {
|
||||||
|
extra = make(map[string]string)
|
||||||
|
}
|
||||||
|
extra["appname"] = config.C.General.AppName
|
||||||
|
|
||||||
|
switch cfg.Type {
|
||||||
|
case "gorm":
|
||||||
|
db, err := gormx.New(gormx.Config{
|
||||||
|
Debug: cast.ToBool(cfg.Options["Debug"]),
|
||||||
|
DBType: cast.ToString(cfg.Options["DBType"]),
|
||||||
|
DSN: cast.ToString(cfg.Options["DSN"]),
|
||||||
|
MaxLifetime: cast.ToInt(cfg.Options["MaxLifetime"]),
|
||||||
|
MaxIdleTime: cast.ToInt(cfg.Options["MaxIdleTime"]),
|
||||||
|
MaxOpenConns: cast.ToInt(cfg.Options["MaxOpenConns"]),
|
||||||
|
MaxIdleConns: cast.ToInt(cfg.Options["MaxIdleConns"]),
|
||||||
|
TablePrefix: config.C.Storage.DB.TablePrefix,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
hook := logging.NewHook(logging.NewGormHook(db),
|
||||||
|
logging.SetHookExtra(cfg.Extra),
|
||||||
|
logging.SetHookMaxJobs(cfg.MaxBuffer),
|
||||||
|
logging.SetHookMaxWorkers(cfg.MaxThread))
|
||||||
|
return hook, nil
|
||||||
|
default:
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
166
internal/config/config.go
Normal file
166
internal/config/config.go
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/pkg/encoding/json"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/logging"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Logger logging.LoggerConfig
|
||||||
|
General General
|
||||||
|
Storage Storage
|
||||||
|
Middleware Middleware
|
||||||
|
Util Util
|
||||||
|
Dictionary Dictionary
|
||||||
|
FileConfig FileConfig
|
||||||
|
}
|
||||||
|
type FileConfig struct {
|
||||||
|
UploadDir string
|
||||||
|
StaticPrefix string
|
||||||
|
}
|
||||||
|
|
||||||
|
type General struct {
|
||||||
|
AppName string `default:"hailinservice"`
|
||||||
|
Version string `default:"v1.0.0"`
|
||||||
|
Debug bool
|
||||||
|
PprofAddr string
|
||||||
|
DisableSwagger bool
|
||||||
|
DisablePrintConfig bool
|
||||||
|
DefaultLoginPwd string `default:"6351623c8cef86fefabfa7da046fc619"` // MD5(abc-123)
|
||||||
|
WorkDir string // From command arguments
|
||||||
|
MenuFile string // From schema.Menus (JSON/YAML)
|
||||||
|
DenyOperateMenu bool
|
||||||
|
HTTP struct {
|
||||||
|
Addr string `default:":8040"`
|
||||||
|
ShutdownTimeout int `default:"10"` // seconds
|
||||||
|
ReadTimeout int `default:"60"` // seconds
|
||||||
|
WriteTimeout int `default:"60"` // seconds
|
||||||
|
IdleTimeout int `default:"10"` // seconds
|
||||||
|
CertFile string
|
||||||
|
KeyFile string
|
||||||
|
}
|
||||||
|
Root struct {
|
||||||
|
ID string `default:"root"`
|
||||||
|
Username string `default:"admin"`
|
||||||
|
Password string
|
||||||
|
Name string `default:"Admin"`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Storage struct {
|
||||||
|
Cache struct {
|
||||||
|
Type string `default:"memory"` // memory/badger/redis
|
||||||
|
Delimiter string `default:":"` // delimiter for key
|
||||||
|
Memory struct {
|
||||||
|
CleanupInterval int `default:"60"` // seconds
|
||||||
|
}
|
||||||
|
Badger struct {
|
||||||
|
Path string `default:"data/cache"`
|
||||||
|
}
|
||||||
|
Redis struct {
|
||||||
|
Addr string
|
||||||
|
Username string
|
||||||
|
Password string
|
||||||
|
DB int
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DB struct {
|
||||||
|
Debug bool
|
||||||
|
Type string `default:"sqlite3"` // sqlite3/mysql/postgres
|
||||||
|
DSN string `default:"data/hailinservice.db"` // database source name
|
||||||
|
MaxLifetime int `default:"86400"` // seconds
|
||||||
|
MaxIdleTime int `default:"3600"` // seconds
|
||||||
|
MaxOpenConns int `default:"100"` // connections
|
||||||
|
MaxIdleConns int `default:"50"` // connections
|
||||||
|
TablePrefix string `default:""`
|
||||||
|
AutoMigrate bool
|
||||||
|
PrepareStmt bool
|
||||||
|
Resolver []struct {
|
||||||
|
DBType string // sqlite3/mysql/postgres
|
||||||
|
Sources []string // DSN
|
||||||
|
Replicas []string // DSN
|
||||||
|
Tables []string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Util struct {
|
||||||
|
Captcha struct {
|
||||||
|
Length int `default:"4"`
|
||||||
|
Width int `default:"400"`
|
||||||
|
Height int `default:"160"`
|
||||||
|
CacheType string `default:"memory"` // memory/redis
|
||||||
|
Redis struct {
|
||||||
|
Addr string
|
||||||
|
Username string
|
||||||
|
Password string
|
||||||
|
DB int
|
||||||
|
KeyPrefix string `default:"captcha:"`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Prometheus struct {
|
||||||
|
Enable bool
|
||||||
|
Port int `default:"9100"`
|
||||||
|
BasicUsername string `default:"admin"`
|
||||||
|
BasicPassword string `default:"admin"`
|
||||||
|
LogApis []string
|
||||||
|
LogMethods []string
|
||||||
|
DefaultCollect bool
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Dictionary struct {
|
||||||
|
UserCacheExp int `default:"4"` // hours
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) IsDebug() bool {
|
||||||
|
return c.General.Debug
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) String() string {
|
||||||
|
b, err := json.MarshalIndent(c, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
panic("Failed to marshal config: " + err.Error())
|
||||||
|
}
|
||||||
|
return string(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) PreLoad() {
|
||||||
|
if addr := c.Storage.Cache.Redis.Addr; addr != "" {
|
||||||
|
username := c.Storage.Cache.Redis.Username
|
||||||
|
password := c.Storage.Cache.Redis.Password
|
||||||
|
if c.Util.Captcha.CacheType == "redis" &&
|
||||||
|
c.Util.Captcha.Redis.Addr == "" {
|
||||||
|
c.Util.Captcha.Redis.Addr = addr
|
||||||
|
c.Util.Captcha.Redis.Username = username
|
||||||
|
c.Util.Captcha.Redis.Password = password
|
||||||
|
}
|
||||||
|
if c.Middleware.RateLimiter.Store.Type == "redis" &&
|
||||||
|
c.Middleware.RateLimiter.Store.Redis.Addr == "" {
|
||||||
|
c.Middleware.RateLimiter.Store.Redis.Addr = addr
|
||||||
|
c.Middleware.RateLimiter.Store.Redis.Username = username
|
||||||
|
c.Middleware.RateLimiter.Store.Redis.Password = password
|
||||||
|
}
|
||||||
|
if c.Middleware.Auth.Store.Type == "redis" &&
|
||||||
|
c.Middleware.Auth.Store.Redis.Addr == "" {
|
||||||
|
c.Middleware.Auth.Store.Redis.Addr = addr
|
||||||
|
c.Middleware.Auth.Store.Redis.Username = username
|
||||||
|
c.Middleware.Auth.Store.Redis.Password = password
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) Print() {
|
||||||
|
if c.General.DisablePrintConfig {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println("// ----------------------- Load configurations start ------------------------")
|
||||||
|
fmt.Println(c.String())
|
||||||
|
fmt.Println("// ----------------------- Load configurations end --------------------------")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) FormatTableName(name string) string {
|
||||||
|
return c.Storage.DB.TablePrefix + name
|
||||||
|
}
|
||||||
16
internal/config/consts.go
Normal file
16
internal/config/consts.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
const (
|
||||||
|
CacheNSForUser = "user"
|
||||||
|
CacheNSForRole = "role"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
CacheKeyForSyncToCasbin = "sync:casbin"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ErrInvalidTokenID = "com.invalid.token"
|
||||||
|
ErrInvalidCaptchaID = "com.invalid.captcha"
|
||||||
|
ErrInvalidUsernameOrPassword = "com.invalid.username-or-password"
|
||||||
|
)
|
||||||
90
internal/config/middleware.go
Normal file
90
internal/config/middleware.go
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
type Middleware struct {
|
||||||
|
Recovery struct {
|
||||||
|
Skip int `default:"3"` // skip the first n stack frames
|
||||||
|
}
|
||||||
|
CORS struct {
|
||||||
|
Enable bool
|
||||||
|
AllowAllOrigins bool
|
||||||
|
AllowOrigins []string
|
||||||
|
AllowMethods []string
|
||||||
|
AllowHeaders []string
|
||||||
|
AllowCredentials bool
|
||||||
|
ExposeHeaders []string
|
||||||
|
MaxAge int
|
||||||
|
AllowWildcard bool
|
||||||
|
AllowBrowserExtensions bool
|
||||||
|
AllowWebSockets bool
|
||||||
|
AllowFiles bool
|
||||||
|
}
|
||||||
|
Trace struct {
|
||||||
|
SkippedPathPrefixes []string
|
||||||
|
RequestHeaderKey string `default:"X-Request-Id"`
|
||||||
|
ResponseTraceKey string `default:"X-Trace-Id"`
|
||||||
|
}
|
||||||
|
Logger struct {
|
||||||
|
SkippedPathPrefixes []string
|
||||||
|
MaxOutputRequestBodyLen int `default:"4096"`
|
||||||
|
MaxOutputResponseBodyLen int `default:"1024"`
|
||||||
|
}
|
||||||
|
CopyBody struct {
|
||||||
|
SkippedPathPrefixes []string
|
||||||
|
MaxContentLen int64 `default:"33554432"` // max content length (default 32MB)
|
||||||
|
}
|
||||||
|
Auth struct {
|
||||||
|
Disable bool
|
||||||
|
SkippedPathPrefixes []string
|
||||||
|
SigningMethod string `default:"HS512"` // HS256/HS384/HS512
|
||||||
|
SigningKey string `default:"XnEsT0S@"` // secret key
|
||||||
|
OldSigningKey string // old secret key (for migration)
|
||||||
|
Expired int `default:"86400"` // seconds
|
||||||
|
Store struct {
|
||||||
|
Type string `default:"memory"` // memory/badger/redis
|
||||||
|
Delimiter string `default:":"` // delimiter for key
|
||||||
|
Memory struct {
|
||||||
|
CleanupInterval int `default:"60"` // seconds
|
||||||
|
}
|
||||||
|
Badger struct {
|
||||||
|
Path string `default:"data/auth"`
|
||||||
|
}
|
||||||
|
Redis struct {
|
||||||
|
Addr string
|
||||||
|
Username string
|
||||||
|
Password string
|
||||||
|
DB int
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RateLimiter struct {
|
||||||
|
Enable bool
|
||||||
|
SkippedPathPrefixes []string
|
||||||
|
Period int // seconds
|
||||||
|
MaxRequestsPerIP int
|
||||||
|
MaxRequestsPerUser int
|
||||||
|
Store struct {
|
||||||
|
Type string // memory/redis
|
||||||
|
Memory struct {
|
||||||
|
Expiration int `default:"3600"` // seconds
|
||||||
|
CleanupInterval int `default:"60"` // seconds
|
||||||
|
}
|
||||||
|
Redis struct {
|
||||||
|
Addr string
|
||||||
|
Username string
|
||||||
|
Password string
|
||||||
|
DB int
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Casbin struct {
|
||||||
|
Disable bool
|
||||||
|
SkippedPathPrefixes []string
|
||||||
|
LoadThread int `default:"2"`
|
||||||
|
AutoLoadInterval int `default:"3"` // seconds
|
||||||
|
ModelFile string `default:"rbac_model.conf"`
|
||||||
|
GenPolicyFile string `default:"gen_rbac_policy.csv"`
|
||||||
|
}
|
||||||
|
Static struct {
|
||||||
|
Dir string // Static files directory (From command arguments)
|
||||||
|
}
|
||||||
|
}
|
||||||
84
internal/config/parse.go
Normal file
84
internal/config/parse.go
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/pkg/encoding/json"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/encoding/toml"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/errors"
|
||||||
|
"github.com/creasty/defaults"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
once sync.Once
|
||||||
|
C = new(Config)
|
||||||
|
)
|
||||||
|
|
||||||
|
func MustLoad(dir string, names ...string) {
|
||||||
|
once.Do(func() {
|
||||||
|
if err := Load(dir, names...); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loads configuration files in various formats from a directory and parses them into
|
||||||
|
// a struct.
|
||||||
|
func Load(dir string, names ...string) error {
|
||||||
|
// Set default values
|
||||||
|
if err := defaults.Set(C); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
supportExts := []string{".json", ".toml"}
|
||||||
|
parseFile := func(name string) error {
|
||||||
|
ext := filepath.Ext(name)
|
||||||
|
if ext == "" || !strings.Contains(strings.Join(supportExts, ","), ext) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
buf, err := os.ReadFile(name)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to read config file %s", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ext {
|
||||||
|
case ".json":
|
||||||
|
err = json.Unmarshal(buf, C)
|
||||||
|
case ".toml":
|
||||||
|
err = toml.Unmarshal(buf, C)
|
||||||
|
}
|
||||||
|
return errors.Wrapf(err, "failed to unmarshal config %s", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, name := range names {
|
||||||
|
fullname := filepath.Join(dir, name)
|
||||||
|
info, err := os.Stat(fullname)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to get config file %s", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if info.IsDir() {
|
||||||
|
err := filepath.WalkDir(fullname, func(path string, d os.DirEntry, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if d.IsDir() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return parseFile(path)
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to walk config dir %s", name)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err := parseFile(fullname); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
59
internal/mods/mods.go
Normal file
59
internal/mods/mods.go
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
package mods
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/config"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/google/wire"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
apiPrefix = "/api/"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Collection of wire providers
|
||||||
|
var Set = wire.NewSet(
|
||||||
|
wire.Struct(new(Mods), "*"),
|
||||||
|
rbac.Set,
|
||||||
|
)
|
||||||
|
|
||||||
|
type Mods struct {
|
||||||
|
RBAC *rbac.RBAC
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Mods) Init(ctx context.Context) error {
|
||||||
|
if err := a.RBAC.Init(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Mods) RouterPrefixes() []string {
|
||||||
|
return []string{
|
||||||
|
apiPrefix,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Mods) RegisterRouters(ctx context.Context, e *gin.Engine) error {
|
||||||
|
gAPI := e.Group(apiPrefix)
|
||||||
|
e.Static(config.C.FileConfig.StaticPrefix, config.C.FileConfig.UploadDir)
|
||||||
|
v1 := gAPI.Group("v1")
|
||||||
|
|
||||||
|
if err := a.RBAC.RegisterV1Routers(ctx, v1); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Mods) Release(ctx context.Context) error {
|
||||||
|
if err := a.RBAC.Release(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
127
internal/mods/rbac/api/article.api.go
Normal file
127
internal/mods/rbac/api/article.api.go
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/biz"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Banner management for RBAC
|
||||||
|
type Article struct {
|
||||||
|
ArticleBIZ *biz.Article
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags ArticleAPI
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Query Article list
|
||||||
|
// @Param current query int true "pagination index" default(1)
|
||||||
|
// @Param pageSize query int true "pagination size" default(10)
|
||||||
|
// @Param name query string false "name of Article"
|
||||||
|
// @Param status query string false "Status of banner (disabled,enabled)"
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=[]schema.Article}
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/articles [get]
|
||||||
|
func (a *Article) Query(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
var params schema.ArticleQueryParam
|
||||||
|
if err := util.ParseQuery(c, ¶ms); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := a.ArticleBIZ.Query(ctx, params)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResPage(c, result.Data, result.PageResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags ArticleAPI
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Get Article record by ID
|
||||||
|
// @Param id path string true "unique id"
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=schema.Article}
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/articles/{id} [get]
|
||||||
|
func (a *Article) Get(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
item, err := a.ArticleBIZ.Get(ctx, c.Param("id"))
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResSuccess(c, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags ArticleAPI
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Create Article record
|
||||||
|
// @Param body body schema.ArticleForm true "Request body"
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=schema.Article}
|
||||||
|
// @Failure 400 {object} util.ResponseResult
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/articles [post]
|
||||||
|
func (a *Article) Create(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
item := new(schema.ArticleForm)
|
||||||
|
if err := util.ParseJSON(c, item); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := a.ArticleBIZ.Create(ctx, item)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResSuccess(c, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags ArticleAPI
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Update Article record by ID
|
||||||
|
// @Param id path string true "unique id"
|
||||||
|
// @Param body body schema.ArticleForm true "Request body"
|
||||||
|
// @Success 200 {object} util.ResponseResult
|
||||||
|
// @Failure 400 {object} util.ResponseResult
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/articles/{id} [put]
|
||||||
|
func (a *Article) Update(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
item := new(schema.ArticleForm)
|
||||||
|
if err := util.ParseJSON(c, item); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := a.ArticleBIZ.Update(ctx, c.Param("id"), item)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResOK(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags ArticleAPI
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Delete Article record by ID
|
||||||
|
// @Param id path string true "unique id"
|
||||||
|
// @Success 200 {object} util.ResponseResult
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/articles/{id} [delete]
|
||||||
|
func (a *Article) Delete(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
err := a.ArticleBIZ.Delete(ctx, c.Param("id"))
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResOK(c)
|
||||||
|
}
|
||||||
127
internal/mods/rbac/api/banner.api.go
Normal file
127
internal/mods/rbac/api/banner.api.go
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/biz"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Banner management for RBAC
|
||||||
|
type Banner struct {
|
||||||
|
BannerBIZ *biz.Banner
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags BannerAPI
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Query banner list
|
||||||
|
// @Param current query int true "pagination index" default(1)
|
||||||
|
// @Param pageSize query int true "pagination size" default(10)
|
||||||
|
// @Param name query string false "Name of banner"
|
||||||
|
// @Param status query string false "Status of banner (disabled,enabled)"
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=[]schema.Banner}
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/banners [get]
|
||||||
|
func (a *Banner) Query(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
var params schema.BannerQueryParam
|
||||||
|
if err := util.ParseQuery(c, ¶ms); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := a.BannerBIZ.Query(ctx, params)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResPage(c, result.Data, result.PageResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags BannerAPI
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Get banner record by ID
|
||||||
|
// @Param id path string true "unique id"
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=schema.Banner}
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/banners/{id} [get]
|
||||||
|
func (a *Banner) Get(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
item, err := a.BannerBIZ.Get(ctx, c.Param("id"))
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResSuccess(c, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags BannerAPI
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Create banner record
|
||||||
|
// @Param body body schema.BannerForm true "Request body"
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=schema.Banner}
|
||||||
|
// @Failure 400 {object} util.ResponseResult
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/banners [post]
|
||||||
|
func (a *Banner) Create(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
item := new(schema.BannerForm)
|
||||||
|
if err := util.ParseJSON(c, item); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := a.BannerBIZ.Create(ctx, item)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResSuccess(c, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags BannerAPI
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Update banner record by ID
|
||||||
|
// @Param id path string true "unique id"
|
||||||
|
// @Param body body schema.BannerForm true "Request body"
|
||||||
|
// @Success 200 {object} util.ResponseResult
|
||||||
|
// @Failure 400 {object} util.ResponseResult
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/banners/{id} [put]
|
||||||
|
func (a *Banner) Update(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
item := new(schema.BannerForm)
|
||||||
|
if err := util.ParseJSON(c, item); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := a.BannerBIZ.Update(ctx, c.Param("id"), item)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResOK(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags BannerAPI
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Delete banner record by ID
|
||||||
|
// @Param id path string true "unique id"
|
||||||
|
// @Success 200 {object} util.ResponseResult
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/banners/{id} [delete]
|
||||||
|
func (a *Banner) Delete(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
err := a.BannerBIZ.Delete(ctx, c.Param("id"))
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResOK(c)
|
||||||
|
}
|
||||||
244
internal/mods/rbac/api/job.api.go
Normal file
244
internal/mods/rbac/api/job.api.go
Normal file
@ -0,0 +1,244 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/biz"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/resp"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Job struct {
|
||||||
|
JobBIZ *biz.Job
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags 职位模块
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Query Job list
|
||||||
|
// @Param current query int true "pagination index" default(1)
|
||||||
|
// @Param pageSize query int true "pagination size" default(10)
|
||||||
|
// @Param title query string false "title of Job"
|
||||||
|
// @Param jobAreaId query string false "jobAreaId of Job"
|
||||||
|
// @Param status query string false "Status of banner (disabled,enabled)"
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=[]schema.Job}
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/jobs [get]
|
||||||
|
func (a *Job) Query(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
var params schema.JobQueryParam
|
||||||
|
if err := util.ParseQuery(c, ¶ms); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := a.JobBIZ.Query(ctx, params)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
list := result.Data
|
||||||
|
var newList []resp.JobAdminListResp
|
||||||
|
areas, err := a.JobBIZ.QueryJobArea(ctx)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, item := range list {
|
||||||
|
var newitem resp.JobAdminListResp
|
||||||
|
newitem.ID = item.ID
|
||||||
|
newitem.Status = item.Status
|
||||||
|
newitem.JobAreaID = item.JobAreaID
|
||||||
|
newitem.Title = item.Title
|
||||||
|
newitem.Introduce = item.Introduce
|
||||||
|
newitem.Duty = item.Duty
|
||||||
|
newitem.Salary = item.Salary
|
||||||
|
newitem.Sequence = item.Sequence
|
||||||
|
newitem.CreatedAt = item.CreatedAt
|
||||||
|
newitem.UpdatedAt = item.UpdatedAt
|
||||||
|
for _, area := range *areas {
|
||||||
|
if item.JobAreaID == area.ID {
|
||||||
|
newitem.AreaName = area.Name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newList = append(newList, newitem)
|
||||||
|
}
|
||||||
|
util.ResPage(c, newList, result.PageResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags 职位模块
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Get Job record by ID
|
||||||
|
// @Param id path string true "unique id"
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=schema.Job}
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/jobs/{id} [get]
|
||||||
|
func (a *Job) Get(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
item, err := a.JobBIZ.Get(ctx, c.Param("id"))
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResSuccess(c, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags 职位模块
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Create Job record
|
||||||
|
// @Param body body schema.JobForm true "Request body"
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=schema.Job}
|
||||||
|
// @Failure 400 {object} util.ResponseResult
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/jobs [post]
|
||||||
|
func (a *Job) Create(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
item := new(schema.JobForm)
|
||||||
|
if err := util.ParseJSON(c, item); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := a.JobBIZ.Create(ctx, item)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResSuccess(c, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags 职位模块
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Update Job record by ID
|
||||||
|
// @Param id path string true "unique id"
|
||||||
|
// @Param body body schema.JobForm true "Request body"
|
||||||
|
// @Success 200 {object} util.ResponseResult
|
||||||
|
// @Failure 400 {object} util.ResponseResult
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/jobs/{id} [put]
|
||||||
|
func (a *Job) Update(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
item := new(schema.JobForm)
|
||||||
|
if err := util.ParseJSON(c, item); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := a.JobBIZ.Update(ctx, c.Param("id"), item)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResOK(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags 职位模块
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Delete Job record by ID
|
||||||
|
// @Param id path string true "unique id"
|
||||||
|
// @Success 200 {object} util.ResponseResult
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/jobs/{id} [delete]
|
||||||
|
func (a *Job) Delete(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
err := a.JobBIZ.Delete(ctx, c.Param("id"))
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResOK(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags 职位模块
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Query JobArea list
|
||||||
|
// @Param current query int true "pagination index" default(1)
|
||||||
|
// @Param pageSize query int true "pagination size" default(10)
|
||||||
|
// @Param status query string false "Status of banner (disabled,enabled)"
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=[]schema.JobArea}
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/jobs/job_areas [get]
|
||||||
|
func (a *Job) QueryJobArea(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
|
||||||
|
result, err := a.JobBIZ.QueryJobArea(ctx)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResSuccess(c, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags 职位模块
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Create JobArea record
|
||||||
|
// @Param body body schema.JobAreaForm true "Request body"
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=schema.JobAreaForm}
|
||||||
|
// @Failure 400 {object} util.ResponseResult
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/jobs/job_areas [post]
|
||||||
|
func (a *Job) CreateJobArea(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
item := new(schema.JobAreaForm)
|
||||||
|
if err := util.ParseJSON(c, item); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := a.JobBIZ.CreateJobArea(ctx, item)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResSuccess(c, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags 职位模块
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Update JobArea record by ID
|
||||||
|
// @Param id path string true "unique id"
|
||||||
|
// @Param body body schema.JobAreaForm true "Request body"
|
||||||
|
// @Success 200 {object} util.ResponseResult
|
||||||
|
// @Failure 400 {object} util.ResponseResult
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/jobs/job_areas/{id} [put]
|
||||||
|
func (a *Job) UpdateJobArea(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
item := new(schema.JobAreaForm)
|
||||||
|
if err := util.ParseJSON(c, item); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := a.JobBIZ.UpdateJobArea(ctx, c.Param("id"), item)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResOK(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags 职位模块
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Delete JobArea record by ID
|
||||||
|
// @Param id path string true "unique id"
|
||||||
|
// @Success 200 {object} util.ResponseResult
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/jobs/job_areas/{id} [delete]
|
||||||
|
func (a *Job) DeleteJobArea(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
err := a.JobBIZ.DeleteJobArea(ctx, c.Param("id"))
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResOK(c)
|
||||||
|
}
|
||||||
45
internal/mods/rbac/api/logger.api.go
Normal file
45
internal/mods/rbac/api/logger.api.go
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/biz"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Logger management
|
||||||
|
type Logger struct {
|
||||||
|
LoggerBIZ *biz.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags LoggerAPI
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Query logger list
|
||||||
|
// @Param current query int true "pagination index" default(1)
|
||||||
|
// @Param pageSize query int true "pagination size" default(10)
|
||||||
|
// @Param level query string false "log level"
|
||||||
|
// @Param traceID query string false "trace ID"
|
||||||
|
// @Param userName query string false "user name"
|
||||||
|
// @Param tag query string false "log tag"
|
||||||
|
// @Param message query string false "log message"
|
||||||
|
// @Param startTime query string false "start time"
|
||||||
|
// @Param endTime query string false "end time"
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=[]schema.Logger}
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/loggers [get]
|
||||||
|
func (a *Logger) Query(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
var params schema.LoggerQueryParam
|
||||||
|
if err := util.ParseQuery(c, ¶ms); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := a.LoggerBIZ.Query(ctx, params)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResPage(c, result.Data, result.PageResult)
|
||||||
|
}
|
||||||
182
internal/mods/rbac/api/login.api.go
Normal file
182
internal/mods/rbac/api/login.api.go
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/biz"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Login struct {
|
||||||
|
LoginBIZ *biz.Login
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags LoginAPI
|
||||||
|
// @Summary Get captcha ID
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=schema.Captcha}
|
||||||
|
// @Router /api/v1/captcha/id [get]
|
||||||
|
func (a *Login) GetCaptcha(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
data, err := a.LoginBIZ.GetCaptcha(ctx)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResSuccess(c, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags LoginAPI
|
||||||
|
// @Summary Response captcha image
|
||||||
|
// @Param id query string true "Captcha ID"
|
||||||
|
// @Param reload query number false "Reload captcha image (reload=1)"
|
||||||
|
// @Produce image/png
|
||||||
|
// @Success 200 "Captcha image"
|
||||||
|
// @Failure 404 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/captcha/image [get]
|
||||||
|
func (a *Login) ResponseCaptcha(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
err := a.LoginBIZ.ResponseCaptcha(ctx, c.Writer, c.Query("id"), c.Query("reload") == "1")
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags LoginAPI
|
||||||
|
// @Summary Login system with username and password
|
||||||
|
// @Param body body schema.LoginForm true "Request body"
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=schema.LoginToken}
|
||||||
|
// @Failure 400 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/login [post]
|
||||||
|
func (a *Login) Login(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
item := new(schema.LoginForm)
|
||||||
|
if err := util.ParseJSON(c, item); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := a.LoginBIZ.Login(ctx, item.Trim())
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResSuccess(c, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags LoginAPI
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Logout system
|
||||||
|
// @Success 200 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/current/logout [post]
|
||||||
|
func (a *Login) Logout(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
err := a.LoginBIZ.Logout(ctx)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResOK(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags LoginAPI
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Refresh current access token
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=schema.LoginToken}
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/current/refresh-token [post]
|
||||||
|
func (a *Login) RefreshToken(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
data, err := a.LoginBIZ.RefreshToken(ctx)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResSuccess(c, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags LoginAPI
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Get current user info
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=schema.User}
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/current/user [get]
|
||||||
|
func (a *Login) GetUserInfo(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
data, err := a.LoginBIZ.GetUserInfo(ctx)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResSuccess(c, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags LoginAPI
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Change current user password
|
||||||
|
// @Param body body schema.UpdateLoginPassword true "Request body"
|
||||||
|
// @Success 200 {object} util.ResponseResult
|
||||||
|
// @Failure 400 {object} util.ResponseResult
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/current/password [put]
|
||||||
|
func (a *Login) UpdatePassword(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
item := new(schema.UpdateLoginPassword)
|
||||||
|
if err := util.ParseJSON(c, item); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := a.LoginBIZ.UpdatePassword(ctx, item)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResOK(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags LoginAPI
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Query current user menus based on the current user role
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=[]schema.Menu}
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/current/menus [get]
|
||||||
|
func (a *Login) QueryMenus(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
data, err := a.LoginBIZ.QueryMenus(ctx)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResSuccess(c, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags LoginAPI
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Update current user info
|
||||||
|
// @Param body body schema.UpdateCurrentUser true "Request body"
|
||||||
|
// @Success 200 {object} util.ResponseResult
|
||||||
|
// @Failure 400 {object} util.ResponseResult
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/current/user [put]
|
||||||
|
func (a *Login) UpdateUser(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
item := new(schema.UpdateCurrentUser)
|
||||||
|
if err := util.ParseJSON(c, item); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := a.LoginBIZ.UpdateUser(ctx, item)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResOK(c)
|
||||||
|
}
|
||||||
128
internal/mods/rbac/api/memorabilia.api.go
Normal file
128
internal/mods/rbac/api/memorabilia.api.go
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/biz"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Memorabilia struct {
|
||||||
|
MemorabiliaBIZ *biz.Memorabilia
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags 发展历程模块
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Query Memorabilia list
|
||||||
|
// @Param current query int true "pagination index" default(1)
|
||||||
|
// @Param pageSize query int true "pagination size" default(10)
|
||||||
|
// @Param title query string false "title of Memorabilia"
|
||||||
|
// @Param month query string false "month of Memorabilia"
|
||||||
|
// @Param year query string false "year of Memorabilia"
|
||||||
|
// @Param status query string false "Status of banner (disabled,enabled)"
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=[]schema.Memorabilia}
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/memorabilias [get]
|
||||||
|
func (a *Memorabilia) Query(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
var params schema.MemorabiliaQueryParam
|
||||||
|
if err := util.ParseQuery(c, ¶ms); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := a.MemorabiliaBIZ.Query(ctx, params)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResPage(c, result.Data, result.PageResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags 发展历程模块
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Get Memorabilia record by ID
|
||||||
|
// @Param id path string true "unique id"
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=schema.Memorabilia}
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/memorabilias/{id} [get]
|
||||||
|
func (a *Memorabilia) Get(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
item, err := a.MemorabiliaBIZ.Get(ctx, c.Param("id"))
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResSuccess(c, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags 发展历程模块
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Create Article record
|
||||||
|
// @Param body body schema.MemorabiliaForm true "Request body"
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=schema.Memorabilia}
|
||||||
|
// @Failure 400 {object} util.ResponseResult
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/memorabilias [post]
|
||||||
|
func (a *Memorabilia) Create(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
item := new(schema.MemorabiliaForm)
|
||||||
|
if err := util.ParseJSON(c, item); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := a.MemorabiliaBIZ.Create(ctx, item)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResSuccess(c, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags 发展历程模块
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Update Article record by ID
|
||||||
|
// @Param id path string true "unique id"
|
||||||
|
// @Param body body schema.MemorabiliaForm true "Request body"
|
||||||
|
// @Success 200 {object} util.ResponseResult
|
||||||
|
// @Failure 400 {object} util.ResponseResult
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/memorabilias/{id} [put]
|
||||||
|
func (a *Memorabilia) Update(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
item := new(schema.MemorabiliaForm)
|
||||||
|
if err := util.ParseJSON(c, item); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := a.MemorabiliaBIZ.Update(ctx, c.Param("id"), item)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResOK(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags 发展历程模块
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Delete Article record by ID
|
||||||
|
// @Param id path string true "unique id"
|
||||||
|
// @Success 200 {object} util.ResponseResult
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/memorabilias/{id} [delete]
|
||||||
|
func (a *Memorabilia) Delete(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
err := a.MemorabiliaBIZ.Delete(ctx, c.Param("id"))
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResOK(c)
|
||||||
|
}
|
||||||
132
internal/mods/rbac/api/menu.api.go
Normal file
132
internal/mods/rbac/api/menu.api.go
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/biz"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Menu management for RBAC
|
||||||
|
type Menu struct {
|
||||||
|
MenuBIZ *biz.Menu
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags MenuAPI
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Query menu tree data
|
||||||
|
// @Param code query string false "Code path of menu (like xxx.xxx.xxx)"
|
||||||
|
// @Param name query string false "Name of menu"
|
||||||
|
// @Param includeResources query bool false "Whether to include menu resources"
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=[]schema.Menu}
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/menus [get]
|
||||||
|
func (a *Menu) Query(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
var params schema.MenuQueryParam
|
||||||
|
if err := util.ParseQuery(c, ¶ms); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := a.MenuBIZ.Query(ctx, params)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResPage(c, result.Data, result.PageResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags MenuAPI
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Get menu record by ID
|
||||||
|
// @Param id path string true "unique id"
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=schema.Menu}
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/menus/{id} [get]
|
||||||
|
func (a *Menu) Get(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
item, err := a.MenuBIZ.Get(ctx, c.Param("id"))
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResSuccess(c, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags MenuAPI
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Create menu record
|
||||||
|
// @Param body body schema.MenuForm true "Request body"
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=schema.Menu}
|
||||||
|
// @Failure 400 {object} util.ResponseResult
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/menus [post]
|
||||||
|
func (a *Menu) Create(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
item := new(schema.MenuForm)
|
||||||
|
if err := util.ParseJSON(c, item); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
} else if err := item.Validate(); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := a.MenuBIZ.Create(ctx, item)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResSuccess(c, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags MenuAPI
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Update menu record by ID
|
||||||
|
// @Param id path string true "unique id"
|
||||||
|
// @Param body body schema.MenuForm true "Request body"
|
||||||
|
// @Success 200 {object} util.ResponseResult
|
||||||
|
// @Failure 400 {object} util.ResponseResult
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/menus/{id} [put]
|
||||||
|
func (a *Menu) Update(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
item := new(schema.MenuForm)
|
||||||
|
if err := util.ParseJSON(c, item); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
} else if err := item.Validate(); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := a.MenuBIZ.Update(ctx, c.Param("id"), item)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResOK(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags MenuAPI
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Delete menu record by ID
|
||||||
|
// @Param id path string true "unique id"
|
||||||
|
// @Success 200 {object} util.ResponseResult
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/menus/{id} [delete]
|
||||||
|
func (a *Menu) Delete(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
err := a.MenuBIZ.Delete(ctx, c.Param("id"))
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResOK(c)
|
||||||
|
}
|
||||||
178
internal/mods/rbac/api/product.api.go
Normal file
178
internal/mods/rbac/api/product.api.go
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/biz"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Product struct {
|
||||||
|
ProductBIZ *biz.Product
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags 产品模块
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Query Product list
|
||||||
|
// @Param current query int true "pagination index" default(1)
|
||||||
|
// @Param pageSize query int true "pagination size" default(10)
|
||||||
|
// @Param title query string false "title of Product"
|
||||||
|
// @Param categoryId query int false "categoryId of Product"
|
||||||
|
// @Param code query string false "code of Product"
|
||||||
|
// @Param status query string false "Status of Product (disabled,enabled)"
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=[]schema.Product}
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/products [get]
|
||||||
|
func (a *Product) Query(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
var params schema.ProductQueryParam
|
||||||
|
if err := util.ParseQuery(c, ¶ms); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := a.ProductBIZ.Query(ctx, params)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResPage(c, result.Data, result.PageResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Option struct {
|
||||||
|
Value interface{} `json:"value"`
|
||||||
|
Label string `json:"label"`
|
||||||
|
Children []Option `json:"children"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToOptions(categories *[]schema.ProductCategory) []Option {
|
||||||
|
if categories == nil {
|
||||||
|
return []Option{}
|
||||||
|
}
|
||||||
|
optMap := make(map[uint]*Option, len(*categories))
|
||||||
|
for _, cat := range *categories {
|
||||||
|
optMap[cat.ID] = &Option{
|
||||||
|
Value: cat.ID,
|
||||||
|
Label: cat.Label,
|
||||||
|
Children: []Option{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var roots []Option
|
||||||
|
for _, cat := range *categories {
|
||||||
|
node := optMap[cat.ID]
|
||||||
|
if cat.ParentID == 0 {
|
||||||
|
roots = append(roots, *node)
|
||||||
|
} else if parent, ok := optMap[cat.ParentID]; ok {
|
||||||
|
parent.Children = append(parent.Children, *node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return roots
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags 产品模块
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Query ProductCategory list
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=[]schema.ProductCategory}
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/products/categorys [get]
|
||||||
|
func (a *Product) QueryCategory(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
|
||||||
|
result, err := a.ProductBIZ.QueryProductCategory(ctx)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
list := ToOptions(result)
|
||||||
|
util.ResSuccess(c, list)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags 产品模块
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Get Product record by ID
|
||||||
|
// @Param id path string true "unique id"
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=schema.Product}
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/products/{id} [get]
|
||||||
|
func (a *Product) Get(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
item, err := a.ProductBIZ.Get(ctx, c.Param("id"))
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResSuccess(c, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags 产品模块
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Create Product record
|
||||||
|
// @Param body body schema.ProductForm true "Request body"
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=schema.Product}
|
||||||
|
// @Failure 400 {object} util.ResponseResult
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/products [post]
|
||||||
|
func (a *Product) Create(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
item := new(schema.ProductForm)
|
||||||
|
if err := util.ParseJSON(c, item); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := a.ProductBIZ.Create(ctx, item)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResSuccess(c, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags 产品模块
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Update Product record by ID
|
||||||
|
// @Param id path string true "unique id"
|
||||||
|
// @Param body body schema.ProductForm true "Request body"
|
||||||
|
// @Success 200 {object} util.ResponseResult
|
||||||
|
// @Failure 400 {object} util.ResponseResult
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/products/{id} [put]
|
||||||
|
func (a *Product) Update(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
item := new(schema.ProductForm)
|
||||||
|
if err := util.ParseJSON(c, item); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := a.ProductBIZ.Update(ctx, c.Param("id"), item)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResOK(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags 产品模块
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Delete Product record by ID
|
||||||
|
// @Param id path string true "unique id"
|
||||||
|
// @Success 200 {object} util.ResponseResult
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/products/{id} [delete]
|
||||||
|
func (a *Product) Delete(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
err := a.ProductBIZ.Delete(ctx, c.Param("id"))
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResOK(c)
|
||||||
|
}
|
||||||
133
internal/mods/rbac/api/role.api.go
Normal file
133
internal/mods/rbac/api/role.api.go
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/biz"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Role management for RBAC
|
||||||
|
type Role struct {
|
||||||
|
RoleBIZ *biz.Role
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags RoleAPI
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Query role list
|
||||||
|
// @Param current query int true "pagination index" default(1)
|
||||||
|
// @Param pageSize query int true "pagination size" default(10)
|
||||||
|
// @Param name query string false "Display name of role"
|
||||||
|
// @Param status query string false "Status of role (disabled, enabled)"
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=[]schema.Role}
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/roles [get]
|
||||||
|
func (a *Role) Query(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
var params schema.RoleQueryParam
|
||||||
|
if err := util.ParseQuery(c, ¶ms); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := a.RoleBIZ.Query(ctx, params)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResPage(c, result.Data, result.PageResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags RoleAPI
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Get role record by ID
|
||||||
|
// @Param id path string true "unique id"
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=schema.Role}
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/roles/{id} [get]
|
||||||
|
func (a *Role) Get(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
item, err := a.RoleBIZ.Get(ctx, c.Param("id"))
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResSuccess(c, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags RoleAPI
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Create role record
|
||||||
|
// @Param body body schema.RoleForm true "Request body"
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=schema.Role}
|
||||||
|
// @Failure 400 {object} util.ResponseResult
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/roles [post]
|
||||||
|
func (a *Role) Create(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
item := new(schema.RoleForm)
|
||||||
|
if err := util.ParseJSON(c, item); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
} else if err := item.Validate(); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := a.RoleBIZ.Create(ctx, item)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResSuccess(c, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags RoleAPI
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Update role record by ID
|
||||||
|
// @Param id path string true "unique id"
|
||||||
|
// @Param body body schema.RoleForm true "Request body"
|
||||||
|
// @Success 200 {object} util.ResponseResult
|
||||||
|
// @Failure 400 {object} util.ResponseResult
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/roles/{id} [put]
|
||||||
|
func (a *Role) Update(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
item := new(schema.RoleForm)
|
||||||
|
if err := util.ParseJSON(c, item); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
} else if err := item.Validate(); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := a.RoleBIZ.Update(ctx, c.Param("id"), item)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResOK(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags RoleAPI
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Delete role record by ID
|
||||||
|
// @Param id path string true "unique id"
|
||||||
|
// @Success 200 {object} util.ResponseResult
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/roles/{id} [delete]
|
||||||
|
func (a *Role) Delete(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
err := a.RoleBIZ.Delete(ctx, c.Param("id"))
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResOK(c)
|
||||||
|
}
|
||||||
126
internal/mods/rbac/api/team.api.go
Normal file
126
internal/mods/rbac/api/team.api.go
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/biz"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Team struct {
|
||||||
|
TeamBIZ *biz.Team
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags 团队模块
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Query Team list
|
||||||
|
// @Param current query int true "pagination index" default(1)
|
||||||
|
// @Param pageSize query int true "pagination size" default(10)
|
||||||
|
// @Param name query string false "name of Team"
|
||||||
|
// @Param status query string false "Status of banner (disabled,enabled)"
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=[]schema.Team}
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/teams [get]
|
||||||
|
func (a *Team) Query(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
var params schema.TeamQueryParam
|
||||||
|
if err := util.ParseQuery(c, ¶ms); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := a.TeamBIZ.Query(ctx, params)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResPage(c, result.Data, result.PageResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags 团队模块
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Get Team record by ID
|
||||||
|
// @Param id path string true "unique id"
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=schema.Team}
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/teams/{id} [get]
|
||||||
|
func (a *Team) Get(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
item, err := a.TeamBIZ.Get(ctx, c.Param("id"))
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResSuccess(c, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags 团队模块
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Create Article record
|
||||||
|
// @Param body body schema.TeamForm true "Request body"
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=schema.Team}
|
||||||
|
// @Failure 400 {object} util.ResponseResult
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/teams [post]
|
||||||
|
func (a *Team) Create(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
item := new(schema.TeamForm)
|
||||||
|
if err := util.ParseJSON(c, item); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := a.TeamBIZ.Create(ctx, item)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResSuccess(c, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags 团队模块
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Update Article record by ID
|
||||||
|
// @Param id path string true "unique id"
|
||||||
|
// @Param body body schema.TeamForm true "Request body"
|
||||||
|
// @Success 200 {object} util.ResponseResult
|
||||||
|
// @Failure 400 {object} util.ResponseResult
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/teams/{id} [put]
|
||||||
|
func (a *Team) Update(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
item := new(schema.TeamForm)
|
||||||
|
if err := util.ParseJSON(c, item); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := a.TeamBIZ.Update(ctx, c.Param("id"), item)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResOK(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags 团队模块
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Delete Article record by ID
|
||||||
|
// @Param id path string true "unique id"
|
||||||
|
// @Success 200 {object} util.ResponseResult
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/teams/{id} [delete]
|
||||||
|
func (a *Team) Delete(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
err := a.TeamBIZ.Delete(ctx, c.Param("id"))
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResOK(c)
|
||||||
|
}
|
||||||
24
internal/mods/rbac/api/upload.api.go
Normal file
24
internal/mods/rbac/api/upload.api.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/guxuan/hailin_service/internal/config"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/biz"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Upload struct {
|
||||||
|
UploadBIZ *biz.Upload
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Upload) SaveFile(c *gin.Context) {
|
||||||
|
file, err := c.FormFile("file")
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
result, err := a.UploadBIZ.SaveFile(c, file)
|
||||||
|
fileURL := fmt.Sprintf("%s/%s", config.C.FileConfig.StaticPrefix, result)
|
||||||
|
util.ResSuccess(c, fileURL)
|
||||||
|
}
|
||||||
152
internal/mods/rbac/api/user.api.go
Normal file
152
internal/mods/rbac/api/user.api.go
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/biz"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// User management for RBAC
|
||||||
|
type User struct {
|
||||||
|
UserBIZ *biz.User
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags UserAPI
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Query user list
|
||||||
|
// @Param current query int true "pagination index" default(1)
|
||||||
|
// @Param pageSize query int true "pagination size" default(10)
|
||||||
|
// @Param username query string false "Username for login"
|
||||||
|
// @Param name query string false "Name of user"
|
||||||
|
// @Param status query string false "Status of user (activated, freezed)"
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=[]schema.User}
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/users [get]
|
||||||
|
func (a *User) Query(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
var params schema.UserQueryParam
|
||||||
|
if err := util.ParseQuery(c, ¶ms); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := a.UserBIZ.Query(ctx, params)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResPage(c, result.Data, result.PageResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags UserAPI
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Get user record by ID
|
||||||
|
// @Param id path string true "unique id"
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=schema.User}
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/users/{id} [get]
|
||||||
|
func (a *User) Get(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
item, err := a.UserBIZ.Get(ctx, c.Param("id"))
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResSuccess(c, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags UserAPI
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Create user record
|
||||||
|
// @Param body body schema.UserForm true "Request body"
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=schema.User}
|
||||||
|
// @Failure 400 {object} util.ResponseResult
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/users [post]
|
||||||
|
func (a *User) Create(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
item := new(schema.UserForm)
|
||||||
|
if err := util.ParseJSON(c, item); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
} else if err := item.Validate(); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := a.UserBIZ.Create(ctx, item)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResSuccess(c, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags UserAPI
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Update user record by ID
|
||||||
|
// @Param id path string true "unique id"
|
||||||
|
// @Param body body schema.UserForm true "Request body"
|
||||||
|
// @Success 200 {object} util.ResponseResult
|
||||||
|
// @Failure 400 {object} util.ResponseResult
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/users/{id} [put]
|
||||||
|
func (a *User) Update(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
item := new(schema.UserForm)
|
||||||
|
if err := util.ParseJSON(c, item); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
} else if err := item.Validate(); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := a.UserBIZ.Update(ctx, c.Param("id"), item)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResOK(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags UserAPI
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Delete user record by ID
|
||||||
|
// @Param id path string true "unique id"
|
||||||
|
// @Success 200 {object} util.ResponseResult
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/users/{id} [delete]
|
||||||
|
func (a *User) Delete(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
err := a.UserBIZ.Delete(ctx, c.Param("id"))
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResOK(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags UserAPI
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Reset user password by ID
|
||||||
|
// @Param id path string true "unique id"
|
||||||
|
// @Success 200 {object} util.ResponseResult
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/users/{id}/reset-pwd [patch]
|
||||||
|
func (a *User) ResetPassword(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
err := a.UserBIZ.ResetPassword(ctx, c.Param("id"))
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResOK(c)
|
||||||
|
}
|
||||||
127
internal/mods/rbac/api/video.api.go
Normal file
127
internal/mods/rbac/api/video.api.go
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/biz"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Banner management for RBAC
|
||||||
|
type Video struct {
|
||||||
|
VideoBIZ *biz.Video
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags VideoAPI
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Query Video list
|
||||||
|
// @Param current query int true "pagination index" default(1)
|
||||||
|
// @Param pageSize query int true "pagination size" default(10)
|
||||||
|
// @Param title query string false "title of Video"
|
||||||
|
// @Param status query string false "Status of banner (disabled,enabled)"
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=[]schema.Video}
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/videos [get]
|
||||||
|
func (a *Video) Query(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
var params schema.VideoQueryParam
|
||||||
|
if err := util.ParseQuery(c, ¶ms); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := a.VideoBIZ.Query(ctx, params)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResPage(c, result.Data, result.PageResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags VideoAPI
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Get Video record by ID
|
||||||
|
// @Param id path string true "unique id"
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=schema.Video}
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/videos/{id} [get]
|
||||||
|
func (a *Video) Get(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
item, err := a.VideoBIZ.Get(ctx, c.Param("id"))
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResSuccess(c, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags VideoAPI
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Create banner record
|
||||||
|
// @Param body body schema.VideoForm true "Request body"
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=schema.Video}
|
||||||
|
// @Failure 400 {object} util.ResponseResult
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/videos [post]
|
||||||
|
func (a *Video) Create(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
item := new(schema.VideoForm)
|
||||||
|
if err := util.ParseJSON(c, item); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := a.VideoBIZ.Create(ctx, item)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResSuccess(c, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags VideoAPI
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Update Video record by ID
|
||||||
|
// @Param id path string true "unique id"
|
||||||
|
// @Param body body schema.BannerForm true "Request body"
|
||||||
|
// @Success 200 {object} util.ResponseResult
|
||||||
|
// @Failure 400 {object} util.ResponseResult
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/videos/{id} [put]
|
||||||
|
func (a *Video) Update(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
item := new(schema.VideoForm)
|
||||||
|
if err := util.ParseJSON(c, item); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := a.VideoBIZ.Update(ctx, c.Param("id"), item)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResOK(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags VideoAPI
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Delete Video record by ID
|
||||||
|
// @Param id path string true "unique id"
|
||||||
|
// @Success 200 {object} util.ResponseResult
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/videos/{id} [delete]
|
||||||
|
func (a *Video) Delete(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
err := a.VideoBIZ.Delete(ctx, c.Param("id"))
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResOK(c)
|
||||||
|
}
|
||||||
56
internal/mods/rbac/api/web.go
Normal file
56
internal/mods/rbac/api/web.go
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/biz"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Banner management for RBAC
|
||||||
|
type Web struct {
|
||||||
|
ArticleBIZ *biz.Article
|
||||||
|
JobBIZ *biz.Job
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags 网页模块
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary 获取职位列表
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=[]schema.WebJobData}
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/web/jobs [get]
|
||||||
|
func (a *Web) QueryJob(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
list, err := a.JobBIZ.QueryWebJobList(ctx)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResSuccess(c, list)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags 网页模块
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary 获取公司动态
|
||||||
|
// @Param current query int true "pagination index" default(1)
|
||||||
|
// @Param pageSize query int true "pagination size" default(10)
|
||||||
|
// @Param jobAreaId query string false "jobAreaId of Job"
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=[]schema.Article}
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/web/articles [get]
|
||||||
|
func (a *Web) QueryArticle(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
var params schema.ArticleQueryParam
|
||||||
|
if err := util.ParseQuery(c, ¶ms); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
result, err := a.ArticleBIZ.Query(ctx, params)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResPage(c, result.Data, result.PageResult)
|
||||||
|
}
|
||||||
82
internal/mods/rbac/api/webSite.api.go
Normal file
82
internal/mods/rbac/api/webSite.api.go
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/biz"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Banner management for RBAC
|
||||||
|
type WebSite struct {
|
||||||
|
WebSiteBIZ *biz.WebSite
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags 网页设置
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Query WebSite info
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=[]schema.WebSite}
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/web_site [get]
|
||||||
|
func (a *WebSite) Query(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
|
||||||
|
result, err := a.WebSiteBIZ.Query(ctx)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResSuccess(c, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags ArticleAPI
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Create WebSite record
|
||||||
|
// @Param body body schema.WebSiteForm true "Request body"
|
||||||
|
// @Success 200 {object} util.ResponseResult{data=schema.WebSite}
|
||||||
|
// @Failure 400 {object} util.ResponseResult
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/web_site [post]
|
||||||
|
func (a *WebSite) Create(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
item := new(schema.WebSiteForm)
|
||||||
|
if err := util.ParseJSON(c, item); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := a.WebSiteBIZ.Create(ctx, item)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResSuccess(c, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags 网页设置
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Summary Update WebSite record by ID
|
||||||
|
// @Param id path string true "unique id"
|
||||||
|
// @Param body body schema.WebSiteForm true "Request body"
|
||||||
|
// @Success 200 {object} util.ResponseResult
|
||||||
|
// @Failure 400 {object} util.ResponseResult
|
||||||
|
// @Failure 401 {object} util.ResponseResult
|
||||||
|
// @Failure 500 {object} util.ResponseResult
|
||||||
|
// @Router /api/v1/web_site/{id} [put]
|
||||||
|
func (a *WebSite) Update(c *gin.Context) {
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
item := new(schema.WebSiteForm)
|
||||||
|
if err := util.ParseJSON(c, item); err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := a.WebSiteBIZ.Update(ctx, c.Param("id"), item)
|
||||||
|
if err != nil {
|
||||||
|
util.ResError(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
util.ResOK(c)
|
||||||
|
}
|
||||||
100
internal/mods/rbac/biz/article.biz.go
Normal file
100
internal/mods/rbac/biz/article.biz.go
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
package biz
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/dal"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/cachex"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/errors"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Role management for RBAC
|
||||||
|
type Article struct {
|
||||||
|
Cache cachex.Cacher
|
||||||
|
Trans *util.Trans
|
||||||
|
ArticleDAL *dal.Article
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query roles from the data access object based on the provided parameters and options.
|
||||||
|
func (a *Article) Query(ctx context.Context, params schema.ArticleQueryParam) (*schema.ArticleQueryResult, error) {
|
||||||
|
params.Pagination = true
|
||||||
|
result, err := a.ArticleDAL.Query(ctx, params, schema.ArticleQueryOptions{
|
||||||
|
QueryOptions: util.QueryOptions{
|
||||||
|
OrderFields: []util.OrderByParam{
|
||||||
|
{Field: "created_at", Direction: util.DESC},
|
||||||
|
{Field: "sequence", Direction: util.ASC},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the specified role from the data access object.
|
||||||
|
func (a *Article) Get(ctx context.Context, id string) (*schema.Article, error) {
|
||||||
|
article, err := a.ArticleDAL.Get(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if article == nil {
|
||||||
|
return nil, errors.NotFound("", "Banner not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return article, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new role in the data access object.
|
||||||
|
func (a *Article) Create(ctx context.Context, formItem *schema.ArticleForm) (*schema.Article, error) {
|
||||||
|
|
||||||
|
article := &schema.Article{
|
||||||
|
ID: util.NewXID(),
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
}
|
||||||
|
if err := formItem.FillTo(article); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := a.ArticleDAL.Create(ctx, article); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return article, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the specified role in the data access object.
|
||||||
|
func (a *Article) Update(ctx context.Context, id string, formItem *schema.ArticleForm) error {
|
||||||
|
article, err := a.ArticleDAL.Get(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := formItem.FillTo(article); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
article.UpdatedAt = time.Now()
|
||||||
|
|
||||||
|
if err := a.ArticleDAL.Update(ctx, article); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the specified role from the data access object.
|
||||||
|
func (a *Article) Delete(ctx context.Context, id string) error {
|
||||||
|
exists, err := a.ArticleDAL.Exists(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if !exists {
|
||||||
|
return errors.NotFound("", "Role not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := a.ArticleDAL.Delete(ctx, id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
99
internal/mods/rbac/biz/banner.biz.go
Normal file
99
internal/mods/rbac/biz/banner.biz.go
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
package biz
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/dal"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/cachex"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/errors"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Role management for RBAC
|
||||||
|
type Banner struct {
|
||||||
|
Cache cachex.Cacher
|
||||||
|
Trans *util.Trans
|
||||||
|
BannerDAL *dal.Banner
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query roles from the data access object based on the provided parameters and options.
|
||||||
|
func (a *Banner) Query(ctx context.Context, params schema.BannerQueryParam) (*schema.BannerQueryResult, error) {
|
||||||
|
params.Pagination = true
|
||||||
|
result, err := a.BannerDAL.Query(ctx, params, schema.BannerQueryOptions{
|
||||||
|
QueryOptions: util.QueryOptions{
|
||||||
|
OrderFields: []util.OrderByParam{
|
||||||
|
{Field: "sequence", Direction: util.DESC},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the specified role from the data access object.
|
||||||
|
func (a *Banner) Get(ctx context.Context, id string) (*schema.Banner, error) {
|
||||||
|
banner, err := a.BannerDAL.Get(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if banner == nil {
|
||||||
|
return nil, errors.NotFound("", "Banner not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return banner, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new role in the data access object.
|
||||||
|
func (a *Banner) Create(ctx context.Context, formItem *schema.BannerForm) (*schema.Banner, error) {
|
||||||
|
|
||||||
|
banner := &schema.Banner{
|
||||||
|
ID: util.NewXID(),
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
}
|
||||||
|
if err := formItem.FillTo(banner); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := a.BannerDAL.Create(ctx, banner); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return banner, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the specified role in the data access object.
|
||||||
|
func (a *Banner) Update(ctx context.Context, id string, formItem *schema.BannerForm) error {
|
||||||
|
banner, err := a.BannerDAL.Get(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := formItem.FillTo(banner); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
banner.UpdatedAt = time.Now()
|
||||||
|
|
||||||
|
if err := a.BannerDAL.Update(ctx, banner); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the specified role from the data access object.
|
||||||
|
func (a *Banner) Delete(ctx context.Context, id string) error {
|
||||||
|
exists, err := a.BannerDAL.Exists(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if !exists {
|
||||||
|
return errors.NotFound("", "Role not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := a.BannerDAL.Delete(ctx, id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
178
internal/mods/rbac/biz/job.biz.go
Normal file
178
internal/mods/rbac/biz/job.biz.go
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
package biz
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/dal"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/cachex"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/errors"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Role management for RBAC
|
||||||
|
type Job struct {
|
||||||
|
Cache cachex.Cacher
|
||||||
|
Trans *util.Trans
|
||||||
|
JobDAL *dal.Job
|
||||||
|
JobAreaDAL *dal.JobArea
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query roles from the data access object based on the provided parameters and options.
|
||||||
|
func (a *Job) QueryJobArea(ctx context.Context) (*[]schema.JobArea, error) {
|
||||||
|
return a.JobAreaDAL.Query(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new role in the data access object.
|
||||||
|
func (a *Job) CreateJobArea(ctx context.Context, formItem *schema.JobAreaForm) (*schema.JobArea, error) {
|
||||||
|
area := &schema.JobArea{
|
||||||
|
ID: util.NewXID(),
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
}
|
||||||
|
area.Name = formItem.Name
|
||||||
|
area.Status = formItem.Status
|
||||||
|
if err := a.JobAreaDAL.Create(ctx, area); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return area, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Job) QueryWebJobList(ctx context.Context) ([]*schema.WebJobData, error) {
|
||||||
|
var result []*schema.WebJobData
|
||||||
|
|
||||||
|
query, err := a.JobAreaDAL.Query(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, area := range *query {
|
||||||
|
if area.Status == "enabled" {
|
||||||
|
queryResult, err := a.JobDAL.Query(ctx, schema.JobQueryParam{JobAreaID: area.ID, Status: "enabled"}, schema.JobQueryOptions{
|
||||||
|
QueryOptions: util.QueryOptions{
|
||||||
|
OrderFields: []util.OrderByParam{
|
||||||
|
{Field: "sequence", Direction: util.ASC},
|
||||||
|
},
|
||||||
|
}})
|
||||||
|
if err == nil {
|
||||||
|
var info schema.WebJobData
|
||||||
|
info.JobAreaTitle = area.Name
|
||||||
|
info.JobList = queryResult.Data
|
||||||
|
result = append(result, &info)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the specified role in the data access object.
|
||||||
|
func (a *Job) UpdateJobArea(ctx context.Context, id string, formItem *schema.JobAreaForm) error {
|
||||||
|
area, err := a.JobAreaDAL.Get(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
area.UpdatedAt = time.Now()
|
||||||
|
area.Name = formItem.Name
|
||||||
|
area.Status = formItem.Status
|
||||||
|
if err := a.JobAreaDAL.Update(ctx, area); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the specified role from the data access object.
|
||||||
|
func (a *Job) DeleteJobArea(ctx context.Context, id string) error {
|
||||||
|
exists, err := a.JobAreaDAL.Exists(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if !exists {
|
||||||
|
return errors.NotFound("", "Role not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := a.JobAreaDAL.Delete(ctx, id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query roles from the data access object based on the provided parameters and options.
|
||||||
|
func (a *Job) Query(ctx context.Context, params schema.JobQueryParam) (*schema.JobQueryResult, error) {
|
||||||
|
params.Pagination = true
|
||||||
|
result, err := a.JobDAL.Query(ctx, params, schema.JobQueryOptions{
|
||||||
|
QueryOptions: util.QueryOptions{
|
||||||
|
OrderFields: []util.OrderByParam{
|
||||||
|
{Field: "sequence", Direction: util.ASC},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the specified role from the data access object.
|
||||||
|
func (a *Job) Get(ctx context.Context, id string) (*schema.Job, error) {
|
||||||
|
job, err := a.JobDAL.Get(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if job == nil {
|
||||||
|
return nil, errors.NotFound("", "Banner not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return job, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new role in the data access object.
|
||||||
|
func (a *Job) Create(ctx context.Context, formItem *schema.JobForm) (*schema.Job, error) {
|
||||||
|
|
||||||
|
job := &schema.Job{
|
||||||
|
ID: util.NewXID(),
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
}
|
||||||
|
if err := formItem.FillTo(job); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := a.JobDAL.Create(ctx, job); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return job, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the specified role in the data access object.
|
||||||
|
func (a *Job) Update(ctx context.Context, id string, formItem *schema.JobForm) error {
|
||||||
|
job, err := a.JobDAL.Get(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := formItem.FillTo(job); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
job.UpdatedAt = time.Now()
|
||||||
|
|
||||||
|
if err := a.JobDAL.Update(ctx, job); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the specified role from the data access object.
|
||||||
|
func (a *Job) Delete(ctx context.Context, id string) error {
|
||||||
|
exists, err := a.JobDAL.Exists(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if !exists {
|
||||||
|
return errors.NotFound("", "Role not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := a.JobDAL.Delete(ctx, id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
31
internal/mods/rbac/biz/logger.biz.go
Normal file
31
internal/mods/rbac/biz/logger.biz.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package biz
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/dal"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Logger management
|
||||||
|
type Logger struct {
|
||||||
|
LoggerDAL *dal.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query loggers from the data access object based on the provided parameters and options.
|
||||||
|
func (a *Logger) Query(ctx context.Context, params schema.LoggerQueryParam) (*schema.LoggerQueryResult, error) {
|
||||||
|
params.Pagination = true
|
||||||
|
|
||||||
|
result, err := a.LoggerDAL.Query(ctx, params, schema.LoggerQueryOptions{
|
||||||
|
QueryOptions: util.QueryOptions{
|
||||||
|
OrderFields: []util.OrderByParam{
|
||||||
|
{Field: "created_at", Direction: util.DESC},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
374
internal/mods/rbac/biz/login.biz.go
Normal file
374
internal/mods/rbac/biz/login.biz.go
Normal file
@ -0,0 +1,374 @@
|
|||||||
|
package biz
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
"sort"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/LyricTian/captcha"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/guxuan/hailin_service/internal/config"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/dal"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/cachex"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/crypto/hash"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/errors"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/jwtx"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/logging"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Login management for RBAC
|
||||||
|
type Login struct {
|
||||||
|
Cache cachex.Cacher
|
||||||
|
Auth jwtx.Auther
|
||||||
|
UserDAL *dal.User
|
||||||
|
UserRoleDAL *dal.UserRole
|
||||||
|
MenuDAL *dal.Menu
|
||||||
|
UserBIZ *User
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Login) ParseUserID(c *gin.Context) (string, error) {
|
||||||
|
rootID := config.C.General.Root.ID
|
||||||
|
if config.C.Middleware.Auth.Disable {
|
||||||
|
return rootID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
invalidToken := errors.Unauthorized(config.ErrInvalidTokenID, "Invalid access token")
|
||||||
|
token := util.GetToken(c)
|
||||||
|
if token == "" {
|
||||||
|
return "", invalidToken
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
ctx = util.NewUserToken(ctx, token)
|
||||||
|
|
||||||
|
userID, err := a.Auth.ParseSubject(ctx, token)
|
||||||
|
if err != nil {
|
||||||
|
if err == jwtx.ErrInvalidToken {
|
||||||
|
return "", invalidToken
|
||||||
|
}
|
||||||
|
return "", err
|
||||||
|
} else if userID == rootID {
|
||||||
|
c.Request = c.Request.WithContext(util.NewIsRootUser(ctx))
|
||||||
|
return userID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
userCacheVal, ok, err := a.Cache.Get(ctx, config.CacheNSForUser, userID)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
} else if ok {
|
||||||
|
userCache := util.ParseUserCache(userCacheVal)
|
||||||
|
c.Request = c.Request.WithContext(util.NewUserCache(ctx, userCache))
|
||||||
|
return userID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check user status, if not activated, force to logout
|
||||||
|
user, err := a.UserDAL.Get(ctx, userID, schema.UserQueryOptions{
|
||||||
|
QueryOptions: util.QueryOptions{SelectFields: []string{"status"}},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
} else if user == nil || user.Status != schema.UserStatusActivated {
|
||||||
|
return "", invalidToken
|
||||||
|
}
|
||||||
|
|
||||||
|
roleIDs, err := a.UserBIZ.GetRoleIDs(ctx, userID)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
userCache := util.UserCache{
|
||||||
|
RoleIDs: roleIDs,
|
||||||
|
}
|
||||||
|
err = a.Cache.Set(ctx, config.CacheNSForUser, userID, userCache.String())
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Request = c.Request.WithContext(util.NewUserCache(ctx, userCache))
|
||||||
|
return userID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function generates a new captcha ID and returns it as a `schema.Captcha` struct. The length of
|
||||||
|
// the captcha is determined by the `config.C.Util.Captcha.Length` configuration value.
|
||||||
|
func (a *Login) GetCaptcha(ctx context.Context) (*schema.Captcha, error) {
|
||||||
|
return &schema.Captcha{
|
||||||
|
CaptchaID: captcha.NewLen(config.C.Util.Captcha.Length),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Response captcha image
|
||||||
|
func (a *Login) ResponseCaptcha(ctx context.Context, w http.ResponseWriter, id string, reload bool) error {
|
||||||
|
if reload && !captcha.Reload(id) {
|
||||||
|
return errors.NotFound("", "Captcha id not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
err := captcha.WriteImage(w, id, config.C.Util.Captcha.Width, config.C.Util.Captcha.Height)
|
||||||
|
if err != nil {
|
||||||
|
if err == captcha.ErrNotFound {
|
||||||
|
return errors.NotFound("", "Captcha id not found")
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
|
||||||
|
w.Header().Set("Pragma", "no-cache")
|
||||||
|
w.Header().Set("Expires", "0")
|
||||||
|
w.Header().Set("Content-Type", "image/png")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Login) genUserToken(ctx context.Context, userID string) (*schema.LoginToken, error) {
|
||||||
|
token, err := a.Auth.GenerateToken(ctx, userID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenBuf, err := token.EncodeToJSON()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
logging.Context(ctx).Info("Generate user token", zap.Any("token", string(tokenBuf)))
|
||||||
|
|
||||||
|
return &schema.LoginToken{
|
||||||
|
AccessToken: token.GetAccessToken(),
|
||||||
|
TokenType: token.GetTokenType(),
|
||||||
|
ExpiresAt: token.GetExpiresAt(),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Login) Login(ctx context.Context, formItem *schema.LoginForm) (*schema.LoginToken, error) {
|
||||||
|
// verify captcha
|
||||||
|
//if !captcha.VerifyString(formItem.CaptchaID, formItem.CaptchaCode) {
|
||||||
|
// return nil, errors.BadRequest(config.ErrInvalidCaptchaID, "Incorrect captcha")
|
||||||
|
//}
|
||||||
|
|
||||||
|
ctx = logging.NewTag(ctx, logging.TagKeyLogin)
|
||||||
|
|
||||||
|
// login by root
|
||||||
|
if formItem.Username == config.C.General.Root.Username {
|
||||||
|
if formItem.Password != config.C.General.Root.Password {
|
||||||
|
return nil, errors.BadRequest(config.ErrInvalidUsernameOrPassword, "账号密码错误!")
|
||||||
|
}
|
||||||
|
|
||||||
|
userID := config.C.General.Root.ID
|
||||||
|
ctx = logging.NewUserID(ctx, userID)
|
||||||
|
logging.Context(ctx).Info("Login by root")
|
||||||
|
return a.genUserToken(ctx, userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// get user info
|
||||||
|
user, err := a.UserDAL.GetByUsername(ctx, formItem.Username, schema.UserQueryOptions{
|
||||||
|
QueryOptions: util.QueryOptions{
|
||||||
|
SelectFields: []string{"id", "password", "status"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if user == nil {
|
||||||
|
return nil, errors.BadRequest(config.ErrInvalidUsernameOrPassword, "Incorrect username or password")
|
||||||
|
} else if user.Status != schema.UserStatusActivated {
|
||||||
|
return nil, errors.BadRequest("", "User status is not activated, please contact the administrator")
|
||||||
|
}
|
||||||
|
|
||||||
|
// check password
|
||||||
|
if err := hash.CompareHashAndPassword(user.Password, formItem.Password); err != nil {
|
||||||
|
return nil, errors.BadRequest(config.ErrInvalidUsernameOrPassword, "Incorrect username or password")
|
||||||
|
}
|
||||||
|
|
||||||
|
userID := user.ID
|
||||||
|
ctx = logging.NewUserID(ctx, userID)
|
||||||
|
|
||||||
|
// set user cache with role ids
|
||||||
|
roleIDs, err := a.UserBIZ.GetRoleIDs(ctx, userID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
userCache := util.UserCache{RoleIDs: roleIDs}
|
||||||
|
err = a.Cache.Set(ctx, config.CacheNSForUser, userID, userCache.String(),
|
||||||
|
time.Duration(config.C.Dictionary.UserCacheExp)*time.Hour)
|
||||||
|
if err != nil {
|
||||||
|
logging.Context(ctx).Error("Failed to set cache", zap.Error(err))
|
||||||
|
}
|
||||||
|
logging.Context(ctx).Info("Login success", zap.String("username", formItem.Username))
|
||||||
|
|
||||||
|
// generate token
|
||||||
|
return a.genUserToken(ctx, userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Login) RefreshToken(ctx context.Context) (*schema.LoginToken, error) {
|
||||||
|
userID := util.FromUserID(ctx)
|
||||||
|
|
||||||
|
user, err := a.UserDAL.Get(ctx, userID, schema.UserQueryOptions{
|
||||||
|
QueryOptions: util.QueryOptions{
|
||||||
|
SelectFields: []string{"status"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if user == nil {
|
||||||
|
return nil, errors.BadRequest("", "Incorrect user")
|
||||||
|
} else if user.Status != schema.UserStatusActivated {
|
||||||
|
return nil, errors.BadRequest("", "User status is not activated, please contact the administrator")
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.genUserToken(ctx, userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Login) Logout(ctx context.Context) error {
|
||||||
|
userToken := util.FromUserToken(ctx)
|
||||||
|
if userToken == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = logging.NewTag(ctx, logging.TagKeyLogout)
|
||||||
|
if err := a.Auth.DestroyToken(ctx, userToken); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
userID := util.FromUserID(ctx)
|
||||||
|
err := a.Cache.Delete(ctx, config.CacheNSForUser, userID)
|
||||||
|
if err != nil {
|
||||||
|
logging.Context(ctx).Error("Failed to delete user cache", zap.Error(err))
|
||||||
|
}
|
||||||
|
logging.Context(ctx).Info("Logout success")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get user info
|
||||||
|
func (a *Login) GetUserInfo(ctx context.Context) (*schema.User, error) {
|
||||||
|
if util.FromIsRootUser(ctx) {
|
||||||
|
return &schema.User{
|
||||||
|
ID: config.C.General.Root.ID,
|
||||||
|
Username: config.C.General.Root.Username,
|
||||||
|
Name: config.C.General.Root.Name,
|
||||||
|
Status: schema.UserStatusActivated,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
userID := util.FromUserID(ctx)
|
||||||
|
user, err := a.UserDAL.Get(ctx, userID, schema.UserQueryOptions{
|
||||||
|
QueryOptions: util.QueryOptions{
|
||||||
|
OmitFields: []string{"password"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if user == nil {
|
||||||
|
return nil, errors.NotFound("", "User not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
userRoleResult, err := a.UserRoleDAL.Query(ctx, schema.UserRoleQueryParam{
|
||||||
|
UserID: userID,
|
||||||
|
}, schema.UserRoleQueryOptions{
|
||||||
|
JoinRole: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
user.Roles = userRoleResult.Data
|
||||||
|
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change login password
|
||||||
|
func (a *Login) UpdatePassword(ctx context.Context, updateItem *schema.UpdateLoginPassword) error {
|
||||||
|
if util.FromIsRootUser(ctx) {
|
||||||
|
return errors.BadRequest("", "Root user cannot change password")
|
||||||
|
}
|
||||||
|
|
||||||
|
userID := util.FromUserID(ctx)
|
||||||
|
user, err := a.UserDAL.Get(ctx, userID, schema.UserQueryOptions{
|
||||||
|
QueryOptions: util.QueryOptions{
|
||||||
|
SelectFields: []string{"password"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if user == nil {
|
||||||
|
return errors.NotFound("", "User not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
// check old password
|
||||||
|
if err := hash.CompareHashAndPassword(user.Password, updateItem.OldPassword); err != nil {
|
||||||
|
return errors.BadRequest("", "Incorrect old password")
|
||||||
|
}
|
||||||
|
|
||||||
|
// update password
|
||||||
|
newPassword, err := hash.GeneratePassword(updateItem.NewPassword)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return a.UserDAL.UpdatePasswordByID(ctx, userID, newPassword)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query menus based on user permissions
|
||||||
|
func (a *Login) QueryMenus(ctx context.Context) (schema.Menus, error) {
|
||||||
|
menuQueryParams := schema.MenuQueryParam{
|
||||||
|
Status: schema.MenuStatusEnabled,
|
||||||
|
}
|
||||||
|
|
||||||
|
isRoot := util.FromIsRootUser(ctx)
|
||||||
|
if !isRoot {
|
||||||
|
menuQueryParams.UserID = util.FromUserID(ctx)
|
||||||
|
}
|
||||||
|
menuResult, err := a.MenuDAL.Query(ctx, menuQueryParams, schema.MenuQueryOptions{
|
||||||
|
QueryOptions: util.QueryOptions{
|
||||||
|
OrderFields: schema.MenusOrderParams,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if isRoot {
|
||||||
|
return menuResult.Data.ToTree(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// fill parent menus
|
||||||
|
if parentIDs := menuResult.Data.SplitParentIDs(); len(parentIDs) > 0 {
|
||||||
|
var missMenusIDs []string
|
||||||
|
menuIDMapper := menuResult.Data.ToMap()
|
||||||
|
for _, parentID := range parentIDs {
|
||||||
|
if _, ok := menuIDMapper[parentID]; !ok {
|
||||||
|
missMenusIDs = append(missMenusIDs, parentID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(missMenusIDs) > 0 {
|
||||||
|
parentResult, err := a.MenuDAL.Query(ctx, schema.MenuQueryParam{
|
||||||
|
InIDs: missMenusIDs,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
menuResult.Data = append(menuResult.Data, parentResult.Data...)
|
||||||
|
sort.Sort(menuResult.Data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return menuResult.Data.ToTree(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update current user info
|
||||||
|
func (a *Login) UpdateUser(ctx context.Context, updateItem *schema.UpdateCurrentUser) error {
|
||||||
|
if util.FromIsRootUser(ctx) {
|
||||||
|
return errors.BadRequest("", "Root user cannot update")
|
||||||
|
}
|
||||||
|
|
||||||
|
userID := util.FromUserID(ctx)
|
||||||
|
user, err := a.UserDAL.Get(ctx, userID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if user == nil {
|
||||||
|
return errors.NotFound("", "User not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
user.Name = updateItem.Name
|
||||||
|
user.Phone = updateItem.Phone
|
||||||
|
user.Email = updateItem.Email
|
||||||
|
user.Remark = updateItem.Remark
|
||||||
|
return a.UserDAL.Update(ctx, user, "name", "phone", "email", "remark")
|
||||||
|
}
|
||||||
99
internal/mods/rbac/biz/memorabilia.biz.go
Normal file
99
internal/mods/rbac/biz/memorabilia.biz.go
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
package biz
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/dal"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/cachex"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/errors"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Role management for RBAC
|
||||||
|
type Memorabilia struct {
|
||||||
|
Cache cachex.Cacher
|
||||||
|
Trans *util.Trans
|
||||||
|
MemorabiliaDAL *dal.Memorabilia
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query roles from the data access object based on the provided parameters and options.
|
||||||
|
func (a *Memorabilia) Query(ctx context.Context, params schema.MemorabiliaQueryParam) (*schema.MemorabiliaQueryResult, error) {
|
||||||
|
params.Pagination = true
|
||||||
|
result, err := a.MemorabiliaDAL.Query(ctx, params, schema.MemorabiliaQueryOptions{
|
||||||
|
QueryOptions: util.QueryOptions{
|
||||||
|
OrderFields: []util.OrderByParam{
|
||||||
|
{Field: "sequence", Direction: util.DESC},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the specified role from the data access object.
|
||||||
|
func (a *Memorabilia) Get(ctx context.Context, id string) (*schema.Memorabilia, error) {
|
||||||
|
memorabilia, err := a.MemorabiliaDAL.Get(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if memorabilia == nil {
|
||||||
|
return nil, errors.NotFound("", "Banner not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return memorabilia, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new role in the data access object.
|
||||||
|
func (a *Memorabilia) Create(ctx context.Context, formItem *schema.MemorabiliaForm) (*schema.Memorabilia, error) {
|
||||||
|
|
||||||
|
memorabilia := &schema.Memorabilia{
|
||||||
|
ID: util.NewXID(),
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
}
|
||||||
|
if err := formItem.FillTo(memorabilia); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := a.MemorabiliaDAL.Create(ctx, memorabilia); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return memorabilia, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the specified role in the data access object.
|
||||||
|
func (a *Memorabilia) Update(ctx context.Context, id string, formItem *schema.MemorabiliaForm) error {
|
||||||
|
memorabilia, err := a.MemorabiliaDAL.Get(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := formItem.FillTo(memorabilia); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
memorabilia.UpdatedAt = time.Now()
|
||||||
|
|
||||||
|
if err := a.MemorabiliaDAL.Update(ctx, memorabilia); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the specified role from the data access object.
|
||||||
|
func (a *Memorabilia) Delete(ctx context.Context, id string) error {
|
||||||
|
exists, err := a.MemorabiliaDAL.Exists(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if !exists {
|
||||||
|
return errors.NotFound("", "Role not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := a.MemorabiliaDAL.Delete(ctx, id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
515
internal/mods/rbac/biz/menu.biz.go
Normal file
515
internal/mods/rbac/biz/menu.biz.go
Normal file
@ -0,0 +1,515 @@
|
|||||||
|
package biz
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/config"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/dal"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/cachex"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/encoding/json"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/encoding/yaml"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/errors"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/logging"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Menu management for RBAC
|
||||||
|
type Menu struct {
|
||||||
|
Cache cachex.Cacher
|
||||||
|
Trans *util.Trans
|
||||||
|
MenuDAL *dal.Menu
|
||||||
|
MenuResourceDAL *dal.MenuResource
|
||||||
|
RoleMenuDAL *dal.RoleMenu
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Menu) InitFromFile(ctx context.Context, menuFile string) error {
|
||||||
|
f, err := os.ReadFile(menuFile)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, os.ErrNotExist) {
|
||||||
|
logging.Context(ctx).Warn("Menu data file not found, skip init menu data from file", zap.String("file", menuFile))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var menus schema.Menus
|
||||||
|
if ext := filepath.Ext(menuFile); ext == ".json" {
|
||||||
|
if err := json.Unmarshal(f, &menus); err != nil {
|
||||||
|
return errors.Wrapf(err, "Unmarshal JSON file '%s' failed", menuFile)
|
||||||
|
}
|
||||||
|
} else if ext == ".yaml" || ext == ".yml" {
|
||||||
|
if err := yaml.Unmarshal(f, &menus); err != nil {
|
||||||
|
return errors.Wrapf(err, "Unmarshal YAML file '%s' failed", menuFile)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return errors.Errorf("Unsupported file type '%s'", ext)
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.Trans.Exec(ctx, func(ctx context.Context) error {
|
||||||
|
return a.createInBatchByParent(ctx, menus, nil)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Menu) createInBatchByParent(ctx context.Context, items schema.Menus, parent *schema.Menu) error {
|
||||||
|
total := len(items)
|
||||||
|
|
||||||
|
for i, item := range items {
|
||||||
|
var parentID string
|
||||||
|
if parent != nil {
|
||||||
|
parentID = parent.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
menuItem *schema.Menu
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
if item.ID != "" {
|
||||||
|
menuItem, err = a.MenuDAL.Get(ctx, item.ID)
|
||||||
|
} else if item.Code != "" {
|
||||||
|
menuItem, err = a.MenuDAL.GetByCodeAndParentID(ctx, item.Code, parentID)
|
||||||
|
} else if item.Name != "" {
|
||||||
|
menuItem, err = a.MenuDAL.GetByNameAndParentID(ctx, item.Name, parentID)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if item.Status == "" {
|
||||||
|
item.Status = schema.MenuStatusEnabled
|
||||||
|
}
|
||||||
|
|
||||||
|
if menuItem != nil {
|
||||||
|
changed := false
|
||||||
|
if menuItem.Name != item.Name {
|
||||||
|
menuItem.Name = item.Name
|
||||||
|
changed = true
|
||||||
|
}
|
||||||
|
if menuItem.Description != item.Description {
|
||||||
|
menuItem.Description = item.Description
|
||||||
|
changed = true
|
||||||
|
}
|
||||||
|
if menuItem.Path != item.Path {
|
||||||
|
menuItem.Path = item.Path
|
||||||
|
changed = true
|
||||||
|
}
|
||||||
|
if menuItem.Type != item.Type {
|
||||||
|
menuItem.Type = item.Type
|
||||||
|
changed = true
|
||||||
|
}
|
||||||
|
if menuItem.Sequence != item.Sequence {
|
||||||
|
menuItem.Sequence = item.Sequence
|
||||||
|
changed = true
|
||||||
|
}
|
||||||
|
if menuItem.Status != item.Status {
|
||||||
|
menuItem.Status = item.Status
|
||||||
|
changed = true
|
||||||
|
}
|
||||||
|
if changed {
|
||||||
|
menuItem.UpdatedAt = time.Now()
|
||||||
|
if err := a.MenuDAL.Update(ctx, menuItem); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if item.ID == "" {
|
||||||
|
item.ID = util.NewXID()
|
||||||
|
}
|
||||||
|
if item.Sequence == 0 {
|
||||||
|
item.Sequence = total - i
|
||||||
|
}
|
||||||
|
item.ParentID = parentID
|
||||||
|
if parent != nil {
|
||||||
|
item.ParentPath = parent.ParentPath + parentID + util.TreePathDelimiter
|
||||||
|
}
|
||||||
|
menuItem = item
|
||||||
|
if err := a.MenuDAL.Create(ctx, item); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, res := range item.Resources {
|
||||||
|
if res.ID != "" {
|
||||||
|
exists, err := a.MenuResourceDAL.Exists(ctx, res.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if exists {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.Path != "" {
|
||||||
|
exists, err := a.MenuResourceDAL.ExistsMethodPathByMenuID(ctx, res.Method, res.Path, menuItem.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if exists {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if res.ID == "" {
|
||||||
|
res.ID = util.NewXID()
|
||||||
|
}
|
||||||
|
res.MenuID = menuItem.ID
|
||||||
|
if err := a.MenuResourceDAL.Create(ctx, res); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if item.Children != nil {
|
||||||
|
if err := a.createInBatchByParent(ctx, *item.Children, menuItem); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query menus from the data access object based on the provided parameters and options.
|
||||||
|
func (a *Menu) Query(ctx context.Context, params schema.MenuQueryParam) (*schema.MenuQueryResult, error) {
|
||||||
|
params.Pagination = false
|
||||||
|
|
||||||
|
if err := a.fillQueryParam(ctx, ¶ms); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := a.MenuDAL.Query(ctx, params, schema.MenuQueryOptions{
|
||||||
|
QueryOptions: util.QueryOptions{
|
||||||
|
OrderFields: schema.MenusOrderParams,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.LikeName != "" || params.CodePath != "" {
|
||||||
|
result.Data, err = a.appendChildren(ctx, result.Data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.IncludeResources {
|
||||||
|
for i, item := range result.Data {
|
||||||
|
resResult, err := a.MenuResourceDAL.Query(ctx, schema.MenuResourceQueryParam{
|
||||||
|
MenuID: item.ID,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.Data[i].Resources = resResult.Data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Data = result.Data.ToTree()
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Menu) fillQueryParam(ctx context.Context, params *schema.MenuQueryParam) error {
|
||||||
|
if params.CodePath != "" {
|
||||||
|
var (
|
||||||
|
codes []string
|
||||||
|
lastMenu schema.Menu
|
||||||
|
)
|
||||||
|
for _, code := range strings.Split(params.CodePath, util.TreePathDelimiter) {
|
||||||
|
if code == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
codes = append(codes, code)
|
||||||
|
menu, err := a.MenuDAL.GetByCodeAndParentID(ctx, code, lastMenu.ParentID, schema.MenuQueryOptions{
|
||||||
|
QueryOptions: util.QueryOptions{
|
||||||
|
SelectFields: []string{"id", "parent_id", "parent_path"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if menu == nil {
|
||||||
|
return errors.NotFound("", "Menu not found by code '%s'", strings.Join(codes, util.TreePathDelimiter))
|
||||||
|
}
|
||||||
|
lastMenu = *menu
|
||||||
|
}
|
||||||
|
params.ParentPathPrefix = lastMenu.ParentPath + lastMenu.ID + util.TreePathDelimiter
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Menu) appendChildren(ctx context.Context, data schema.Menus) (schema.Menus, error) {
|
||||||
|
if len(data) == 0 {
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
existsInData := func(id string) bool {
|
||||||
|
for _, item := range data {
|
||||||
|
if item.ID == id {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, item := range data {
|
||||||
|
childResult, err := a.MenuDAL.Query(ctx, schema.MenuQueryParam{
|
||||||
|
ParentPathPrefix: item.ParentPath + item.ID + util.TreePathDelimiter,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, child := range childResult.Data {
|
||||||
|
if existsInData(child.ID) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
data = append(data, child)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if parentIDs := data.SplitParentIDs(); len(parentIDs) > 0 {
|
||||||
|
parentResult, err := a.MenuDAL.Query(ctx, schema.MenuQueryParam{
|
||||||
|
InIDs: parentIDs,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, p := range parentResult.Data {
|
||||||
|
if existsInData(p.ID) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
data = append(data, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort.Sort(data)
|
||||||
|
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the specified menu from the data access object.
|
||||||
|
func (a *Menu) Get(ctx context.Context, id string) (*schema.Menu, error) {
|
||||||
|
menu, err := a.MenuDAL.Get(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if menu == nil {
|
||||||
|
return nil, errors.NotFound("", "Menu not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
menuResResult, err := a.MenuResourceDAL.Query(ctx, schema.MenuResourceQueryParam{
|
||||||
|
MenuID: menu.ID,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
menu.Resources = menuResResult.Data
|
||||||
|
|
||||||
|
return menu, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new menu in the data access object.
|
||||||
|
func (a *Menu) Create(ctx context.Context, formItem *schema.MenuForm) (*schema.Menu, error) {
|
||||||
|
if config.C.General.DenyOperateMenu {
|
||||||
|
return nil, errors.BadRequest("", "Menu creation is not allowed")
|
||||||
|
}
|
||||||
|
|
||||||
|
menu := &schema.Menu{
|
||||||
|
ID: util.NewXID(),
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if parentID := formItem.ParentID; parentID != "" {
|
||||||
|
parent, err := a.MenuDAL.Get(ctx, parentID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if parent == nil {
|
||||||
|
return nil, errors.NotFound("", "Parent not found")
|
||||||
|
}
|
||||||
|
menu.ParentPath = parent.ParentPath + parent.ID + util.TreePathDelimiter
|
||||||
|
}
|
||||||
|
|
||||||
|
if exists, err := a.MenuDAL.ExistsCodeByParentID(ctx, formItem.Code, formItem.ParentID); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if exists {
|
||||||
|
return nil, errors.BadRequest("", "Menu code already exists at the same level")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := formItem.FillTo(menu); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err := a.Trans.Exec(ctx, func(ctx context.Context) error {
|
||||||
|
if err := a.MenuDAL.Create(ctx, menu); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, res := range formItem.Resources {
|
||||||
|
res.ID = util.NewXID()
|
||||||
|
res.MenuID = menu.ID
|
||||||
|
res.CreatedAt = time.Now()
|
||||||
|
if err := a.MenuResourceDAL.Create(ctx, res); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return menu, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the specified menu in the data access object.
|
||||||
|
func (a *Menu) Update(ctx context.Context, id string, formItem *schema.MenuForm) error {
|
||||||
|
if config.C.General.DenyOperateMenu {
|
||||||
|
return errors.BadRequest("", "Menu update is not allowed")
|
||||||
|
}
|
||||||
|
|
||||||
|
menu, err := a.MenuDAL.Get(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if menu == nil {
|
||||||
|
return errors.NotFound("", "Menu not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
oldParentPath := menu.ParentPath
|
||||||
|
oldStatus := menu.Status
|
||||||
|
var childData schema.Menus
|
||||||
|
if menu.ParentID != formItem.ParentID {
|
||||||
|
if parentID := formItem.ParentID; parentID != "" {
|
||||||
|
parent, err := a.MenuDAL.Get(ctx, parentID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if parent == nil {
|
||||||
|
return errors.NotFound("", "Parent not found")
|
||||||
|
}
|
||||||
|
menu.ParentPath = parent.ParentPath + parent.ID + util.TreePathDelimiter
|
||||||
|
} else {
|
||||||
|
menu.ParentPath = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
childResult, err := a.MenuDAL.Query(ctx, schema.MenuQueryParam{
|
||||||
|
ParentPathPrefix: oldParentPath + menu.ID + util.TreePathDelimiter,
|
||||||
|
}, schema.MenuQueryOptions{
|
||||||
|
QueryOptions: util.QueryOptions{
|
||||||
|
SelectFields: []string{"id", "parent_path"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
childData = childResult.Data
|
||||||
|
}
|
||||||
|
|
||||||
|
if menu.Code != formItem.Code {
|
||||||
|
if exists, err := a.MenuDAL.ExistsCodeByParentID(ctx, formItem.Code, formItem.ParentID); err != nil {
|
||||||
|
return err
|
||||||
|
} else if exists {
|
||||||
|
return errors.BadRequest("", "Menu code already exists at the same level")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := formItem.FillTo(menu); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.Trans.Exec(ctx, func(ctx context.Context) error {
|
||||||
|
if oldStatus != formItem.Status {
|
||||||
|
oldPath := oldParentPath + menu.ID + util.TreePathDelimiter
|
||||||
|
if err := a.MenuDAL.UpdateStatusByParentPath(ctx, oldPath, formItem.Status); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, child := range childData {
|
||||||
|
oldPath := oldParentPath + menu.ID + util.TreePathDelimiter
|
||||||
|
newPath := menu.ParentPath + menu.ID + util.TreePathDelimiter
|
||||||
|
err := a.MenuDAL.UpdateParentPath(ctx, child.ID, strings.Replace(child.ParentPath, oldPath, newPath, 1))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := a.MenuDAL.Update(ctx, menu); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := a.MenuResourceDAL.DeleteByMenuID(ctx, id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, res := range formItem.Resources {
|
||||||
|
if res.ID == "" {
|
||||||
|
res.ID = util.NewXID()
|
||||||
|
}
|
||||||
|
res.MenuID = id
|
||||||
|
if res.CreatedAt.IsZero() {
|
||||||
|
res.CreatedAt = time.Now()
|
||||||
|
}
|
||||||
|
res.UpdatedAt = time.Now()
|
||||||
|
if err := a.MenuResourceDAL.Create(ctx, res); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.syncToCasbin(ctx)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the specified menu from the data access object.
|
||||||
|
func (a *Menu) Delete(ctx context.Context, id string) error {
|
||||||
|
if config.C.General.DenyOperateMenu {
|
||||||
|
return errors.BadRequest("", "Menu deletion is not allowed")
|
||||||
|
}
|
||||||
|
|
||||||
|
menu, err := a.MenuDAL.Get(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if menu == nil {
|
||||||
|
return errors.NotFound("", "Menu not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
childResult, err := a.MenuDAL.Query(ctx, schema.MenuQueryParam{
|
||||||
|
ParentPathPrefix: menu.ParentPath + menu.ID + util.TreePathDelimiter,
|
||||||
|
}, schema.MenuQueryOptions{
|
||||||
|
QueryOptions: util.QueryOptions{
|
||||||
|
SelectFields: []string{"id"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.Trans.Exec(ctx, func(ctx context.Context) error {
|
||||||
|
if err := a.delete(ctx, id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, child := range childResult.Data {
|
||||||
|
if err := a.delete(ctx, child.ID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.syncToCasbin(ctx)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Menu) delete(ctx context.Context, id string) error {
|
||||||
|
if err := a.MenuDAL.Delete(ctx, id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := a.MenuResourceDAL.DeleteByMenuID(ctx, id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := a.RoleMenuDAL.DeleteByMenuID(ctx, id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Menu) syncToCasbin(ctx context.Context) error {
|
||||||
|
return a.Cache.Set(ctx, config.CacheNSForRole, config.CacheKeyForSyncToCasbin, fmt.Sprintf("%d", time.Now().Unix()))
|
||||||
|
}
|
||||||
102
internal/mods/rbac/biz/product.biz.go
Normal file
102
internal/mods/rbac/biz/product.biz.go
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
package biz
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/dal"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/cachex"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/errors"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Product struct {
|
||||||
|
Cache cachex.Cacher
|
||||||
|
Trans *util.Trans
|
||||||
|
ProductDAL *dal.Product
|
||||||
|
ProductCategoryDAL *dal.ProductCategory
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Product) QueryProductCategory(ctx context.Context) (*[]schema.ProductCategory, error) {
|
||||||
|
query, err := a.ProductCategoryDAL.Query(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return query, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Product) Query(ctx context.Context, params schema.ProductQueryParam) (*schema.ProductQueryResult, error) {
|
||||||
|
params.Pagination = true
|
||||||
|
result, err := a.ProductDAL.Query(ctx, params, schema.ProductQueryOptions{
|
||||||
|
QueryOptions: util.QueryOptions{
|
||||||
|
OrderFields: []util.OrderByParam{
|
||||||
|
{Field: "sequence", Direction: util.DESC},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Product) Get(ctx context.Context, id string) (*schema.Product, error) {
|
||||||
|
product, err := a.ProductDAL.Get(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if product == nil {
|
||||||
|
return nil, errors.NotFound("", "Banner not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return product, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Product) Create(ctx context.Context, formItem *schema.ProductForm) (*schema.Product, error) {
|
||||||
|
|
||||||
|
product := &schema.Product{
|
||||||
|
ID: util.NewXID(),
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
}
|
||||||
|
if err := formItem.FillTo(product); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := a.ProductDAL.Create(ctx, product); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return product, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Product) Update(ctx context.Context, id string, formItem *schema.ProductForm) error {
|
||||||
|
product, err := a.ProductDAL.Get(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := formItem.FillTo(product); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
product.UpdatedAt = time.Now()
|
||||||
|
|
||||||
|
if err := a.ProductDAL.Update(ctx, product); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Product) Delete(ctx context.Context, id string) error {
|
||||||
|
exists, err := a.ProductDAL.Exists(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if !exists {
|
||||||
|
return errors.NotFound("", "Role not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := a.ProductDAL.Delete(ctx, id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
179
internal/mods/rbac/biz/role.biz.go
Normal file
179
internal/mods/rbac/biz/role.biz.go
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
package biz
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/config"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/dal"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/cachex"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/errors"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Role management for RBAC
|
||||||
|
type Role struct {
|
||||||
|
Cache cachex.Cacher
|
||||||
|
Trans *util.Trans
|
||||||
|
RoleDAL *dal.Role
|
||||||
|
RoleMenuDAL *dal.RoleMenu
|
||||||
|
UserRoleDAL *dal.UserRole
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query roles from the data access object based on the provided parameters and options.
|
||||||
|
func (a *Role) Query(ctx context.Context, params schema.RoleQueryParam) (*schema.RoleQueryResult, error) {
|
||||||
|
params.Pagination = true
|
||||||
|
|
||||||
|
var selectFields []string
|
||||||
|
if params.ResultType == schema.RoleResultTypeSelect {
|
||||||
|
params.Pagination = false
|
||||||
|
selectFields = []string{"id", "name"}
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := a.RoleDAL.Query(ctx, params, schema.RoleQueryOptions{
|
||||||
|
QueryOptions: util.QueryOptions{
|
||||||
|
OrderFields: []util.OrderByParam{
|
||||||
|
{Field: "sequence", Direction: util.DESC},
|
||||||
|
{Field: "created_at", Direction: util.DESC},
|
||||||
|
},
|
||||||
|
SelectFields: selectFields,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the specified role from the data access object.
|
||||||
|
func (a *Role) Get(ctx context.Context, id string) (*schema.Role, error) {
|
||||||
|
role, err := a.RoleDAL.Get(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if role == nil {
|
||||||
|
return nil, errors.NotFound("", "Role not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
roleMenuResult, err := a.RoleMenuDAL.Query(ctx, schema.RoleMenuQueryParam{
|
||||||
|
RoleID: id,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
role.Menus = roleMenuResult.Data
|
||||||
|
|
||||||
|
return role, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new role in the data access object.
|
||||||
|
func (a *Role) Create(ctx context.Context, formItem *schema.RoleForm) (*schema.Role, error) {
|
||||||
|
if exists, err := a.RoleDAL.ExistsCode(ctx, formItem.Code); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if exists {
|
||||||
|
return nil, errors.BadRequest("", "Role code already exists")
|
||||||
|
}
|
||||||
|
|
||||||
|
role := &schema.Role{
|
||||||
|
ID: util.NewXID(),
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
}
|
||||||
|
if err := formItem.FillTo(role); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err := a.Trans.Exec(ctx, func(ctx context.Context) error {
|
||||||
|
if err := a.RoleDAL.Create(ctx, role); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, roleMenu := range formItem.Menus {
|
||||||
|
roleMenu.ID = util.NewXID()
|
||||||
|
roleMenu.RoleID = role.ID
|
||||||
|
roleMenu.CreatedAt = time.Now()
|
||||||
|
if err := a.RoleMenuDAL.Create(ctx, roleMenu); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return a.syncToCasbin(ctx)
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
role.Menus = formItem.Menus
|
||||||
|
|
||||||
|
return role, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the specified role in the data access object.
|
||||||
|
func (a *Role) Update(ctx context.Context, id string, formItem *schema.RoleForm) error {
|
||||||
|
role, err := a.RoleDAL.Get(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if role == nil {
|
||||||
|
return errors.NotFound("", "Role not found")
|
||||||
|
} else if role.Code != formItem.Code {
|
||||||
|
if exists, err := a.RoleDAL.ExistsCode(ctx, formItem.Code); err != nil {
|
||||||
|
return err
|
||||||
|
} else if exists {
|
||||||
|
return errors.BadRequest("", "Role code already exists")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := formItem.FillTo(role); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
role.UpdatedAt = time.Now()
|
||||||
|
|
||||||
|
return a.Trans.Exec(ctx, func(ctx context.Context) error {
|
||||||
|
if err := a.RoleDAL.Update(ctx, role); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := a.RoleMenuDAL.DeleteByRoleID(ctx, id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, roleMenu := range formItem.Menus {
|
||||||
|
if roleMenu.ID == "" {
|
||||||
|
roleMenu.ID = util.NewXID()
|
||||||
|
}
|
||||||
|
roleMenu.RoleID = role.ID
|
||||||
|
if roleMenu.CreatedAt.IsZero() {
|
||||||
|
roleMenu.CreatedAt = time.Now()
|
||||||
|
}
|
||||||
|
roleMenu.UpdatedAt = time.Now()
|
||||||
|
if err := a.RoleMenuDAL.Create(ctx, roleMenu); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return a.syncToCasbin(ctx)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the specified role from the data access object.
|
||||||
|
func (a *Role) Delete(ctx context.Context, id string) error {
|
||||||
|
exists, err := a.RoleDAL.Exists(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if !exists {
|
||||||
|
return errors.NotFound("", "Role not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.Trans.Exec(ctx, func(ctx context.Context) error {
|
||||||
|
if err := a.RoleDAL.Delete(ctx, id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := a.RoleMenuDAL.DeleteByRoleID(ctx, id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := a.UserRoleDAL.DeleteByRoleID(ctx, id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.syncToCasbin(ctx)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Role) syncToCasbin(ctx context.Context) error {
|
||||||
|
return a.Cache.Set(ctx, config.CacheNSForRole, config.CacheKeyForSyncToCasbin, fmt.Sprintf("%d", time.Now().Unix()))
|
||||||
|
}
|
||||||
94
internal/mods/rbac/biz/team.biz.go
Normal file
94
internal/mods/rbac/biz/team.biz.go
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
package biz
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/dal"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/cachex"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/errors"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Team struct {
|
||||||
|
Cache cachex.Cacher
|
||||||
|
Trans *util.Trans
|
||||||
|
TeamDAL *dal.Team
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Team) Query(ctx context.Context, params schema.TeamQueryParam) (*schema.TeamQueryResult, error) {
|
||||||
|
params.Pagination = true
|
||||||
|
result, err := a.TeamDAL.Query(ctx, params, schema.TeamQueryOptions{
|
||||||
|
QueryOptions: util.QueryOptions{
|
||||||
|
OrderFields: []util.OrderByParam{
|
||||||
|
{Field: "sequence", Direction: util.DESC},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the specified role from the data access object.
|
||||||
|
func (a *Team) Get(ctx context.Context, id string) (*schema.Team, error) {
|
||||||
|
item, err := a.TeamDAL.Get(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if item == nil {
|
||||||
|
return nil, errors.NotFound("", "Banner not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return item, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Team) Create(ctx context.Context, formItem *schema.TeamForm) (*schema.Team, error) {
|
||||||
|
|
||||||
|
team := &schema.Team{
|
||||||
|
ID: util.NewXID(),
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
}
|
||||||
|
if err := formItem.FillTo(team); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := a.TeamDAL.Create(ctx, team); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return team, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Team) Update(ctx context.Context, id string, formItem *schema.TeamForm) error {
|
||||||
|
team, err := a.TeamDAL.Get(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := formItem.FillTo(team); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
team.UpdatedAt = time.Now()
|
||||||
|
|
||||||
|
if err := a.TeamDAL.Update(ctx, team); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Team) Delete(ctx context.Context, id string) error {
|
||||||
|
exists, err := a.TeamDAL.Exists(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if !exists {
|
||||||
|
return errors.NotFound("", "Role not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := a.TeamDAL.Delete(ctx, id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
54
internal/mods/rbac/biz/upload.biz.go
Normal file
54
internal/mods/rbac/biz/upload.biz.go
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
package biz
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"github.com/guxuan/hailin_service/internal/config"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/cachex"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
"io"
|
||||||
|
"mime/multipart"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Role management for RBAC
|
||||||
|
type Upload struct {
|
||||||
|
Cache cachex.Cacher
|
||||||
|
Trans *util.Trans
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Upload) SaveFile(ctx context.Context, file *multipart.FileHeader) (string, error) {
|
||||||
|
ext := strings.ToLower(filepath.Ext(file.Filename))
|
||||||
|
// 简单过滤危险扩展名
|
||||||
|
blacklist := []string{".exe", ".bat", ".sh", ".php", ".js"}
|
||||||
|
for _, b := range blacklist {
|
||||||
|
if ext == b {
|
||||||
|
return "", fmt.Errorf("不支持的文件类型: %s", ext)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 确保上传目录存在
|
||||||
|
if err := os.MkdirAll(config.C.FileConfig.UploadDir, os.ModePerm); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
// 构造保存路径
|
||||||
|
dstPath := filepath.Join(config.C.FileConfig.UploadDir, file.Filename)
|
||||||
|
// 打开源文件
|
||||||
|
srcFile, err := file.Open()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer srcFile.Close()
|
||||||
|
// 在目标位置创建文件
|
||||||
|
outFile, err := os.Create(dstPath)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer outFile.Close()
|
||||||
|
// 复制内容
|
||||||
|
if _, err := io.Copy(outFile, srcFile); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return file.Filename, nil
|
||||||
|
}
|
||||||
227
internal/mods/rbac/biz/user.biz.go
Normal file
227
internal/mods/rbac/biz/user.biz.go
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
package biz
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/config"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/dal"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/cachex"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/crypto/hash"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/errors"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// User management for RBAC
|
||||||
|
type User struct {
|
||||||
|
Cache cachex.Cacher
|
||||||
|
Trans *util.Trans
|
||||||
|
UserDAL *dal.User
|
||||||
|
UserRoleDAL *dal.UserRole
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query users from the data access object based on the provided parameters and options.
|
||||||
|
func (a *User) Query(ctx context.Context, params schema.UserQueryParam) (*schema.UserQueryResult, error) {
|
||||||
|
params.Pagination = true
|
||||||
|
|
||||||
|
result, err := a.UserDAL.Query(ctx, params, schema.UserQueryOptions{
|
||||||
|
QueryOptions: util.QueryOptions{
|
||||||
|
OrderFields: []util.OrderByParam{
|
||||||
|
{Field: "created_at", Direction: util.DESC},
|
||||||
|
},
|
||||||
|
OmitFields: []string{"password"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if userIDs := result.Data.ToIDs(); len(userIDs) > 0 {
|
||||||
|
userRoleResult, err := a.UserRoleDAL.Query(ctx, schema.UserRoleQueryParam{
|
||||||
|
InUserIDs: userIDs,
|
||||||
|
}, schema.UserRoleQueryOptions{
|
||||||
|
JoinRole: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
userRolesMap := userRoleResult.Data.ToUserIDMap()
|
||||||
|
for _, user := range result.Data {
|
||||||
|
user.Roles = userRolesMap[user.ID]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the specified user from the data access object.
|
||||||
|
func (a *User) Get(ctx context.Context, id string) (*schema.User, error) {
|
||||||
|
user, err := a.UserDAL.Get(ctx, id, schema.UserQueryOptions{
|
||||||
|
QueryOptions: util.QueryOptions{
|
||||||
|
OmitFields: []string{"password"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if user == nil {
|
||||||
|
return nil, errors.NotFound("", "User not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
userRoleResult, err := a.UserRoleDAL.Query(ctx, schema.UserRoleQueryParam{
|
||||||
|
UserID: id,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
user.Roles = userRoleResult.Data
|
||||||
|
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new user in the data access object.
|
||||||
|
func (a *User) Create(ctx context.Context, formItem *schema.UserForm) (*schema.User, error) {
|
||||||
|
existsUsername, err := a.UserDAL.ExistsUsername(ctx, formItem.Username)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if existsUsername {
|
||||||
|
return nil, errors.BadRequest("", "Username already exists")
|
||||||
|
}
|
||||||
|
|
||||||
|
user := &schema.User{
|
||||||
|
ID: util.NewXID(),
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if formItem.Password == "" {
|
||||||
|
formItem.Password = config.C.General.DefaultLoginPwd
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := formItem.FillTo(user); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = a.Trans.Exec(ctx, func(ctx context.Context) error {
|
||||||
|
if err := a.UserDAL.Create(ctx, user); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, userRole := range formItem.Roles {
|
||||||
|
userRole.ID = util.NewXID()
|
||||||
|
userRole.UserID = user.ID
|
||||||
|
userRole.CreatedAt = time.Now()
|
||||||
|
if err := a.UserRoleDAL.Create(ctx, userRole); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
user.Roles = formItem.Roles
|
||||||
|
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the specified user in the data access object.
|
||||||
|
func (a *User) Update(ctx context.Context, id string, formItem *schema.UserForm) error {
|
||||||
|
user, err := a.UserDAL.Get(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if user == nil {
|
||||||
|
return errors.NotFound("", "User not found")
|
||||||
|
} else if user.Username != formItem.Username {
|
||||||
|
existsUsername, err := a.UserDAL.ExistsUsername(ctx, formItem.Username)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if existsUsername {
|
||||||
|
return errors.BadRequest("", "Username already exists")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := formItem.FillTo(user); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
user.UpdatedAt = time.Now()
|
||||||
|
|
||||||
|
return a.Trans.Exec(ctx, func(ctx context.Context) error {
|
||||||
|
if err := a.UserDAL.Update(ctx, user); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := a.UserRoleDAL.DeleteByUserID(ctx, id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, userRole := range formItem.Roles {
|
||||||
|
if userRole.ID == "" {
|
||||||
|
userRole.ID = util.NewXID()
|
||||||
|
}
|
||||||
|
userRole.UserID = user.ID
|
||||||
|
if userRole.CreatedAt.IsZero() {
|
||||||
|
userRole.CreatedAt = time.Now()
|
||||||
|
}
|
||||||
|
userRole.UpdatedAt = time.Now()
|
||||||
|
if err := a.UserRoleDAL.Create(ctx, userRole); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.Cache.Delete(ctx, config.CacheNSForUser, id)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the specified user from the data access object.
|
||||||
|
func (a *User) Delete(ctx context.Context, id string) error {
|
||||||
|
exists, err := a.UserDAL.Exists(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if !exists {
|
||||||
|
return errors.NotFound("", "User not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.Trans.Exec(ctx, func(ctx context.Context) error {
|
||||||
|
if err := a.UserDAL.Delete(ctx, id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := a.UserRoleDAL.DeleteByUserID(ctx, id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return a.Cache.Delete(ctx, config.CacheNSForUser, id)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *User) ResetPassword(ctx context.Context, id string) error {
|
||||||
|
exists, err := a.UserDAL.Exists(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if !exists {
|
||||||
|
return errors.NotFound("", "User not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
hashPass, err := hash.GeneratePassword(config.C.General.DefaultLoginPwd)
|
||||||
|
if err != nil {
|
||||||
|
return errors.BadRequest("", "Failed to generate hash password: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.Trans.Exec(ctx, func(ctx context.Context) error {
|
||||||
|
if err := a.UserDAL.UpdatePasswordByID(ctx, id, hashPass); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *User) GetRoleIDs(ctx context.Context, id string) ([]string, error) {
|
||||||
|
userRoleResult, err := a.UserRoleDAL.Query(ctx, schema.UserRoleQueryParam{
|
||||||
|
UserID: id,
|
||||||
|
}, schema.UserRoleQueryOptions{
|
||||||
|
QueryOptions: util.QueryOptions{
|
||||||
|
SelectFields: []string{"role_id"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return userRoleResult.Data.ToRoleIDs(), nil
|
||||||
|
}
|
||||||
99
internal/mods/rbac/biz/video.biz.go
Normal file
99
internal/mods/rbac/biz/video.biz.go
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
package biz
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/dal"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/cachex"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/errors"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Role management for RBAC
|
||||||
|
type Video struct {
|
||||||
|
Cache cachex.Cacher
|
||||||
|
Trans *util.Trans
|
||||||
|
VideoDAL *dal.Video
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query roles from the data access object based on the provided parameters and options.
|
||||||
|
func (a *Video) Query(ctx context.Context, params schema.VideoQueryParam) (*schema.VideoQueryResult, error) {
|
||||||
|
params.Pagination = true
|
||||||
|
result, err := a.VideoDAL.Query(ctx, params, schema.VideoQueryOptions{
|
||||||
|
QueryOptions: util.QueryOptions{
|
||||||
|
OrderFields: []util.OrderByParam{
|
||||||
|
{Field: "sequence", Direction: util.DESC},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the specified role from the data access object.
|
||||||
|
func (a *Video) Get(ctx context.Context, id string) (*schema.Video, error) {
|
||||||
|
video, err := a.VideoDAL.Get(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if video == nil {
|
||||||
|
return nil, errors.NotFound("", "Banner not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return video, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new role in the data access object.
|
||||||
|
func (a *Video) Create(ctx context.Context, formItem *schema.VideoForm) (*schema.Video, error) {
|
||||||
|
|
||||||
|
video := &schema.Video{
|
||||||
|
ID: util.NewXID(),
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
}
|
||||||
|
if err := formItem.FillTo(video); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := a.VideoDAL.Create(ctx, video); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return video, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the specified role in the data access object.
|
||||||
|
func (a *Video) Update(ctx context.Context, id string, formItem *schema.VideoForm) error {
|
||||||
|
video, err := a.VideoDAL.Get(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := formItem.FillTo(video); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
video.UpdatedAt = time.Now()
|
||||||
|
|
||||||
|
if err := a.VideoDAL.Update(ctx, video); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the specified role from the data access object.
|
||||||
|
func (a *Video) Delete(ctx context.Context, id string) error {
|
||||||
|
exists, err := a.VideoDAL.Exists(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if !exists {
|
||||||
|
return errors.NotFound("", "Role not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := a.VideoDAL.Delete(ctx, id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
63
internal/mods/rbac/biz/webSite.biz.go
Normal file
63
internal/mods/rbac/biz/webSite.biz.go
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
package biz
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/dal"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/cachex"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Role management for RBAC
|
||||||
|
type WebSite struct {
|
||||||
|
Cache cachex.Cacher
|
||||||
|
Trans *util.Trans
|
||||||
|
WebSiteDAL *dal.WebSite
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query roles from the data access object based on the provided parameters and options.
|
||||||
|
func (a *WebSite) Query(ctx context.Context) (*schema.WebSite, error) {
|
||||||
|
result, err := a.WebSiteDAL.Query(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new role in the data access object.
|
||||||
|
func (a *WebSite) Create(ctx context.Context, formItem *schema.WebSiteForm) (*schema.WebSite, error) {
|
||||||
|
|
||||||
|
item := &schema.WebSite{
|
||||||
|
ID: util.NewXID(),
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
}
|
||||||
|
if err := formItem.FillTo(item); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := a.WebSiteDAL.Create(ctx, item); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return item, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the specified role in the data access object.
|
||||||
|
func (a *WebSite) Update(ctx context.Context, id string, formItem *schema.WebSiteForm) error {
|
||||||
|
article, err := a.WebSiteDAL.Get(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := formItem.FillTo(article); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
article.UpdatedAt = time.Now()
|
||||||
|
|
||||||
|
if err := a.WebSiteDAL.Update(ctx, article); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
222
internal/mods/rbac/casbin.go
Normal file
222
internal/mods/rbac/casbin.go
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
package rbac
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/config"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/dal"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/cachex"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/logging"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
"github.com/casbin/casbin/v2"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Load rbac permissions to casbin
|
||||||
|
type Casbinx struct {
|
||||||
|
enforcer *atomic.Value `wire:"-"`
|
||||||
|
ticker *time.Ticker `wire:"-"`
|
||||||
|
Cache cachex.Cacher
|
||||||
|
MenuDAL *dal.Menu
|
||||||
|
MenuResourceDAL *dal.MenuResource
|
||||||
|
RoleDAL *dal.Role
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Casbinx) GetEnforcer() *casbin.Enforcer {
|
||||||
|
if v := a.enforcer.Load(); v != nil {
|
||||||
|
return v.(*casbin.Enforcer)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type policyQueueItem struct {
|
||||||
|
RoleID string
|
||||||
|
Resources schema.MenuResources
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Casbinx) Load(ctx context.Context) error {
|
||||||
|
if config.C.Middleware.Casbin.Disable {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
a.enforcer = new(atomic.Value)
|
||||||
|
if err := a.load(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
go a.autoLoad(ctx)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Casbinx) load(ctx context.Context) error {
|
||||||
|
start := time.Now()
|
||||||
|
roleResult, err := a.RoleDAL.Query(ctx, schema.RoleQueryParam{
|
||||||
|
Status: schema.RoleStatusEnabled,
|
||||||
|
}, schema.RoleQueryOptions{
|
||||||
|
QueryOptions: util.QueryOptions{SelectFields: []string{"id"}},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if len(roleResult.Data) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var resCount int32
|
||||||
|
queue := make(chan *policyQueueItem, len(roleResult.Data))
|
||||||
|
threadNum := config.C.Middleware.Casbin.LoadThread
|
||||||
|
lock := new(sync.Mutex)
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
|
||||||
|
wg := new(sync.WaitGroup)
|
||||||
|
wg.Add(threadNum)
|
||||||
|
for i := 0; i < threadNum; i++ {
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
ibuf := new(bytes.Buffer)
|
||||||
|
for item := range queue {
|
||||||
|
for _, res := range item.Resources {
|
||||||
|
_, _ = ibuf.WriteString(fmt.Sprintf("p, %s, %s, %s \n", item.RoleID, res.Path, res.Method))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lock.Lock()
|
||||||
|
_, _ = buf.Write(ibuf.Bytes())
|
||||||
|
lock.Unlock()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, item := range roleResult.Data {
|
||||||
|
resources, err := a.queryRoleResources(ctx, item.ID)
|
||||||
|
if err != nil {
|
||||||
|
logging.Context(ctx).Error("Failed to query role resources", zap.Error(err))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
atomic.AddInt32(&resCount, int32(len(resources)))
|
||||||
|
queue <- &policyQueueItem{
|
||||||
|
RoleID: item.ID,
|
||||||
|
Resources: resources,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(queue)
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
if buf.Len() > 0 {
|
||||||
|
policyFile := filepath.Join(config.C.General.WorkDir, config.C.Middleware.Casbin.GenPolicyFile)
|
||||||
|
_ = os.Rename(policyFile, policyFile+".bak")
|
||||||
|
_ = os.MkdirAll(filepath.Dir(policyFile), 0755)
|
||||||
|
if err := os.WriteFile(policyFile, buf.Bytes(), 0666); err != nil {
|
||||||
|
logging.Context(ctx).Error("Failed to write policy file", zap.Error(err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// set readonly
|
||||||
|
_ = os.Chmod(policyFile, 0444)
|
||||||
|
|
||||||
|
modelFile := filepath.Join(config.C.General.WorkDir, config.C.Middleware.Casbin.ModelFile)
|
||||||
|
e, err := casbin.NewEnforcer(modelFile, policyFile)
|
||||||
|
if err != nil {
|
||||||
|
logging.Context(ctx).Error("Failed to create casbin enforcer", zap.Error(err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
e.EnableLog(config.C.IsDebug())
|
||||||
|
a.enforcer.Store(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
logging.Context(ctx).Info("Casbin load policy",
|
||||||
|
zap.Duration("cost", time.Since(start)),
|
||||||
|
zap.Int("roles", len(roleResult.Data)),
|
||||||
|
zap.Int32("resources", resCount),
|
||||||
|
zap.Int("bytes", buf.Len()),
|
||||||
|
)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Casbinx) queryRoleResources(ctx context.Context, roleID string) (schema.MenuResources, error) {
|
||||||
|
menuResult, err := a.MenuDAL.Query(ctx, schema.MenuQueryParam{
|
||||||
|
RoleID: roleID,
|
||||||
|
Status: schema.MenuStatusEnabled,
|
||||||
|
}, schema.MenuQueryOptions{
|
||||||
|
QueryOptions: util.QueryOptions{
|
||||||
|
SelectFields: []string{"id", "parent_id", "parent_path"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if len(menuResult.Data) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
menuIDs := make([]string, 0, len(menuResult.Data))
|
||||||
|
menuIDMapper := make(map[string]struct{})
|
||||||
|
for _, item := range menuResult.Data {
|
||||||
|
if _, ok := menuIDMapper[item.ID]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
menuIDs = append(menuIDs, item.ID)
|
||||||
|
menuIDMapper[item.ID] = struct{}{}
|
||||||
|
if pp := item.ParentPath; pp != "" {
|
||||||
|
for _, pid := range strings.Split(pp, util.TreePathDelimiter) {
|
||||||
|
if pid == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _, ok := menuIDMapper[pid]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
menuIDs = append(menuIDs, pid)
|
||||||
|
menuIDMapper[pid] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
menuResourceResult, err := a.MenuResourceDAL.Query(ctx, schema.MenuResourceQueryParam{
|
||||||
|
MenuIDs: menuIDs,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return menuResourceResult.Data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Casbinx) autoLoad(ctx context.Context) {
|
||||||
|
var lastUpdated int64
|
||||||
|
a.ticker = time.NewTicker(time.Duration(config.C.Middleware.Casbin.AutoLoadInterval) * time.Second)
|
||||||
|
for range a.ticker.C {
|
||||||
|
val, ok, err := a.Cache.Get(ctx, config.CacheNSForRole, config.CacheKeyForSyncToCasbin)
|
||||||
|
if err != nil {
|
||||||
|
logging.Context(ctx).Error("Failed to get cache", zap.Error(err), zap.String("key", config.CacheKeyForSyncToCasbin))
|
||||||
|
continue
|
||||||
|
} else if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
updated, err := strconv.ParseInt(val, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
logging.Context(ctx).Error("Failed to parse cache value", zap.Error(err), zap.String("val", val))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if lastUpdated < updated {
|
||||||
|
if err := a.load(ctx); err != nil {
|
||||||
|
logging.Context(ctx).Error("Failed to load casbin policy", zap.Error(err))
|
||||||
|
} else {
|
||||||
|
lastUpdated = updated
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Casbinx) Release(ctx context.Context) error {
|
||||||
|
if a.ticker != nil {
|
||||||
|
a.ticker.Stop()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
89
internal/mods/rbac/dal/article.dal.go
Normal file
89
internal/mods/rbac/dal/article.dal.go
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
package dal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/errors"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetArticleDB(ctx context.Context, defDB *gorm.DB) *gorm.DB {
|
||||||
|
return util.GetDB(ctx, defDB).Model(new(schema.Article))
|
||||||
|
}
|
||||||
|
|
||||||
|
type Article struct {
|
||||||
|
DB *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query roles from the database based on the provided parameters and options.
|
||||||
|
func (a *Article) Query(ctx context.Context, params schema.ArticleQueryParam, opts ...schema.ArticleQueryOptions) (*schema.ArticleQueryResult, error) {
|
||||||
|
var opt schema.ArticleQueryOptions
|
||||||
|
if len(opts) > 0 {
|
||||||
|
opt = opts[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
db := GetArticleDB(ctx, a.DB)
|
||||||
|
|
||||||
|
if v := params.LikeTitle; len(v) > 0 {
|
||||||
|
db = db.Where("title LIKE ?", "%"+v+"%")
|
||||||
|
}
|
||||||
|
if v := params.Status; len(v) > 0 {
|
||||||
|
db = db.Where("status = ?", v)
|
||||||
|
}
|
||||||
|
if v := params.Typer; len(v) > 0 {
|
||||||
|
db = db.Where("type = ?", v)
|
||||||
|
}
|
||||||
|
var list schema.Articles
|
||||||
|
pageResult, err := util.WrapPageQuery(ctx, db, params.PaginationParam, opt.QueryOptions, &list)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
queryResult := &schema.ArticleQueryResult{
|
||||||
|
PageResult: pageResult,
|
||||||
|
Data: list,
|
||||||
|
}
|
||||||
|
return queryResult, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the specified role from the database.
|
||||||
|
func (a *Article) Get(ctx context.Context, id string, opts ...schema.ArticleQueryOptions) (*schema.Article, error) {
|
||||||
|
var opt schema.ArticleQueryOptions
|
||||||
|
if len(opts) > 0 {
|
||||||
|
opt = opts[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
item := new(schema.Article)
|
||||||
|
ok, err := util.FindOne(ctx, GetArticleDB(ctx, a.DB).Where("id=?", id), opt.QueryOptions, item)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
} else if !ok {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return item, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exist checks if the specified role exists in the database.
|
||||||
|
func (a *Article) Exists(ctx context.Context, id string) (bool, error) {
|
||||||
|
ok, err := util.Exists(ctx, GetArticleDB(ctx, a.DB).Where("id=?", id))
|
||||||
|
return ok, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new role.
|
||||||
|
func (a *Article) Create(ctx context.Context, item *schema.Article) error {
|
||||||
|
result := GetArticleDB(ctx, a.DB).Create(item)
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the specified role in the database.
|
||||||
|
func (a *Article) Update(ctx context.Context, item *schema.Article) error {
|
||||||
|
result := GetArticleDB(ctx, a.DB).Where("id=?", item.ID).Select("*").Omit("created_at").Updates(item)
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the specified role from the database.
|
||||||
|
func (a *Article) Delete(ctx context.Context, id string) error {
|
||||||
|
result := GetArticleDB(ctx, a.DB).Where("id=?", id).Delete(new(schema.Article))
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
88
internal/mods/rbac/dal/banner.dal.go
Normal file
88
internal/mods/rbac/dal/banner.dal.go
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
package dal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/errors"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetBannerDB(ctx context.Context, defDB *gorm.DB) *gorm.DB {
|
||||||
|
return util.GetDB(ctx, defDB).Model(new(schema.Banner))
|
||||||
|
}
|
||||||
|
|
||||||
|
type Banner struct {
|
||||||
|
DB *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query roles from the database based on the provided parameters and options.
|
||||||
|
func (a *Banner) Query(ctx context.Context, params schema.BannerQueryParam, opts ...schema.BannerQueryOptions) (*schema.BannerQueryResult, error) {
|
||||||
|
var opt schema.BannerQueryOptions
|
||||||
|
if len(opts) > 0 {
|
||||||
|
opt = opts[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
db := GetBannerDB(ctx, a.DB)
|
||||||
|
|
||||||
|
if v := params.LikeName; len(v) > 0 {
|
||||||
|
db = db.Where("name LIKE ?", "%"+v+"%")
|
||||||
|
}
|
||||||
|
if v := params.Status; len(v) > 0 {
|
||||||
|
db = db.Where("status = ?", v)
|
||||||
|
}
|
||||||
|
|
||||||
|
var list schema.Banners
|
||||||
|
pageResult, err := util.WrapPageQuery(ctx, db, params.PaginationParam, opt.QueryOptions, &list)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
queryResult := &schema.BannerQueryResult{
|
||||||
|
PageResult: pageResult,
|
||||||
|
Data: list,
|
||||||
|
}
|
||||||
|
return queryResult, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the specified role from the database.
|
||||||
|
func (a *Banner) Get(ctx context.Context, id string, opts ...schema.BannerQueryOptions) (*schema.Banner, error) {
|
||||||
|
var opt schema.BannerQueryOptions
|
||||||
|
if len(opts) > 0 {
|
||||||
|
opt = opts[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
item := new(schema.Banner)
|
||||||
|
ok, err := util.FindOne(ctx, GetBannerDB(ctx, a.DB).Where("id=?", id), opt.QueryOptions, item)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
} else if !ok {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return item, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exist checks if the specified role exists in the database.
|
||||||
|
func (a *Banner) Exists(ctx context.Context, id string) (bool, error) {
|
||||||
|
ok, err := util.Exists(ctx, GetBannerDB(ctx, a.DB).Where("id=?", id))
|
||||||
|
return ok, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new role.
|
||||||
|
func (a *Banner) Create(ctx context.Context, item *schema.Banner) error {
|
||||||
|
result := GetBannerDB(ctx, a.DB).Create(item)
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the specified role in the database.
|
||||||
|
func (a *Banner) Update(ctx context.Context, item *schema.Banner) error {
|
||||||
|
result := GetBannerDB(ctx, a.DB).Where("id=?", item.ID).Select("*").Omit("created_at").Updates(item)
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the specified role from the database.
|
||||||
|
func (a *Banner) Delete(ctx context.Context, id string) error {
|
||||||
|
result := GetBannerDB(ctx, a.DB).Where("id=?", id).Delete(new(schema.Banner))
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
83
internal/mods/rbac/dal/job.dal.go
Normal file
83
internal/mods/rbac/dal/job.dal.go
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
package dal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/errors"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetJobDB(ctx context.Context, defDB *gorm.DB) *gorm.DB {
|
||||||
|
return util.GetDB(ctx, defDB).Model(new(schema.Job))
|
||||||
|
}
|
||||||
|
|
||||||
|
type Job struct {
|
||||||
|
DB *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Job) Query(ctx context.Context, params schema.JobQueryParam, opts ...schema.JobQueryOptions) (*schema.JobQueryResult, error) {
|
||||||
|
var opt schema.JobQueryOptions
|
||||||
|
if len(opts) > 0 {
|
||||||
|
opt = opts[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
db := GetJobDB(ctx, a.DB)
|
||||||
|
|
||||||
|
if v := params.LikeTitle; len(v) > 0 {
|
||||||
|
db = db.Where("title LIKE ?", "%"+v+"%")
|
||||||
|
}
|
||||||
|
if v := params.Status; len(v) > 0 {
|
||||||
|
db = db.Where("status = ?", v)
|
||||||
|
}
|
||||||
|
if v := params.JobAreaID; len(v) > 0 {
|
||||||
|
db = db.Where("jobAreaId = ?", v)
|
||||||
|
}
|
||||||
|
var list schema.Jobs
|
||||||
|
pageResult, err := util.WrapPageQuery(ctx, db, params.PaginationParam, opt.QueryOptions, &list)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
queryResult := &schema.JobQueryResult{
|
||||||
|
PageResult: pageResult,
|
||||||
|
Data: list,
|
||||||
|
}
|
||||||
|
return queryResult, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Job) Get(ctx context.Context, id string, opts ...schema.JobQueryOptions) (*schema.Job, error) {
|
||||||
|
var opt schema.JobQueryOptions
|
||||||
|
if len(opts) > 0 {
|
||||||
|
opt = opts[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
item := new(schema.Job)
|
||||||
|
ok, err := util.FindOne(ctx, GetJobDB(ctx, a.DB).Where("id=?", id), opt.QueryOptions, item)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
} else if !ok {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return item, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Job) Exists(ctx context.Context, id string) (bool, error) {
|
||||||
|
ok, err := util.Exists(ctx, GetJobDB(ctx, a.DB).Where("id=?", id))
|
||||||
|
return ok, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Job) Create(ctx context.Context, item *schema.Job) error {
|
||||||
|
result := GetJobDB(ctx, a.DB).Create(item)
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Job) Update(ctx context.Context, item *schema.Job) error {
|
||||||
|
result := GetJobDB(ctx, a.DB).Where("id=?", item.ID).Select("*").Omit("created_at").Updates(item)
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Job) Delete(ctx context.Context, id string) error {
|
||||||
|
result := GetJobDB(ctx, a.DB).Where("id=?", id).Delete(new(schema.Job))
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
58
internal/mods/rbac/dal/jobArea.dal.go
Normal file
58
internal/mods/rbac/dal/jobArea.dal.go
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
package dal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/errors"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetJobAreaDB(ctx context.Context, defDB *gorm.DB) *gorm.DB {
|
||||||
|
return util.GetDB(ctx, defDB).Model(new(schema.JobArea))
|
||||||
|
}
|
||||||
|
|
||||||
|
type JobArea struct {
|
||||||
|
DB *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *JobArea) Query(ctx context.Context) (*[]schema.JobArea, error) {
|
||||||
|
|
||||||
|
var list []schema.JobArea
|
||||||
|
tx := GetJobAreaDB(ctx, a.DB).Find(&list)
|
||||||
|
if tx.Error != nil {
|
||||||
|
return nil, errors.WithStack(tx.Error)
|
||||||
|
|
||||||
|
}
|
||||||
|
return &list, nil
|
||||||
|
}
|
||||||
|
func (a *JobArea) Get(ctx context.Context, id string) (*schema.JobArea, error) {
|
||||||
|
|
||||||
|
item := new(schema.JobArea)
|
||||||
|
ok, err := util.FindOne(ctx, GetJobAreaDB(ctx, a.DB).Where("id=?", id), util.QueryOptions{}, item)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
} else if !ok {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return item, nil
|
||||||
|
}
|
||||||
|
func (a *JobArea) Exists(ctx context.Context, name string) (bool, error) {
|
||||||
|
ok, err := util.Exists(ctx, GetJobAreaDB(ctx, a.DB).Where("name =?", name))
|
||||||
|
return ok, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *JobArea) Create(ctx context.Context, item *schema.JobArea) error {
|
||||||
|
result := GetJobAreaDB(ctx, a.DB).Create(item)
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *JobArea) Update(ctx context.Context, item *schema.JobArea) error {
|
||||||
|
result := GetJobAreaDB(ctx, a.DB).Where("id=?", item.ID).Select("*").Omit("created_at").Updates(item)
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *JobArea) Delete(ctx context.Context, id string) error {
|
||||||
|
result := GetJobAreaDB(ctx, a.DB).Where("id=?", id).Delete(new(schema.JobArea))
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
64
internal/mods/rbac/dal/logger.dal.go
Normal file
64
internal/mods/rbac/dal/logger.dal.go
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
package dal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/errors"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Get logger storage instance
|
||||||
|
func GetLoggerDB(ctx context.Context, defDB *gorm.DB) *gorm.DB {
|
||||||
|
return util.GetDB(ctx, defDB).Model(new(schema.Logger))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logger management
|
||||||
|
type Logger struct {
|
||||||
|
DB *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query loggers from the database based on the provided parameters and options.
|
||||||
|
func (a *Logger) Query(ctx context.Context, params schema.LoggerQueryParam, opts ...schema.LoggerQueryOptions) (*schema.LoggerQueryResult, error) {
|
||||||
|
var opt schema.LoggerQueryOptions
|
||||||
|
if len(opts) > 0 {
|
||||||
|
opt = opts[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
db := a.DB.Table(fmt.Sprintf("%s AS a", new(schema.Logger).TableName()))
|
||||||
|
db = db.Joins(fmt.Sprintf("left join %s b on a.user_id=b.id", new(schema.User).TableName()))
|
||||||
|
db = db.Select("a.*,b.name as user_name,b.username as login_name")
|
||||||
|
|
||||||
|
if v := params.Level; v != "" {
|
||||||
|
db = db.Where("a.level = ?", v)
|
||||||
|
}
|
||||||
|
if v := params.LikeMessage; len(v) > 0 {
|
||||||
|
db = db.Where("a.message LIKE ?", "%"+v+"%")
|
||||||
|
}
|
||||||
|
if v := params.TraceID; v != "" {
|
||||||
|
db = db.Where("a.trace_id = ?", v)
|
||||||
|
}
|
||||||
|
if v := params.LikeUserName; v != "" {
|
||||||
|
db = db.Where("b.username LIKE ?", "%"+v+"%")
|
||||||
|
}
|
||||||
|
if v := params.Tag; v != "" {
|
||||||
|
db = db.Where("a.tag = ?", v)
|
||||||
|
}
|
||||||
|
if start, end := params.StartTime, params.EndTime; start != "" && end != "" {
|
||||||
|
db = db.Where("a.created_at BETWEEN ? AND ?", start, end)
|
||||||
|
}
|
||||||
|
|
||||||
|
var list schema.Loggers
|
||||||
|
pageResult, err := util.WrapPageQuery(ctx, db, params.PaginationParam, opt.QueryOptions, &list)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
queryResult := &schema.LoggerQueryResult{
|
||||||
|
PageResult: pageResult,
|
||||||
|
Data: list,
|
||||||
|
}
|
||||||
|
return queryResult, nil
|
||||||
|
}
|
||||||
86
internal/mods/rbac/dal/memorabilia.dal.go
Normal file
86
internal/mods/rbac/dal/memorabilia.dal.go
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
package dal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/errors"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetMemorabiliaDB(ctx context.Context, defDB *gorm.DB) *gorm.DB {
|
||||||
|
return util.GetDB(ctx, defDB).Model(new(schema.Memorabilia))
|
||||||
|
}
|
||||||
|
|
||||||
|
type Memorabilia struct {
|
||||||
|
DB *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Memorabilia) Query(ctx context.Context, params schema.MemorabiliaQueryParam, opts ...schema.MemorabiliaQueryOptions) (*schema.MemorabiliaQueryResult, error) {
|
||||||
|
var opt schema.MemorabiliaQueryOptions
|
||||||
|
if len(opts) > 0 {
|
||||||
|
opt = opts[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
db := GetMemorabiliaDB(ctx, a.DB)
|
||||||
|
|
||||||
|
if v := params.LikeTitle; len(v) > 0 {
|
||||||
|
db = db.Where("title LIKE ?", "%"+v+"%")
|
||||||
|
}
|
||||||
|
if v := params.Status; len(v) > 0 {
|
||||||
|
db = db.Where("status = ?", v)
|
||||||
|
}
|
||||||
|
if v := params.Year; v > 0 {
|
||||||
|
db = db.Where("year = ?", v)
|
||||||
|
}
|
||||||
|
if v := params.Month; v > 0 {
|
||||||
|
db = db.Where("month = ?", v)
|
||||||
|
}
|
||||||
|
var list schema.Memorabilias
|
||||||
|
pageResult, err := util.WrapPageQuery(ctx, db, params.PaginationParam, opt.QueryOptions, &list)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
queryResult := &schema.MemorabiliaQueryResult{
|
||||||
|
PageResult: pageResult,
|
||||||
|
Data: list,
|
||||||
|
}
|
||||||
|
return queryResult, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Memorabilia) Get(ctx context.Context, id string, opts ...schema.MemorabiliaQueryOptions) (*schema.Memorabilia, error) {
|
||||||
|
var opt schema.MemorabiliaQueryOptions
|
||||||
|
if len(opts) > 0 {
|
||||||
|
opt = opts[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
item := new(schema.Memorabilia)
|
||||||
|
ok, err := util.FindOne(ctx, GetMemorabiliaDB(ctx, a.DB).Where("id=?", id), opt.QueryOptions, item)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
} else if !ok {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return item, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Memorabilia) Exists(ctx context.Context, id string) (bool, error) {
|
||||||
|
ok, err := util.Exists(ctx, GetMemorabiliaDB(ctx, a.DB).Where("id=?", id))
|
||||||
|
return ok, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Memorabilia) Create(ctx context.Context, item *schema.Memorabilia) error {
|
||||||
|
result := GetMemorabiliaDB(ctx, a.DB).Create(item)
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Memorabilia) Update(ctx context.Context, item *schema.Memorabilia) error {
|
||||||
|
result := GetMemorabiliaDB(ctx, a.DB).Where("id=?", item.ID).Select("*").Omit("created_at").Updates(item)
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Memorabilia) Delete(ctx context.Context, id string) error {
|
||||||
|
result := GetMemorabiliaDB(ctx, a.DB).Where("id=?", id).Delete(new(schema.Memorabilia))
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
165
internal/mods/rbac/dal/menu.dal.go
Normal file
165
internal/mods/rbac/dal/menu.dal.go
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
package dal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/errors"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Get menu storage instance
|
||||||
|
func GetMenuDB(ctx context.Context, defDB *gorm.DB) *gorm.DB {
|
||||||
|
return util.GetDB(ctx, defDB).Model(new(schema.Menu))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Menu management for RBAC
|
||||||
|
type Menu struct {
|
||||||
|
DB *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query menus from the database based on the provided parameters and options.
|
||||||
|
func (a *Menu) Query(ctx context.Context, params schema.MenuQueryParam, opts ...schema.MenuQueryOptions) (*schema.MenuQueryResult, error) {
|
||||||
|
var opt schema.MenuQueryOptions
|
||||||
|
if len(opts) > 0 {
|
||||||
|
opt = opts[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
db := GetMenuDB(ctx, a.DB)
|
||||||
|
|
||||||
|
if v := params.InIDs; len(v) > 0 {
|
||||||
|
db = db.Where("id IN ?", v)
|
||||||
|
}
|
||||||
|
if v := params.LikeName; len(v) > 0 {
|
||||||
|
db = db.Where("name LIKE ?", "%"+v+"%")
|
||||||
|
}
|
||||||
|
if v := params.Status; len(v) > 0 {
|
||||||
|
db = db.Where("status = ?", v)
|
||||||
|
}
|
||||||
|
if v := params.ParentID; len(v) > 0 {
|
||||||
|
db = db.Where("parent_id = ?", v)
|
||||||
|
}
|
||||||
|
if v := params.ParentPathPrefix; len(v) > 0 {
|
||||||
|
db = db.Where("parent_path LIKE ?", v+"%")
|
||||||
|
}
|
||||||
|
if v := params.UserID; len(v) > 0 {
|
||||||
|
userRoleQuery := GetUserRoleDB(ctx, a.DB).Where("user_id = ?", v).Select("role_id")
|
||||||
|
roleMenuQuery := GetRoleMenuDB(ctx, a.DB).Where("role_id IN (?)", userRoleQuery).Select("menu_id")
|
||||||
|
db = db.Where("id IN (?)", roleMenuQuery)
|
||||||
|
}
|
||||||
|
if v := params.RoleID; len(v) > 0 {
|
||||||
|
roleMenuQuery := GetRoleMenuDB(ctx, a.DB).Where("role_id = ?", v).Select("menu_id")
|
||||||
|
db = db.Where("id IN (?)", roleMenuQuery)
|
||||||
|
}
|
||||||
|
|
||||||
|
var list schema.Menus
|
||||||
|
pageResult, err := util.WrapPageQuery(ctx, db, params.PaginationParam, opt.QueryOptions, &list)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
queryResult := &schema.MenuQueryResult{
|
||||||
|
PageResult: pageResult,
|
||||||
|
Data: list,
|
||||||
|
}
|
||||||
|
return queryResult, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the specified menu from the database.
|
||||||
|
func (a *Menu) Get(ctx context.Context, id string, opts ...schema.MenuQueryOptions) (*schema.Menu, error) {
|
||||||
|
var opt schema.MenuQueryOptions
|
||||||
|
if len(opts) > 0 {
|
||||||
|
opt = opts[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
item := new(schema.Menu)
|
||||||
|
ok, err := util.FindOne(ctx, GetMenuDB(ctx, a.DB).Where("id=?", id), opt.QueryOptions, item)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
} else if !ok {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return item, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Menu) GetByCodeAndParentID(ctx context.Context, code, parentID string, opts ...schema.MenuQueryOptions) (*schema.Menu, error) {
|
||||||
|
var opt schema.MenuQueryOptions
|
||||||
|
if len(opts) > 0 {
|
||||||
|
opt = opts[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
item := new(schema.Menu)
|
||||||
|
ok, err := util.FindOne(ctx, GetMenuDB(ctx, a.DB).Where("code=? AND parent_id=?", code, parentID), opt.QueryOptions, item)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
} else if !ok {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return item, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetByNameAndParentID get the specified menu from the database.
|
||||||
|
func (a *Menu) GetByNameAndParentID(ctx context.Context, name, parentID string, opts ...schema.MenuQueryOptions) (*schema.Menu, error) {
|
||||||
|
var opt schema.MenuQueryOptions
|
||||||
|
if len(opts) > 0 {
|
||||||
|
opt = opts[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
item := new(schema.Menu)
|
||||||
|
ok, err := util.FindOne(ctx, GetMenuDB(ctx, a.DB).Where("name=? AND parent_id=?", name, parentID), opt.QueryOptions, item)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
} else if !ok {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return item, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks if the specified menu exists in the database.
|
||||||
|
func (a *Menu) Exists(ctx context.Context, id string) (bool, error) {
|
||||||
|
ok, err := util.Exists(ctx, GetMenuDB(ctx, a.DB).Where("id=?", id))
|
||||||
|
return ok, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks if a menu with the specified `code` exists under the specified `parentID` in the database.
|
||||||
|
func (a *Menu) ExistsCodeByParentID(ctx context.Context, code, parentID string) (bool, error) {
|
||||||
|
ok, err := util.Exists(ctx, GetMenuDB(ctx, a.DB).Where("code=? AND parent_id=?", code, parentID))
|
||||||
|
return ok, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks if a menu with the specified `name` exists under the specified `parentID` in the database.
|
||||||
|
func (a *Menu) ExistsNameByParentID(ctx context.Context, name, parentID string) (bool, error) {
|
||||||
|
ok, err := util.Exists(ctx, GetMenuDB(ctx, a.DB).Where("name=? AND parent_id=?", name, parentID))
|
||||||
|
return ok, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new menu.
|
||||||
|
func (a *Menu) Create(ctx context.Context, item *schema.Menu) error {
|
||||||
|
result := GetMenuDB(ctx, a.DB).Create(item)
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the specified menu in the database.
|
||||||
|
func (a *Menu) Update(ctx context.Context, item *schema.Menu) error {
|
||||||
|
result := GetMenuDB(ctx, a.DB).Where("id=?", item.ID).Select("*").Omit("created_at").Updates(item)
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the specified menu from the database.
|
||||||
|
func (a *Menu) Delete(ctx context.Context, id string) error {
|
||||||
|
result := GetMenuDB(ctx, a.DB).Where("id=?", id).Delete(new(schema.Menu))
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updates the parent path of the specified menu.
|
||||||
|
func (a *Menu) UpdateParentPath(ctx context.Context, id, parentPath string) error {
|
||||||
|
result := GetMenuDB(ctx, a.DB).Where("id=?", id).Update("parent_path", parentPath)
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updates the status of all menus whose parent path starts with the provided parent path.
|
||||||
|
func (a *Menu) UpdateStatusByParentPath(ctx context.Context, parentPath, status string) error {
|
||||||
|
result := GetMenuDB(ctx, a.DB).Where("parent_path like ?", parentPath+"%").Update("status", status)
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
101
internal/mods/rbac/dal/menu_resource.dal.go
Normal file
101
internal/mods/rbac/dal/menu_resource.dal.go
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
package dal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/errors"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Get menu resource storage instance
|
||||||
|
func GetMenuResourceDB(ctx context.Context, defDB *gorm.DB) *gorm.DB {
|
||||||
|
return util.GetDB(ctx, defDB).Model(new(schema.MenuResource))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Menu resource management for RBAC
|
||||||
|
type MenuResource struct {
|
||||||
|
DB *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query menu resources from the database based on the provided parameters and options.
|
||||||
|
func (a *MenuResource) Query(ctx context.Context, params schema.MenuResourceQueryParam, opts ...schema.MenuResourceQueryOptions) (*schema.MenuResourceQueryResult, error) {
|
||||||
|
var opt schema.MenuResourceQueryOptions
|
||||||
|
if len(opts) > 0 {
|
||||||
|
opt = opts[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
db := GetMenuResourceDB(ctx, a.DB)
|
||||||
|
if v := params.MenuID; len(v) > 0 {
|
||||||
|
db = db.Where("menu_id = ?", v)
|
||||||
|
}
|
||||||
|
if v := params.MenuIDs; len(v) > 0 {
|
||||||
|
db = db.Where("menu_id IN ?", v)
|
||||||
|
}
|
||||||
|
|
||||||
|
var list schema.MenuResources
|
||||||
|
pageResult, err := util.WrapPageQuery(ctx, db, params.PaginationParam, opt.QueryOptions, &list)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
queryResult := &schema.MenuResourceQueryResult{
|
||||||
|
PageResult: pageResult,
|
||||||
|
Data: list,
|
||||||
|
}
|
||||||
|
return queryResult, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the specified menu resource from the database.
|
||||||
|
func (a *MenuResource) Get(ctx context.Context, id string, opts ...schema.MenuResourceQueryOptions) (*schema.MenuResource, error) {
|
||||||
|
var opt schema.MenuResourceQueryOptions
|
||||||
|
if len(opts) > 0 {
|
||||||
|
opt = opts[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
item := new(schema.MenuResource)
|
||||||
|
ok, err := util.FindOne(ctx, GetMenuResourceDB(ctx, a.DB).Where("id=?", id), opt.QueryOptions, item)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
} else if !ok {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return item, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exist checks if the specified menu resource exists in the database.
|
||||||
|
func (a *MenuResource) Exists(ctx context.Context, id string) (bool, error) {
|
||||||
|
ok, err := util.Exists(ctx, GetMenuResourceDB(ctx, a.DB).Where("id=?", id))
|
||||||
|
return ok, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExistsMethodPathByMenuID checks if the specified menu resource exists in the database.
|
||||||
|
func (a *MenuResource) ExistsMethodPathByMenuID(ctx context.Context, method, path, menuID string) (bool, error) {
|
||||||
|
ok, err := util.Exists(ctx, GetMenuResourceDB(ctx, a.DB).Where("method=? AND path=? AND menu_id=?", method, path, menuID))
|
||||||
|
return ok, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new menu resource.
|
||||||
|
func (a *MenuResource) Create(ctx context.Context, item *schema.MenuResource) error {
|
||||||
|
result := GetMenuResourceDB(ctx, a.DB).Create(item)
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the specified menu resource in the database.
|
||||||
|
func (a *MenuResource) Update(ctx context.Context, item *schema.MenuResource) error {
|
||||||
|
result := GetMenuResourceDB(ctx, a.DB).Where("id=?", item.ID).Select("*").Omit("created_at").Updates(item)
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the specified menu resource from the database.
|
||||||
|
func (a *MenuResource) Delete(ctx context.Context, id string) error {
|
||||||
|
result := GetMenuResourceDB(ctx, a.DB).Where("id=?", id).Delete(new(schema.MenuResource))
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deletes the menu resource by menu id.
|
||||||
|
func (a *MenuResource) DeleteByMenuID(ctx context.Context, menuID string) error {
|
||||||
|
result := GetMenuResourceDB(ctx, a.DB).Where("menu_id=?", menuID).Delete(new(schema.MenuResource))
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
83
internal/mods/rbac/dal/product.dal.go
Normal file
83
internal/mods/rbac/dal/product.dal.go
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
package dal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/errors"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetProductDB(ctx context.Context, defDB *gorm.DB) *gorm.DB {
|
||||||
|
return util.GetDB(ctx, defDB).Model(new(schema.Product))
|
||||||
|
}
|
||||||
|
|
||||||
|
type Product struct {
|
||||||
|
DB *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Product) Query(ctx context.Context, params schema.ProductQueryParam, opts ...schema.ProductQueryOptions) (*schema.ProductQueryResult, error) {
|
||||||
|
var opt schema.ProductQueryOptions
|
||||||
|
if len(opts) > 0 {
|
||||||
|
opt = opts[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
db := GetProductDB(ctx, a.DB)
|
||||||
|
|
||||||
|
if v := params.LikeTitle; len(v) > 0 {
|
||||||
|
db = db.Where("title LIKE ?", "%"+v+"%")
|
||||||
|
}
|
||||||
|
if v := params.Status; len(v) > 0 {
|
||||||
|
db = db.Where("status = ?", v)
|
||||||
|
}
|
||||||
|
if v := params.CategoryID; v > 0 {
|
||||||
|
db = db.Where("categoryId = ?", v)
|
||||||
|
}
|
||||||
|
var list schema.Products
|
||||||
|
pageResult, err := util.WrapPageQuery(ctx, db, params.PaginationParam, opt.QueryOptions, &list)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
queryResult := &schema.ProductQueryResult{
|
||||||
|
PageResult: pageResult,
|
||||||
|
Data: list,
|
||||||
|
}
|
||||||
|
return queryResult, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Product) Get(ctx context.Context, id string, opts ...schema.ProductQueryOptions) (*schema.Product, error) {
|
||||||
|
var opt schema.ProductQueryOptions
|
||||||
|
if len(opts) > 0 {
|
||||||
|
opt = opts[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
item := new(schema.Product)
|
||||||
|
ok, err := util.FindOne(ctx, GetProductDB(ctx, a.DB).Where("id=?", id), opt.QueryOptions, item)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
} else if !ok {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return item, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Product) Exists(ctx context.Context, id string) (bool, error) {
|
||||||
|
ok, err := util.Exists(ctx, GetProductDB(ctx, a.DB).Where("id=?", id))
|
||||||
|
return ok, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Product) Create(ctx context.Context, item *schema.Product) error {
|
||||||
|
result := GetProductDB(ctx, a.DB).Create(item)
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Product) Update(ctx context.Context, item *schema.Product) error {
|
||||||
|
result := GetProductDB(ctx, a.DB).Where("id=?", item.ID).Select("*").Omit("created_at").Updates(item)
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Product) Delete(ctx context.Context, id string) error {
|
||||||
|
result := GetProductDB(ctx, a.DB).Where("id=?", id).Delete(new(schema.Product))
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
59
internal/mods/rbac/dal/productCategory.dal.go
Normal file
59
internal/mods/rbac/dal/productCategory.dal.go
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
package dal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/errors"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetProductCategoryDB(ctx context.Context, defDB *gorm.DB) *gorm.DB {
|
||||||
|
return util.GetDB(ctx, defDB).Model(new(schema.ProductCategory))
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProductCategory struct {
|
||||||
|
DB *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ProductCategory) Query(ctx context.Context) (*[]schema.ProductCategory, error) {
|
||||||
|
|
||||||
|
db := GetProductCategoryDB(ctx, a.DB)
|
||||||
|
|
||||||
|
var list []schema.ProductCategory
|
||||||
|
tx := db.Find(&list)
|
||||||
|
if tx.Error != nil {
|
||||||
|
return nil, errors.WithStack(tx.Error)
|
||||||
|
}
|
||||||
|
return &list, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ProductCategory) Get(ctx context.Context, id uint) (*schema.ProductCategory, error) {
|
||||||
|
|
||||||
|
item := new(schema.ProductCategory)
|
||||||
|
tx := GetProductCategoryDB(ctx, a.DB).Where("id=?", id).First(item)
|
||||||
|
if tx.Error != nil { // 没有找到
|
||||||
|
return nil, errors.WithStack(tx.Error)
|
||||||
|
}
|
||||||
|
return item, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ProductCategory) Exists(ctx context.Context, id uint) (bool, error) {
|
||||||
|
ok, err := util.Exists(ctx, GetProductCategoryDB(ctx, a.DB).Where("id=?", id))
|
||||||
|
return ok, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ProductCategory) Create(ctx context.Context, item *schema.ProductCategory) error {
|
||||||
|
result := GetProductCategoryDB(ctx, a.DB).Create(item)
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ProductCategory) Update(ctx context.Context, item *schema.ProductCategory) error {
|
||||||
|
result := GetProductCategoryDB(ctx, a.DB).Where("id=?", item.ID).Select("*").Omit("created_at").Updates(item)
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ProductCategory) Delete(ctx context.Context, id string) error {
|
||||||
|
result := GetProductCategoryDB(ctx, a.DB).Where("id=?", id).Delete(new(schema.ProductCategory))
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
100
internal/mods/rbac/dal/role.dal.go
Normal file
100
internal/mods/rbac/dal/role.dal.go
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
package dal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/errors"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Get role storage instance
|
||||||
|
func GetRoleDB(ctx context.Context, defDB *gorm.DB) *gorm.DB {
|
||||||
|
return util.GetDB(ctx, defDB).Model(new(schema.Role))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Role management for RBAC
|
||||||
|
type Role struct {
|
||||||
|
DB *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query roles from the database based on the provided parameters and options.
|
||||||
|
func (a *Role) Query(ctx context.Context, params schema.RoleQueryParam, opts ...schema.RoleQueryOptions) (*schema.RoleQueryResult, error) {
|
||||||
|
var opt schema.RoleQueryOptions
|
||||||
|
if len(opts) > 0 {
|
||||||
|
opt = opts[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
db := GetRoleDB(ctx, a.DB)
|
||||||
|
if v := params.InIDs; len(v) > 0 {
|
||||||
|
db = db.Where("id IN (?)", v)
|
||||||
|
}
|
||||||
|
if v := params.LikeName; len(v) > 0 {
|
||||||
|
db = db.Where("name LIKE ?", "%"+v+"%")
|
||||||
|
}
|
||||||
|
if v := params.Status; len(v) > 0 {
|
||||||
|
db = db.Where("status = ?", v)
|
||||||
|
}
|
||||||
|
if v := params.GtUpdatedAt; v != nil {
|
||||||
|
db = db.Where("updated_at > ?", v)
|
||||||
|
}
|
||||||
|
|
||||||
|
var list schema.Roles
|
||||||
|
pageResult, err := util.WrapPageQuery(ctx, db, params.PaginationParam, opt.QueryOptions, &list)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
queryResult := &schema.RoleQueryResult{
|
||||||
|
PageResult: pageResult,
|
||||||
|
Data: list,
|
||||||
|
}
|
||||||
|
return queryResult, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the specified role from the database.
|
||||||
|
func (a *Role) Get(ctx context.Context, id string, opts ...schema.RoleQueryOptions) (*schema.Role, error) {
|
||||||
|
var opt schema.RoleQueryOptions
|
||||||
|
if len(opts) > 0 {
|
||||||
|
opt = opts[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
item := new(schema.Role)
|
||||||
|
ok, err := util.FindOne(ctx, GetRoleDB(ctx, a.DB).Where("id=?", id), opt.QueryOptions, item)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
} else if !ok {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return item, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exist checks if the specified role exists in the database.
|
||||||
|
func (a *Role) Exists(ctx context.Context, id string) (bool, error) {
|
||||||
|
ok, err := util.Exists(ctx, GetRoleDB(ctx, a.DB).Where("id=?", id))
|
||||||
|
return ok, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Role) ExistsCode(ctx context.Context, code string) (bool, error) {
|
||||||
|
ok, err := util.Exists(ctx, GetRoleDB(ctx, a.DB).Where("code=?", code))
|
||||||
|
return ok, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new role.
|
||||||
|
func (a *Role) Create(ctx context.Context, item *schema.Role) error {
|
||||||
|
result := GetRoleDB(ctx, a.DB).Create(item)
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the specified role in the database.
|
||||||
|
func (a *Role) Update(ctx context.Context, item *schema.Role) error {
|
||||||
|
result := GetRoleDB(ctx, a.DB).Where("id=?", item.ID).Select("*").Omit("created_at").Updates(item)
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the specified role from the database.
|
||||||
|
func (a *Role) Delete(ctx context.Context, id string) error {
|
||||||
|
result := GetRoleDB(ctx, a.DB).Where("id=?", id).Delete(new(schema.Role))
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
98
internal/mods/rbac/dal/role_menu.dal.go
Normal file
98
internal/mods/rbac/dal/role_menu.dal.go
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
package dal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/errors"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Get role menu storage instance
|
||||||
|
func GetRoleMenuDB(ctx context.Context, defDB *gorm.DB) *gorm.DB {
|
||||||
|
return util.GetDB(ctx, defDB).Model(new(schema.RoleMenu))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Role permissions for RBAC
|
||||||
|
type RoleMenu struct {
|
||||||
|
DB *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query role menus from the database based on the provided parameters and options.
|
||||||
|
func (a *RoleMenu) Query(ctx context.Context, params schema.RoleMenuQueryParam, opts ...schema.RoleMenuQueryOptions) (*schema.RoleMenuQueryResult, error) {
|
||||||
|
var opt schema.RoleMenuQueryOptions
|
||||||
|
if len(opts) > 0 {
|
||||||
|
opt = opts[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
db := GetRoleMenuDB(ctx, a.DB)
|
||||||
|
if v := params.RoleID; len(v) > 0 {
|
||||||
|
db = db.Where("role_id = ?", v)
|
||||||
|
}
|
||||||
|
|
||||||
|
var list schema.RoleMenus
|
||||||
|
pageResult, err := util.WrapPageQuery(ctx, db, params.PaginationParam, opt.QueryOptions, &list)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
queryResult := &schema.RoleMenuQueryResult{
|
||||||
|
PageResult: pageResult,
|
||||||
|
Data: list,
|
||||||
|
}
|
||||||
|
return queryResult, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the specified role menu from the database.
|
||||||
|
func (a *RoleMenu) Get(ctx context.Context, id string, opts ...schema.RoleMenuQueryOptions) (*schema.RoleMenu, error) {
|
||||||
|
var opt schema.RoleMenuQueryOptions
|
||||||
|
if len(opts) > 0 {
|
||||||
|
opt = opts[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
item := new(schema.RoleMenu)
|
||||||
|
ok, err := util.FindOne(ctx, GetRoleMenuDB(ctx, a.DB).Where("id=?", id), opt.QueryOptions, item)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
} else if !ok {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return item, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exist checks if the specified role menu exists in the database.
|
||||||
|
func (a *RoleMenu) Exists(ctx context.Context, id string) (bool, error) {
|
||||||
|
ok, err := util.Exists(ctx, GetRoleMenuDB(ctx, a.DB).Where("id=?", id))
|
||||||
|
return ok, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new role menu.
|
||||||
|
func (a *RoleMenu) Create(ctx context.Context, item *schema.RoleMenu) error {
|
||||||
|
result := GetRoleMenuDB(ctx, a.DB).Create(item)
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the specified role menu in the database.
|
||||||
|
func (a *RoleMenu) Update(ctx context.Context, item *schema.RoleMenu) error {
|
||||||
|
result := GetRoleMenuDB(ctx, a.DB).Where("id=?", item.ID).Select("*").Omit("created_at").Updates(item)
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the specified role menu from the database.
|
||||||
|
func (a *RoleMenu) Delete(ctx context.Context, id string) error {
|
||||||
|
result := GetRoleMenuDB(ctx, a.DB).Where("id=?", id).Delete(new(schema.RoleMenu))
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deletes role menus by role id.
|
||||||
|
func (a *RoleMenu) DeleteByRoleID(ctx context.Context, roleID string) error {
|
||||||
|
result := GetRoleMenuDB(ctx, a.DB).Where("role_id=?", roleID).Delete(new(schema.RoleMenu))
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deletes role menus by menu id.
|
||||||
|
func (a *RoleMenu) DeleteByMenuID(ctx context.Context, menuID string) error {
|
||||||
|
result := GetRoleMenuDB(ctx, a.DB).Where("menu_id=?", menuID).Delete(new(schema.RoleMenu))
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
81
internal/mods/rbac/dal/team.go
Normal file
81
internal/mods/rbac/dal/team.go
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
package dal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/errors"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetTeamDB(ctx context.Context, defDB *gorm.DB) *gorm.DB {
|
||||||
|
return util.GetDB(ctx, defDB).Model(new(schema.Team))
|
||||||
|
}
|
||||||
|
|
||||||
|
type Team struct {
|
||||||
|
DB *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Team) Query(ctx context.Context, params schema.TeamQueryParam, opts ...schema.TeamQueryOptions) (*schema.TeamQueryResult, error) {
|
||||||
|
var opt schema.TeamQueryOptions
|
||||||
|
if len(opts) > 0 {
|
||||||
|
opt = opts[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
db := GetTeamDB(ctx, a.DB)
|
||||||
|
|
||||||
|
if v := params.LikeName; len(v) > 0 {
|
||||||
|
db = db.Where("name LIKE ?", "%"+v+"%")
|
||||||
|
}
|
||||||
|
if v := params.Status; len(v) > 0 {
|
||||||
|
db = db.Where("status = ?", v)
|
||||||
|
}
|
||||||
|
|
||||||
|
var list schema.Teams
|
||||||
|
pageResult, err := util.WrapPageQuery(ctx, db, params.PaginationParam, opt.QueryOptions, &list)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
queryResult := &schema.TeamQueryResult{
|
||||||
|
PageResult: pageResult,
|
||||||
|
Data: list,
|
||||||
|
}
|
||||||
|
return queryResult, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Team) Get(ctx context.Context, id string, opts ...schema.TeamQueryOptions) (*schema.Team, error) {
|
||||||
|
var opt schema.TeamQueryOptions
|
||||||
|
if len(opts) > 0 {
|
||||||
|
opt = opts[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
item := new(schema.Team)
|
||||||
|
ok, err := util.FindOne(ctx, GetTeamDB(ctx, a.DB).Where("id=?", id), opt.QueryOptions, item)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
} else if !ok {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return item, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Team) Exists(ctx context.Context, id string) (bool, error) {
|
||||||
|
ok, err := util.Exists(ctx, GetTeamDB(ctx, a.DB).Where("id=?", id))
|
||||||
|
return ok, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Team) Create(ctx context.Context, item *schema.Team) error {
|
||||||
|
result := GetTeamDB(ctx, a.DB).Create(item)
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Team) Update(ctx context.Context, item *schema.Team) error {
|
||||||
|
result := GetTeamDB(ctx, a.DB).Where("id=?", item.ID).Select("*").Omit("created_at").Updates(item)
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Team) Delete(ctx context.Context, id string) error {
|
||||||
|
result := GetTeamDB(ctx, a.DB).Where("id=?", id).Delete(new(schema.Team))
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
124
internal/mods/rbac/dal/user.dal.go
Normal file
124
internal/mods/rbac/dal/user.dal.go
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
package dal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/errors"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Get user storage instance
|
||||||
|
func GetUserDB(ctx context.Context, defDB *gorm.DB) *gorm.DB {
|
||||||
|
return util.GetDB(ctx, defDB).Model(new(schema.User))
|
||||||
|
}
|
||||||
|
|
||||||
|
// User management for RBAC
|
||||||
|
type User struct {
|
||||||
|
DB *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query users from the database based on the provided parameters and options.
|
||||||
|
func (a *User) Query(ctx context.Context, params schema.UserQueryParam, opts ...schema.UserQueryOptions) (*schema.UserQueryResult, error) {
|
||||||
|
var opt schema.UserQueryOptions
|
||||||
|
if len(opts) > 0 {
|
||||||
|
opt = opts[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
db := GetUserDB(ctx, a.DB)
|
||||||
|
if v := params.LikeUsername; len(v) > 0 {
|
||||||
|
db = db.Where("username LIKE ?", "%"+v+"%")
|
||||||
|
}
|
||||||
|
if v := params.LikeName; len(v) > 0 {
|
||||||
|
db = db.Where("name LIKE ?", "%"+v+"%")
|
||||||
|
}
|
||||||
|
if v := params.Status; len(v) > 0 {
|
||||||
|
db = db.Where("status = ?", v)
|
||||||
|
}
|
||||||
|
|
||||||
|
var list schema.Users
|
||||||
|
pageResult, err := util.WrapPageQuery(ctx, db, params.PaginationParam, opt.QueryOptions, &list)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
queryResult := &schema.UserQueryResult{
|
||||||
|
PageResult: pageResult,
|
||||||
|
Data: list,
|
||||||
|
}
|
||||||
|
return queryResult, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the specified user from the database.
|
||||||
|
func (a *User) Get(ctx context.Context, id string, opts ...schema.UserQueryOptions) (*schema.User, error) {
|
||||||
|
var opt schema.UserQueryOptions
|
||||||
|
if len(opts) > 0 {
|
||||||
|
opt = opts[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
item := new(schema.User)
|
||||||
|
ok, err := util.FindOne(ctx, GetUserDB(ctx, a.DB).Where("id=?", id), opt.QueryOptions, item)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
} else if !ok {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return item, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *User) GetByUsername(ctx context.Context, username string, opts ...schema.UserQueryOptions) (*schema.User, error) {
|
||||||
|
var opt schema.UserQueryOptions
|
||||||
|
if len(opts) > 0 {
|
||||||
|
opt = opts[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
item := new(schema.User)
|
||||||
|
ok, err := util.FindOne(ctx, GetUserDB(ctx, a.DB).Where("username=?", username), opt.QueryOptions, item)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
} else if !ok {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return item, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exist checks if the specified user exists in the database.
|
||||||
|
func (a *User) Exists(ctx context.Context, id string) (bool, error) {
|
||||||
|
ok, err := util.Exists(ctx, GetUserDB(ctx, a.DB).Where("id=?", id))
|
||||||
|
return ok, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *User) ExistsUsername(ctx context.Context, username string) (bool, error) {
|
||||||
|
ok, err := util.Exists(ctx, GetUserDB(ctx, a.DB).Where("username=?", username))
|
||||||
|
return ok, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new user.
|
||||||
|
func (a *User) Create(ctx context.Context, item *schema.User) error {
|
||||||
|
result := GetUserDB(ctx, a.DB).Create(item)
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the specified user in the database.
|
||||||
|
func (a *User) Update(ctx context.Context, item *schema.User, selectFields ...string) error {
|
||||||
|
db := GetUserDB(ctx, a.DB).Where("id=?", item.ID)
|
||||||
|
if len(selectFields) > 0 {
|
||||||
|
db = db.Select(selectFields)
|
||||||
|
} else {
|
||||||
|
db = db.Select("*").Omit("created_at")
|
||||||
|
}
|
||||||
|
result := db.Updates(item)
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the specified user from the database.
|
||||||
|
func (a *User) Delete(ctx context.Context, id string) error {
|
||||||
|
result := GetUserDB(ctx, a.DB).Where("id=?", id).Delete(new(schema.User))
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *User) UpdatePasswordByID(ctx context.Context, id string, password string) error {
|
||||||
|
result := GetUserDB(ctx, a.DB).Where("id=?", id).Select("password").Updates(schema.User{Password: password})
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
108
internal/mods/rbac/dal/user_role.dal.go
Normal file
108
internal/mods/rbac/dal/user_role.dal.go
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
package dal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/errors"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Get user role storage instance
|
||||||
|
func GetUserRoleDB(ctx context.Context, defDB *gorm.DB) *gorm.DB {
|
||||||
|
return util.GetDB(ctx, defDB).Model(new(schema.UserRole))
|
||||||
|
}
|
||||||
|
|
||||||
|
// User roles for RBAC
|
||||||
|
type UserRole struct {
|
||||||
|
DB *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query user roles from the database based on the provided parameters and options.
|
||||||
|
func (a *UserRole) Query(ctx context.Context, params schema.UserRoleQueryParam, opts ...schema.UserRoleQueryOptions) (*schema.UserRoleQueryResult, error) {
|
||||||
|
var opt schema.UserRoleQueryOptions
|
||||||
|
if len(opts) > 0 {
|
||||||
|
opt = opts[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
db := a.DB.Table(fmt.Sprintf("%s AS a", new(schema.UserRole).TableName()))
|
||||||
|
if opt.JoinRole {
|
||||||
|
db = db.Joins(fmt.Sprintf("left join %s b on a.role_id=b.id", new(schema.Role).TableName()))
|
||||||
|
db = db.Select("a.*,b.name as role_name")
|
||||||
|
}
|
||||||
|
|
||||||
|
if v := params.InUserIDs; len(v) > 0 {
|
||||||
|
db = db.Where("a.user_id IN (?)", v)
|
||||||
|
}
|
||||||
|
if v := params.UserID; len(v) > 0 {
|
||||||
|
db = db.Where("a.user_id = ?", v)
|
||||||
|
}
|
||||||
|
if v := params.RoleID; len(v) > 0 {
|
||||||
|
db = db.Where("a.role_id = ?", v)
|
||||||
|
}
|
||||||
|
|
||||||
|
var list schema.UserRoles
|
||||||
|
pageResult, err := util.WrapPageQuery(ctx, db, params.PaginationParam, opt.QueryOptions, &list)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
queryResult := &schema.UserRoleQueryResult{
|
||||||
|
PageResult: pageResult,
|
||||||
|
Data: list,
|
||||||
|
}
|
||||||
|
return queryResult, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the specified user role from the database.
|
||||||
|
func (a *UserRole) Get(ctx context.Context, id string, opts ...schema.UserRoleQueryOptions) (*schema.UserRole, error) {
|
||||||
|
var opt schema.UserRoleQueryOptions
|
||||||
|
if len(opts) > 0 {
|
||||||
|
opt = opts[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
item := new(schema.UserRole)
|
||||||
|
ok, err := util.FindOne(ctx, GetUserRoleDB(ctx, a.DB).Where("id=?", id), opt.QueryOptions, item)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
} else if !ok {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return item, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exist checks if the specified user role exists in the database.
|
||||||
|
func (a *UserRole) Exists(ctx context.Context, id string) (bool, error) {
|
||||||
|
ok, err := util.Exists(ctx, GetUserRoleDB(ctx, a.DB).Where("id=?", id))
|
||||||
|
return ok, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new user role.
|
||||||
|
func (a *UserRole) Create(ctx context.Context, item *schema.UserRole) error {
|
||||||
|
result := GetUserRoleDB(ctx, a.DB).Create(item)
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the specified user role in the database.
|
||||||
|
func (a *UserRole) Update(ctx context.Context, item *schema.UserRole) error {
|
||||||
|
result := GetUserRoleDB(ctx, a.DB).Where("id=?", item.ID).Select("*").Omit("created_at").Updates(item)
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the specified user role from the database.
|
||||||
|
func (a *UserRole) Delete(ctx context.Context, id string) error {
|
||||||
|
result := GetUserRoleDB(ctx, a.DB).Where("id=?", id).Delete(new(schema.UserRole))
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *UserRole) DeleteByUserID(ctx context.Context, userID string) error {
|
||||||
|
result := GetUserRoleDB(ctx, a.DB).Where("user_id=?", userID).Delete(new(schema.UserRole))
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *UserRole) DeleteByRoleID(ctx context.Context, roleID string) error {
|
||||||
|
result := GetUserRoleDB(ctx, a.DB).Where("role_id=?", roleID).Delete(new(schema.UserRole))
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
88
internal/mods/rbac/dal/video.dal.go
Normal file
88
internal/mods/rbac/dal/video.dal.go
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
package dal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/errors"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetVideoDB(ctx context.Context, defDB *gorm.DB) *gorm.DB {
|
||||||
|
return util.GetDB(ctx, defDB).Model(new(schema.Video))
|
||||||
|
}
|
||||||
|
|
||||||
|
type Video struct {
|
||||||
|
DB *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query roles from the database based on the provided parameters and options.
|
||||||
|
func (a *Video) Query(ctx context.Context, params schema.VideoQueryParam, opts ...schema.VideoQueryOptions) (*schema.VideoQueryResult, error) {
|
||||||
|
var opt schema.VideoQueryOptions
|
||||||
|
if len(opts) > 0 {
|
||||||
|
opt = opts[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
db := GetVideoDB(ctx, a.DB)
|
||||||
|
|
||||||
|
if v := params.LikeTitle; len(v) > 0 {
|
||||||
|
db = db.Where("title LIKE ?", "%"+v+"%")
|
||||||
|
}
|
||||||
|
if v := params.Status; len(v) > 0 {
|
||||||
|
db = db.Where("status = ?", v)
|
||||||
|
}
|
||||||
|
|
||||||
|
var list schema.Videos
|
||||||
|
pageResult, err := util.WrapPageQuery(ctx, db, params.PaginationParam, opt.QueryOptions, &list)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
queryResult := &schema.VideoQueryResult{
|
||||||
|
PageResult: pageResult,
|
||||||
|
Data: list,
|
||||||
|
}
|
||||||
|
return queryResult, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the specified role from the database.
|
||||||
|
func (a *Video) Get(ctx context.Context, id string, opts ...schema.VideoQueryOptions) (*schema.Video, error) {
|
||||||
|
var opt schema.VideoQueryOptions
|
||||||
|
if len(opts) > 0 {
|
||||||
|
opt = opts[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
item := new(schema.Video)
|
||||||
|
ok, err := util.FindOne(ctx, GetVideoDB(ctx, a.DB).Where("id=?", id), opt.QueryOptions, item)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
} else if !ok {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return item, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exist checks if the specified role exists in the database.
|
||||||
|
func (a *Video) Exists(ctx context.Context, id string) (bool, error) {
|
||||||
|
ok, err := util.Exists(ctx, GetVideoDB(ctx, a.DB).Where("id=?", id))
|
||||||
|
return ok, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new role.
|
||||||
|
func (a *Video) Create(ctx context.Context, item *schema.Video) error {
|
||||||
|
result := GetVideoDB(ctx, a.DB).Create(item)
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the specified role in the database.
|
||||||
|
func (a *Video) Update(ctx context.Context, item *schema.Video) error {
|
||||||
|
result := GetVideoDB(ctx, a.DB).Where("id=?", item.ID).Select("*").Omit("created_at").Updates(item)
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the specified role from the database.
|
||||||
|
func (a *Video) Delete(ctx context.Context, id string) error {
|
||||||
|
result := GetVideoDB(ctx, a.DB).Where("id=?", id).Delete(new(schema.Video))
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
46
internal/mods/rbac/dal/website.dal.go
Normal file
46
internal/mods/rbac/dal/website.dal.go
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package dal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/errors"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetWebSiteDB(ctx context.Context, defDB *gorm.DB) *gorm.DB {
|
||||||
|
return util.GetDB(ctx, defDB).Model(new(schema.WebSite))
|
||||||
|
}
|
||||||
|
|
||||||
|
type WebSite struct {
|
||||||
|
DB *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *WebSite) Get(ctx context.Context, id string) (*schema.WebSite, error) {
|
||||||
|
|
||||||
|
item := new(schema.WebSite)
|
||||||
|
ok, err := util.FindOne(ctx, GetJobDB(ctx, a.DB).Where("id=?", id), util.QueryOptions{}, item)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
} else if !ok {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return item, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *WebSite) Query(ctx context.Context) (*schema.WebSite, error) {
|
||||||
|
db := GetWebSiteDB(ctx, a.DB)
|
||||||
|
var info schema.WebSite
|
||||||
|
db.First(&info)
|
||||||
|
return &info, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *WebSite) Create(ctx context.Context, item *schema.WebSite) error {
|
||||||
|
result := GetWebSiteDB(ctx, a.DB).Create(item)
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *WebSite) Update(ctx context.Context, item *schema.WebSite) error {
|
||||||
|
result := GetWebSiteDB(ctx, a.DB).Where("id=?", item.ID).Select("*").Omit("created_at").Updates(item)
|
||||||
|
return errors.WithStack(result.Error)
|
||||||
|
}
|
||||||
217
internal/mods/rbac/main.go
Normal file
217
internal/mods/rbac/main.go
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
package rbac
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/guxuan/hailin_service/internal/config"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/api"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/logging"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RBAC struct {
|
||||||
|
DB *gorm.DB
|
||||||
|
MenuAPI *api.Menu
|
||||||
|
RoleAPI *api.Role
|
||||||
|
UserAPI *api.User
|
||||||
|
LoginAPI *api.Login
|
||||||
|
LoggerAPI *api.Logger
|
||||||
|
BannerAPI *api.Banner
|
||||||
|
ArticleAPI *api.Article
|
||||||
|
VideoAPI *api.Video
|
||||||
|
UploadAPI *api.Upload
|
||||||
|
JobAPI *api.Job
|
||||||
|
WebAPI *api.Web
|
||||||
|
WebSiteAPI *api.WebSite
|
||||||
|
TeamAPI *api.Team
|
||||||
|
MemorabiliaAPI *api.Memorabilia
|
||||||
|
ProductAPI *api.Product
|
||||||
|
|
||||||
|
Casbinx *Casbinx
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *RBAC) AutoMigrate(ctx context.Context) error {
|
||||||
|
return a.DB.AutoMigrate(
|
||||||
|
new(schema.Menu),
|
||||||
|
new(schema.MenuResource),
|
||||||
|
new(schema.Role),
|
||||||
|
new(schema.RoleMenu),
|
||||||
|
new(schema.User),
|
||||||
|
new(schema.UserRole),
|
||||||
|
new(schema.Banner),
|
||||||
|
new(schema.Article),
|
||||||
|
new(schema.Video),
|
||||||
|
new(schema.Memorabilia),
|
||||||
|
new(schema.Job),
|
||||||
|
new(schema.JobArea),
|
||||||
|
new(schema.WebSite),
|
||||||
|
new(schema.Team),
|
||||||
|
new(schema.Product),
|
||||||
|
new(schema.ProductCategory),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *RBAC) Init(ctx context.Context) error {
|
||||||
|
if config.C.Storage.DB.AutoMigrate {
|
||||||
|
if err := a.AutoMigrate(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := a.Casbinx.Load(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if name := config.C.General.MenuFile; name != "" {
|
||||||
|
fullPath := filepath.Join(config.C.General.WorkDir, name)
|
||||||
|
if err := a.MenuAPI.MenuBIZ.InitFromFile(ctx, fullPath); err != nil {
|
||||||
|
logging.Context(ctx).Error("failed to init menu data", zap.Error(err), zap.String("file", fullPath))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *RBAC) RegisterV1Routers(ctx context.Context, v1 *gin.RouterGroup) error {
|
||||||
|
captcha := v1.Group("captcha")
|
||||||
|
{
|
||||||
|
captcha.GET("id", a.LoginAPI.GetCaptcha)
|
||||||
|
captcha.GET("image", a.LoginAPI.ResponseCaptcha)
|
||||||
|
}
|
||||||
|
|
||||||
|
v1.POST("login", a.LoginAPI.Login)
|
||||||
|
v1.POST("upload", a.UploadAPI.SaveFile)
|
||||||
|
|
||||||
|
current := v1.Group("current")
|
||||||
|
{
|
||||||
|
current.POST("refresh-token", a.LoginAPI.RefreshToken)
|
||||||
|
current.GET("user", a.LoginAPI.GetUserInfo)
|
||||||
|
current.GET("menus", a.LoginAPI.QueryMenus)
|
||||||
|
current.PUT("password", a.LoginAPI.UpdatePassword)
|
||||||
|
current.PUT("user", a.LoginAPI.UpdateUser)
|
||||||
|
current.POST("logout", a.LoginAPI.Logout)
|
||||||
|
}
|
||||||
|
|
||||||
|
banner := v1.Group("banners")
|
||||||
|
{
|
||||||
|
banner.GET("", a.BannerAPI.Query)
|
||||||
|
banner.GET(":id", a.BannerAPI.Get)
|
||||||
|
banner.POST("", a.BannerAPI.Create)
|
||||||
|
banner.PUT(":id", a.BannerAPI.Update)
|
||||||
|
banner.DELETE(":id", a.BannerAPI.Delete)
|
||||||
|
}
|
||||||
|
|
||||||
|
job := v1.Group("jobs")
|
||||||
|
{
|
||||||
|
job.GET("", a.JobAPI.Query)
|
||||||
|
job.GET("job_areas", a.JobAPI.QueryJobArea)
|
||||||
|
job.POST("job_areas", a.JobAPI.CreateJobArea)
|
||||||
|
job.PUT("job_areas/:id", a.JobAPI.UpdateJobArea)
|
||||||
|
job.DELETE("job_areas/:id", a.JobAPI.DeleteJobArea)
|
||||||
|
job.GET(":id", a.JobAPI.Get)
|
||||||
|
job.POST("", a.JobAPI.Create)
|
||||||
|
job.PUT(":id", a.JobAPI.Update)
|
||||||
|
job.DELETE(":id", a.JobAPI.Delete)
|
||||||
|
}
|
||||||
|
memorabilia := v1.Group("memorabilias")
|
||||||
|
{
|
||||||
|
memorabilia.GET("", a.MemorabiliaAPI.Query)
|
||||||
|
memorabilia.GET(":id", a.MemorabiliaAPI.Get)
|
||||||
|
memorabilia.POST("", a.MemorabiliaAPI.Create)
|
||||||
|
memorabilia.PUT(":id", a.MemorabiliaAPI.Update)
|
||||||
|
memorabilia.DELETE(":id", a.MemorabiliaAPI.Delete)
|
||||||
|
}
|
||||||
|
team := v1.Group("teams")
|
||||||
|
{
|
||||||
|
team.GET("", a.TeamAPI.Query)
|
||||||
|
team.GET(":id", a.TeamAPI.Get)
|
||||||
|
team.POST("", a.TeamAPI.Create)
|
||||||
|
team.PUT(":id", a.TeamAPI.Update)
|
||||||
|
team.DELETE(":id", a.TeamAPI.Delete)
|
||||||
|
}
|
||||||
|
webSite := v1.Group("web_site")
|
||||||
|
{
|
||||||
|
webSite.GET("", a.WebSiteAPI.Query)
|
||||||
|
webSite.POST("", a.WebSiteAPI.Create)
|
||||||
|
webSite.PUT(":id", a.WebSiteAPI.Update)
|
||||||
|
}
|
||||||
|
product := v1.Group("products")
|
||||||
|
{
|
||||||
|
product.GET("", a.ProductAPI.Query)
|
||||||
|
product.GET("categorys", a.ProductAPI.QueryCategory)
|
||||||
|
product.GET(":id", a.ProductAPI.Get)
|
||||||
|
product.POST("", a.ProductAPI.Create)
|
||||||
|
product.PUT(":id", a.ProductAPI.Update)
|
||||||
|
product.DELETE(":id", a.ProductAPI.Delete)
|
||||||
|
}
|
||||||
|
|
||||||
|
article := v1.Group("articles")
|
||||||
|
{
|
||||||
|
article.GET("", a.ArticleAPI.Query)
|
||||||
|
article.GET(":id", a.ArticleAPI.Get)
|
||||||
|
article.POST("", a.ArticleAPI.Create)
|
||||||
|
article.PUT(":id", a.ArticleAPI.Update)
|
||||||
|
article.DELETE(":id", a.ArticleAPI.Delete)
|
||||||
|
}
|
||||||
|
video := v1.Group("videos")
|
||||||
|
{
|
||||||
|
video.GET("", a.VideoAPI.Query)
|
||||||
|
video.GET(":id", a.VideoAPI.Get)
|
||||||
|
video.POST("", a.VideoAPI.Create)
|
||||||
|
video.PUT(":id", a.VideoAPI.Update)
|
||||||
|
video.DELETE(":id", a.VideoAPI.Delete)
|
||||||
|
}
|
||||||
|
|
||||||
|
menu := v1.Group("menus")
|
||||||
|
{
|
||||||
|
menu.GET("", a.MenuAPI.Query)
|
||||||
|
menu.GET(":id", a.MenuAPI.Get)
|
||||||
|
menu.POST("", a.MenuAPI.Create)
|
||||||
|
menu.PUT(":id", a.MenuAPI.Update)
|
||||||
|
menu.DELETE(":id", a.MenuAPI.Delete)
|
||||||
|
}
|
||||||
|
|
||||||
|
role := v1.Group("roles")
|
||||||
|
{
|
||||||
|
role.GET("", a.RoleAPI.Query)
|
||||||
|
role.GET(":id", a.RoleAPI.Get)
|
||||||
|
role.POST("", a.RoleAPI.Create)
|
||||||
|
role.PUT(":id", a.RoleAPI.Update)
|
||||||
|
role.DELETE(":id", a.RoleAPI.Delete)
|
||||||
|
}
|
||||||
|
|
||||||
|
user := v1.Group("users")
|
||||||
|
{
|
||||||
|
user.GET("", a.UserAPI.Query)
|
||||||
|
user.GET(":id", a.UserAPI.Get)
|
||||||
|
user.POST("", a.UserAPI.Create)
|
||||||
|
user.PUT(":id", a.UserAPI.Update)
|
||||||
|
user.DELETE(":id", a.UserAPI.Delete)
|
||||||
|
user.PATCH(":id/reset-pwd", a.UserAPI.ResetPassword)
|
||||||
|
}
|
||||||
|
|
||||||
|
web := v1.Group("web")
|
||||||
|
{
|
||||||
|
web.GET("jobs", a.WebAPI.QueryJob)
|
||||||
|
web.GET("articles", a.WebAPI.QueryArticle)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
logger := v1.Group("loggers")
|
||||||
|
{
|
||||||
|
logger.GET("", a.LoggerAPI.Query)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *RBAC) Release(ctx context.Context) error {
|
||||||
|
if err := a.Casbinx.Release(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
17
internal/mods/rbac/resp/job.go
Normal file
17
internal/mods/rbac/resp/job.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package resp
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type JobAdminListResp struct {
|
||||||
|
AreaName string `json:"areaName"`
|
||||||
|
ID string `json:"id" `
|
||||||
|
JobAreaID string `json:"jobAreaId"`
|
||||||
|
Title string `json:"title" `
|
||||||
|
Introduce string `json:"introduce" `
|
||||||
|
Duty string `json:"duty" `
|
||||||
|
Salary string `json:"salary" `
|
||||||
|
Sequence int `json:"sequence"`
|
||||||
|
Status string `json:"status" `
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at" `
|
||||||
|
}
|
||||||
1
internal/mods/rbac/resp/web.go
Normal file
1
internal/mods/rbac/resp/web.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package resp
|
||||||
91
internal/mods/rbac/schema/article.go
Normal file
91
internal/mods/rbac/schema/article.go
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
package schema
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/config"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ArticleStatusDisabled = "disabled"
|
||||||
|
ArticleStatusEnabled = "enabled"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ArticleOrderParams = []util.OrderByParam{
|
||||||
|
{Field: "created_at", Direction: util.DESC},
|
||||||
|
{Field: "sequence", Direction: util.DESC},
|
||||||
|
}
|
||||||
|
ArticleOrderNoCreatedAtParams = []util.OrderByParam{
|
||||||
|
{Field: "sequence", Direction: util.DESC},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Article management for RBAC
|
||||||
|
type Article struct {
|
||||||
|
ID string `json:"id" gorm:"size:20;primarykey;"` // Unique ID
|
||||||
|
Title string `json:"title" gorm:"size:128;not null;index"` // Display name of banner
|
||||||
|
Img string `json:"img" gorm:"size:1024"` // Details about banner
|
||||||
|
Sequence int `json:"sequence" gorm:"index;"` // Sequence for sorting (Order by desc)
|
||||||
|
Link string `json:"link" gorm:"size:1024;"`
|
||||||
|
Content string `json:"content" gorm:"type:text;comment:详情"`
|
||||||
|
PushAt string `json:"pushAt" gorm:"size:50;index"`
|
||||||
|
Typer string `json:"type" gorm:"size:50;not null;index"` // Type of banner (banner, link) // Parent menu``
|
||||||
|
Status string `json:"status" gorm:"size:20;index"` // Status of banner (enabled, disabled) // Child menus
|
||||||
|
CreatedAt time.Time `json:"created_at" gorm:"index;"` // Create time
|
||||||
|
UpdatedAt time.Time `json:"updated_at" gorm:"index;"` // Update time
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Article) TableName() string {
|
||||||
|
return config.C.FormatTableName("article")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query parameters for the `Menu` struct.
|
||||||
|
type ArticleQueryParam struct {
|
||||||
|
util.PaginationParam
|
||||||
|
LikeTitle string `form:"title"` // Display name of menu
|
||||||
|
Typer string `form:"type" bind:"required,max=50"`
|
||||||
|
Status string `form:"status"` // Status of menu (enabled, disabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query options for the `Menu` struct.
|
||||||
|
type ArticleQueryOptions struct {
|
||||||
|
util.QueryOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query result for the `Menu` struct.
|
||||||
|
type ArticleQueryResult struct {
|
||||||
|
Data Articles
|
||||||
|
PageResult *util.PaginationResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the slice of `Menu` struct.
|
||||||
|
type Articles []*Article
|
||||||
|
|
||||||
|
func (a Articles) Len() int {
|
||||||
|
return len(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ArticleForm struct {
|
||||||
|
Title string `json:"title" binding:"required,max=128"` // Display name of menu
|
||||||
|
Sequence int `json:"sequence"` // Sequence for sorting (Order by desc)
|
||||||
|
Link string `json:"link" `
|
||||||
|
Content string `json:"content"`
|
||||||
|
PushAt string `json:"pushAt"`
|
||||||
|
Typer string `json:"type" binding:"required,oneof=banner home achievement honor talent_center team news"` // Type of menu (banner, link) // Parent menu``
|
||||||
|
Img string `json:"img" ` // Details about banner
|
||||||
|
Status string `json:"status" binding:"required,oneof=disabled enabled"` // Status of menu (enabled, disabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ArticleForm) FillTo(article *Article) error {
|
||||||
|
article.Title = a.Title
|
||||||
|
article.PushAt = a.PushAt
|
||||||
|
article.Sequence = a.Sequence
|
||||||
|
article.Content = a.Content
|
||||||
|
article.Img = a.Img
|
||||||
|
article.Link = a.Link
|
||||||
|
article.Typer = a.Typer
|
||||||
|
article.Status = a.Status
|
||||||
|
return nil
|
||||||
|
}
|
||||||
84
internal/mods/rbac/schema/banner.go
Normal file
84
internal/mods/rbac/schema/banner.go
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
package schema
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/guxuan/hailin_service/internal/config"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
BannerStatusDisabled = "disabled"
|
||||||
|
BannerStatusEnabled = "enabled"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
BannerOrderParams = []util.OrderByParam{
|
||||||
|
{Field: "created_at", Direction: util.DESC},
|
||||||
|
{Field: "sequence", Direction: util.DESC},
|
||||||
|
}
|
||||||
|
BannerOrderNoCreatedAtParams = []util.OrderByParam{
|
||||||
|
{Field: "sequence", Direction: util.DESC},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Menu management for RBAC
|
||||||
|
type Banner struct {
|
||||||
|
ID string `json:"id" gorm:"size:20;primarykey;"` // Unique ID
|
||||||
|
Name string `json:"name" gorm:"size:128;not null;index"` // Display name of banner
|
||||||
|
Img string `json:"img" gorm:"size:1024"` // Details about banner
|
||||||
|
Sequence int `json:"sequence" gorm:"index;"` // Sequence for sorting (Order by desc)
|
||||||
|
Link string `json:"link" gorm:"size:1024;"`
|
||||||
|
Typer int `json:"type" gorm:"size:11;not null;index"` // Type of banner (banner, link) // Parent menu``
|
||||||
|
Status string `json:"status" gorm:"size:20;index"` // Status of banner (enabled, disabled) // Child menus
|
||||||
|
CreatedAt time.Time `json:"created_at" gorm:"index;"` // Create time
|
||||||
|
UpdatedAt time.Time `json:"updated_at" gorm:"index;"` // Update time
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Banner) TableName() string {
|
||||||
|
return config.C.FormatTableName("banner")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query parameters for the `Menu` struct.
|
||||||
|
type BannerQueryParam struct {
|
||||||
|
util.PaginationParam
|
||||||
|
LikeName string `form:"name"` // Display name of menu
|
||||||
|
Typer int `form:"type" bind:"required,max=11"`
|
||||||
|
Status string `form:"status"` // Status of menu (enabled, disabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query options for the `Menu` struct.
|
||||||
|
type BannerQueryOptions struct {
|
||||||
|
util.QueryOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query result for the `Menu` struct.
|
||||||
|
type BannerQueryResult struct {
|
||||||
|
Data Banners
|
||||||
|
PageResult *util.PaginationResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the slice of `Menu` struct.
|
||||||
|
type Banners []*Banner
|
||||||
|
|
||||||
|
func (a Banners) Len() int {
|
||||||
|
return len(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
type BannerForm struct {
|
||||||
|
Name string `json:"name" binding:"required,max=128"` // Display name of menu
|
||||||
|
Sequence int `json:"sequence"` // Sequence for sorting (Order by desc)
|
||||||
|
Link string `json:"link" `
|
||||||
|
Typer int `json:"type" binding:"required"` // Type of menu (banner, link) // Parent menu``
|
||||||
|
Img string `json:"img" gorm:"size:1024"` // Details about banner
|
||||||
|
Status string `json:"status" binding:"required,oneof=disabled enabled"` // Status of menu (enabled, disabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *BannerForm) FillTo(banner *Banner) error {
|
||||||
|
banner.Name = a.Name
|
||||||
|
banner.Sequence = a.Sequence
|
||||||
|
banner.Img = a.Img
|
||||||
|
banner.Link = a.Link
|
||||||
|
banner.Typer = a.Typer
|
||||||
|
banner.Status = a.Status
|
||||||
|
return nil
|
||||||
|
}
|
||||||
108
internal/mods/rbac/schema/job.go
Normal file
108
internal/mods/rbac/schema/job.go
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
package schema
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/config"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
JobStatusDisabled = "disabled"
|
||||||
|
JobStatusEnabled = "enabled"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
JobOrderParams = []util.OrderByParam{
|
||||||
|
{Field: "created_at", Direction: util.DESC},
|
||||||
|
{Field: "sequence", Direction: util.DESC},
|
||||||
|
}
|
||||||
|
JobOrderNoCreatedAtParams = []util.OrderByParam{
|
||||||
|
{Field: "sequence", Direction: util.DESC},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Article management for RBAC
|
||||||
|
type Job struct {
|
||||||
|
ID string `json:"id" gorm:"size:20;primarykey;"` //主键
|
||||||
|
JobAreaID string `json:"jobAreaId" gorm:"size:20;not null;index"` //职位地区id
|
||||||
|
Title string `json:"title" gorm:"size:128;not null;index"` //标题
|
||||||
|
Introduce string `json:"introduce" gorm:"type:text"` //要求
|
||||||
|
Duty string `json:"duty" gorm:"type:text"` //职责
|
||||||
|
Salary string `json:"salary" gorm:"size:50"` //薪资
|
||||||
|
Sequence int `json:"sequence" gorm:"index;"` //排序
|
||||||
|
Status string `json:"status" gorm:"size:20;index"` //状态
|
||||||
|
CreatedAt time.Time `json:"created_at" gorm:"index;"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at" gorm:"index;"`
|
||||||
|
}
|
||||||
|
type JobArea struct {
|
||||||
|
ID string `json:"id" gorm:"size:20;primarykey;"` // Unique ID
|
||||||
|
Name string `json:"name" gorm:"size:128;not null;index"` // 区域名字
|
||||||
|
Status string `json:"status" gorm:"size:20;index"` // Status of banner (enabled, disabled) // Child menus
|
||||||
|
CreatedAt time.Time `json:"created_at" gorm:"index;"` // Create time
|
||||||
|
UpdatedAt time.Time `json:"updated_at" gorm:"index;"` // Update time
|
||||||
|
}
|
||||||
|
|
||||||
|
type WebJobData struct {
|
||||||
|
JobAreaTitle string `json:"jobAreaTitle"`
|
||||||
|
JobList Jobs `json:"jobList"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Job) TableName() string {
|
||||||
|
return config.C.FormatTableName("job")
|
||||||
|
}
|
||||||
|
func (a *JobArea) TableName() string {
|
||||||
|
return config.C.FormatTableName("job_area")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query parameters for the `Menu` struct.
|
||||||
|
type JobQueryParam struct {
|
||||||
|
util.PaginationParam
|
||||||
|
JobAreaID string `form:"jobAreaId"` // Display name of menu
|
||||||
|
LikeTitle string `form:"title"` // Display name of menu
|
||||||
|
Status string `form:"status"` // Status of menu (enabled, disabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query options for the `Menu` struct.
|
||||||
|
type JobQueryOptions struct {
|
||||||
|
util.QueryOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query result for the `Menu` struct.
|
||||||
|
type JobQueryResult struct {
|
||||||
|
Data Jobs
|
||||||
|
PageResult *util.PaginationResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the slice of `Menu` struct.
|
||||||
|
type Jobs []*Job
|
||||||
|
|
||||||
|
func (a Jobs) Len() int {
|
||||||
|
return len(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
type JobForm struct {
|
||||||
|
Title string `json:"title" binding:"required,max=128"` // Display name of menu
|
||||||
|
Sequence int `json:"sequence"` // Sequence for sorting (Order by desc)
|
||||||
|
JobAreaId string `json:"jobAreaId" `
|
||||||
|
Introduce string `json:"introduce"`
|
||||||
|
Duty string `json:"duty" `
|
||||||
|
Salary string `json:"salary"` // Details about banner
|
||||||
|
Status string `json:"status" binding:"required,oneof=disabled enabled"` // Status of menu (enabled, disabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
type JobAreaForm struct {
|
||||||
|
Name string `json:"name" binding:"required,max=128"` // Display name of menu // Details about banner
|
||||||
|
Status string `json:"status" binding:"required,oneof=disabled enabled"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *JobForm) FillTo(job *Job) error {
|
||||||
|
job.Title = a.Title
|
||||||
|
job.JobAreaID = a.JobAreaId
|
||||||
|
job.Sequence = a.Sequence
|
||||||
|
job.Introduce = a.Introduce
|
||||||
|
job.Duty = a.Duty
|
||||||
|
job.Salary = a.Salary
|
||||||
|
job.Status = a.Status
|
||||||
|
return nil
|
||||||
|
}
|
||||||
53
internal/mods/rbac/schema/logger.go
Normal file
53
internal/mods/rbac/schema/logger.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package schema
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/config"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Logger management
|
||||||
|
type Logger struct {
|
||||||
|
ID string `gorm:"size:20;primaryKey;" json:"id"` // Unique ID
|
||||||
|
Level string `gorm:"size:20;index;" json:"level"` // Log level
|
||||||
|
TraceID string `gorm:"size:64;index;" json:"trace_id"` // Trace ID
|
||||||
|
UserID string `gorm:"size:20;index;" json:"user_id"` // User ID
|
||||||
|
Tag string `gorm:"size:32;index;" json:"tag"` // Log tag
|
||||||
|
Message string `gorm:"size:1024;" json:"message"` // Log message
|
||||||
|
Stack string `gorm:"type:text;" json:"stack"` // Error stack
|
||||||
|
Data string `gorm:"type:text;" json:"data"` // Log data
|
||||||
|
CreatedAt time.Time `gorm:"index;" json:"created_at"` // Create time
|
||||||
|
LoginName string `json:"login_name" gorm:"<-:false;-:migration;"` // From User.Username
|
||||||
|
UserName string `json:"user_name" gorm:"<-:false;-:migration;"` // From User.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Logger) TableName() string {
|
||||||
|
return config.C.FormatTableName("logger")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query parameters for the `Logger` struct.
|
||||||
|
type LoggerQueryParam struct {
|
||||||
|
util.PaginationParam
|
||||||
|
Level string `form:"level"` // Log level
|
||||||
|
TraceID string `form:"traceID"` // Trace ID
|
||||||
|
LikeUserName string `form:"userName"` // User Name
|
||||||
|
Tag string `form:"tag"` // Log tag
|
||||||
|
LikeMessage string `form:"message"` // Log message
|
||||||
|
StartTime string `form:"startTime"` // Start time
|
||||||
|
EndTime string `form:"endTime"` // End time
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query options for the `Logger` struct.
|
||||||
|
type LoggerQueryOptions struct {
|
||||||
|
util.QueryOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query result for the `Logger` struct.
|
||||||
|
type LoggerQueryResult struct {
|
||||||
|
Data Loggers
|
||||||
|
PageResult *util.PaginationResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the slice of `Logger` struct.
|
||||||
|
type Loggers []*Logger
|
||||||
38
internal/mods/rbac/schema/login.go
Normal file
38
internal/mods/rbac/schema/login.go
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package schema
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
type Captcha struct {
|
||||||
|
CaptchaID string `json:"captcha_id"` // Captcha ID
|
||||||
|
}
|
||||||
|
|
||||||
|
type LoginForm struct {
|
||||||
|
Username string `json:"username" binding:"required"` // Login name
|
||||||
|
Password string `json:"password" binding:"required"` // Login password (md5 hash)
|
||||||
|
CaptchaID string `json:"captcha_id" ` // Captcha verify id
|
||||||
|
CaptchaCode string `json:"captcha_code" ` // Captcha verify code
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *LoginForm) Trim() *LoginForm {
|
||||||
|
a.Username = strings.TrimSpace(a.Username)
|
||||||
|
a.CaptchaCode = strings.TrimSpace(a.CaptchaCode)
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateLoginPassword struct {
|
||||||
|
OldPassword string `json:"old_password" binding:"required"` // Old password (md5 hash)
|
||||||
|
NewPassword string `json:"new_password" binding:"required"` // New password (md5 hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
type LoginToken struct {
|
||||||
|
AccessToken string `json:"access_token"` // Access token (JWT)
|
||||||
|
TokenType string `json:"token_type"` // Token type (Usage: Authorization=${token_type} ${access_token})
|
||||||
|
ExpiresAt int64 `json:"expires_at"` // Expired time (Unit: second)
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateCurrentUser struct {
|
||||||
|
Name string `json:"name" binding:"required,max=64"` // Name of user
|
||||||
|
Phone string `json:"phone" binding:"max=32"` // Phone number of user
|
||||||
|
Email string `json:"email" binding:"max=128"` // Email of user
|
||||||
|
Remark string `json:"remark" binding:"max=1024"` // Remark of user
|
||||||
|
}
|
||||||
79
internal/mods/rbac/schema/memorabilia.go
Normal file
79
internal/mods/rbac/schema/memorabilia.go
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
package schema
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/config"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
MemorabiliaStatusDisabled = "disabled"
|
||||||
|
MemorabiliaStatusEnabled = "enabled"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
MemorabiliaOrderParams = []util.OrderByParam{
|
||||||
|
{Field: "sequence", Direction: util.DESC},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Article management for RBAC
|
||||||
|
type Memorabilia struct {
|
||||||
|
ID string `json:"id" gorm:"size:20;primarykey;"` // Unique ID
|
||||||
|
Title string `json:"title" gorm:"size:128;not null;index"` // Display name of banner
|
||||||
|
Sequence int `json:"sequence" gorm:"index;default:0"`
|
||||||
|
Year int `json:"year" gorm:"size:10;not null;index"` // Type of banner (banner, link) // Parent menu``
|
||||||
|
Month int `json:"month" gorm:"size:10;not null;index"` // Type of banner (banner, link) // Parent menu``
|
||||||
|
Status string `json:"status" gorm:"size:20;index"` // Status of banner (enabled, disabled) // Child menus
|
||||||
|
CreatedAt time.Time `json:"created_at" gorm:"index;"` // Create time
|
||||||
|
UpdatedAt time.Time `json:"updated_at" gorm:"index;"` // Update time
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Memorabilia) TableName() string {
|
||||||
|
return config.C.FormatTableName("memorabilia")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query parameters for the `Menu` struct.
|
||||||
|
type MemorabiliaQueryParam struct {
|
||||||
|
util.PaginationParam
|
||||||
|
LikeTitle string `form:"title"` // Display name of menu
|
||||||
|
Month int `form:"month"`
|
||||||
|
Year int `form:"year"`
|
||||||
|
Status string `form:"status"` // Status of menu (enabled, disabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query options for the `Menu` struct.
|
||||||
|
type MemorabiliaQueryOptions struct {
|
||||||
|
util.QueryOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query result for the `Menu` struct.
|
||||||
|
type MemorabiliaQueryResult struct {
|
||||||
|
Data Memorabilias
|
||||||
|
PageResult *util.PaginationResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the slice of `Menu` struct.
|
||||||
|
type Memorabilias []*Memorabilia
|
||||||
|
|
||||||
|
func (a Memorabilias) Len() int {
|
||||||
|
return len(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
type MemorabiliaForm struct {
|
||||||
|
Title string `json:"title" binding:"required,max=128"` // Display name of menu
|
||||||
|
Sequence int `json:"sequence"` // Sequence for sorting (Order by desc)
|
||||||
|
Year int `json:"year"`
|
||||||
|
Month int `json:"month"`
|
||||||
|
Status string `json:"status" binding:"required,oneof=disabled enabled"` // Status of menu (enabled, disabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *MemorabiliaForm) FillTo(memorabilia *Memorabilia) error {
|
||||||
|
memorabilia.Title = a.Title
|
||||||
|
memorabilia.Month = a.Month
|
||||||
|
memorabilia.Sequence = a.Sequence
|
||||||
|
memorabilia.Year = a.Year
|
||||||
|
memorabilia.Status = a.Status
|
||||||
|
return nil
|
||||||
|
}
|
||||||
178
internal/mods/rbac/schema/menu.go
Normal file
178
internal/mods/rbac/schema/menu.go
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
package schema
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/config"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/errors"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
MenuStatusDisabled = "disabled"
|
||||||
|
MenuStatusEnabled = "enabled"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
MenusOrderParams = []util.OrderByParam{
|
||||||
|
{Field: "sequence", Direction: util.DESC},
|
||||||
|
{Field: "created_at", Direction: util.DESC},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Menu management for RBAC
|
||||||
|
type Menu struct {
|
||||||
|
ID string `json:"id" gorm:"size:20;primarykey;"` // Unique ID
|
||||||
|
Code string `json:"code" gorm:"size:32;index;"` // Code of menu (unique for each level)
|
||||||
|
Name string `json:"name" gorm:"size:128;index"` // Display name of menu
|
||||||
|
Description string `json:"description" gorm:"size:1024"` // Details about menu
|
||||||
|
Sequence int `json:"sequence" gorm:"index;"` // Sequence for sorting (Order by desc)
|
||||||
|
Type string `json:"type" gorm:"size:20;index"` // Type of menu (page, button)
|
||||||
|
Path string `json:"path" gorm:"size:255;"` // Access path of menu
|
||||||
|
Properties string `json:"properties" gorm:"type:text;"` // Properties of menu (JSON)
|
||||||
|
Status string `json:"status" gorm:"size:20;index"` // Status of menu (enabled, disabled)
|
||||||
|
ParentID string `json:"parent_id" gorm:"size:20;index;"` // Parent ID (From Menu.ID)
|
||||||
|
ParentPath string `json:"parent_path" gorm:"size:255;index;"` // Parent path (split by .)
|
||||||
|
Children *Menus `json:"children" gorm:"-"` // Child menus
|
||||||
|
CreatedAt time.Time `json:"created_at" gorm:"index;"` // Create time
|
||||||
|
UpdatedAt time.Time `json:"updated_at" gorm:"index;"` // Update time
|
||||||
|
Resources MenuResources `json:"resources" gorm:"-"` // Resources of menu
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Menu) TableName() string {
|
||||||
|
return config.C.FormatTableName("menu")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query parameters for the `Menu` struct.
|
||||||
|
type MenuQueryParam struct {
|
||||||
|
util.PaginationParam
|
||||||
|
CodePath string `form:"code"` // Code path (like xxx.xxx.xxx)
|
||||||
|
LikeName string `form:"name"` // Display name of menu
|
||||||
|
IncludeResources bool `form:"includeResources"` // Include resources
|
||||||
|
InIDs []string `form:"-"` // Include menu IDs
|
||||||
|
Status string `form:"-"` // Status of menu (disabled, enabled)
|
||||||
|
ParentID string `form:"-"` // Parent ID (From Menu.ID)
|
||||||
|
ParentPathPrefix string `form:"-"` // Parent path (split by .)
|
||||||
|
UserID string `form:"-"` // User ID
|
||||||
|
RoleID string `form:"-"` // Role ID
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query options for the `Menu` struct.
|
||||||
|
type MenuQueryOptions struct {
|
||||||
|
util.QueryOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query result for the `Menu` struct.
|
||||||
|
type MenuQueryResult struct {
|
||||||
|
Data Menus
|
||||||
|
PageResult *util.PaginationResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the slice of `Menu` struct.
|
||||||
|
type Menus []*Menu
|
||||||
|
|
||||||
|
func (a Menus) Len() int {
|
||||||
|
return len(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a Menus) Less(i, j int) bool {
|
||||||
|
if a[i].Sequence == a[j].Sequence {
|
||||||
|
return a[i].CreatedAt.Unix() > a[j].CreatedAt.Unix()
|
||||||
|
}
|
||||||
|
return a[i].Sequence > a[j].Sequence
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a Menus) Swap(i, j int) {
|
||||||
|
a[i], a[j] = a[j], a[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a Menus) ToMap() map[string]*Menu {
|
||||||
|
m := make(map[string]*Menu)
|
||||||
|
for _, item := range a {
|
||||||
|
m[item.ID] = item
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a Menus) SplitParentIDs() []string {
|
||||||
|
parentIDs := make([]string, 0, len(a))
|
||||||
|
idMapper := make(map[string]struct{})
|
||||||
|
for _, item := range a {
|
||||||
|
if _, ok := idMapper[item.ID]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
idMapper[item.ID] = struct{}{}
|
||||||
|
if pp := item.ParentPath; pp != "" {
|
||||||
|
for _, pid := range strings.Split(pp, util.TreePathDelimiter) {
|
||||||
|
if pid == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _, ok := idMapper[pid]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
parentIDs = append(parentIDs, pid)
|
||||||
|
idMapper[pid] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return parentIDs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a Menus) ToTree() Menus {
|
||||||
|
var list Menus
|
||||||
|
m := a.ToMap()
|
||||||
|
for _, item := range a {
|
||||||
|
if item.ParentID == "" {
|
||||||
|
list = append(list, item)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if parent, ok := m[item.ParentID]; ok {
|
||||||
|
if parent.Children == nil {
|
||||||
|
children := Menus{item}
|
||||||
|
parent.Children = &children
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
*parent.Children = append(*parent.Children, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the data structure for creating a `Menu` struct.
|
||||||
|
type MenuForm struct {
|
||||||
|
Code string `json:"code" binding:"required,max=32"` // Code of menu (unique for each level)
|
||||||
|
Name string `json:"name" binding:"required,max=128"` // Display name of menu
|
||||||
|
Description string `json:"description"` // Details about menu
|
||||||
|
Sequence int `json:"sequence"` // Sequence for sorting (Order by desc)
|
||||||
|
Type string `json:"type" binding:"required,oneof=page button"` // Type of menu (page, button)
|
||||||
|
Path string `json:"path"` // Access path of menu
|
||||||
|
Properties string `json:"properties"` // Properties of menu (JSON)
|
||||||
|
Status string `json:"status" binding:"required,oneof=disabled enabled"` // Status of menu (enabled, disabled)
|
||||||
|
ParentID string `json:"parent_id"` // Parent ID (From Menu.ID)
|
||||||
|
Resources MenuResources `json:"resources"` // Resources of menu
|
||||||
|
}
|
||||||
|
|
||||||
|
// A validation function for the `MenuForm` struct.
|
||||||
|
func (a *MenuForm) Validate() error {
|
||||||
|
if v := a.Properties; v != "" {
|
||||||
|
if !json.Valid([]byte(v)) {
|
||||||
|
return errors.BadRequest("", "invalid properties")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *MenuForm) FillTo(menu *Menu) error {
|
||||||
|
menu.Code = a.Code
|
||||||
|
menu.Name = a.Name
|
||||||
|
menu.Description = a.Description
|
||||||
|
menu.Sequence = a.Sequence
|
||||||
|
menu.Type = a.Type
|
||||||
|
menu.Path = a.Path
|
||||||
|
menu.Properties = a.Properties
|
||||||
|
menu.Status = a.Status
|
||||||
|
menu.ParentID = a.ParentID
|
||||||
|
return nil
|
||||||
|
}
|
||||||
56
internal/mods/rbac/schema/menu_resource.go
Normal file
56
internal/mods/rbac/schema/menu_resource.go
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package schema
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/config"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Menu resource management for RBAC
|
||||||
|
type MenuResource struct {
|
||||||
|
ID string `json:"id" gorm:"size:20;primarykey"` // Unique ID
|
||||||
|
MenuID string `json:"menu_id" gorm:"size:20;index"` // From Menu.ID
|
||||||
|
Method string `json:"method" gorm:"size:20;"` // HTTP method
|
||||||
|
Path string `json:"path" gorm:"size:255;"` // API request path (e.g. /api/v1/users/:id)
|
||||||
|
CreatedAt time.Time `json:"created_at" gorm:"index;"` // Create time
|
||||||
|
UpdatedAt time.Time `json:"updated_at" gorm:"index;"` // Update time
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *MenuResource) TableName() string {
|
||||||
|
return config.C.FormatTableName("menu_resource")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query parameters for the `MenuResource` struct.
|
||||||
|
type MenuResourceQueryParam struct {
|
||||||
|
util.PaginationParam
|
||||||
|
MenuID string `form:"-"` // From Menu.ID
|
||||||
|
MenuIDs []string `form:"-"` // From Menu.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query options for the `MenuResource` struct.
|
||||||
|
type MenuResourceQueryOptions struct {
|
||||||
|
util.QueryOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query result for the `MenuResource` struct.
|
||||||
|
type MenuResourceQueryResult struct {
|
||||||
|
Data MenuResources
|
||||||
|
PageResult *util.PaginationResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the slice of `MenuResource` struct.
|
||||||
|
type MenuResources []*MenuResource
|
||||||
|
|
||||||
|
// Defining the data structure for creating a `MenuResource` struct.
|
||||||
|
type MenuResourceForm struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// A validation function for the `MenuResourceForm` struct.
|
||||||
|
func (a *MenuResourceForm) Validate() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *MenuResourceForm) FillTo(menuResource *MenuResource) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
114
internal/mods/rbac/schema/product.go
Normal file
114
internal/mods/rbac/schema/product.go
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
package schema
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/config"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ProductStatusDisabled = "disabled"
|
||||||
|
ProudctStatusEnabled = "enabled"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ProductOrderParams = []util.OrderByParam{
|
||||||
|
{Field: "created_at", Direction: util.DESC},
|
||||||
|
{Field: "sequence", Direction: util.DESC},
|
||||||
|
}
|
||||||
|
ProductOrderNoCreatedAtParams = []util.OrderByParam{
|
||||||
|
{Field: "sequence", Direction: util.DESC},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Article management for RBAC
|
||||||
|
type Product struct {
|
||||||
|
ID string `json:"id" gorm:"size:20;primarykey;"`
|
||||||
|
CategoryID uint `json:"categoryID" gorm:"index;"`
|
||||||
|
Title string `json:"title" gorm:"size:128;not null;index"` // Display name of banner
|
||||||
|
Images []string `json:"images" gorm:"serializer:json"`
|
||||||
|
Code string `json:"code" gorm:"size:50"` // Details about banner
|
||||||
|
Sequence int `json:"sequence" gorm:"index;"` // Sequence for sorting (Order by desc)
|
||||||
|
Compose string `json:"compose" gorm:"size:1024;"`
|
||||||
|
Target string `json:"target" gorm:"size:1024"`
|
||||||
|
Standard *[]ProductStandard `json:"standard" gorm:"serializer:json"`
|
||||||
|
Feature string `json:"feature" gorm:"size:2048"` // Type of banner (banner, link) // Parent menu``
|
||||||
|
Status string `json:"status" gorm:"size:20;index"` // Status of banner (enabled, disabled) // Child menus
|
||||||
|
CreatedAt time.Time `json:"created_at" gorm:"index;"` // Create time
|
||||||
|
UpdatedAt time.Time `json:"updated_at" gorm:"index;"` // Update time
|
||||||
|
}
|
||||||
|
type ProductStandard struct {
|
||||||
|
Label string
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProductCategory struct {
|
||||||
|
ID uint `json:"id" gorm:"primaryKey"`
|
||||||
|
Label string `json:"label" gorm:"size:128;not null;index"` // Display name of banner
|
||||||
|
ParentID uint `json:"parentID" gorm:"size:50;not null;index"` // Type of banner (banner, link) // Parent menu``
|
||||||
|
Status string `json:"status" gorm:"size:20;index"` // Status of banner (enabled, disabled) // Child menus
|
||||||
|
CreatedAt time.Time `json:"created_at" gorm:"index;"` // Create time
|
||||||
|
UpdatedAt time.Time `json:"updated_at" gorm:"index;"` // Update time
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Product) TableName() string {
|
||||||
|
return config.C.FormatTableName("product")
|
||||||
|
}
|
||||||
|
func (a *ProductCategory) TableName() string {
|
||||||
|
return config.C.FormatTableName("product_category")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query parameters for the `Menu` struct.
|
||||||
|
type ProductQueryParam struct {
|
||||||
|
util.PaginationParam
|
||||||
|
LikeTitle string `form:"title"` // Display name of menu
|
||||||
|
CategoryID uint `form:"categoryId"`
|
||||||
|
Code string `form:"code" `
|
||||||
|
Status string `form:"status"` // Status of menu (enabled, disabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query options for the `Menu` struct.
|
||||||
|
type ProductQueryOptions struct {
|
||||||
|
util.QueryOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query result for the `Menu` struct.
|
||||||
|
type ProductQueryResult struct {
|
||||||
|
Data Products
|
||||||
|
PageResult *util.PaginationResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the slice of `Menu` struct.
|
||||||
|
type Products []*Product
|
||||||
|
|
||||||
|
func (a Products) Len() int {
|
||||||
|
return len(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProductForm struct {
|
||||||
|
CategoryID uint `json:"categoryID" binding:"required,max=11"`
|
||||||
|
Title string `json:"title" binding:"required,max=128"` // Display name of menu
|
||||||
|
Images []string `json:"images"`
|
||||||
|
Sequence int `json:"sequence"` // Sequence for sorting (Order by desc)
|
||||||
|
Code string `json:"code" `
|
||||||
|
Compose string `json:"compose"`
|
||||||
|
Feature string `json:"feature"`
|
||||||
|
Target string `json:"target" ` // Type of menu (banner, link) // Parent menu``
|
||||||
|
Standard *[]ProductStandard `json:"standard" ` // Details about banner
|
||||||
|
Status string `json:"status" binding:"required,oneof=disabled enabled"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ProductForm) FillTo(product *Product) error {
|
||||||
|
product.Title = a.Title
|
||||||
|
product.Compose = a.Compose
|
||||||
|
product.Sequence = a.Sequence
|
||||||
|
product.Code = a.Code
|
||||||
|
product.CategoryID = a.CategoryID
|
||||||
|
product.Standard = a.Standard
|
||||||
|
product.Images = a.Images
|
||||||
|
product.Feature = a.Feature
|
||||||
|
product.Target = a.Target
|
||||||
|
product.Status = a.Status
|
||||||
|
return nil
|
||||||
|
}
|
||||||
80
internal/mods/rbac/schema/role.go
Normal file
80
internal/mods/rbac/schema/role.go
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
package schema
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/config"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
RoleStatusEnabled = "enabled" // Enabled
|
||||||
|
RoleStatusDisabled = "disabled" // Disabled
|
||||||
|
|
||||||
|
RoleResultTypeSelect = "select" // Select
|
||||||
|
)
|
||||||
|
|
||||||
|
// Role management for RBAC
|
||||||
|
type Role struct {
|
||||||
|
ID string `json:"id" gorm:"size:20;primarykey;"` // Unique ID
|
||||||
|
Code string `json:"code" gorm:"size:32;index;"` // Code of role (unique)
|
||||||
|
Name string `json:"name" gorm:"size:128;index"` // Display name of role
|
||||||
|
Description string `json:"description" gorm:"size:1024"` // Details about role
|
||||||
|
Sequence int `json:"sequence" gorm:"index"` // Sequence for sorting
|
||||||
|
Status string `json:"status" gorm:"size:20;index"` // Status of role (disabled, enabled)
|
||||||
|
CreatedAt time.Time `json:"created_at" gorm:"index;"` // Create time
|
||||||
|
UpdatedAt time.Time `json:"updated_at" gorm:"index;"` // Update time
|
||||||
|
Menus RoleMenus `json:"menus" gorm:"-"` // Role menu list
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Role) TableName() string {
|
||||||
|
return config.C.FormatTableName("role")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query parameters for the `Role` struct.
|
||||||
|
type RoleQueryParam struct {
|
||||||
|
util.PaginationParam
|
||||||
|
LikeName string `form:"name"` // Display name of role
|
||||||
|
Status string `form:"status" binding:"oneof=disabled enabled ''"` // Status of role (disabled, enabled)
|
||||||
|
ResultType string `form:"resultType"` // Result type (options: select)
|
||||||
|
InIDs []string `form:"-"` // ID list
|
||||||
|
GtUpdatedAt *time.Time `form:"-"` // Update time is greater than
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query options for the `Role` struct.
|
||||||
|
type RoleQueryOptions struct {
|
||||||
|
util.QueryOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query result for the `Role` struct.
|
||||||
|
type RoleQueryResult struct {
|
||||||
|
Data Roles
|
||||||
|
PageResult *util.PaginationResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the slice of `Role` struct.
|
||||||
|
type Roles []*Role
|
||||||
|
|
||||||
|
// Defining the data structure for creating a `Role` struct.
|
||||||
|
type RoleForm struct {
|
||||||
|
Code string `json:"code" binding:"required,max=32"` // Code of role (unique)
|
||||||
|
Name string `json:"name" binding:"required,max=128"` // Display name of role
|
||||||
|
Description string `json:"description"` // Details about role
|
||||||
|
Sequence int `json:"sequence"` // Sequence for sorting
|
||||||
|
Status string `json:"status" binding:"required,oneof=disabled enabled"` // Status of role (enabled, disabled)
|
||||||
|
Menus RoleMenus `json:"menus"` // Role menu list
|
||||||
|
}
|
||||||
|
|
||||||
|
// A validation function for the `RoleForm` struct.
|
||||||
|
func (a *RoleForm) Validate() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *RoleForm) FillTo(role *Role) error {
|
||||||
|
role.Code = a.Code
|
||||||
|
role.Name = a.Name
|
||||||
|
role.Description = a.Description
|
||||||
|
role.Sequence = a.Sequence
|
||||||
|
role.Status = a.Status
|
||||||
|
return nil
|
||||||
|
}
|
||||||
54
internal/mods/rbac/schema/role_menu.go
Normal file
54
internal/mods/rbac/schema/role_menu.go
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
package schema
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/config"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Role permissions for RBAC
|
||||||
|
type RoleMenu struct {
|
||||||
|
ID string `json:"id" gorm:"size:20;primarykey"` // Unique ID
|
||||||
|
RoleID string `json:"role_id" gorm:"size:20;index"` // From Role.ID
|
||||||
|
MenuID string `json:"menu_id" gorm:"size:20;index"` // From Menu.ID
|
||||||
|
CreatedAt time.Time `json:"created_at" gorm:"index;"` // Create time
|
||||||
|
UpdatedAt time.Time `json:"updated_at" gorm:"index;"` // Update time
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *RoleMenu) TableName() string {
|
||||||
|
return config.C.FormatTableName("role_menu")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query parameters for the `RoleMenu` struct.
|
||||||
|
type RoleMenuQueryParam struct {
|
||||||
|
util.PaginationParam
|
||||||
|
RoleID string `form:"-"` // From Role.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query options for the `RoleMenu` struct.
|
||||||
|
type RoleMenuQueryOptions struct {
|
||||||
|
util.QueryOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query result for the `RoleMenu` struct.
|
||||||
|
type RoleMenuQueryResult struct {
|
||||||
|
Data RoleMenus
|
||||||
|
PageResult *util.PaginationResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the slice of `RoleMenu` struct.
|
||||||
|
type RoleMenus []*RoleMenu
|
||||||
|
|
||||||
|
// Defining the data structure for creating a `RoleMenu` struct.
|
||||||
|
type RoleMenuForm struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// A validation function for the `RoleMenuForm` struct.
|
||||||
|
func (a *RoleMenuForm) Validate() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *RoleMenuForm) FillTo(roleMenu *RoleMenu) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
84
internal/mods/rbac/schema/team.go
Normal file
84
internal/mods/rbac/schema/team.go
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
package schema
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/config"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
TeamStatusDisabled = "disabled"
|
||||||
|
TeamStatusEnabled = "enabled"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
TeamOrderParams = []util.OrderByParam{
|
||||||
|
{Field: "created_at", Direction: util.DESC},
|
||||||
|
{Field: "sequence", Direction: util.DESC},
|
||||||
|
}
|
||||||
|
TeamOrderNoCreatedAtParams = []util.OrderByParam{
|
||||||
|
{Field: "sequence", Direction: util.DESC},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Article management for RBAC
|
||||||
|
type Team struct {
|
||||||
|
ID string `json:"id" gorm:"size:20;primarykey;"` // Unique ID
|
||||||
|
Name string `json:"name" gorm:"size:128;not null;index"` // Display name of banner
|
||||||
|
Img string `json:"img" gorm:"size:1024"` // Details about banner
|
||||||
|
Sequence int `json:"sequence" gorm:"index;"` // Sequence for sorting (Order by desc)
|
||||||
|
Area string `json:"area" gorm:"size:1024"`
|
||||||
|
Rank *[]string `json:"rank" gorm:"serializer:json"` // Type of banner (banner, link) // Parent menu``
|
||||||
|
Status string `json:"status" gorm:"size:20;index"` // Status of banner (enabled, disabled) // Child menus
|
||||||
|
CreatedAt time.Time `json:"created_at" gorm:"index;"` // Create time
|
||||||
|
UpdatedAt time.Time `json:"updated_at" gorm:"index;"` // Update time
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Team) TableName() string {
|
||||||
|
return config.C.FormatTableName("team")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query parameters for the `Menu` struct.
|
||||||
|
type TeamQueryParam struct {
|
||||||
|
util.PaginationParam
|
||||||
|
LikeName string `form:"name"` // Display name of menu
|
||||||
|
Status string `form:"status"` // Status of menu (enabled, disabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query options for the `Menu` struct.
|
||||||
|
type TeamQueryOptions struct {
|
||||||
|
util.QueryOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query result for the `Menu` struct.
|
||||||
|
type TeamQueryResult struct {
|
||||||
|
Data Teams
|
||||||
|
PageResult *util.PaginationResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the slice of `Menu` struct.
|
||||||
|
type Teams []*Team
|
||||||
|
|
||||||
|
func (a Teams) Len() int {
|
||||||
|
return len(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
type TeamForm struct {
|
||||||
|
Name string `json:"name" binding:"required,max=128"` // Display name of menu
|
||||||
|
Sequence int `json:"sequence"` // Sequence for sorting (Order by desc)
|
||||||
|
Area string `json:"area" `
|
||||||
|
Rank *[]string `json:"rank"` // Type of banner (ban
|
||||||
|
Img string `json:"img" ` // Details about banner
|
||||||
|
Status string `json:"status" binding:"required,oneof=disabled enabled"` // Status of menu (enabled, disabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *TeamForm) FillTo(team *Team) error {
|
||||||
|
team.Name = a.Name
|
||||||
|
team.Area = a.Area
|
||||||
|
team.Sequence = a.Sequence
|
||||||
|
team.Img = a.Img
|
||||||
|
team.Rank = a.Rank
|
||||||
|
team.Status = a.Status
|
||||||
|
return nil
|
||||||
|
}
|
||||||
105
internal/mods/rbac/schema/user.go
Normal file
105
internal/mods/rbac/schema/user.go
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
package schema
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/config"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/crypto/hash"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/errors"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
"github.com/go-playground/validator/v10"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
UserStatusActivated = "activated"
|
||||||
|
UserStatusFreezed = "freezed"
|
||||||
|
)
|
||||||
|
|
||||||
|
// User management for RBAC
|
||||||
|
type User struct {
|
||||||
|
ID string `json:"id" gorm:"size:20;primarykey;"` // Unique ID
|
||||||
|
Username string `json:"username" gorm:"size:64;index"` // Username for login
|
||||||
|
Name string `json:"name" gorm:"size:64;index"` // Name of user
|
||||||
|
Password string `json:"-" gorm:"size:64;"` // Password for login (encrypted)
|
||||||
|
Phone string `json:"phone" gorm:"size:32;"` // Phone number of user
|
||||||
|
Email string `json:"email" gorm:"size:128;"` // Email of user
|
||||||
|
Remark string `json:"remark" gorm:"size:1024;"` // Remark of user
|
||||||
|
Status string `json:"status" gorm:"size:20;index"` // Status of user (activated, freezed)
|
||||||
|
CreatedAt time.Time `json:"created_at" gorm:"index;"` // Create time
|
||||||
|
UpdatedAt time.Time `json:"updated_at" gorm:"index;"` // Update time
|
||||||
|
Roles UserRoles `json:"roles" gorm:"-"` // Roles of user
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *User) TableName() string {
|
||||||
|
return config.C.FormatTableName("user")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query parameters for the `User` struct.
|
||||||
|
type UserQueryParam struct {
|
||||||
|
util.PaginationParam
|
||||||
|
LikeUsername string `form:"username"` // Username for login
|
||||||
|
LikeName string `form:"name"` // Name of user
|
||||||
|
Status string `form:"status" binding:"oneof=activated freezed ''"` // Status of user (activated, freezed)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query options for the `User` struct.
|
||||||
|
type UserQueryOptions struct {
|
||||||
|
util.QueryOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query result for the `User` struct.
|
||||||
|
type UserQueryResult struct {
|
||||||
|
Data Users
|
||||||
|
PageResult *util.PaginationResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the slice of `User` struct.
|
||||||
|
type Users []*User
|
||||||
|
|
||||||
|
func (a Users) ToIDs() []string {
|
||||||
|
var ids []string
|
||||||
|
for _, item := range a {
|
||||||
|
ids = append(ids, item.ID)
|
||||||
|
}
|
||||||
|
return ids
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the data structure for creating a `User` struct.
|
||||||
|
type UserForm struct {
|
||||||
|
Username string `json:"username" binding:"required,max=64"` // Username for login
|
||||||
|
Name string `json:"name" binding:"required,max=64"` // Name of user
|
||||||
|
Password string `json:"password" binding:"max=64"` // Password for login (md5 hash)
|
||||||
|
Phone string `json:"phone" binding:"max=32"` // Phone number of user
|
||||||
|
Email string `json:"email" binding:"max=128"` // Email of user
|
||||||
|
Remark string `json:"remark" binding:"max=1024"` // Remark of user
|
||||||
|
Status string `json:"status" binding:"required,oneof=activated freezed"` // Status of user (activated, freezed)
|
||||||
|
Roles UserRoles `json:"roles" binding:"required"` // Roles of user
|
||||||
|
}
|
||||||
|
|
||||||
|
// A validation function for the `UserForm` struct.
|
||||||
|
func (a *UserForm) Validate() error {
|
||||||
|
if a.Email != "" && validator.New().Var(a.Email, "email") != nil {
|
||||||
|
return errors.BadRequest("", "Invalid email address")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert `UserForm` to `User` object.
|
||||||
|
func (a *UserForm) FillTo(user *User) error {
|
||||||
|
user.Username = a.Username
|
||||||
|
user.Name = a.Name
|
||||||
|
user.Phone = a.Phone
|
||||||
|
user.Email = a.Email
|
||||||
|
user.Remark = a.Remark
|
||||||
|
user.Status = a.Status
|
||||||
|
|
||||||
|
if pass := a.Password; pass != "" {
|
||||||
|
hashPass, err := hash.GeneratePassword(pass)
|
||||||
|
if err != nil {
|
||||||
|
return errors.BadRequest("", "Failed to generate hash password: %s", err.Error())
|
||||||
|
}
|
||||||
|
user.Password = hashPass
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
74
internal/mods/rbac/schema/user_role.go
Normal file
74
internal/mods/rbac/schema/user_role.go
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
package schema
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/config"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// User roles for RBAC
|
||||||
|
type UserRole struct {
|
||||||
|
ID string `json:"id" gorm:"size:20;primarykey"` // Unique ID
|
||||||
|
UserID string `json:"user_id" gorm:"size:20;index"` // From User.ID
|
||||||
|
RoleID string `json:"role_id" gorm:"size:20;index"` // From Role.ID
|
||||||
|
CreatedAt time.Time `json:"created_at" gorm:"index;"` // Create time
|
||||||
|
UpdatedAt time.Time `json:"updated_at" gorm:"index;"` // Update time
|
||||||
|
RoleName string `json:"role_name" gorm:"<-:false;-:migration;"` // From Role.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *UserRole) TableName() string {
|
||||||
|
return config.C.FormatTableName("user_role")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query parameters for the `UserRole` struct.
|
||||||
|
type UserRoleQueryParam struct {
|
||||||
|
util.PaginationParam
|
||||||
|
InUserIDs []string `form:"-"` // From User.ID
|
||||||
|
UserID string `form:"-"` // From User.ID
|
||||||
|
RoleID string `form:"-"` // From Role.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query options for the `UserRole` struct.
|
||||||
|
type UserRoleQueryOptions struct {
|
||||||
|
util.QueryOptions
|
||||||
|
JoinRole bool // Join role table
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query result for the `UserRole` struct.
|
||||||
|
type UserRoleQueryResult struct {
|
||||||
|
Data UserRoles
|
||||||
|
PageResult *util.PaginationResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the slice of `UserRole` struct.
|
||||||
|
type UserRoles []*UserRole
|
||||||
|
|
||||||
|
func (a UserRoles) ToUserIDMap() map[string]UserRoles {
|
||||||
|
m := make(map[string]UserRoles)
|
||||||
|
for _, userRole := range a {
|
||||||
|
m[userRole.UserID] = append(m[userRole.UserID], userRole)
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a UserRoles) ToRoleIDs() []string {
|
||||||
|
var ids []string
|
||||||
|
for _, item := range a {
|
||||||
|
ids = append(ids, item.RoleID)
|
||||||
|
}
|
||||||
|
return ids
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the data structure for creating a `UserRole` struct.
|
||||||
|
type UserRoleForm struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// A validation function for the `UserRoleForm` struct.
|
||||||
|
func (a *UserRoleForm) Validate() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *UserRoleForm) FillTo(userRole *UserRole) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
93
internal/mods/rbac/schema/video.go
Normal file
93
internal/mods/rbac/schema/video.go
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
package schema
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/config"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
VideoStatusDisabled = "disabled"
|
||||||
|
VideoStatusEnabled = "enabled"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
VideoOrderParams = []util.OrderByParam{
|
||||||
|
{Field: "created_at", Direction: util.DESC},
|
||||||
|
{Field: "sequence", Direction: util.DESC},
|
||||||
|
}
|
||||||
|
VideoOrderNoCreatedAtParams = []util.OrderByParam{
|
||||||
|
{Field: "sequence", Direction: util.DESC},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Article management for RBAC
|
||||||
|
type Video struct {
|
||||||
|
ID string `json:"id" gorm:"size:20;primarykey;"` // Unique ID
|
||||||
|
Title string `json:"title" gorm:"size:128;not null;index"` // Display name of banner
|
||||||
|
Subheading string `json:"subheading" gorm:"size:128;index"` // Display name of banner
|
||||||
|
SmallImg string `json:"smallImg" gorm:"size:1024"`
|
||||||
|
VideoUrl string `json:"videoUrl" gorm:"size:1024"`
|
||||||
|
|
||||||
|
FullImg string `json:"fullImg" gorm:"size:1024"` // Details about banner
|
||||||
|
Sequence int `json:"sequence" gorm:"index;"` // Sequence for sorting (Order by desc)
|
||||||
|
Link string `json:"link" gorm:"size:1024;"`
|
||||||
|
PushAt string `json:"pushAt" gorm:"size:50;index"`
|
||||||
|
Status string `json:"status" gorm:"size:20;index"` // Status of banner (enabled, disabled) // Child menus
|
||||||
|
CreatedAt time.Time `json:"created_at" gorm:"index;"` // Create time
|
||||||
|
UpdatedAt time.Time `json:"updated_at" gorm:"index;"` // Update time
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Video) TableName() string {
|
||||||
|
return config.C.FormatTableName("video")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query parameters for the `Menu` struct.
|
||||||
|
type VideoQueryParam struct {
|
||||||
|
util.PaginationParam
|
||||||
|
LikeTitle string `form:"title"` // Display name of menu
|
||||||
|
Typer string `form:"type" bind:"required,max=50"`
|
||||||
|
Status string `form:"status"` // Status of menu (enabled, disabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query options for the `Menu` struct.
|
||||||
|
type VideoQueryOptions struct {
|
||||||
|
util.QueryOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the query result for the `Menu` struct.
|
||||||
|
type VideoQueryResult struct {
|
||||||
|
Data Videos
|
||||||
|
PageResult *util.PaginationResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defining the slice of `Menu` struct.
|
||||||
|
type Videos []*Video
|
||||||
|
|
||||||
|
func (a Videos) Len() int {
|
||||||
|
return len(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
type VideoForm struct {
|
||||||
|
Title string `json:"title" binding:"required,max=128"` // Display name of menu
|
||||||
|
Sequence int `json:"sequence"` // Sequence for sorting (Order by desc)
|
||||||
|
Link string `json:"link" `
|
||||||
|
PushAt string `json:"pushAt"`
|
||||||
|
VideoUrl string `json:"videoUrl"`
|
||||||
|
SmallImg string `json:"smallImg" `
|
||||||
|
FullImg string `json:"fullImg" `
|
||||||
|
Status string `json:"status" binding:"required,oneof=disabled enabled"` // Status of menu (enabled, disabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *VideoForm) FillTo(video *Video) error {
|
||||||
|
video.Title = a.Title
|
||||||
|
video.PushAt = a.PushAt
|
||||||
|
video.VideoUrl = a.VideoUrl
|
||||||
|
video.Sequence = a.Sequence
|
||||||
|
video.SmallImg = a.SmallImg
|
||||||
|
video.FullImg = a.FullImg
|
||||||
|
video.Link = a.Link
|
||||||
|
video.Status = a.Status
|
||||||
|
return nil
|
||||||
|
}
|
||||||
59
internal/mods/rbac/schema/website.go
Normal file
59
internal/mods/rbac/schema/website.go
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
package schema
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
type WebSite struct {
|
||||||
|
ID string `json:"id" gorm:"size:20;primarykey;"`
|
||||||
|
ReportNum string `json:"reportNum" gorm:"size:20"`
|
||||||
|
ReportContent string `json:"reportContent" gorm:"size:2048"`
|
||||||
|
ReportImage string `json:"reportImage" gorm:"size:1024"`
|
||||||
|
Address string `json:"address" gorm:"size:1024"`
|
||||||
|
Phone string `json:"phone" gorm:"size:50"`
|
||||||
|
Email string `json:"email" gorm:"size:50"`
|
||||||
|
SocialMedia *[]SocialMedia `json:"socialMedia" gorm:"serializer:json"`
|
||||||
|
Lon float64 `json:"lon" gorm:""`
|
||||||
|
Lat float64 `json:"lat" gorm:""`
|
||||||
|
Affirm string `json:"affirm" gorm:"type:text"`
|
||||||
|
CreatedAt time.Time `json:"created_at" gorm:"index;"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at" gorm:"index;"`
|
||||||
|
}
|
||||||
|
type SocialMedia struct {
|
||||||
|
Name string `json:"name" gorm:"size:50"`
|
||||||
|
Image string `json:"image" gorm:"size:1024"`
|
||||||
|
Link string `json:"link" gorm:"size:1024"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *WebSite) TableName() string {
|
||||||
|
return config.C.FormatTableName("web_site")
|
||||||
|
}
|
||||||
|
|
||||||
|
type WebSiteForm struct {
|
||||||
|
ReportNum string `json:"reportNum"`
|
||||||
|
ReportContent string `json:"reportContent"`
|
||||||
|
ReportImage string `json:"reportImage"`
|
||||||
|
Address string `json:"address"`
|
||||||
|
Phone string `json:"phone" `
|
||||||
|
Email string `json:"email" `
|
||||||
|
SocialMedia *[]SocialMedia `json:"socialMedia" `
|
||||||
|
Lon float64 `json:"lon" `
|
||||||
|
Lat float64 `json:"lat" `
|
||||||
|
Affirm string `json:"affirm"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *WebSiteForm) FillTo(webSite *WebSite) error {
|
||||||
|
webSite.ReportNum = a.ReportNum
|
||||||
|
webSite.ReportContent = a.ReportContent
|
||||||
|
webSite.ReportImage = a.ReportImage
|
||||||
|
webSite.Address = a.Address
|
||||||
|
webSite.Phone = a.Phone
|
||||||
|
webSite.Email = a.Email
|
||||||
|
webSite.SocialMedia = a.SocialMedia
|
||||||
|
webSite.Lon = a.Lon
|
||||||
|
webSite.Lat = a.Lat
|
||||||
|
webSite.Affirm = a.Affirm
|
||||||
|
return nil
|
||||||
|
}
|
||||||
66
internal/mods/rbac/wire.go
Normal file
66
internal/mods/rbac/wire.go
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
package rbac
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/google/wire"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/api"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/biz"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods/rbac/dal"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Collection of wire providers
|
||||||
|
var Set = wire.NewSet(
|
||||||
|
wire.Struct(new(RBAC), "*"),
|
||||||
|
wire.Struct(new(Casbinx), "*"),
|
||||||
|
wire.Struct(new(api.Upload), "*"),
|
||||||
|
wire.Struct(new(biz.Upload), "*"),
|
||||||
|
wire.Struct(new(api.Web), "*"),
|
||||||
|
wire.Struct(new(dal.Article), "*"),
|
||||||
|
wire.Struct(new(biz.Article), "*"),
|
||||||
|
wire.Struct(new(api.Article), "*"),
|
||||||
|
wire.Struct(new(dal.Video), "*"),
|
||||||
|
wire.Struct(new(biz.Video), "*"),
|
||||||
|
wire.Struct(new(api.Video), "*"),
|
||||||
|
wire.Struct(new(dal.Menu), "*"),
|
||||||
|
wire.Struct(new(biz.Menu), "*"),
|
||||||
|
wire.Struct(new(api.Menu), "*"),
|
||||||
|
wire.Struct(new(dal.Banner), "*"),
|
||||||
|
wire.Struct(new(biz.Banner), "*"),
|
||||||
|
wire.Struct(new(api.Banner), "*"),
|
||||||
|
wire.Struct(new(dal.MenuResource), "*"),
|
||||||
|
wire.Struct(new(dal.Role), "*"),
|
||||||
|
wire.Struct(new(biz.Role), "*"),
|
||||||
|
wire.Struct(new(api.Role), "*"),
|
||||||
|
wire.Struct(new(dal.RoleMenu), "*"),
|
||||||
|
wire.Struct(new(dal.User), "*"),
|
||||||
|
wire.Struct(new(biz.User), "*"),
|
||||||
|
wire.Struct(new(api.User), "*"),
|
||||||
|
wire.Struct(new(dal.UserRole), "*"),
|
||||||
|
wire.Struct(new(biz.Login), "*"),
|
||||||
|
wire.Struct(new(api.Login), "*"),
|
||||||
|
wire.Struct(new(api.Logger), "*"),
|
||||||
|
wire.Struct(new(biz.Logger), "*"),
|
||||||
|
wire.Struct(new(dal.Logger), "*"),
|
||||||
|
|
||||||
|
wire.Struct(new(dal.Job), "*"),
|
||||||
|
wire.Struct(new(dal.JobArea), "*"),
|
||||||
|
wire.Struct(new(biz.Job), "*"),
|
||||||
|
wire.Struct(new(api.Job), "*"),
|
||||||
|
|
||||||
|
wire.Struct(new(dal.Memorabilia), "*"),
|
||||||
|
wire.Struct(new(biz.Memorabilia), "*"),
|
||||||
|
wire.Struct(new(api.Memorabilia), "*"),
|
||||||
|
|
||||||
|
wire.Struct(new(dal.Product), "*"),
|
||||||
|
wire.Struct(new(dal.ProductCategory), "*"),
|
||||||
|
|
||||||
|
wire.Struct(new(biz.Product), "*"),
|
||||||
|
wire.Struct(new(api.Product), "*"),
|
||||||
|
|
||||||
|
wire.Struct(new(dal.Team), "*"),
|
||||||
|
wire.Struct(new(biz.Team), "*"),
|
||||||
|
wire.Struct(new(api.Team), "*"),
|
||||||
|
|
||||||
|
wire.Struct(new(dal.WebSite), "*"),
|
||||||
|
wire.Struct(new(biz.WebSite), "*"),
|
||||||
|
wire.Struct(new(api.WebSite), "*"),
|
||||||
|
)
|
||||||
5436
internal/swagger/docs.go
Normal file
5436
internal/swagger/docs.go
Normal file
File diff suppressed because it is too large
Load Diff
5410
internal/swagger/swagger.json
Normal file
5410
internal/swagger/swagger.json
Normal file
File diff suppressed because it is too large
Load Diff
3430
internal/swagger/swagger.yaml
Normal file
3430
internal/swagger/swagger.yaml
Normal file
File diff suppressed because it is too large
Load Diff
36
internal/utility/prom/prom.go
Normal file
36
internal/utility/prom/prom.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package prom
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/guxuan/hailin_service/internal/config"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/promx"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/util"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
Ins *promx.PrometheusWrapper
|
||||||
|
GinMiddleware gin.HandlerFunc
|
||||||
|
)
|
||||||
|
|
||||||
|
func Init() {
|
||||||
|
logMethod := make(map[string]struct{})
|
||||||
|
logAPI := make(map[string]struct{})
|
||||||
|
for _, m := range config.C.Util.Prometheus.LogMethods {
|
||||||
|
logMethod[m] = struct{}{}
|
||||||
|
}
|
||||||
|
for _, a := range config.C.Util.Prometheus.LogApis {
|
||||||
|
logAPI[a] = struct{}{}
|
||||||
|
}
|
||||||
|
Ins = promx.NewPrometheusWrapper(&promx.Config{
|
||||||
|
Enable: config.C.Util.Prometheus.Enable,
|
||||||
|
App: config.C.General.AppName,
|
||||||
|
ListenPort: config.C.Util.Prometheus.Port,
|
||||||
|
BasicUserName: config.C.Util.Prometheus.BasicUsername,
|
||||||
|
BasicPassword: config.C.Util.Prometheus.BasicPassword,
|
||||||
|
LogApi: logAPI,
|
||||||
|
LogMethod: logMethod,
|
||||||
|
Objectives: map[float64]float64{0.9: 0.01, 0.95: 0.005, 0.99: 0.001},
|
||||||
|
DefaultCollect: config.C.Util.Prometheus.DefaultCollect,
|
||||||
|
})
|
||||||
|
GinMiddleware = promx.NewAdapterGin(Ins).Middleware(config.C.Util.Prometheus.Enable, util.ReqBodyKey)
|
||||||
|
}
|
||||||
129
internal/wirex/injector.go
Normal file
129
internal/wirex/injector.go
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
package wirex
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/guxuan/hailin_service/internal/config"
|
||||||
|
"github.com/guxuan/hailin_service/internal/mods"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/cachex"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/gormx"
|
||||||
|
"github.com/guxuan/hailin_service/pkg/jwtx"
|
||||||
|
"github.com/golang-jwt/jwt"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Injector struct {
|
||||||
|
DB *gorm.DB
|
||||||
|
Cache cachex.Cacher
|
||||||
|
Auth jwtx.Auther
|
||||||
|
M *mods.Mods
|
||||||
|
}
|
||||||
|
|
||||||
|
// It creates a new database connection, and returns a function that closes the connection
|
||||||
|
func InitDB(ctx context.Context) (*gorm.DB, func(), error) {
|
||||||
|
cfg := config.C.Storage.DB
|
||||||
|
|
||||||
|
resolver := make([]gormx.ResolverConfig, len(cfg.Resolver))
|
||||||
|
for i, v := range cfg.Resolver {
|
||||||
|
resolver[i] = gormx.ResolverConfig{
|
||||||
|
DBType: v.DBType,
|
||||||
|
Sources: v.Sources,
|
||||||
|
Replicas: v.Replicas,
|
||||||
|
Tables: v.Tables,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
db, err := gormx.New(gormx.Config{
|
||||||
|
Debug: cfg.Debug,
|
||||||
|
PrepareStmt: cfg.PrepareStmt,
|
||||||
|
DBType: cfg.Type,
|
||||||
|
DSN: cfg.DSN,
|
||||||
|
MaxLifetime: cfg.MaxLifetime,
|
||||||
|
MaxIdleTime: cfg.MaxIdleTime,
|
||||||
|
MaxOpenConns: cfg.MaxOpenConns,
|
||||||
|
MaxIdleConns: cfg.MaxIdleConns,
|
||||||
|
TablePrefix: cfg.TablePrefix,
|
||||||
|
Resolver: resolver,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return db, func() {
|
||||||
|
sqlDB, err := db.DB()
|
||||||
|
if err == nil {
|
||||||
|
_ = sqlDB.Close()
|
||||||
|
}
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// It returns a cachex.Cacher instance, a function to close the cache, and an error
|
||||||
|
func InitCacher(ctx context.Context) (cachex.Cacher, func(), error) {
|
||||||
|
cfg := config.C.Storage.Cache
|
||||||
|
|
||||||
|
var cache cachex.Cacher
|
||||||
|
switch cfg.Type {
|
||||||
|
case "redis":
|
||||||
|
cache = cachex.NewRedisCache(cachex.RedisConfig{
|
||||||
|
Addr: cfg.Redis.Addr,
|
||||||
|
DB: cfg.Redis.DB,
|
||||||
|
Username: cfg.Redis.Username,
|
||||||
|
Password: cfg.Redis.Password,
|
||||||
|
}, cachex.WithDelimiter(cfg.Delimiter))
|
||||||
|
case "badger":
|
||||||
|
cache = cachex.NewBadgerCache(cachex.BadgerConfig{
|
||||||
|
Path: cfg.Badger.Path,
|
||||||
|
}, cachex.WithDelimiter(cfg.Delimiter))
|
||||||
|
default:
|
||||||
|
cache = cachex.NewMemoryCache(cachex.MemoryConfig{
|
||||||
|
CleanupInterval: time.Second * time.Duration(cfg.Memory.CleanupInterval),
|
||||||
|
}, cachex.WithDelimiter(cfg.Delimiter))
|
||||||
|
}
|
||||||
|
|
||||||
|
return cache, func() {
|
||||||
|
_ = cache.Close(ctx)
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitAuth(ctx context.Context) (jwtx.Auther, func(), error) {
|
||||||
|
cfg := config.C.Middleware.Auth
|
||||||
|
var opts []jwtx.Option
|
||||||
|
opts = append(opts, jwtx.SetExpired(cfg.Expired))
|
||||||
|
opts = append(opts, jwtx.SetSigningKey(cfg.SigningKey, cfg.OldSigningKey))
|
||||||
|
|
||||||
|
var method jwt.SigningMethod
|
||||||
|
switch cfg.SigningMethod {
|
||||||
|
case "HS256":
|
||||||
|
method = jwt.SigningMethodHS256
|
||||||
|
case "HS384":
|
||||||
|
method = jwt.SigningMethodHS384
|
||||||
|
default:
|
||||||
|
method = jwt.SigningMethodHS512
|
||||||
|
}
|
||||||
|
opts = append(opts, jwtx.SetSigningMethod(method))
|
||||||
|
|
||||||
|
var cache cachex.Cacher
|
||||||
|
switch cfg.Store.Type {
|
||||||
|
case "redis":
|
||||||
|
cache = cachex.NewRedisCache(cachex.RedisConfig{
|
||||||
|
Addr: cfg.Store.Redis.Addr,
|
||||||
|
DB: cfg.Store.Redis.DB,
|
||||||
|
Username: cfg.Store.Redis.Username,
|
||||||
|
Password: cfg.Store.Redis.Password,
|
||||||
|
}, cachex.WithDelimiter(cfg.Store.Delimiter))
|
||||||
|
case "badger":
|
||||||
|
cache = cachex.NewBadgerCache(cachex.BadgerConfig{
|
||||||
|
Path: cfg.Store.Badger.Path,
|
||||||
|
}, cachex.WithDelimiter(cfg.Store.Delimiter))
|
||||||
|
default:
|
||||||
|
cache = cachex.NewMemoryCache(cachex.MemoryConfig{
|
||||||
|
CleanupInterval: time.Second * time.Duration(cfg.Store.Memory.CleanupInterval),
|
||||||
|
}, cachex.WithDelimiter(cfg.Store.Delimiter))
|
||||||
|
}
|
||||||
|
|
||||||
|
auth := jwtx.New(jwtx.NewStoreWithCache(cache), opts...)
|
||||||
|
return auth, func() {
|
||||||
|
_ = auth.Release(ctx)
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user