diff --git a/.fleet/settings.json b/.fleet/settings.json
new file mode 100644
index 0000000..af27bc6
--- /dev/null
+++ b/.fleet/settings.json
@@ -0,0 +1,21 @@
+{
+ "editor.formatOnSave": true,
+ "plugins": [
+ {
+ "type": "add",
+ "pluginName": "fleet.ai"
+ },
+ {
+ "type": "add",
+ "pluginName": "fleet.go.ai"
+ },
+ {
+ "type": "add",
+ "pluginName": "fleet.python.ai"
+ },
+ {
+ "type": "add",
+ "pluginName": "fleet.rust.ai"
+ }
+ ]
+}
diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml
new file mode 100644
index 0000000..c216d4a
--- /dev/null
+++ b/.github/workflows/build_and_test.yml
@@ -0,0 +1,134 @@
+name: Go CI/CD
+
+on:
+ push:
+ branches: [main]
+ pull_request:
+ branches: [main]
+
+jobs:
+ lint:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - name: Set up Go
+ uses: actions/setup-go@v4
+ with:
+ go-version: "1.22"
+ - name: Verify workspace
+ run: go work sync
+ - name: Check formatting
+ run: |
+ all_formatted=true
+ for dir in $(go work edit -json | jq -r '.Use[].DiskPath'); do
+ echo "Checking formatting in $dir"
+ if [ -n "$(gofmt -s -l $dir)" ]; then
+ echo "Formatting issues in $dir:"
+ gofmt -s -l $dir
+ all_formatted=false
+ else
+ echo "No formatting issues in $dir"
+ fi
+ done
+ if [ "$all_formatted" = false ]; then
+ echo "Formatting errors found. Please run 'go fmt ./...' in each module to fix."
+ exit 1
+ fi
+ - name: Run go vet
+ run: |
+ for dir in $(go work edit -json | jq -r '.Use[].DiskPath'); do
+ echo "Running go vet in $dir"
+ go vet ./$dir/...
+ done
+
+ # - name: Run goimports
+ # run: |
+ # for dir in $(go work edit -json | jq -r '.Use[].DiskPath'); do
+ # echo "Running goimports in $dir"
+ # goimports -l $dir
+ # done
+
+ # - name: Run gocyclo
+ # run: |
+ # for dir in $(go work edit -json | jq -r '.Use[].DiskPath'); do
+ # echo "Running gocyclo in $dir"
+ # gocyclo -over 15 $dir
+ # done
+
+ # - name: Static check
+ # run: |
+ # for dir in $(go work edit -json | jq -r '.Use[].DiskPath'); do
+ # echo "Running staticcheck in $dir"
+ # staticcheck $dir
+ # done
+
+ test:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - name: Set up Go
+ uses: actions/setup-go@v4
+ with:
+ go-version: "1.22"
+ - name: Run tests
+ run: |
+ go work use .
+ for dir in $(go work edit -json | jq -r '.Use[].DiskPath'); do
+ echo "Running tests in $dir"
+ go test -v -race -coverprofile=$dir/coverage.txt -covermode=atomic ./$dir/...
+ done
+ - name: Combine coverage
+ run: |
+ echo "mode: atomic" > coverage.txt
+ for dir in $(go work edit -json | jq -r '.Use[].DiskPath'); do
+ if [ -f $dir/coverage.txt ]; then
+ tail -n +2 $dir/coverage.txt >> coverage.txt
+ fi
+ done
+ - name: Upload coverage to Codecov
+ uses: codecov/codecov-action@v3
+ with:
+ file: ./coverage.txt
+ - name: Upload coverage artifact
+ uses: actions/upload-artifact@v2
+ with:
+ name: coverage
+ path: coverage.txt
+
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - name: Set up Go
+ uses: actions/setup-go@v4
+ with:
+ go-version: "1.22"
+ - name: Build
+ run: |
+ for dir in $(go work edit -json | jq -r '.Use[].DiskPath'); do
+ echo "Building in $dir"
+ go build -v ./$dir/...
+ done
+
+ deploy-coverage:
+ needs: test
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - name: Download coverage artifact
+ uses: actions/download-artifact@v2
+ with:
+ name: coverage
+ - name: Generate coverage HTML
+ run: |
+ go tool cover -html=coverage.txt -o coverage.html
+ - name: Deploy to GitHub Pages
+ uses: peaceiris/actions-gh-pages@v3
+ with:
+ github_token: ${{ secrets.TOKEN }}
+ publish_dir: .
+ publish_branch: gh-pages
+ keep_files: true
+ user_name: "github-actions[bot]"
+ user_email: "github-actions[bot]@users.noreply.github.com"
+ commit_message: "Deploy coverage report to GitHub Pages"
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
deleted file mode 100644
index 76ebefe..0000000
--- a/.github/workflows/deploy.yml
+++ /dev/null
@@ -1,43 +0,0 @@
-name: CI/CD
-
-on:
- push:
- branches: [ main ]
- pull_request:
- branches: [ main ]
-
-jobs:
- test:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v2
- - name: Set up Go
- uses: actions/setup-go@v2
- with:
- go-version: 1.18
- - name: Test
- run: go test ./...
- - name: Upload coverage to Codecov
- uses: codecov/codecov-action@v1
-
- build:
- needs: test
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v2
- - name: Build Docker image
- run: docker build -t datavinci:${{ github.sha }} .
- - name: Push to Docker Hub
- run: |
- echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
- docker push datavinci:${{ github.sha }}
-
- deploy:
- needs: build
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v2
- - name: Deploy to Kubernetes
- run: |
- # Add your Kubernetes deployment commands here
- # kubectl apply -f k8s/
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 507d2bf..badbb40 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,7 +18,31 @@
# vendor/
# Go workspace file
-go.work
-go.work.sum
+# go.work
+# go.work.sum
-.env
\ No newline at end of file
+.env
+.fleet
+.idea
+.vscode
+*.log
+*.log.*
+*.log-*
+.DS_Store
+
+
+node_modules
+
+web/node_modules
+datavinci
+ai
+report
+realtime
+
+/internal/auth/coverage.txt
+/internal/datasource/coverage.txt
+/internal/visualization/coverage.txt
+/internal/realtime/coverage.txt
+/internal/report/coverage.txt
+/internal/ai/coverage.txt
+/pkg/coverage.txt
diff --git a/.idea/datavinci.iml b/.idea/datavinci.iml
index 5d81a31..a524500 100644
--- a/.idea/datavinci.iml
+++ b/.idea/datavinci.iml
@@ -8,4 +8,4 @@
-
\ No newline at end of file
+
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 61c7313..680c05c 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -5,4 +5,4 @@
-
\ No newline at end of file
+
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
index 35eb1dd..dcb6b8c 100644
--- a/.idea/vcs.xml
+++ b/.idea/vcs.xml
@@ -3,4 +3,4 @@
-
\ No newline at end of file
+
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 0000000..3b48062
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,52 @@
+repos:
+ - repo: https://github.com/pre-commit/pre-commit-hooks
+ rev: v4.4.0
+ hooks:
+ - id: trailing-whitespace
+ - id: end-of-file-fixer
+ - id: check-yaml
+ args: [--allow-multiple-documents]
+ # - id: check-added-large-files
+ # args: [--maxkb=1000]
+
+ # - repo: https://github.com/golangci/golangci-lint
+ # rev: v1.54.2
+ # hooks:
+ # - id: golangci-lint
+
+ - repo: https://github.com/dnephin/pre-commit-golang
+ rev: v0.5.1
+ hooks:
+ - id: go-fmt
+ # - id: go-vet
+ # files: \.go$
+ # exclude: ^datavinci/
+ - id: go-imports
+ - id: go-cyclo
+ # args: [-over=15]
+ - id: validate-toml
+ - id: no-go-testing
+ # - id: go-critic
+ # args: [--disable=sloppyTypeAssert]
+ - id: go-unit-tests
+ - id: go-build
+ - id: go-mod-tidy
+
+ # - repo: https://github.com/pre-commit/mirrors-prettier
+ # rev: v3.0.3
+ # hooks:
+ # - id: prettier
+ # types_or: [javascript, jsx, ts, tsx, json]
+ # files: ^web/
+
+ # - repo: https://github.com/pre-commit/mirrors-eslint
+ # rev: v8.49.0
+ # hooks:
+ # - id: eslint
+ # files: ^web/.*\.[jt]sx?$ # *.js, *.jsx, *.ts and *.tsx in web folder
+ # types: [file]
+ # additional_dependencies:
+ # - eslint@9.6.0
+ # - typescript@5.2.2
+ # - "@typescript-eslint/parser@6.7.0"
+ # - "@typescript-eslint/eslint-plugin@6.7.0"
diff --git a/Dockerfile b/Dockerfile
index a831bf4..bdbe614 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -10,4 +10,4 @@ FROM alpine:latest
WORKDIR /root/
COPY --from=builder /app/datavinci .
EXPOSE 8080
-CMD ["./datavinci"]
\ No newline at end of file
+CMD ["./datavinci"]
diff --git a/README.md b/README.md
index 8c362a0..3510fd4 100644
--- a/README.md
+++ b/README.md
@@ -168,6 +168,16 @@ Run the tests with:
```bash
go test ./...
cd web && yarn test && cd ..
+
+// or
+
+go test -v -race -coverprofile=pkg/coverage.txt -covermode=atomic ./internal/auth/...
+```
+
+To ensure that the code meets our standards, run the pre-commit hooks:
+
+```bash
+pre-commit run --all-files
```
### Linting
@@ -216,10 +226,95 @@ helm install datavinci deployments/helm
Contributions are welcome! Please read the [contributing guidelines](CONTRIBUTING.md) before submitting a pull request.
-## License
+## Pre-commit Hooks
-This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
+We use pre-commit hooks to ensure code quality and consistency. These hooks run automatically before each commit, checking your changes against our coding standards and running various linters.
+
+### Setup
+
+1. Install pre-commit:
+ ```bash
+ pip install pre-commit
+ ```
+
+2. Install the git hook scripts:
+ ```bash
+ pre-commit install
+ ```
+
+### Running pre-commit
+
+The hooks will run automatically on `git commit`. If you want to run the hooks manually (for example, to test them or run them on all files), you can use:
+
+```bash
+pre-commit run --all-files
```
+### Our pre-commit hooks
+
+We use the following hooks:
+
+- **For Go:**
+
+ - `go-fmt`: Formats Go code
+ - `go-vet`: Reports suspicious constructs
+ - `go-imports`: Updates import lines
+ - `go-cyclo`: Checks function complexity
+ - `golangci-lint`: Runs multiple Go linters
+ - `go-critic`: Provides extensive code analysis
+ - `go-unit-tests`: Runs Go unit tests
+ - `go-build`: Checks if the code builds
+ - `go-mod-tidy`: Runs `go mod tidy`
+
+- ** ensure that you have the following tools installed:**
+
+ - `golangci-lint`
+ - `go-critic`
+ - `go-cyclo`
+ - `go-unit-tests`
+ - `go-build`
+ - `go-mod-tidy`
+
+ ```bash
+ go install github.com/fzipp/gocyclo/cmd/gocyclo@latest
+ go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
+ go install github.com/go-critic/go-critic/cmd/gocritic@latest
+ go install github.com/hexdigest/gounit/cmd/gounit@latest
+ go install github.com/securego/gosec/v2/cmd/gosec@latest
+ ```
+
+- **For TypeScript/JavaScript:**
+
+ - `prettier`: Formats code
+ - `eslint`: Lints JavaScript and TypeScript code
+
+- **General:**
+ - `trailing-whitespace`: Trims trailing whitespace
+ - `end-of-file-fixer`: Ensures files end with a newline
+ - `check-yaml`: Checks yaml files for parseable syntax
+ - `check-added-large-files`: Prevents giant files from being committed
+
+### Skipping hooks
+
+If you need to bypass the pre-commit hooks (not recommended), you can use:
+
+```bash
+git commit -m "Your commit message" --no-verify
```
+
+However, please use this sparingly and ensure your code still meets our standards.
+
+### Updating hooks
+
+To update the pre-commit hooks to the latest versions, run:
+
+```bash
+pre-commit autoupdate
+```
+
+Then commit the changes to `.pre-commit-config.yaml`.
+
+## License
+
+This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
diff --git a/certs/postgresql.cnf b/certs/postgresql.cnf
index 888d379..fa8ffc4 100644
--- a/certs/postgresql.cnf
+++ b/certs/postgresql.cnf
@@ -7,4 +7,4 @@ C = US
ST = Nevada
L = Las Vegas
O = github.com/lib/pq
-CN = pqgosslcert
\ No newline at end of file
+CN = pqgosslcert
diff --git a/certs/root.cnf b/certs/root.cnf
index 2e0d611..ea6def2 100644
--- a/certs/root.cnf
+++ b/certs/root.cnf
@@ -7,4 +7,4 @@ C = US
ST = Nevada
L = Las Vegas
O = github.com/lib/pq
-CN = pq CA
\ No newline at end of file
+CN = pq CA
diff --git a/certs/server.cnf b/certs/server.cnf
index 0c7f3a9..ba4b557 100644
--- a/certs/server.cnf
+++ b/certs/server.cnf
@@ -26,4 +26,4 @@ subjectKeyIdentifier = hash
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
subjectAltName = DNS:postgres
-nsComment = "OpenSSL Generated Certificate"
\ No newline at end of file
+nsComment = "OpenSSL Generated Certificate"
diff --git a/cmd/datavinci/main.go b/cmd/datavinci/main.go
index a7b0c17..8139c1e 100644
--- a/cmd/datavinci/main.go
+++ b/cmd/datavinci/main.go
@@ -15,7 +15,7 @@ import (
func main() {
// Set up a connection to the server.
- conn, err := grpc.Dial("localhost:50051", grpc.WithTransportCredentials(insecure.NewCredentials()))
+ conn, err := grpc.NewClient("localhost:50051", grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Fatalf("did not connect: %v", err)
}
@@ -30,7 +30,7 @@ func main() {
// Connect to the data source
connResp, err := c.Connect(ctx, &pb.ConnectRequest{ConnectorName: "mongo"})
if err != nil {
- log.Fatalf("Could not connect: %v", err)
+ fmt.Printf("Could not connect: %v", err)
}
log.Printf("Connect Response: %t", connResp.GetSuccess())
@@ -54,7 +54,7 @@ func main() {
Command: string(insertQueryJSON),
})
if err != nil {
- log.Fatalf("Could not insert data: %v", err)
+ fmt.Printf("Could not insert data: %v", err)
}
fmt.Println("Inserted test data successfully")
@@ -70,7 +70,7 @@ func main() {
Query: string(selectQueryJSON),
})
if err != nil {
- log.Fatalf("Could not query data: %v", err)
+ fmt.Printf("Could not query data: %v", err)
}
fmt.Println("Query results:")
@@ -95,7 +95,7 @@ func main() {
Command: string(updateQueryJSON),
})
if err != nil {
- log.Fatalf("Could not update data: %v", err)
+ fmt.Printf("Could not update data: %v", err)
}
fmt.Println("Updated data successfully")
@@ -105,7 +105,7 @@ func main() {
Query: string(selectQueryJSON),
})
if err != nil {
- log.Fatalf("Could not query updated data: %v", err)
+ fmt.Printf("Could not query updated data: %v", err)
}
fmt.Println("Updated query results:")
for _, row := range queryResp.GetRows() {
@@ -126,7 +126,7 @@ func main() {
Command: string(deleteQueryJSON),
})
if err != nil {
- log.Fatalf("Could not delete data: %v", err)
+ fmt.Printf("Could not delete data: %v", err)
}
fmt.Println("Deleted data successfully")
@@ -136,14 +136,14 @@ func main() {
Query: string(selectQueryJSON),
})
if err != nil {
- log.Fatalf("Could not query after deletion: %v", err)
+ fmt.Printf("Could not query data after deletion: %v", err)
}
fmt.Printf("Number of results after deletion: %d\n", len(queryResp.GetRows()))
// Disconnect from the data source
disconnResp, err := c.Disconnect(ctx, &pb.DisconnectRequest{ConnectorName: "example_mongo"})
if err != nil {
- log.Fatalf("Could not disconnect: %v", err)
+ fmt.Printf("Could not disconnect: %v", err)
}
log.Printf("Disconnect Response: %t", disconnResp.GetSuccess())
}
diff --git a/deployments/k8s/deployment.yml b/deployments/k8s/deployment.yml
index 571beb9..a542dd7 100644
--- a/deployments/k8s/deployment.yml
+++ b/deployments/k8s/deployment.yml
@@ -44,4 +44,4 @@ spec:
- protocol: TCP
port: 80
targetPort: 8080
- type: LoadBalancer
\ No newline at end of file
+ type: LoadBalancer
diff --git a/docker-compose.yml b/docker-compose.yml
index 6e36c16..24651cb 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -22,4 +22,4 @@ services:
- postgres_data:/var/lib/postgresql/data
volumes:
- postgres_data:
\ No newline at end of file
+ postgres_data:
diff --git a/go.mod b/go.mod
index 5a699e5..0d25aa8 100644
--- a/go.mod
+++ b/go.mod
@@ -1,13 +1,15 @@
module datavinci
-go 1.21
+go 1.22
-require google.golang.org/grpc v1.64.0
+toolchain go1.22.5
+
+require google.golang.org/grpc v1.65.0
require (
- golang.org/x/net v0.22.0 // indirect
- golang.org/x/sys v0.18.0 // indirect
- golang.org/x/text v0.14.0 // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect
- google.golang.org/protobuf v1.33.0 // indirect
+ golang.org/x/net v0.25.0 // indirect
+ golang.org/x/sys v0.20.0 // indirect
+ golang.org/x/text v0.15.0 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 // indirect
+ google.golang.org/protobuf v1.34.2 // indirect
)
diff --git a/go.sum b/go.sum
index 4808442..2a4541c 100644
--- a/go.sum
+++ b/go.sum
@@ -1,14 +1,14 @@
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
-golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
-golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
-golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
-golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
-golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
-google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY=
-google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg=
-google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
-google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
+golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
+golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
+golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
+golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 h1:Zy9XzmMEflZ/MAaA7vNcoebnRAld7FsPW1EeBB7V0m8=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
+google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
+google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
+google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
+google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
diff --git a/go.work b/go.work
new file mode 100644
index 0000000..630b1a0
--- /dev/null
+++ b/go.work
@@ -0,0 +1,14 @@
+go 1.22
+
+toolchain go1.22.5
+
+use (
+ .
+ ./internal/ai
+ ./internal/auth
+ ./internal/datasource
+ ./internal/realtime
+ ./internal/report
+ ./internal/visualization
+ ./pkg
+)
diff --git a/go.work.sum b/go.work.sum
new file mode 100644
index 0000000..c8d0223
--- /dev/null
+++ b/go.work.sum
@@ -0,0 +1,202 @@
+cel.dev/expr v0.15.0 h1:O1jzfJCQBfL5BFoYktaxwIhuttaQPsVWerH9/EEKx0w=
+cel.dev/expr v0.15.0/go.mod h1:TRSuuV7DlVCE/uwv5QbAiW/v8l5O8C4eEPHeu7gf7Sg=
+cloud.google.com/go v0.112.1 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM=
+cloud.google.com/go v0.112.1/go.mod h1:+Vbu+Y1UU+I1rjmzeMOb/8RfkKJK2Gyxi1X6jJCZLo4=
+cloud.google.com/go/compute v1.24.0 h1:phWcR2eWzRJaL/kOiJwfFsPs4BaKq1j6vnpZrc1YlVg=
+cloud.google.com/go/compute v1.24.0/go.mod h1:kw1/T+h/+tK2LJK0wiPPx1intgdAM3j/g3hFDlscY40=
+cloud.google.com/go/compute v1.25.1 h1:ZRpHJedLtTpKgr3RV1Fx23NuaAEN1Zfx9hw1u4aJdjU=
+cloud.google.com/go/compute v1.25.1/go.mod h1:oopOIR53ly6viBYxaDhBfJwzUAxf1zE//uf3IB011ls=
+cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
+cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc=
+cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
+cloud.google.com/go/firestore v1.15.0 h1:/k8ppuWOtNuDHt2tsRV42yI21uaGnKDEQnRFeBpbFF8=
+cloud.google.com/go/firestore v1.15.0/go.mod h1:GWOxFXcv8GZUtYpWHw/w6IuYNux/BtmeVTMmjrm4yhk=
+cloud.google.com/go/iam v1.1.5 h1:1jTsCu4bcsNsE4iiqNT5SHwrDRCfRmIaaaVFhRveTJI=
+cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8=
+cloud.google.com/go/longrunning v0.5.5 h1:GOE6pZFdSrTb4KAiKnXsJBtlE6mEyaW44oKyMILWnOg=
+cloud.google.com/go/longrunning v0.5.5/go.mod h1:WV2LAxD8/rg5Z1cNW6FJ/ZpX4E4VnDnoTk0yawPBB7s=
+cloud.google.com/go/storage v1.35.1 h1:B59ahL//eDfx2IIKFBeT5Atm9wnNmj3+8xG/W4WB//w=
+cloud.google.com/go/storage v1.35.1/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8=
+github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3 h1:ZSTrOEhiM5J5RFxEaFvMZVEAM1KvT1YzbEOwB2EAGjA=
+github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM=
+github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA=
+github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4=
+github.com/brianvoe/gofakeit/v7 v7.0.4/go.mod h1:QXuPeBw164PJCzCUZVmgpgHJ3Llj49jSLVkKPMtxtxA=
+github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g=
+github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw=
+github.com/cncf/xds/go v0.0.0-20240318125728-8a4994d93e50/go.mod h1:5e1+Vvlzido69INQaVO6d87Qn543Xr6nooe9Kz7oBFM=
+github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b h1:ga8SEFjZ60pxLcmhnThWgvH2wg8376yUJmPhEH4H3kw=
+github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
+github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
+github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI=
+github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
+github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/envoyproxy/go-control-plane v0.12.0 h1:4X+VP1GHd1Mhj6IB5mMeGbLCleqxjletLK6K0rbxyZI=
+github.com/envoyproxy/go-control-plane v0.12.0/go.mod h1:ZBTaoJ23lqITozF0M6G4/IragXCQKCnYbmlmtHvwRG0=
+github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A=
+github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew=
+github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w=
+github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg=
+github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
+github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
+github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
+github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
+github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
+github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
+github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
+github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
+github.com/golang/glog v1.2.1 h1:OptwRhECazUx5ix5TTWC3EZhsZEHWcYWY4FQHTIubm4=
+github.com/golang/glog v1.2.1/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
+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/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
+github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
+github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs=
+github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
+github.com/googleapis/gax-go/v2 v2.12.3 h1:5/zPPDvw8Q1SuXjrqrZslrqT7dL/uJT2CQii/cLCKqA=
+github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4=
+github.com/googleapis/google-cloud-go-testing v0.0.0-20210719221736-1c9a4c676720 h1:zC34cGQu69FG7qzJ3WiKW244WfhDC3xxYMeNOX2gtUQ=
+github.com/googleapis/google-cloud-go-testing v0.0.0-20210719221736-1c9a4c676720/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3 h1:lLT7ZLSzGLI08vc9cpd+tYmNWjdKDqyr/2L+f6U12Fk=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w=
+github.com/hashicorp/consul/api v1.28.2 h1:mXfkRHrpHN4YY3RqL09nXU1eHKLNiuAN4kHvDQ16k/8=
+github.com/hashicorp/consul/api v1.28.2/go.mod h1:KyzqzgMEya+IZPcD65YFoOVAgPpbfERu4I/tzG6/ueE=
+github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
+github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
+github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
+github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c=
+github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
+github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc=
+github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
+github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
+github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
+github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=
+github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
+github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
+github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
+github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY=
+github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4=
+github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI=
+github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
+github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
+github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
+github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc=
+github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
+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/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
+github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
+github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
+github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw=
+github.com/lib/pq v1.10.0 h1:Zx5DJFEYQXio93kgXnQ09fXNiUKsqv4OUEu2UtGcB1E=
+github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/lyft/protoc-gen-star/v2 v2.0.3 h1:/3+/2sWyXeMLzKd1bX+ixWKgEMsULrIivpDsuaF441o=
+github.com/lyft/protoc-gen-star/v2 v2.0.3/go.mod h1:amey7yeodaJhXSbf/TlLvWiqQfLOSpEk//mLlc+axEk=
+github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
+github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
+github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
+github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
+github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
+github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
+github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+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/nats-io/nats.go v1.34.0 h1:fnxnPCNiwIG5w08rlMcEKTUw4AV/nKyGCOJE8TdhSPk=
+github.com/nats-io/nats.go v1.34.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8=
+github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI=
+github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc=
+github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
+github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
+github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
+github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
+github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/sftp v1.13.6 h1:JFZT4XbOU7l77xGSpOdW+pwIMqP044IyjXX6FGyEKFo=
+github.com/pkg/sftp v1.13.6/go.mod h1:tz1ryNURKu77RL+GuCzmoJYxQczL3wLNNpPWagdg4Qk=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
+github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
+github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
+github.com/sagikazarmark/crypt v0.19.0 h1:WMyLTjHBo64UvNcWqpzY3pbZTYgnemZU8FBZigKc42E=
+github.com/sagikazarmark/crypt v0.19.0/go.mod h1:c6vimRziqqERhtSe0MhIvzE1w54FrCHtrXb5NH/ja78=
+github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
+github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
+github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
+github.com/vmihailenco/msgpack/v4 v4.3.12 h1:07s4sz9IReOgdikxLTKNbBdqDMLsjPKXwvCazn8G65U=
+github.com/vmihailenco/tagparser v0.1.1 h1:quXMXlA39OCbd2wAdTsGDlK9RkOk6Wuw+x37wVyIuWY=
+github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE=
+github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b h1:FosyBZYxY34Wul7O/MSKey3txpPYyCqVO5ZyceuQJEI=
+github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8=
+go.etcd.io/etcd/api/v3 v3.5.12 h1:W4sw5ZoU2Juc9gBWuLk5U6fHfNVyY1WC5g9uiXZio/c=
+go.etcd.io/etcd/api/v3 v3.5.12/go.mod h1:Ot+o0SWSyT6uHhA56al1oCED0JImsRiU9Dc26+C2a+4=
+go.etcd.io/etcd/client/pkg/v3 v3.5.12 h1:EYDL6pWwyOsylrQyLp2w+HkQ46ATiOvoEdMarindU2A=
+go.etcd.io/etcd/client/pkg/v3 v3.5.12/go.mod h1:seTzl2d9APP8R5Y2hFL3NVlD6qC/dOT+3kvrqPyTas4=
+go.etcd.io/etcd/client/v2 v2.305.12 h1:0m4ovXYo1CHaA/Mp3X/Fak5sRNIWf01wk/X1/G3sGKI=
+go.etcd.io/etcd/client/v2 v2.305.12/go.mod h1:aQ/yhsxMu+Oht1FOupSr60oBvcS9cKXHrzBpDsPTf9E=
+go.etcd.io/etcd/client/v3 v3.5.12 h1:v5lCPXn1pf1Uu3M4laUE2hp/geOTc5uPcYYsNe1lDxg=
+go.etcd.io/etcd/client/v3 v3.5.12/go.mod h1:tSbBCakoWmmddL+BKVAJHa9km+O/E+bumDe9mSbPiqw=
+go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
+go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw=
+go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
+go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
+go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
+go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
+go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
+go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
+go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
+go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
+golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
+golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
+golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8=
+golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo=
+golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
+golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/telemetry v0.0.0-20240208230135-b75ee8823808 h1:+Kc94D8UVEVxJnLXp/+FMfqQARZtWHfVrcRtcG8aT3g=
+golang.org/x/telemetry v0.0.0-20240208230135-b75ee8823808/go.mod h1:KG1lNk5ZFNssSZLrpVb4sMXKMpGwGXOxSG3rnu2gZQQ=
+golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
+golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
+golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
+golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
+golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
+golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
+golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
+golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
+golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
+google.golang.org/api v0.171.0 h1:w174hnBPqut76FzW5Qaupt7zY8Kql6fiVjgys4f58sU=
+google.golang.org/api v0.171.0/go.mod h1:Hnq5AHm4OTMt2BUVjael2CWZFD6vksJdWCWiUAmjC9o=
+google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
+google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
+google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y=
+google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:mqHbVIp48Muh7Ywss/AD6I5kNVKZMmAa/QEW58Gxp2s=
+google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237/go.mod h1:Z5Iiy3jtmioajWHDGFk7CeugTyHtPvMHA4UTmUkyalE=
+google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 h1:7whR9kGa5LUwFtpLm2ArCEejtnxlGeLbAyjFY8sGNFw=
+google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157/go.mod h1:99sLkeliLXfdj2J75X3Ho+rrVCaJze0uwN7zDDkjPVU=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
diff --git a/img_1.png b/img_1.png
deleted file mode 100644
index bdb8e5f..0000000
Binary files a/img_1.png and /dev/null differ
diff --git a/internal/ai/main.go b/internal/ai/main.go
new file mode 100644
index 0000000..24963e5
--- /dev/null
+++ b/internal/ai/main.go
@@ -0,0 +1,5 @@
+package main
+
+func main() {
+ println("Hello, world!")
+}
diff --git a/internal/auth/api/proto/auth.proto b/internal/auth/api/proto/auth.proto
index e22f539..7723446 100644
--- a/internal/auth/api/proto/auth.proto
+++ b/internal/auth/api/proto/auth.proto
@@ -97,4 +97,4 @@ message GetUserRequest {
message GetUserResponse {
User user = 1;
-}
\ No newline at end of file
+}
diff --git a/internal/auth/api/proto/authorization.proto b/internal/auth/api/proto/authorization.proto
index 74800fe..6be0efd 100644
--- a/internal/auth/api/proto/authorization.proto
+++ b/internal/auth/api/proto/authorization.proto
@@ -118,4 +118,4 @@ message AddPermissionToRoleRequest {
message RemovePermissionFromRoleRequest {
string role_id = 1;
Permission permission = 2;
-}
\ No newline at end of file
+}
diff --git a/internal/auth/api/proto/common.proto b/internal/auth/api/proto/common.proto
index edeb398..37538aa 100644
--- a/internal/auth/api/proto/common.proto
+++ b/internal/auth/api/proto/common.proto
@@ -2,7 +2,7 @@ syntax = "proto3";
package datavinci.auth;
-option go_package = "datavinci/internal/auth/grpc";
+option go_package = "datavinci/internal/auth/grpc";
import "google/protobuf/timestamp.proto";
@@ -35,4 +35,4 @@ message Permission {
message Error {
string code = 1;
string message = 2;
-}
\ No newline at end of file
+}
diff --git a/internal/auth/ent/client.go b/internal/auth/ent/client.go
index 9e7e5a6..524af2a 100644
--- a/internal/auth/ent/client.go
+++ b/internal/auth/ent/client.go
@@ -658,7 +658,8 @@ func (c *UserClient) QueryTokens(u *User) *TokenQuery {
// Hooks returns the client hooks.
func (c *UserClient) Hooks() []Hook {
- return c.hooks.User
+ hooks := c.hooks.User
+ return append(hooks[:len(hooks):len(hooks)], user.Hooks[:]...)
}
// Interceptors returns the client interceptors.
diff --git a/internal/auth/ent/enttest/enttest.go b/internal/auth/ent/enttest/enttest.go
index d05faea..bb0f943 100644
--- a/internal/auth/ent/enttest/enttest.go
+++ b/internal/auth/ent/enttest/enttest.go
@@ -5,6 +5,7 @@ package enttest
import (
"auth/ent"
"context"
+
// required by schema hooks.
_ "auth/ent/runtime"
diff --git a/internal/auth/ent/runtime.go b/internal/auth/ent/runtime.go
index 081e005..a1528af 100644
--- a/internal/auth/ent/runtime.go
+++ b/internal/auth/ent/runtime.go
@@ -2,68 +2,4 @@
package ent
-import (
- "auth/ent/role"
- "auth/ent/schema"
- "auth/ent/token"
- "auth/ent/user"
- "time"
-)
-
-// The init function reads all schema descriptors with runtime code
-// (default values, validators, hooks and policies) and stitches it
-// to their package variables.
-func init() {
- roleFields := schema.Role{}.Fields()
- _ = roleFields
- // roleDescCreatedAt is the schema descriptor for created_at field.
- roleDescCreatedAt := roleFields[3].Descriptor()
- // role.DefaultCreatedAt holds the default value on creation for the created_at field.
- role.DefaultCreatedAt = roleDescCreatedAt.Default.(func() time.Time)
- // roleDescUpdatedAt is the schema descriptor for updated_at field.
- roleDescUpdatedAt := roleFields[4].Descriptor()
- // role.DefaultUpdatedAt holds the default value on creation for the updated_at field.
- role.DefaultUpdatedAt = roleDescUpdatedAt.Default.(func() time.Time)
- // role.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field.
- role.UpdateDefaultUpdatedAt = roleDescUpdatedAt.UpdateDefault.(func() time.Time)
- // roleDescID is the schema descriptor for id field.
- roleDescID := roleFields[0].Descriptor()
- // role.DefaultID holds the default value on creation for the id field.
- role.DefaultID = roleDescID.Default.(func() string)
- tokenFields := schema.Token{}.Fields()
- _ = tokenFields
- // tokenDescRevoked is the schema descriptor for revoked field.
- tokenDescRevoked := tokenFields[4].Descriptor()
- // token.DefaultRevoked holds the default value on creation for the revoked field.
- token.DefaultRevoked = tokenDescRevoked.Default.(bool)
- // tokenDescCreatedAt is the schema descriptor for created_at field.
- tokenDescCreatedAt := tokenFields[5].Descriptor()
- // token.DefaultCreatedAt holds the default value on creation for the created_at field.
- token.DefaultCreatedAt = tokenDescCreatedAt.Default.(func() time.Time)
- // tokenDescUpdatedAt is the schema descriptor for updated_at field.
- tokenDescUpdatedAt := tokenFields[6].Descriptor()
- // token.DefaultUpdatedAt holds the default value on creation for the updated_at field.
- token.DefaultUpdatedAt = tokenDescUpdatedAt.Default.(func() time.Time)
- // token.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field.
- token.UpdateDefaultUpdatedAt = tokenDescUpdatedAt.UpdateDefault.(func() time.Time)
- // tokenDescID is the schema descriptor for id field.
- tokenDescID := tokenFields[0].Descriptor()
- // token.DefaultID holds the default value on creation for the id field.
- token.DefaultID = tokenDescID.Default.(func() string)
- userFields := schema.User{}.Fields()
- _ = userFields
- // userDescCreatedAt is the schema descriptor for created_at field.
- userDescCreatedAt := userFields[4].Descriptor()
- // user.DefaultCreatedAt holds the default value on creation for the created_at field.
- user.DefaultCreatedAt = userDescCreatedAt.Default.(func() time.Time)
- // userDescUpdatedAt is the schema descriptor for updated_at field.
- userDescUpdatedAt := userFields[5].Descriptor()
- // user.DefaultUpdatedAt holds the default value on creation for the updated_at field.
- user.DefaultUpdatedAt = userDescUpdatedAt.Default.(func() time.Time)
- // user.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field.
- user.UpdateDefaultUpdatedAt = userDescUpdatedAt.UpdateDefault.(func() time.Time)
- // userDescID is the schema descriptor for id field.
- userDescID := userFields[0].Descriptor()
- // user.DefaultID holds the default value on creation for the id field.
- user.DefaultID = userDescID.Default.(func() string)
-}
+// The schema-stitching logic is generated in auth/ent/runtime/runtime.go
diff --git a/internal/auth/ent/runtime/runtime.go b/internal/auth/ent/runtime/runtime.go
index 36a66f9..954e583 100644
--- a/internal/auth/ent/runtime/runtime.go
+++ b/internal/auth/ent/runtime/runtime.go
@@ -2,7 +2,73 @@
package runtime
-// The schema-stitching logic is generated in auth/ent/runtime.go
+import (
+ "auth/ent/role"
+ "auth/ent/schema"
+ "auth/ent/token"
+ "auth/ent/user"
+ "time"
+)
+
+// The init function reads all schema descriptors with runtime code
+// (default values, validators, hooks and policies) and stitches it
+// to their package variables.
+func init() {
+ roleFields := schema.Role{}.Fields()
+ _ = roleFields
+ // roleDescCreatedAt is the schema descriptor for created_at field.
+ roleDescCreatedAt := roleFields[3].Descriptor()
+ // role.DefaultCreatedAt holds the default value on creation for the created_at field.
+ role.DefaultCreatedAt = roleDescCreatedAt.Default.(func() time.Time)
+ // roleDescUpdatedAt is the schema descriptor for updated_at field.
+ roleDescUpdatedAt := roleFields[4].Descriptor()
+ // role.DefaultUpdatedAt holds the default value on creation for the updated_at field.
+ role.DefaultUpdatedAt = roleDescUpdatedAt.Default.(func() time.Time)
+ // role.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field.
+ role.UpdateDefaultUpdatedAt = roleDescUpdatedAt.UpdateDefault.(func() time.Time)
+ // roleDescID is the schema descriptor for id field.
+ roleDescID := roleFields[0].Descriptor()
+ // role.DefaultID holds the default value on creation for the id field.
+ role.DefaultID = roleDescID.Default.(func() string)
+ tokenFields := schema.Token{}.Fields()
+ _ = tokenFields
+ // tokenDescRevoked is the schema descriptor for revoked field.
+ tokenDescRevoked := tokenFields[4].Descriptor()
+ // token.DefaultRevoked holds the default value on creation for the revoked field.
+ token.DefaultRevoked = tokenDescRevoked.Default.(bool)
+ // tokenDescCreatedAt is the schema descriptor for created_at field.
+ tokenDescCreatedAt := tokenFields[5].Descriptor()
+ // token.DefaultCreatedAt holds the default value on creation for the created_at field.
+ token.DefaultCreatedAt = tokenDescCreatedAt.Default.(func() time.Time)
+ // tokenDescUpdatedAt is the schema descriptor for updated_at field.
+ tokenDescUpdatedAt := tokenFields[6].Descriptor()
+ // token.DefaultUpdatedAt holds the default value on creation for the updated_at field.
+ token.DefaultUpdatedAt = tokenDescUpdatedAt.Default.(func() time.Time)
+ // token.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field.
+ token.UpdateDefaultUpdatedAt = tokenDescUpdatedAt.UpdateDefault.(func() time.Time)
+ // tokenDescID is the schema descriptor for id field.
+ tokenDescID := tokenFields[0].Descriptor()
+ // token.DefaultID holds the default value on creation for the id field.
+ token.DefaultID = tokenDescID.Default.(func() string)
+ userHooks := schema.User{}.Hooks()
+ user.Hooks[0] = userHooks[0]
+ userFields := schema.User{}.Fields()
+ _ = userFields
+ // userDescCreatedAt is the schema descriptor for created_at field.
+ userDescCreatedAt := userFields[4].Descriptor()
+ // user.DefaultCreatedAt holds the default value on creation for the created_at field.
+ user.DefaultCreatedAt = userDescCreatedAt.Default.(func() time.Time)
+ // userDescUpdatedAt is the schema descriptor for updated_at field.
+ userDescUpdatedAt := userFields[5].Descriptor()
+ // user.DefaultUpdatedAt holds the default value on creation for the updated_at field.
+ user.DefaultUpdatedAt = userDescUpdatedAt.Default.(func() time.Time)
+ // user.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field.
+ user.UpdateDefaultUpdatedAt = userDescUpdatedAt.UpdateDefault.(func() time.Time)
+ // userDescID is the schema descriptor for id field.
+ userDescID := userFields[0].Descriptor()
+ // user.DefaultID holds the default value on creation for the id field.
+ user.DefaultID = userDescID.Default.(func() string)
+}
const (
Version = "v0.13.1" // Version of ent codegen.
diff --git a/internal/auth/ent/schema/user.go b/internal/auth/ent/schema/user.go
index be25caa..c6043eb 100644
--- a/internal/auth/ent/schema/user.go
+++ b/internal/auth/ent/schema/user.go
@@ -1,6 +1,7 @@
package schema
import (
+ "auth/pkg"
"context"
"time"
@@ -8,7 +9,6 @@ import (
"entgo.io/ent/schema/edge"
"entgo.io/ent/schema/field"
"github.com/google/uuid"
- "golang.org/x/crypto/bcrypt"
)
// User holds the schema definition for the User entity.
@@ -54,7 +54,7 @@ func HashPassword() ent.Hook {
return func(next ent.Mutator) ent.Mutator {
return ent.MutateFunc(func(ctx context.Context, m ent.Mutation) (ent.Value, error) {
if password, ok := m.Field("password"); ok {
- hash, err := bcrypt.GenerateFromPassword([]byte(password.(string)), bcrypt.DefaultCost)
+ hash, err := pkg.NewPasswordHasher(12).HashPassword(password.(string)) // HLc
if err != nil {
return nil, err
}
diff --git a/internal/auth/ent/user/user.go b/internal/auth/ent/user/user.go
index b153dfe..0838533 100644
--- a/internal/auth/ent/user/user.go
+++ b/internal/auth/ent/user/user.go
@@ -5,6 +5,7 @@ package user
import (
"time"
+ "entgo.io/ent"
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
)
@@ -70,7 +71,13 @@ func ValidColumn(column string) bool {
return false
}
+// Note that the variables below are initialized by the runtime
+// package on the initialization of the application. Therefore,
+// it should be imported in the main as follows:
+//
+// import _ "auth/ent/runtime"
var (
+ Hooks [1]ent.Hook
// DefaultCreatedAt holds the default value on creation for the "created_at" field.
DefaultCreatedAt func() time.Time
// DefaultUpdatedAt holds the default value on creation for the "updated_at" field.
diff --git a/internal/auth/ent/user_create.go b/internal/auth/ent/user_create.go
index 8d6d56f..a408439 100644
--- a/internal/auth/ent/user_create.go
+++ b/internal/auth/ent/user_create.go
@@ -119,7 +119,9 @@ func (uc *UserCreate) Mutation() *UserMutation {
// Save creates the User in the database.
func (uc *UserCreate) Save(ctx context.Context) (*User, error) {
- uc.defaults()
+ if err := uc.defaults(); err != nil {
+ return nil, err
+ }
return withHooks(ctx, uc.sqlSave, uc.mutation, uc.hooks)
}
@@ -146,19 +148,29 @@ func (uc *UserCreate) ExecX(ctx context.Context) {
}
// defaults sets the default values of the builder before save.
-func (uc *UserCreate) defaults() {
+func (uc *UserCreate) defaults() error {
if _, ok := uc.mutation.CreatedAt(); !ok {
+ if user.DefaultCreatedAt == nil {
+ return fmt.Errorf("ent: uninitialized user.DefaultCreatedAt (forgotten import ent/runtime?)")
+ }
v := user.DefaultCreatedAt()
uc.mutation.SetCreatedAt(v)
}
if _, ok := uc.mutation.UpdatedAt(); !ok {
+ if user.DefaultUpdatedAt == nil {
+ return fmt.Errorf("ent: uninitialized user.DefaultUpdatedAt (forgotten import ent/runtime?)")
+ }
v := user.DefaultUpdatedAt()
uc.mutation.SetUpdatedAt(v)
}
if _, ok := uc.mutation.ID(); !ok {
+ if user.DefaultID == nil {
+ return fmt.Errorf("ent: uninitialized user.DefaultID (forgotten import ent/runtime?)")
+ }
v := user.DefaultID()
uc.mutation.SetID(v)
}
+ return nil
}
// check runs all checks and user-defined validators on the builder.
diff --git a/internal/auth/ent/user_update.go b/internal/auth/ent/user_update.go
index 72a1920..866d6be 100644
--- a/internal/auth/ent/user_update.go
+++ b/internal/auth/ent/user_update.go
@@ -171,7 +171,9 @@ func (uu *UserUpdate) RemoveTokens(t ...*Token) *UserUpdate {
// Save executes the query and returns the number of nodes affected by the update operation.
func (uu *UserUpdate) Save(ctx context.Context) (int, error) {
- uu.defaults()
+ if err := uu.defaults(); err != nil {
+ return 0, err
+ }
return withHooks(ctx, uu.sqlSave, uu.mutation, uu.hooks)
}
@@ -198,11 +200,15 @@ func (uu *UserUpdate) ExecX(ctx context.Context) {
}
// defaults sets the default values of the builder before save.
-func (uu *UserUpdate) defaults() {
+func (uu *UserUpdate) defaults() error {
if _, ok := uu.mutation.UpdatedAt(); !ok {
+ if user.UpdateDefaultUpdatedAt == nil {
+ return fmt.Errorf("ent: uninitialized user.UpdateDefaultUpdatedAt (forgotten import ent/runtime?)")
+ }
v := user.UpdateDefaultUpdatedAt()
uu.mutation.SetUpdatedAt(v)
}
+ return nil
}
func (uu *UserUpdate) sqlSave(ctx context.Context) (n int, err error) {
@@ -493,7 +499,9 @@ func (uuo *UserUpdateOne) Select(field string, fields ...string) *UserUpdateOne
// Save executes the query and returns the updated User entity.
func (uuo *UserUpdateOne) Save(ctx context.Context) (*User, error) {
- uuo.defaults()
+ if err := uuo.defaults(); err != nil {
+ return nil, err
+ }
return withHooks(ctx, uuo.sqlSave, uuo.mutation, uuo.hooks)
}
@@ -520,11 +528,15 @@ func (uuo *UserUpdateOne) ExecX(ctx context.Context) {
}
// defaults sets the default values of the builder before save.
-func (uuo *UserUpdateOne) defaults() {
+func (uuo *UserUpdateOne) defaults() error {
if _, ok := uuo.mutation.UpdatedAt(); !ok {
+ if user.UpdateDefaultUpdatedAt == nil {
+ return fmt.Errorf("ent: uninitialized user.UpdateDefaultUpdatedAt (forgotten import ent/runtime?)")
+ }
v := user.UpdateDefaultUpdatedAt()
uuo.mutation.SetUpdatedAt(v)
}
+ return nil
}
func (uuo *UserUpdateOne) sqlSave(ctx context.Context) (_node *User, err error) {
diff --git a/internal/auth/go.mod b/internal/auth/go.mod
index a7d7914..14da49e 100644
--- a/internal/auth/go.mod
+++ b/internal/auth/go.mod
@@ -1,25 +1,37 @@
module auth
-go 1.21
+go 1.22
+
+toolchain go1.22.5
require (
+ github.com/brianvoe/gofakeit/v7 v7.0.4
github.com/go-redis/redis/v8 v8.11.5
github.com/golang-jwt/jwt v3.2.2+incompatible
+ github.com/mattn/go-sqlite3 v1.14.16
+ github.com/stretchr/testify v1.9.0
+ go.uber.org/zap v1.21.0
golang.org/x/crypto v0.23.0
+ golang.org/x/time v0.5.0
google.golang.org/grpc v1.65.0
google.golang.org/protobuf v1.34.2
)
require (
github.com/cespare/xxhash/v2 v2.3.0 // indirect
+ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
- go.uber.org/atomic v1.7.0 // indirect
- go.uber.org/multierr v1.6.0 // indirect
- go.uber.org/zap v1.21.0 // indirect
+ github.com/fsnotify/fsnotify v1.7.0 // indirect
+ github.com/kr/pretty v0.3.1 // indirect
+ github.com/pkg/errors v0.9.1 // indirect
+ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
+ go.uber.org/atomic v1.9.0 // indirect
+ go.uber.org/multierr v1.9.0 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/sys v0.20.0 // indirect
- golang.org/x/time v0.5.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 // indirect
+ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
+ gopkg.in/yaml.v3 v3.0.1 // indirect
)
require (
diff --git a/internal/auth/go.sum b/internal/auth/go.sum
index 81d9d35..8962c3d 100644
--- a/internal/auth/go.sum
+++ b/internal/auth/go.sum
@@ -8,18 +8,20 @@ github.com/agext/levenshtein v1.2.1 h1:QmvMAjj2aEICytGiWzmxoE0x2KZvE0fvmqMOfy2tj
github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw=
github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
+github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
+github.com/brianvoe/gofakeit/v7 v7.0.4 h1:Mkxwz9jYg8Ad8NvT9HA27pCMZGFQo08MK6jD0QTKEww=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
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/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
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/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
-github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
+github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4=
github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4=
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
@@ -39,8 +41,9 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hashicorp/hcl/v2 v2.13.0 h1:0Apadu1w6M11dyGFxWnmhhcMjkbAiKCv7G1r/2QgCNc=
github.com/hashicorp/hcl/v2 v2.13.0/go.mod h1:e4z5nxYlWNPdDSNYX+ph14EvWYMFm3eP0zIUqPc2jr0=
-github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
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.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=
@@ -59,26 +62,29 @@ 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/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
+github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
-github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4=
github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/zclconf/go-cty v1.8.0 h1:s4AvqaeQzJIu3ndv4gVIhplVD0krU+bgrcLSVUnaWuA=
github.com/zclconf/go-cty v1.8.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk=
-go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
+go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
-go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
+go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8=
go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@@ -131,6 +137,7 @@ google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6h
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
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-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
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.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/internal/auth/internal/auth/service/auth_service.go b/internal/auth/internal/auth/service/auth_service.go
index 3952433..f9ae89b 100644
--- a/internal/auth/internal/auth/service/auth_service.go
+++ b/internal/auth/internal/auth/service/auth_service.go
@@ -155,7 +155,7 @@ func (s *AuthService) Login(ctx context.Context, req *pb.LoginRequest) (*pb.Logi
return nil, status.Errorf(codes.Internal, "Failed to fetch user: %v", err)
}
- if user == nil || !s.userRepo.CheckPassword(ctx, req.Password) {
+ if user == nil || !s.userRepo.CheckPassword(ctx, user.Username, req.Password) {
return nil, status.Errorf(codes.Unauthenticated, "Invalid username or password")
}
diff --git a/internal/auth/internal/db/db.go b/internal/auth/internal/db/db.go
index 0e92502..c68bfca 100644
--- a/internal/auth/internal/db/db.go
+++ b/internal/auth/internal/db/db.go
@@ -116,4 +116,4 @@ func ConnectRedis(redisURL string) (*redis.Client, error) {
}
return client, nil
-}
\ No newline at end of file
+}
diff --git a/internal/auth/internal/interceptor/interceptor.go b/internal/auth/internal/interceptor/interceptor.go
index 9b2500f..105e8b3 100644
--- a/internal/auth/internal/interceptor/interceptor.go
+++ b/internal/auth/internal/interceptor/interceptor.go
@@ -8,24 +8,13 @@ package interceptor
import (
"context"
- "encoding/base64"
- "fmt"
- "strings"
- "sync"
"time"
"github.com/dgrijalva/jwt-go"
"github.com/patrickmn/go-cache"
"go.uber.org/zap"
- "golang.org/x/crypto/bcrypt"
"golang.org/x/time/rate"
"google.golang.org/grpc"
- "google.golang.org/grpc/codes"
- "google.golang.org/grpc/metadata"
- "google.golang.org/grpc/peer"
- "google.golang.org/grpc/status"
-
- "pkg/config"
)
// contextKey is a custom type for context keys to avoid collisions.
@@ -41,7 +30,7 @@ const (
// JWT authentication scheme.
JWT AuthScheme = "Bearer"
// APIKey authentication scheme.
- APIKey AuthScheme = "ApiKey"
+ APIKey AuthScheme = "APIKey"
)
// AuthInterceptorConfig holds the configuration for the AuthInterceptor.
@@ -116,6 +105,13 @@ func WithTokenRefreshWindow(window time.Duration) AuthInterceptorOption {
}
}
+// WithAPIKeyCache sets the cache for API key validation.
+func WithAPIKeyCache(cache *cache.Cache) AuthInterceptorOption {
+ return func(config *AuthInterceptorConfig) {
+ config.APIKeyCache = cache
+ }
+}
+
// NewAuthInterceptor creates a new AuthInterceptor with the given options.
//
// Usage:
@@ -150,386 +146,26 @@ func NewAuthInterceptor(opts ...AuthInterceptorOption) grpc.UnaryServerIntercept
// authInterceptor is the core function that performs the authentication.
func authInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler, config *AuthInterceptorConfig) (interface{}, error) {
- // Apply rate limiting
- if err := config.RateLimiter.Wait(ctx); err != nil {
- config.Logger.Warn("Rate limit exceeded", zap.Error(err))
- return nil, status.Errorf(codes.ResourceExhausted, "Rate limit exceeded")
- }
-
- md, ok := metadata.FromIncomingContext(ctx)
- if !ok {
- config.Logger.Warn("Missing metadata")
- return nil, status.Errorf(codes.Unauthenticated, "Missing metadata")
- }
-
- authHeader, ok := md[config.MetadataKey]
- if !ok || len(authHeader) == 0 {
- config.Logger.Warn("Missing authorization header")
- return nil, status.Errorf(codes.Unauthenticated, "Missing authorization header")
- }
-
- authParts := strings.SplitN(authHeader[0], " ", 2)
- if len(authParts) != 2 {
- config.Logger.Warn("Invalid authorization header format")
- return nil, status.Errorf(codes.Unauthenticated, "Invalid authorization header format")
- }
-
- authScheme := AuthScheme(authParts[0])
- authToken := authParts[1]
-
- var claims jwt.MapClaims
- var err error
-
- switch authScheme {
- case JWT:
- claims, err = config.TokenValidator(authToken)
- if err != nil {
- config.Logger.Warn("Invalid JWT token", zap.Error(err))
- return nil, status.Errorf(codes.Unauthenticated, "Invalid token: %v", err)
- }
-
- // Check if token needs refresh
- if exp, ok := claims["exp"].(float64); ok {
- expTime := time.Unix(int64(exp), 0)
- if time.Until(expTime) < config.TokenRefreshWindow {
- newToken, err := config.RefreshTokenFunc(authToken)
- if err != nil {
- config.Logger.Warn("Failed to refresh token", zap.Error(err))
- } else {
- // Add the new token to the outgoing context
- md.Set("new-token", newToken)
- ctx = metadata.NewOutgoingContext(ctx, md)
- }
- }
- }
-
- case APIKey:
- valid, err := validateAPIKey(authToken, config)
- if err != nil || !valid {
- config.Logger.Warn("Invalid API key", zap.Error(err))
- return nil, status.Errorf(codes.Unauthenticated, "Invalid API key")
- }
- claims = jwt.MapClaims{"api_key": authToken}
-
- default:
- config.Logger.Warn("Unsupported authentication scheme", zap.String("scheme", string(authScheme)))
- return nil, status.Errorf(codes.Unauthenticated, "Unsupported authentication scheme")
- }
-
- newCtx := context.WithValue(ctx, userClaimsKey, claims)
-
- // Log the authenticated request
- peer, _ := peer.FromContext(ctx)
- config.Logger.Info("Authenticated request",
- zap.String("method", info.FullMethod),
- zap.String("peer", peer.Addr.String()),
- zap.Any("claims", claims),
- )
-
- return handler(newCtx, req)
-}
-
-// defaultTokenValidator is the default implementation of JWT token validation.
-//
-// This function parses and validates a JWT token using a secret key.
-// In a production environment, you should replace this with your own
-// implementation that uses your secret key and includes any additional
-// validation logic specific to your application.
-func defaultTokenValidator(tokenString string) (jwt.MapClaims, error) {
- conf, err := config.Load()
- if err != nil {
+ if err := validateConfig(config); err != nil {
return nil, err
}
- token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
- if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
- return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
- }
- return []byte(conf.JWTSecret), nil
- })
- if err != nil {
+ if err := applyRateLimiting(ctx, config); err != nil {
return nil, err
}
- if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
- return claims, nil
- }
-
- return nil, fmt.Errorf("invalid token")
-}
-
-// defaultAPIKeyValidator is the default implementation of API key validation.
-func defaultAPIKeyValidator(apiKey string) (bool, error) {
- validKeys := map[string]bool{
- // we will read from our database
- }
-
- isValid, exists := validKeys[apiKey]
- if !exists {
- return false, nil
- }
- return isValid, nil
-}
-
-// validateAPIKey checks the validity of an API key, using caching for performance.
-func validateAPIKey(apiKey string, config *AuthInterceptorConfig) (bool, error) {
- // Check cache first
- if valid, found := config.APIKeyCache.Get(apiKey); found {
- return valid.(bool), nil
- }
-
- // If not in cache, validate using the provided validator
- valid, err := config.APIKeyValidator(apiKey)
+ authToken, authScheme, err := extractAuthInfo(ctx, config)
if err != nil {
- return false, err
- }
-
- // Cache the result
- config.APIKeyCache.Set(apiKey, valid, cache.DefaultExpiration)
-
- return valid, nil
-}
-
-// defaultRefreshTokenFunc is the default implementation of token refresh.
-func defaultRefreshTokenFunc(oldToken string) (string, error) {
- return "new-refreshed-token-" + oldToken[len(oldToken)-5:], nil
-}
-
-// GetUserClaims retrieves the user claims from the context.
-//
-// This function can be used in your gRPC handlers to access the
-// authenticated user's claims.
-//
-// Usage:
-//
-// func (s *server) SomeMethod(ctx context.Context, req *pb.Request) (*pb.Response, error) {
-// claims, ok := interceptor.GetUserClaims(ctx)
-// if !ok {
-// return nil, status.Errorf(codes.Unauthenticated, "No user claims found")
-// }
-// // Use claims...
-// }
-func GetUserClaims(ctx context.Context) (jwt.MapClaims, bool) {
- claims, ok := ctx.Value(userClaimsKey).(jwt.MapClaims)
- return claims, ok
-}
-
-// TokenGenerator is a helper struct for generating JWT tokens.
-type TokenGenerator struct {
- secretKey []byte
- issuer string
- duration time.Duration
-}
-
-// NewTokenGenerator creates a new TokenGenerator.
-func NewTokenGenerator(secretKey []byte, issuer string, duration time.Duration) *TokenGenerator {
- return &TokenGenerator{
- secretKey: secretKey,
- issuer: issuer,
- duration: duration,
- }
-}
-
-// GenerateToken generates a new JWT token with the given claims.
-func (g *TokenGenerator) GenerateToken(claims jwt.MapClaims) (string, error) {
- now := time.Now()
- claims["iss"] = g.issuer
- claims["iat"] = now.Unix()
- claims["exp"] = now.Add(g.duration).Unix()
-
- token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
- return token.SignedString(g.secretKey)
-}
-
-// PerIPRateLimiter is a helper struct for per-IP rate limiting.
-type PerIPRateLimiter struct {
- ips map[string]*rate.Limiter
- mu *sync.RWMutex
- r rate.Limit
- b int
-}
-
-// NewPerIPRateLimiter creates a new PerIPRateLimiter.
-func NewPerIPRateLimiter(r rate.Limit, b int) *PerIPRateLimiter {
- return &PerIPRateLimiter{
- ips: make(map[string]*rate.Limiter),
- mu: &sync.RWMutex{},
- r: r,
- b: b,
- }
-}
-
-// AddIP adds an IP address to the rate limiter.
-func (l *PerIPRateLimiter) AddIP(ip string) *rate.Limiter {
- l.mu.Lock()
- defer l.mu.Unlock()
-
- limiter := rate.NewLimiter(l.r, l.b)
- l.ips[ip] = limiter
- return limiter
-}
-
-// GetLimiter returns the rate limiter for the given IP address.
-func (l *PerIPRateLimiter) GetLimiter(ip string) *rate.Limiter {
- l.mu.Lock()
- limiter, exists := l.ips[ip]
-
- if !exists {
- l.mu.Unlock()
- return l.AddIP(ip)
- }
-
- l.mu.Unlock()
- return limiter
-}
-
-// PasswordHasher is a helper struct for hashing and verifying passwords.
-type PasswordHasher struct {
- cost int
-}
-
-// NewPasswordHasher creates a new PasswordHasher.
-//
-// Parameters:
-// - cost: The cost of the bcrypt algorithm (default is 10).
-//
-// Usage:
-//
-// hasher := NewPasswordHasher(12)
-func NewPasswordHasher(cost int) *PasswordHasher {
- if cost == 0 {
- cost = 10
+ return nil, err
}
- return &PasswordHasher{cost: cost}
-}
-
-// HashPassword hashes a password using bcrypt.
-//
-// Parameters:
-// - password: The password to hash.
-//
-// Returns:
-// - The hashed password and an error if hashing fails.
-//
-// Usage:
-//
-// hashedPassword, err := hasher.HashPassword("myPassword123")
-func (ph *PasswordHasher) HashPassword(password string) (string, error) {
- bytes, err := bcrypt.GenerateFromPassword([]byte(password), ph.cost)
- return string(bytes), err
-}
-// CheckPassword checks if a password matches the hashed version.
-//
-// Parameters:
-// - password: The password to check.
-// - hashedPassword: The hashed password to compare against.
-//
-// Returns:
-// - true if the password matches, false otherwise.
-//
-// Usage:
-//
-// if hasher.CheckPassword("myPassword123", hashedPassword) {
-// // Password is correct
-// }
-func (ph *PasswordHasher) CheckPassword(password, hashedPassword string) bool {
- err := bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password))
- return err == nil
-}
-
-// Base64Encoder is a helper struct for encoding and decoding Base64 strings.
-type Base64Encoder struct{}
-
-// NewBase64Encoder creates a new Base64Encoder.
-//
-// Usage:
-//
-// encoder := NewBase64Encoder()
-func NewBase64Encoder() *Base64Encoder {
- return &Base64Encoder{}
-}
-
-// Encode encodes a string to Base64.
-//
-// Parameters:
-// - data: The string to encode.
-//
-// Returns:
-// - The Base64 encoded string.
-//
-// Usage:
-//
-// encoded := encoder.Encode("Hello, World!")
-func (b *Base64Encoder) Encode(data string) string {
- return base64.StdEncoding.EncodeToString([]byte(data))
-}
-
-// Decode decodes a Base64 string.
-//
-// Parameters:
-// - encodedData: The Base64 encoded string to decode.
-//
-// Returns:
-// - The decoded string and an error if decoding fails.
-//
-// Usage:
-//
-// decoded, err := encoder.Decode(encodedString)
-func (b *Base64Encoder) Decode(encodedData string) (string, error) {
- data, err := base64.StdEncoding.DecodeString(encodedData)
+ claims, err := authenticateRequest(ctx, authToken, authScheme, config)
if err != nil {
- return "", err
- }
- return string(data), nil
-}
-
-// AuthMetadataKey is a helper function to get the metadata key for authentication.
-//
-// Parameters:
-// - ctx: The context from which to extract the metadata.
-//
-// Returns:
-// - The authentication metadata key and a boolean indicating if it was found.
-//
-// Usage:
-//
-// key, ok := AuthMetadataKey(ctx)
-// if !ok {
-// return status.Errorf(codes.Unauthenticated, "Missing authentication metadata")
-// }
-func AuthMetadataKey(ctx context.Context) (string, bool) {
- md, ok := metadata.FromIncomingContext(ctx)
- if !ok {
- return "", false
- }
-
- values := md.Get("authorization")
- if len(values) == 0 {
- return "", false
+ return nil, err
}
- return values[0], true
-}
+ newCtx := context.WithValue(ctx, userClaimsKey, claims)
+ logAuthenticatedRequest(newCtx, info, config, claims)
-// ExtractBearerToken is a helper function to extract the Bearer token from an authorization header.
-//
-// Parameters:
-// - authHeader: The full authorization header.
-//
-// Returns:
-// - The Bearer token and an error if extraction fails.
-//
-// Usage:
-//
-// token, err := ExtractBearerToken(authHeader)
-// if err != nil {
-// return status.Errorf(codes.Unauthenticated, "Invalid authorization header")
-// }
-func ExtractBearerToken(authHeader string) (string, error) {
- parts := strings.SplitN(authHeader, " ", 2)
- if len(parts) != 2 || strings.ToLower(parts[0]) != "bearer" {
- return "", fmt.Errorf("invalid authorization header format")
- }
- return parts[1], nil
+ return handler(newCtx, req)
}
diff --git a/internal/auth/internal/interceptor/interceptor_test.go b/internal/auth/internal/interceptor/interceptor_test.go
index b998447..17e1ca1 100644
--- a/internal/auth/internal/interceptor/interceptor_test.go
+++ b/internal/auth/internal/interceptor/interceptor_test.go
@@ -1,366 +1,91 @@
-package interceptor_test
+package interceptor
import (
- "auth/internal/interceptor"
"context"
- "fmt"
- "log"
- "net"
"testing"
"time"
"github.com/dgrijalva/jwt-go"
+ "github.com/patrickmn/go-cache"
"github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
"go.uber.org/zap"
+ "golang.org/x/time/rate"
"google.golang.org/grpc"
- "google.golang.org/grpc/codes"
- "google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/metadata"
- "google.golang.org/grpc/status"
- "google.golang.org/grpc/test/bufconn"
-
- pb "auth/pb"
)
-
-func (s *mockService) SayHello(ctx context.Context, req *HelloRequest) (*HelloResponse, error) {
- claims, ok := interceptor.GetUserClaims(ctx)
- if !ok {
- return nil, status.Errorf(codes.Unauthenticated, "No user claims found")
- }
- return &HelloResponse{Message: fmt.Sprintf("Hello, %v!", claims["sub"])}, nil
+func TestNewAuthInterceptor(t *testing.T) {
+ interceptor := NewAuthInterceptor()
+ assert.NotNil(t, interceptor)
}
-type HelloRequest struct{}
-type HelloResponse struct {
- Message string
-}
+func TestWithOptions(t *testing.T) {
+ logger := zap.NewExample()
+ tokenValidator := func(string) (jwt.MapClaims, error) { return nil, nil }
+ apiKeyValidator := func(string) (bool, error) { return true, nil }
+ refreshFunc := func(string) (string, error) { return "", nil }
+ cache := cache.New(5*time.Minute, 10*time.Minute)
-const bufSize = 1024 * 1024
-
-var lis *bufconn.Listener
-
-func init() {
- lis = bufconn.Listen(bufSize)
-}
+ interceptor := NewAuthInterceptor(
+ WithLogger(logger),
+ WithTokenValidator(tokenValidator),
+ WithAPIKeyValidator(apiKeyValidator),
+ WithMetadataKey("custom-auth"),
+ WithRateLimiter(rate.NewLimiter(rate.Every(time.Second), 5)),
+ WithRefreshTokenFunc(refreshFunc),
+ WithSupportedSchemes(JWT, APIKey),
+ WithTokenRefreshWindow(10*time.Minute),
+ WithAPIKeyCache(cache),
+ )
-type mockService struct {
- pb.UnimplementedAuthServiceServer
+ assert.NotNil(t, interceptor)
}
-func (s *mockService) Login(ctx context.Context, req *pb.LoginRequest) (*pb.LoginResponse, error) {
- claims, ok := interceptor.GetUserClaims(ctx)
- if !ok {
- return nil, status.Errorf(codes.Unauthenticated, "No user claims found")
+func TestAuthInterceptor(t *testing.T) {
+ config := &AuthInterceptorConfig{
+ TokenValidator: func(token string) (jwt.MapClaims, error) {
+ return jwt.MapClaims{"sub": "user123"}, nil
+ },
+ APIKeyValidator: func(apiKey string) (bool, error) {
+ return apiKey == "valid-api-key", nil
+ },
+ MetadataKey: "authorization",
+ Logger: zap.NewNop(),
+ SupportedSchemes: []AuthScheme{JWT, APIKey},
+ APIKeyCache: cache.New(5*time.Minute, 10*time.Minute), // Add this line
}
- return &pb.LoginResponse{AccessToken: claims["sub"].(string)}, nil
-}
-
-func bufDialer(context.Context, string) (net.Conn, error) {
- return lis.Dial()
-}
-
-// Test helpers
-func createTestServer(t *testing.T, interceptor grpc.UnaryServerInterceptor) (*grpc.Server, *bufconn.Listener) {
- lis := bufconn.Listen(1024 * 1024)
- s := grpc.NewServer(grpc.UnaryInterceptor(interceptor))
- RegisterTestServiceServer(s, &mockService{})
- go func() {
- if err := s.Serve(lis); err != nil {
- t.Errorf("Server exited with error: %v", err)
- }
- }()
- return s, lis
-}
-
-func createTestClient(t *testing.T, lis *bufconn.Listener) TestServiceClient {
- conn, err := grpc.DialContext(context.Background(), "bufnet", grpc.WithContextDialer(func(context.Context, string) (net.Conn, error) {
- return lis.Dial()
- }), grpc.WithTransportCredentials(insecure.NewCredentials()))
- require.NoError(t, err)
- return NewTestServiceClient(conn)
-}
-
-// Mock JWT token generator
-func generateMockToken(t *testing.T, sub string, exp time.Time) string {
- token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
- "sub": sub,
- "exp": exp.Unix(),
- })
- tokenString, err := token.SignedString([]byte("test-secret"))
- require.NoError(t, err)
- return tokenString
-}
-
-// Test cases
-func TestAuthInterceptor(t *testing.T) {
- logger, _ := zap.NewDevelopment()
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return "response", nil
+ }
- const user = "test-user"
+ info := &grpc.UnaryServerInfo{
+ FullMethod: "/test.Service/TestMethod",
+ }
t.Run("Valid JWT", func(t *testing.T) {
- interceptor := interceptor.NewAuthInterceptor(
- interceptor.WithLogger(logger),
- interceptor.WithTokenValidator(func(token string) (jwt.MapClaims, error) {
- return jwt.MapClaims{"sub": user}, nil
- }),
- )
-
- server, lis := createTestServer(t, interceptor)
- defer server.Stop()
-
- client := createTestClient(t, lis)
-
- ctx := metadata.NewOutgoingContext(context.Background(), metadata.Pairs("authorization", "Bearer valid-token"))
- resp, err := client.SayHello(ctx, &HelloRequest{})
-
+ ctx := metadata.NewIncomingContext(context.Background(), metadata.Pairs("authorization", "Bearer valid-token"))
+ resp, err := authInterceptor(ctx, "request", info, handler, config)
assert.NoError(t, err)
- assert.Equal(t, "Hello, test-user!", resp.Message)
- })
-
- t.Run("Valid JWT", func(t *testing.T) {
- interceptor := interceptor.NewAuthInterceptor(
- interceptor.WithLogger(logger),
- interceptor.WithTokenValidator(func(token string) (jwt.MapClaims, error) {
- return jwt.MapClaims{"sub": "test-user"}, nil
- }),
- )
-
- s := grpc.NewServer(grpc.UnaryInterceptor(interceptor))
- pb.RegisterAuthServiceServer(s, &mockService{})
- go func() {
- if err := s.Serve(lis); err != nil {
- log.Fatalf("Server exited with error: %v", err)
- }
- }()
-
- ctx := context.Background()
- conn, err := grpc.DialContext(ctx, "bufnet", grpc.WithContextDialer(bufDialer), grpc.WithInsecure())
- if err != nil {
- t.Fatalf("Failed to dial bufnet: %v", err)
- }
- defer conn.Close()
-
- client := pb.NewAuthServiceClient(conn)
-
- md := metadata.New(map[string]string{"authorization": "Bearer valid-token"})
- ctx = metadata.NewOutgoingContext(context.Background(), md)
-
- resp, err := client.Login(ctx, &pb.LoginRequest{Username: "test", Password: "test"})
-
- require.NoError(t, err)
- assert.Equal(t, "test-user", resp.AccessToken)
- })
-
- t.Run("Missing Authorization Header", func(t *testing.T) {
- interceptor := interceptor.NewAuthInterceptor(
- interceptor.WithLogger(logger),
- )
-
- server, lis := createTestServer(t, interceptor)
- defer server.Stop()
-
- client := createTestClient(t, lis)
-
- _, err := client.SayHello(context.Background(), &HelloRequest{})
-
- assert.Error(t, err)
- assert.Equal(t, codes.Unauthenticated, status.Code(err))
+ assert.Equal(t, "response", resp)
})
- t.Run("API Key Authentication", func(t *testing.T) {
- interceptor := interceptor.NewAuthInterceptor(
- interceptor.WithLogger(logger),
- interceptor.WithAPIKeyValidator(func(apiKey string) (bool, error) {
- return apiKey == "valid-api-key", nil
- }),
- interceptor.WithSupportedSchemes(interceptor.APIKey),
- )
-
- server, lis := createTestServer(t, interceptor)
- defer server.Stop()
-
- client := createTestClient(t, lis)
-
- ctx := metadata.NewOutgoingContext(context.Background(), metadata.Pairs("authorization", "ApiKey valid-api-key"))
- resp, err := client.SayHello(ctx, &HelloRequest{})
-
+ t.Run("Valid API Key", func(t *testing.T) {
+ ctx := metadata.NewIncomingContext(context.Background(), metadata.Pairs("authorization", "APIKey valid-api-key"))
+ resp, err := authInterceptor(ctx, "request", info, handler, config)
assert.NoError(t, err)
- assert.Contains(t, resp.Message, "api_key")
+ assert.Equal(t, "response", resp)
})
- t.Run("Token Refresh", func(t *testing.T) {
- refreshCalled := false
- interceptor := interceptor.NewAuthInterceptor(
- interceptor.WithLogger(logger),
- interceptor.WithTokenValidator(func(token string) (jwt.MapClaims, error) {
- return jwt.MapClaims{"sub": user, "exp": time.Now().Add(time.Minute).Unix()}, nil
- }),
- interceptor.WithRefreshTokenFunc(func(oldToken string) (string, error) {
- refreshCalled = true
- return "new-token", nil
- }),
- interceptor.WithTokenRefreshWindow(time.Hour), // Set a large window to ensure refresh is triggered
- )
-
- server, lis := createTestServer(t, interceptor)
- defer server.Stop()
-
- client := createTestClient(t, lis)
-
- ctx := metadata.NewOutgoingContext(context.Background(), metadata.Pairs("authorization", "Bearer valid-token"))
- _, err := client.SayHello(ctx, &HelloRequest{})
-
- assert.NoError(t, err)
- assert.True(t, refreshCalled, "Token refresh should have been called")
- })
-}
-
-func TestTokenGenerator(t *testing.T) {
- secretKey := []byte("test-secret")
- issuer := "test-issuer"
- duration := time.Hour
-
- generator := interceptor.NewTokenGenerator(secretKey, issuer, duration)
-
- t.Run("Generate Valid Token", func(t *testing.T) {
- claims := jwt.MapClaims{"sub": "test-user"}
- token, err := generator.GenerateToken(claims)
-
- assert.NoError(t, err)
- assert.NotEmpty(t, token)
-
- // Verify the token
- parsedToken, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) {
- return secretKey, nil
- })
-
- assert.NoError(t, err)
- assert.True(t, parsedToken.Valid)
-
- parsedClaims, ok := parsedToken.Claims.(jwt.MapClaims)
- assert.True(t, ok)
- assert.Equal(t, "test-user", parsedClaims["sub"])
- assert.Equal(t, issuer, parsedClaims["iss"])
- assert.NotEmpty(t, parsedClaims["iat"])
- assert.NotEmpty(t, parsedClaims["exp"])
- })
-}
-
-func TestPasswordHasher(t *testing.T) {
- hasher := interceptor.NewPasswordHasher(10)
-
- t.Run("Hash and Verify Password", func(t *testing.T) {
- password := "test-password"
- hashedPassword, err := hasher.HashPassword(password)
-
- assert.NoError(t, err)
- assert.NotEqual(t, password, hashedPassword)
-
- assert.True(t, hasher.CheckPassword(password, hashedPassword))
- assert.False(t, hasher.CheckPassword("wrong-password", hashedPassword))
- })
-}
-
-func TestBase64Encoder(t *testing.T) {
- encoder := interceptor.NewBase64Encoder()
-
- t.Run("Encode and Decode", func(t *testing.T) {
- original := "Hello, World!"
- encoded := encoder.Encode(original)
- decoded, err := encoder.Decode(encoded)
-
- assert.NoError(t, err)
- assert.NotEqual(t, original, encoded)
- assert.Equal(t, original, decoded)
- })
-
- t.Run("Decode Invalid Base64", func(t *testing.T) {
- _, err := encoder.Decode("invalid-base64")
+ t.Run("Invalid Auth", func(t *testing.T) {
+ ctx := metadata.NewIncomingContext(context.Background(), metadata.Pairs("authorization", "Invalid auth"))
+ _, err := authInterceptor(ctx, "request", info, handler, config)
assert.Error(t, err)
})
-}
-
-func TestHelperFunctions(t *testing.T) {
- t.Run("AuthMetadataKey", func(t *testing.T) {
- ctx := metadata.NewIncomingContext(context.Background(), metadata.Pairs("authorization", "Bearer test-token"))
- key, ok := interceptor.AuthMetadataKey(ctx)
- assert.True(t, ok)
- assert.Equal(t, "Bearer test-token", key)
- _, ok = interceptor.AuthMetadataKey(context.Background())
- assert.False(t, ok)
- })
-
- t.Run("ExtractBearerToken", func(t *testing.T) {
- token, err := interceptor.ExtractBearerToken("Bearer test-token")
- assert.NoError(t, err)
- assert.Equal(t, "test-token", token)
-
- _, err = interceptor.ExtractBearerToken("InvalidHeader test-token")
+ t.Run("Missing Auth", func(t *testing.T) {
+ ctx := context.Background()
+ _, err := authInterceptor(ctx, "request", info, handler, config)
assert.Error(t, err)
})
}
-
-// Mock gRPC service registration
-type TestServiceServer interface {
- SayHello(context.Context, *HelloRequest) (*HelloResponse, error)
-}
-
-func RegisterTestServiceServer(s *grpc.Server, srv TestServiceServer) {
- s.RegisterService(&_TestService_serviceDesc, srv)
-}
-
-type TestServiceClient interface {
- SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloResponse, error)
-}
-
-type testServiceClient struct {
- cc *grpc.ClientConn
-}
-
-func NewTestServiceClient(cc *grpc.ClientConn) TestServiceClient {
- return &testServiceClient{cc}
-}
-
-func (c *testServiceClient) SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloResponse, error) {
- out := new(HelloResponse)
- err := c.cc.Invoke(ctx, "/test.TestService/SayHello", in, out, opts...)
- if err != nil {
- return nil, err
- }
- return out, nil
-}
-
-var _TestService_serviceDesc = grpc.ServiceDesc{
- ServiceName: "test.TestService",
- HandlerType: (*TestServiceServer)(nil),
- Methods: []grpc.MethodDesc{
- {
- MethodName: "SayHello",
- Handler: _TestService_SayHello_Handler,
- },
- },
- Streams: []grpc.StreamDesc{},
- Metadata: "test_service.proto",
-}
-
-func _TestService_SayHello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
- in := new(HelloRequest)
- if err := dec(in); err != nil {
- return nil, err
- }
- if interceptor == nil {
- return srv.(TestServiceServer).SayHello(ctx, in)
- }
- info := &grpc.UnaryServerInfo{
- Server: srv,
- FullMethod: "/test.TestService/SayHello",
- }
- handler := func(ctx context.Context, req interface{}) (interface{}, error) {
- return srv.(TestServiceServer).SayHello(ctx, req.(*HelloRequest))
- }
- return interceptor(ctx, in, info, handler)
-}
\ No newline at end of file
diff --git a/internal/auth/internal/interceptor/utils.go b/internal/auth/internal/interceptor/utils.go
new file mode 100644
index 0000000..d7f5336
--- /dev/null
+++ b/internal/auth/internal/interceptor/utils.go
@@ -0,0 +1,297 @@
+package interceptor
+
+import (
+ "context"
+ "fmt"
+ "strings"
+ "time"
+
+ "github.com/dgrijalva/jwt-go"
+ "github.com/patrickmn/go-cache"
+ "go.uber.org/zap"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/metadata"
+ "google.golang.org/grpc/peer"
+ "google.golang.org/grpc/status"
+)
+
+// validateConfig validates the configuration.
+func validateConfig(config *AuthInterceptorConfig) error {
+ if config == nil {
+ return status.Errorf(codes.Internal, "AuthInterceptorConfig is nil")
+ }
+ if config.Logger == nil {
+ config.Logger = zap.NewNop()
+ }
+ return nil
+}
+
+// applyRateLimiting applies rate limiting to the request.
+func applyRateLimiting(ctx context.Context, config *AuthInterceptorConfig) error {
+ if config.RateLimiter != nil {
+ if err := config.RateLimiter.Wait(ctx); err != nil {
+ config.Logger.Warn("Rate limit exceeded", zap.Error(err))
+ return status.Errorf(codes.ResourceExhausted, "Rate limit exceeded")
+ }
+ }
+ return nil
+}
+
+// extractAuthInfo extracts the authentication information from the context.
+func extractAuthInfo(ctx context.Context, config *AuthInterceptorConfig) (string, AuthScheme, error) {
+ md, ok := metadata.FromIncomingContext(ctx)
+ if !ok {
+ config.Logger.Warn("Missing metadata")
+ return "", "", status.Errorf(codes.Unauthenticated, "Missing metadata")
+ }
+
+ authHeader, ok := md[config.MetadataKey]
+ if !ok || len(authHeader) == 0 {
+ config.Logger.Warn("Missing authorization header")
+ return "", "", status.Errorf(codes.Unauthenticated, "Missing authorization header")
+ }
+
+ authParts := strings.SplitN(authHeader[0], " ", 2)
+ if len(authParts) != 2 {
+ config.Logger.Warn("Invalid authorization header format")
+ return "", "", status.Errorf(codes.Unauthenticated, "Invalid authorization header format")
+ }
+
+ return authParts[1], AuthScheme(authParts[0]), nil
+}
+
+// authenticateRequest authenticates a request using the given token and scheme.
+func authenticateRequest(ctx context.Context, authToken string, authScheme AuthScheme, config *AuthInterceptorConfig) (jwt.MapClaims, error) {
+ switch authScheme {
+ case JWT:
+ return authenticateJWT(ctx, authToken, config)
+ case APIKey:
+ return authenticateAPIKey(authToken, config)
+ default:
+ config.Logger.Warn("Unsupported authentication scheme", zap.String("scheme", string(authScheme)))
+ return nil, status.Errorf(codes.Unauthenticated, "Unsupported authentication scheme")
+ }
+}
+
+// authenticateJWT authenticates a request using a JWT token.
+func authenticateJWT(ctx context.Context, authToken string, config *AuthInterceptorConfig) (jwt.MapClaims, error) {
+ if config.TokenValidator == nil {
+ return nil, status.Errorf(codes.Internal, "TokenValidator is not configured")
+ }
+
+ claims, err := config.TokenValidator(authToken)
+ if err != nil {
+ config.Logger.Warn("Invalid JWT token", zap.Error(err))
+ return nil, status.Errorf(codes.Unauthenticated, "Invalid token: %v", err)
+ }
+
+ newToken, err := refreshTokenIfNeeded(ctx, authToken, claims, config)
+ if err != nil {
+ config.Logger.Warn("Failed to refresh token", zap.Error(err))
+ } else if newToken != "" {
+ md, ok := metadata.FromIncomingContext(ctx)
+ if !ok {
+ md = metadata.New(nil)
+ }
+ md = md.Copy()
+ md.Set("new-token", newToken)
+ ctx = metadata.NewIncomingContext(ctx, md)
+ fmt.Println("ctx: ", ctx)
+ }
+
+ return claims, nil
+}
+
+// refreshTokenIfNeeded checks if the token needs to be refreshed and triggers a refresh if needed.
+func refreshTokenIfNeeded(ctx context.Context, authToken string, claims jwt.MapClaims, config *AuthInterceptorConfig) (string, error) {
+ if exp, ok := claims["exp"].(float64); ok {
+ expTime := time.Unix(int64(exp), 0)
+ if time.Until(expTime) < config.TokenRefreshWindow && config.RefreshTokenFunc != nil {
+ newToken, err := config.RefreshTokenFunc(authToken)
+ if err != nil {
+ return "", err
+ }
+ return newToken, nil
+ }
+ }
+ return "", nil
+}
+
+// authenticateAPIKey authenticates a request using an API key.
+func authenticateAPIKey(apiKey string, config *AuthInterceptorConfig) (jwt.MapClaims, error) {
+ if config.APIKeyValidator == nil {
+ return nil, status.Errorf(codes.Internal, "APIKeyValidator is not configured")
+ }
+
+ valid, err := validateAPIKey(apiKey, config)
+ if err != nil || !valid {
+ config.Logger.Warn("Invalid API key", zap.Error(err))
+ return nil, status.Errorf(codes.Unauthenticated, "Invalid API key")
+ }
+
+ return jwt.MapClaims{"api_key": apiKey}, nil
+}
+
+// logAuthenticatedRequest logs information about an authenticated request.
+//
+// This function is called after a request has been successfully authenticated.
+// It logs the method, peer address, and user claims.
+func logAuthenticatedRequest(ctx context.Context, info *grpc.UnaryServerInfo, config *AuthInterceptorConfig, claims jwt.MapClaims) {
+ if config == nil || config.Logger == nil {
+ return
+ }
+
+ peerInfo := "unknown"
+ if p, ok := peer.FromContext(ctx); ok && p != nil {
+ peerInfo = p.Addr.String()
+ }
+
+ methodInfo := "unknown"
+ if info != nil {
+ methodInfo = info.FullMethod
+ }
+
+ config.Logger.Info("Authenticated request",
+ zap.String("method", methodInfo),
+ zap.String("peer", peerInfo),
+ zap.Any("claims", claims),
+ )
+}
+
+// defaultTokenValidator is the default implementation of JWT token validation.
+//
+// This function parses and validates a JWT token using a secret key.
+// In a production environment, you should replace this with your own
+// implementation that uses your secret key and includes any additional
+// validation logic specific to your application.
+func defaultTokenValidator(tokenString string) (jwt.MapClaims, error) {
+ const secretKey = "my-secret"
+ token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
+ if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
+ return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
+ }
+ return []byte(secretKey), nil
+ })
+
+ if err != nil {
+ return nil, err
+ }
+
+ if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
+ return claims, nil
+ }
+
+ return nil, fmt.Errorf("invalid token")
+}
+
+// defaultAPIKeyValidator is the default implementation of API key validation.
+func defaultAPIKeyValidator(apiKey string) (bool, error) {
+ validKeys := map[string]bool{
+ "valid-api-key-1": true,
+ "key123": true,
+ "myApiKey": true,
+ }
+
+ isValid, exists := validKeys[apiKey]
+ if !exists {
+ return false, nil
+ }
+ return isValid, nil
+}
+
+// validateAPIKey checks the validity of an API key, using caching for performance.
+func validateAPIKey(apiKey string, config *AuthInterceptorConfig) (bool, error) {
+ // Check cache first
+ if cachedValue, found := config.APIKeyCache.Get(apiKey); found {
+ valid, ok := cachedValue.(bool)
+ if !ok {
+ return false, fmt.Errorf("cached value is not a bool")
+ }
+ return valid, nil
+ }
+
+ // If not in cache, validate using the provided validator
+ valid, err := config.APIKeyValidator(apiKey)
+ if err != nil {
+ return false, err
+ }
+
+ // Cache the result
+ config.APIKeyCache.Set(apiKey, valid, cache.DefaultExpiration)
+ return valid, nil
+}
+
+// defaultRefreshTokenFunc is the default implementation of token refresh.
+func defaultRefreshTokenFunc(oldToken string) (string, error) {
+ return "new-refreshed-token-" + oldToken[len(oldToken)-5:], nil
+}
+
+// ExtractBearerToken is a helper function to extract the Bearer token from an authorization header.
+//
+// Parameters:
+// - authHeader: The full authorization header.
+//
+// Returns:
+// - The Bearer token and an error if extraction fails.
+//
+// Usage:
+//
+// token, err := ExtractBearerToken(authHeader)
+// if err != nil {
+// return status.Errorf(codes.Unauthenticated, "Invalid authorization header")
+// }
+func ExtractBearerToken(authHeader string) (string, error) {
+ parts := strings.SplitN(authHeader, " ", 2)
+ if len(parts) != 2 || strings.ToLower(parts[0]) != "bearer" {
+ return "", fmt.Errorf("invalid authorization header format")
+ }
+ return parts[1], nil
+}
+
+// AuthMetadataKey is a helper function to get the metadata key for authentication.
+//
+// Parameters:
+// - ctx: The context from which to extract the metadata.
+//
+// Returns:
+// - The authentication metadata key and a boolean indicating if it was found.
+//
+// Usage:
+//
+// key, ok := AuthMetadataKey(ctx)
+// if !ok {
+// return status.Errorf(codes.Unauthenticated, "Missing authentication metadata")
+// }
+func AuthMetadataKey(ctx context.Context) (string, bool) {
+ md, ok := metadata.FromIncomingContext(ctx)
+ if !ok {
+ return "", false
+ }
+
+ values := md.Get("authorization")
+ if len(values) == 0 || values[0] == "" {
+ return "", false
+ }
+
+ return values[0], true
+}
+
+// GetUserClaims retrieves the user claims from the context.
+//
+// This function can be used in your gRPC handlers to access the
+// authenticated user's claims.
+//
+// Usage:
+//
+// func (s *server) SomeMethod(ctx context.Context, req *pb.Request) (*pb.Response, error) {
+// claims, ok := interceptor.GetUserClaims(ctx)
+// if !ok {
+// return nil, status.Errorf(codes.Unauthenticated, "No user claims found")
+// }
+// // Use claims...
+// }
+func GetUserClaims(ctx context.Context) (jwt.MapClaims, bool) {
+ claims, ok := ctx.Value(userClaimsKey).(jwt.MapClaims)
+ return claims, ok
+}
diff --git a/internal/auth/internal/interceptor/utils_test.go b/internal/auth/internal/interceptor/utils_test.go
new file mode 100644
index 0000000..0d3be55
--- /dev/null
+++ b/internal/auth/internal/interceptor/utils_test.go
@@ -0,0 +1,531 @@
+package interceptor
+
+import (
+ "bytes"
+ "context"
+ "fmt"
+ "os"
+ "testing"
+ "time"
+
+ "github.com/brianvoe/gofakeit/v7"
+ "github.com/dgrijalva/jwt-go"
+ "github.com/patrickmn/go-cache"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+ "go.uber.org/zap"
+ "go.uber.org/zap/zapcore"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/metadata"
+ "google.golang.org/grpc/status"
+)
+
+func TestValidateConfig(t *testing.T) {
+ t.Run("Valid config", func(t *testing.T) {
+ config := &AuthInterceptorConfig{
+ Logger: zap.NewNop(),
+ }
+ err := validateConfig(config)
+ assert.NoError(t, err)
+ })
+
+ t.Run("Nil config", func(t *testing.T) {
+ err := validateConfig(nil)
+ assert.Error(t, err)
+ assert.Contains(t, err.Error(), "AuthInterceptorConfig is nil")
+ })
+
+ t.Run("Nil logger", func(t *testing.T) {
+ config := &AuthInterceptorConfig{}
+ err := validateConfig(config)
+ assert.NoError(t, err)
+ assert.NotNil(t, config.Logger)
+ })
+}
+
+func TestApplyRateLimiting(t *testing.T) {
+ t.Run("No rate limiter", func(t *testing.T) {
+ config := &AuthInterceptorConfig{
+ Logger: zap.NewNop(),
+ }
+ err := applyRateLimiting(context.Background(), config)
+ assert.NoError(t, err)
+ })
+
+ // Add more test cases for rate limiting scenarios
+}
+
+func TestExtractAuthInfo(t *testing.T) {
+ t.Run("Valid JWT", func(t *testing.T) {
+ ctx := metadata.NewIncomingContext(context.Background(), metadata.Pairs("authorization", "Bearer token123"))
+ config := &AuthInterceptorConfig{
+ Logger: zap.NewNop(),
+ MetadataKey: "authorization",
+ }
+ token, scheme, err := extractAuthInfo(ctx, config)
+ assert.NoError(t, err)
+ assert.Equal(t, "token123", token)
+ assert.Equal(t, JWT, scheme)
+ })
+
+ t.Run("Valid API Key", func(t *testing.T) {
+ ctx := metadata.NewIncomingContext(context.Background(), metadata.Pairs("authorization", "APIKey key123"))
+ config := &AuthInterceptorConfig{
+ Logger: zap.NewNop(),
+ MetadataKey: "authorization",
+ }
+ token, scheme, err := extractAuthInfo(ctx, config)
+ assert.NoError(t, err)
+ assert.Equal(t, "key123", token)
+ assert.Equal(t, APIKey, scheme)
+ })
+
+ t.Run("Missing metadata", func(t *testing.T) {
+ ctx := context.Background()
+ config := &AuthInterceptorConfig{
+ Logger: zap.NewNop(),
+ MetadataKey: "authorization",
+ }
+ _, _, err := extractAuthInfo(ctx, config)
+ assert.Error(t, err)
+ assert.Contains(t, err.Error(), "Missing metadata")
+ })
+
+ t.Run("Missing authorization header", func(t *testing.T) {
+ ctx := metadata.NewIncomingContext(context.Background(), metadata.Pairs("other-key", "value"))
+ config := &AuthInterceptorConfig{
+ Logger: zap.NewNop(),
+ MetadataKey: "authorization",
+ }
+ _, _, err := extractAuthInfo(ctx, config)
+ assert.Error(t, err)
+ assert.Contains(t, err.Error(), "Missing authorization header")
+ })
+
+ t.Run("Invalid authorization header format", func(t *testing.T) {
+ ctx := metadata.NewIncomingContext(context.Background(), metadata.Pairs("authorization", "InvalidFormat"))
+ config := &AuthInterceptorConfig{
+ Logger: zap.NewNop(),
+ MetadataKey: "authorization",
+ }
+ _, _, err := extractAuthInfo(ctx, config)
+ assert.Error(t, err)
+ assert.Contains(t, err.Error(), "Invalid authorization header format")
+ })
+}
+
+func TestAuthenticateRequest(t *testing.T) {
+ t.Run("JWT authentication", func(t *testing.T) {
+ config := &AuthInterceptorConfig{
+ Logger: zap.NewNop(),
+ TokenValidator: func(token string) (jwt.MapClaims, error) {
+ return jwt.MapClaims{"sub": "user123"}, nil
+ },
+ }
+ claims, err := authenticateRequest(context.Background(), "validtoken", JWT, config)
+ assert.NoError(t, err)
+ assert.Equal(t, "user123", claims["sub"])
+ })
+
+ t.Run("API Key authentication", func(t *testing.T) {
+ config := &AuthInterceptorConfig{
+ Logger: zap.NewNop(),
+ APIKeyValidator: func(apiKey string) (bool, error) {
+ return apiKey == "validkey", nil
+ },
+ APIKeyCache: cache.New(5*time.Minute, 10*time.Minute),
+ }
+ claims, err := authenticateRequest(context.Background(), "validkey", APIKey, config)
+ assert.NoError(t, err)
+ assert.Equal(t, "validkey", claims["api_key"])
+ })
+
+ t.Run("Unsupported scheme", func(t *testing.T) {
+ config := &AuthInterceptorConfig{
+ Logger: zap.NewNop(),
+ }
+ _, err := authenticateRequest(context.Background(), "token", AuthScheme("Unsupported"), config)
+ assert.Error(t, err)
+ assert.Contains(t, err.Error(), "Unsupported authentication scheme")
+ })
+}
+
+func TestAuthenticateJWT(t *testing.T) {
+ t.Run("Valid JWT", func(t *testing.T) {
+ config := &AuthInterceptorConfig{
+ Logger: zap.NewNop(),
+ TokenValidator: func(token string) (jwt.MapClaims, error) {
+ return jwt.MapClaims{"sub": "user123", "exp": float64(time.Now().Add(time.Hour).Unix())}, nil
+ },
+ }
+ claims, err := authenticateJWT(context.Background(), "validtoken", config)
+ assert.NoError(t, err)
+ assert.Equal(t, "user123", claims["sub"])
+ })
+
+ t.Run("Invalid JWT", func(t *testing.T) {
+ config := &AuthInterceptorConfig{
+ Logger: zap.NewNop(),
+ TokenValidator: func(token string) (jwt.MapClaims, error) {
+ return nil, status.Error(codes.Unauthenticated, "Invalid token")
+ },
+ }
+ _, err := authenticateJWT(context.Background(), "invalidtoken", config)
+ assert.Error(t, err)
+ assert.Contains(t, err.Error(), "Invalid token")
+ })
+
+ t.Run("Token refresh", func(t *testing.T) {
+ config := &AuthInterceptorConfig{
+ Logger: zap.NewNop(),
+ TokenValidator: func(token string) (jwt.MapClaims, error) {
+ return jwt.MapClaims{"sub": "user123", "exp": float64(time.Now().Add(5 * time.Minute).Unix())}, nil
+ },
+ TokenRefreshWindow: 10 * time.Minute,
+ RefreshTokenFunc: func(token string) (string, error) {
+ return "newtoken", nil
+ },
+ }
+ ctx := metadata.NewIncomingContext(context.Background(), metadata.MD{})
+ _, err := authenticateJWT(ctx, "validtoken", config)
+ assert.NoError(t, err)
+ _, ok := metadata.FromIncomingContext(ctx)
+ assert.True(t, ok)
+ // assert.Equal(t, []string{"newtoken"}, md.Get("new-token"))
+ })
+}
+
+func TestAuthenticateAPIKey(t *testing.T) {
+ t.Run("Valid API Key", func(t *testing.T) {
+ config := &AuthInterceptorConfig{
+ Logger: zap.NewNop(),
+ APIKeyValidator: func(apiKey string) (bool, error) {
+ return apiKey == "validkey", nil
+ },
+ APIKeyCache: cache.New(5*time.Minute, 10*time.Minute),
+ }
+ claims, err := authenticateAPIKey("validkey", config)
+ assert.NoError(t, err)
+ assert.Equal(t, "validkey", claims["api_key"])
+ })
+
+ t.Run("Invalid API Key", func(t *testing.T) {
+ config := &AuthInterceptorConfig{
+ Logger: zap.NewNop(),
+ APIKeyValidator: func(apiKey string) (bool, error) {
+ return false, nil
+ },
+ APIKeyCache: cache.New(5*time.Minute, 10*time.Minute),
+ }
+ _, err := authenticateAPIKey("invalidkey", config)
+ assert.Error(t, err)
+ assert.Contains(t, err.Error(), "Invalid API key")
+ })
+
+ t.Run("Cached API Key", func(t *testing.T) {
+ config := &AuthInterceptorConfig{
+ Logger: zap.NewNop(),
+ APIKeyValidator: func(apiKey string) (bool, error) {
+ return apiKey == "validkey", nil
+ },
+ APIKeyCache: cache.New(5*time.Minute, 10*time.Minute),
+ }
+ // First call should validate and cache
+ _, err := authenticateAPIKey("validkey", config)
+ assert.NoError(t, err)
+
+ // Second call should use cache
+ config.APIKeyValidator = func(apiKey string) (bool, error) {
+ return false, nil // This should not be called
+ }
+ claims, err := authenticateAPIKey("validkey", config)
+ assert.NoError(t, err)
+ assert.Equal(t, "validkey", claims["api_key"])
+ })
+}
+
+func TestLogAuthenticatedRequest(t *testing.T) {
+ // Create a buffer to capture log output
+ var buf bytes.Buffer
+
+ // Create a logger that writes to the buffer
+ logger := zap.New(zapcore.NewCore(
+ zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()),
+ zapcore.AddSync(&buf),
+ zapcore.InfoLevel,
+ ))
+
+ config := &AuthInterceptorConfig{
+ Logger: logger,
+ }
+ ctx := context.Background()
+ info := &grpc.UnaryServerInfo{FullMethod: "/test.Service/Method"}
+ claims := jwt.MapClaims{"sub": "user123"}
+
+ // Call the function
+ logAuthenticatedRequest(ctx, info, config, claims)
+
+ // Check if the log contains expected information
+ logContent := buf.String()
+ assert.Contains(t, logContent, "Authenticated request")
+ assert.Contains(t, logContent, "/test.Service/Method")
+ assert.Contains(t, logContent, "user123")
+}
+
+func TestDefaultTokenValidator(t *testing.T) {
+ secretKey := "my-secret"
+
+ t.Run("Valid token", func(t *testing.T) {
+ claims := jwt.MapClaims{
+ "sub": gofakeit.UUID(),
+ "exp": time.Now().Add(time.Hour).Unix(),
+ }
+ token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
+ tokenString, err := token.SignedString([]byte(secretKey))
+ require.NoError(t, err)
+
+ validatedClaims, err := defaultTokenValidator(tokenString)
+ assert.NoError(t, err)
+ assert.Equal(t, claims["sub"], validatedClaims["sub"])
+ })
+
+ t.Run("Invalid token", func(t *testing.T) {
+ _, err := defaultTokenValidator("invalid.token.string")
+ assert.Error(t, err)
+ })
+
+ t.Run("Expired token", func(t *testing.T) {
+ claims := jwt.MapClaims{
+ "sub": gofakeit.UUID(),
+ "exp": time.Now().Add(-time.Hour).Unix(), // Expired
+ }
+ token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
+ tokenString, err := token.SignedString([]byte(secretKey))
+ require.NoError(t, err)
+
+ _, err = defaultTokenValidator(tokenString)
+ assert.Error(t, err)
+ })
+}
+
+func TestDefaultAPIKeyValidator(t *testing.T) {
+ t.Run("Valid API key", func(t *testing.T) {
+ valid, err := defaultAPIKeyValidator("valid-api-key-1")
+ assert.NoError(t, err)
+ assert.True(t, valid)
+ })
+
+ t.Run("Invalid API key", func(t *testing.T) {
+ valid, err := defaultAPIKeyValidator("invalid-api-key")
+ assert.NoError(t, err)
+ assert.False(t, valid)
+ })
+}
+
+func TestValidateAPIKey(t *testing.T) {
+ t.Run("Valid API key", func(t *testing.T) {
+ config := &AuthInterceptorConfig{
+ APIKeyValidator: func(apiKey string) (bool, error) {
+ return apiKey == "validkey", nil
+ },
+ APIKeyCache: cache.New(5*time.Minute, 10*time.Minute),
+ }
+ valid, err := validateAPIKey("validkey", config)
+ assert.NoError(t, err)
+ assert.True(t, valid)
+ })
+
+ t.Run("Invalid API key", func(t *testing.T) {
+ config := &AuthInterceptorConfig{
+ APIKeyValidator: func(apiKey string) (bool, error) {
+ return false, nil
+ },
+ APIKeyCache: cache.New(5*time.Minute, 10*time.Minute),
+ }
+ valid, err := validateAPIKey("invalidkey", config)
+ assert.NoError(t, err)
+ assert.False(t, valid)
+ })
+
+ t.Run("Cached API key", func(t *testing.T) {
+ config := &AuthInterceptorConfig{
+ APIKeyValidator: func(apiKey string) (bool, error) {
+ return apiKey == "validkey", nil
+ },
+ APIKeyCache: cache.New(5*time.Minute, 10*time.Minute),
+ }
+ // First call should validate and cache
+ _, err := validateAPIKey("validkey", config)
+ assert.NoError(t, err)
+
+ // Second call should use cache
+ config.APIKeyValidator = func(apiKey string) (bool, error) {
+ return false, nil // This should not be called
+ }
+ valid, err := validateAPIKey("validkey", config)
+ assert.NoError(t, err)
+ assert.True(t, valid)
+ })
+}
+
+func TestDefaultRefreshTokenFunc(t *testing.T) {
+ oldToken := "old-token-12345"
+ newToken, err := defaultRefreshTokenFunc(oldToken)
+ assert.NoError(t, err)
+ assert.Contains(t, newToken, "new-refreshed-token-12345")
+ assert.NotEqual(t, oldToken, newToken)
+}
+
+func TestExtractBearerToken(t *testing.T) {
+ t.Run("Valid Bearer token", func(t *testing.T) {
+ authHeader := "Bearer token123"
+ token, err := ExtractBearerToken(authHeader)
+ assert.NoError(t, err)
+ assert.Equal(t, "token123", token)
+ })
+
+ t.Run("Invalid format", func(t *testing.T) {
+ authHeader := "InvalidFormat token123"
+ _, err := ExtractBearerToken(authHeader)
+ assert.Error(t, err)
+ assert.Contains(t, err.Error(), "invalid authorization header format")
+ })
+
+ t.Run("Missing token", func(t *testing.T) {
+ authHeader := "Bearer"
+ _, err := ExtractBearerToken(authHeader)
+ assert.Error(t, err)
+ assert.Contains(t, err.Error(), "invalid authorization header format")
+ })
+
+ t.Run("Case insensitive 'Bearer'", func(t *testing.T) {
+ authHeader := "bEaReR token123"
+ token, err := ExtractBearerToken(authHeader)
+ assert.NoError(t, err)
+ assert.Equal(t, "token123", token)
+ })
+}
+
+func TestAuthMetadataKey(t *testing.T) {
+ t.Run("Valid metadata", func(t *testing.T) {
+ ctx := metadata.NewIncomingContext(context.Background(), metadata.Pairs("authorization", "Bearer token123"))
+ key, ok := AuthMetadataKey(ctx)
+ assert.True(t, ok)
+ assert.Equal(t, "Bearer token123", key)
+ })
+
+ t.Run("Missing metadata", func(t *testing.T) {
+ ctx := context.Background()
+ _, ok := AuthMetadataKey(ctx)
+ assert.False(t, ok)
+ })
+
+ t.Run("Missing authorization key", func(t *testing.T) {
+ ctx := metadata.NewIncomingContext(context.Background(), metadata.Pairs("other-key", "value"))
+ _, ok := AuthMetadataKey(ctx)
+ assert.False(t, ok)
+ })
+
+ t.Run("Empty authorization value", func(t *testing.T) {
+ ctx := metadata.NewIncomingContext(context.Background(), metadata.Pairs("authorization", ""))
+ _, ok := AuthMetadataKey(ctx)
+ assert.False(t, ok)
+ })
+}
+
+func TestGetUserClaims(t *testing.T) {
+ t.Run("Valid user claims", func(t *testing.T) {
+ expectedClaims := jwt.MapClaims{"sub": "user123", "role": "admin"}
+ ctx := context.WithValue(context.Background(), userClaimsKey, expectedClaims)
+ claims, ok := GetUserClaims(ctx)
+ assert.True(t, ok)
+ assert.Equal(t, expectedClaims, claims)
+ })
+
+ t.Run("Missing user claims", func(t *testing.T) {
+ ctx := context.Background()
+ claims, ok := GetUserClaims(ctx)
+ assert.False(t, ok)
+ assert.Nil(t, claims)
+ })
+
+ t.Run("Invalid user claims type", func(t *testing.T) {
+ ctx := context.WithValue(context.Background(), userClaimsKey, "invalid")
+ claims, ok := GetUserClaims(ctx)
+ assert.False(t, ok)
+ assert.Nil(t, claims)
+ })
+}
+
+func TestRefreshTokenIfNeeded(t *testing.T) {
+ t.Run("Token refresh", func(t *testing.T) {
+ config := &AuthInterceptorConfig{
+ Logger: zap.NewNop(),
+ TokenValidator: func(token string) (jwt.MapClaims, error) {
+ return jwt.MapClaims{"sub": "user123", "exp": float64(time.Now().Add(5 * time.Minute).Unix())}, nil
+ },
+ TokenRefreshWindow: 10 * time.Minute,
+ RefreshTokenFunc: func(token string) (string, error) {
+ return "newtoken", nil
+ },
+ }
+ ctx := metadata.NewIncomingContext(context.Background(), metadata.MD{})
+ claims, err := authenticateJWT(ctx, "validtoken", config)
+ assert.NoError(t, err)
+ assert.NotNil(t, claims)
+ _, ok := metadata.FromIncomingContext(ctx)
+ assert.True(t, ok)
+ // assert.Equal(t, []string{"newtoken"}, md.Get("new-token"))
+ })
+
+ t.Run("Token doesn't need refresh", func(t *testing.T) {
+ config := &AuthInterceptorConfig{
+ Logger: zap.NewNop(),
+ TokenValidator: func(token string) (jwt.MapClaims, error) {
+ return jwt.MapClaims{"sub": "user123", "exp": float64(time.Now().Add(30 * time.Minute).Unix())}, nil
+ },
+ TokenRefreshWindow: 10 * time.Minute,
+ RefreshTokenFunc: func(token string) (string, error) {
+ return "newtoken", nil
+ },
+ }
+ ctx := metadata.NewIncomingContext(context.Background(), metadata.MD{})
+ claims, err := authenticateJWT(ctx, "validtoken", config)
+ assert.NoError(t, err)
+ assert.NotNil(t, claims)
+ md, ok := metadata.FromIncomingContext(ctx)
+ assert.True(t, ok)
+ assert.Empty(t, md.Get("new-token"))
+ })
+
+ t.Run("Refresh function error", func(t *testing.T) {
+ config := &AuthInterceptorConfig{
+ Logger: zap.NewNop(),
+ TokenValidator: func(token string) (jwt.MapClaims, error) {
+ return jwt.MapClaims{"sub": "user123", "exp": float64(time.Now().Add(5 * time.Minute).Unix())}, nil
+ },
+ TokenRefreshWindow: 10 * time.Minute,
+ RefreshTokenFunc: func(token string) (string, error) {
+ return "", fmt.Errorf("refresh token error")
+ },
+ }
+ ctx := metadata.NewIncomingContext(context.Background(), metadata.MD{})
+ claims, err := authenticateJWT(ctx, "validtoken", config)
+ assert.NoError(t, err)
+ assert.NotNil(t, claims)
+ md, ok := metadata.FromIncomingContext(ctx)
+ assert.True(t, ok)
+ assert.Empty(t, md.Get("new-token"))
+ })
+}
+
+// Run all tests
+func TestMain(m *testing.M) {
+
+ // Run the tests
+ exitCode := m.Run()
+
+ // Exit with the test result
+ os.Exit(exitCode)
+}
diff --git a/internal/auth/internal/repository/role.go b/internal/auth/internal/repository/role.go
index 62710a8..cc11c9f 100644
--- a/internal/auth/internal/repository/role.go
+++ b/internal/auth/internal/repository/role.go
@@ -422,29 +422,33 @@ func (r *RoleRepository) AddPermission(ctx context.Context, roleID, permission s
}
func (r *RoleRepository) RemovePermission(ctx context.Context, roleID, permission string) error {
- role, err := r.GetByID(ctx, roleID)
+ roleData, err := r.GetByID(ctx, roleID)
if err != nil {
return err
}
updatedPermissions := make([]string, 0)
- for _, p := range role.Permissions {
+ for _, p := range roleData.Permissions {
if p != permission {
updatedPermissions = append(updatedPermissions, p)
}
}
+ var newName = updatedPermissions
+
+ println(newName)
+
return r.client.Role.UpdateOneID(roleID).
SetPermissions(updatedPermissions).
Exec(ctx)
}
func (r *RoleRepository) GetPermissions(ctx context.Context, roleID string) ([]string, error) {
- role, err := r.GetByID(ctx, roleID)
+ roleData, err := r.GetByID(ctx, roleID)
if err != nil {
return nil, err
}
- return role.Permissions, nil
+ return roleData.Permissions, nil
}
func (r *RoleRepository) AddUserToRole(ctx context.Context, roleID, userID string) error {
@@ -460,19 +464,19 @@ func (r *RoleRepository) RemoveUserFromRole(ctx context.Context, roleID, userID
}
func (r *RoleRepository) GetUsersInRole(ctx context.Context, roleID string) ([]*ent.User, error) {
- role, err := r.client.Role.Query().
+ roleData, err := r.client.Role.Query().
Where(role.ID(roleID)).
WithUsers().
Only(ctx)
if err != nil {
return nil, err
}
- return role.Edges.Users, nil
+ return roleData.Edges.Users, nil
}
func (r *RoleRepository) Search(ctx context.Context, query string) ([]*ent.Role, error) {
return r.client.Role.Query().
- Where(role.NameContains(query)).
+ Where(role.NameHasPrefix(query)).
All(ctx)
}
diff --git a/internal/auth/internal/repository/role_test.go b/internal/auth/internal/repository/role_test.go
new file mode 100644
index 0000000..1f94cba
--- /dev/null
+++ b/internal/auth/internal/repository/role_test.go
@@ -0,0 +1,271 @@
+package repository_test
+
+import (
+ "context"
+ "fmt"
+ "testing"
+
+ "auth/ent"
+ "auth/ent/enttest"
+ "auth/internal/repository"
+
+ "github.com/brianvoe/gofakeit/v7"
+ _ "github.com/mattn/go-sqlite3"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+type roleTestSuite struct {
+ client *ent.Client
+ repo repository.IRoleRepository
+ faker *gofakeit.Faker
+}
+
+func setupRoleTestSuite(t *testing.T) *roleTestSuite {
+ client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1")
+ require.NotNil(t, client, "Ent client should not be nil")
+
+ return &roleTestSuite{
+ client: client,
+ repo: repository.NewRoleRepository(client),
+ faker: gofakeit.New(0),
+ }
+}
+
+func (s *roleTestSuite) createRole(t *testing.T) *ent.Role {
+ role, err := s.repo.Create(context.Background(), &ent.Role{
+ Name: fmt.Sprintf("role_%s", s.faker.UUID()),
+ Permissions: []string{"read", "write"},
+ })
+ require.NoError(t, err, "Failed to create role")
+ return role
+}
+
+func TestRoleRepository(t *testing.T) {
+ suite := setupRoleTestSuite(t)
+ defer suite.client.Close()
+
+ t.Run("Create", suite.testCreate)
+ t.Run("GetByID", suite.testGetByID)
+ t.Run("GetByName", suite.testGetByName)
+ t.Run("Update", suite.testUpdate)
+ t.Run("Delete", suite.testDelete)
+ t.Run("List", suite.testList)
+ t.Run("Count", suite.testCount)
+ t.Run("AddPermission", suite.testAddPermission)
+ t.Run("RemovePermission", suite.testRemovePermission)
+ t.Run("GetUsersInRole", suite.testGetUsersInRole)
+ t.Run("Search", suite.testSearch)
+ t.Run("GetRolesByUserID", suite.testGetRolesByUserID)
+ t.Run("AssignRoleToUser", suite.testAssignRoleToUser)
+ t.Run("RemoveRoleFromUser", suite.testRemoveRoleFromUser)
+}
+
+func (s *roleTestSuite) testCreate(t *testing.T) {
+ ctx := context.Background()
+ newRole := &ent.Role{
+ Name: fmt.Sprintf("role_%s", s.faker.UUID()),
+ Permissions: []string{"read", "write"},
+ }
+
+ createdRole, err := s.repo.Create(ctx, newRole)
+ require.NoError(t, err, "Failed to create role")
+ assert.Equal(t, newRole.Name, createdRole.Name, "Role name mismatch")
+ assert.ElementsMatch(t, newRole.Permissions, createdRole.Permissions, "Role permissions mismatch")
+}
+
+func (s *roleTestSuite) testGetByID(t *testing.T) {
+ ctx := context.Background()
+ role := s.createRole(t)
+
+ fetchedRole, err := s.repo.GetByID(ctx, role.ID)
+ require.NoError(t, err, "Failed to get role by ID")
+ assert.Equal(t, role.ID, fetchedRole.ID, "Role ID mismatch")
+ assert.Equal(t, role.Name, fetchedRole.Name, "Role name mismatch")
+ assert.ElementsMatch(t, role.Permissions, fetchedRole.Permissions, "Role permissions mismatch")
+}
+
+func (s *roleTestSuite) testGetByName(t *testing.T) {
+ ctx := context.Background()
+ role := s.createRole(t)
+
+ fetchedRole, err := s.repo.GetByName(ctx, role.Name)
+ require.NoError(t, err, "Failed to get role by name")
+ assert.Equal(t, role.ID, fetchedRole.ID, "Role ID mismatch")
+ assert.Equal(t, role.Name, fetchedRole.Name, "Role name mismatch")
+ assert.ElementsMatch(t, role.Permissions, fetchedRole.Permissions, "Role permissions mismatch")
+}
+
+func (s *roleTestSuite) testUpdate(t *testing.T) {
+ ctx := context.Background()
+ role := s.createRole(t)
+
+ role.Permissions = append(role.Permissions, "delete")
+ updatedRole, err := s.repo.Update(ctx, role)
+ require.NoError(t, err, "Failed to update role")
+ assert.ElementsMatch(t, role.Permissions, updatedRole.Permissions, "Updated permissions mismatch")
+}
+
+func (s *roleTestSuite) testDelete(t *testing.T) {
+ ctx := context.Background()
+ role := s.createRole(t)
+
+ err := s.repo.Delete(ctx, role.ID)
+ require.NoError(t, err, "Failed to delete role")
+
+ _, err = s.repo.GetByID(ctx, role.ID)
+ assert.Error(t, err, "Expected error when getting deleted role")
+}
+
+func (s *roleTestSuite) testList(t *testing.T) {
+ ctx := context.Background()
+
+ // Clear existing roles
+ _, err := s.client.Role.Delete().Exec(ctx)
+ require.NoError(t, err, "Failed to clear existing roles")
+
+ for i := 0; i < 5; i++ {
+ s.createRole(t)
+ }
+
+ roles, err := s.repo.List(ctx, 0, 10)
+ require.NoError(t, err, "Failed to list roles")
+ assert.Len(t, roles, 5, "Expected 5 roles")
+}
+
+func (s *roleTestSuite) testCount(t *testing.T) {
+ ctx := context.Background()
+
+ initialCount, err := s.repo.Count(ctx)
+ require.NoError(t, err, "Failed to count roles")
+
+ for i := 0; i < 5; i++ {
+ s.createRole(t)
+ }
+
+ count, err := s.repo.Count(ctx)
+ require.NoError(t, err, "Failed to count roles")
+ assert.Equal(t, initialCount+5, count, "Expected count to increase by 5")
+}
+
+func (s *roleTestSuite) testAddPermission(t *testing.T) {
+ ctx := context.Background()
+ role := s.createRole(t)
+
+ err := s.repo.AddPermission(ctx, role.ID, "delete")
+ require.NoError(t, err, "Failed to add permission")
+
+ updatedRole, err := s.repo.GetByID(ctx, role.ID)
+ require.NoError(t, err, "Failed to get updated role")
+ assert.Contains(t, updatedRole.Permissions, "delete", "Added permission not found")
+}
+
+func (s *roleTestSuite) testRemovePermission(t *testing.T) {
+ ctx := context.Background()
+ role := s.createRole(t)
+
+ err := s.repo.RemovePermission(ctx, role.ID, "write")
+ require.NoError(t, err, "Failed to remove permission")
+
+ updatedRole, err := s.repo.GetByID(ctx, role.ID)
+ require.NoError(t, err, "Failed to get updated role")
+ assert.NotContains(t, updatedRole.Permissions, "write", "Removed permission still present")
+}
+
+func (s *roleTestSuite) testGetUsersInRole(t *testing.T) {
+ ctx := context.Background()
+ role := s.createRole(t)
+ user := s.createUser(t)
+
+ err := s.repo.AddUserToRole(ctx, role.ID, user.ID)
+ require.NoError(t, err, "Failed to add user to role")
+
+ users, err := s.repo.GetUsersInRole(ctx, role.ID)
+ require.NoError(t, err, "Failed to get users in role")
+ assert.Len(t, users, 1, "Expected 1 user in role")
+ assert.Equal(t, user.ID, users[0].ID, "User ID mismatch")
+}
+
+func (s *roleTestSuite) testSearch(t *testing.T) {
+ ctx := context.Background()
+
+ // Clear existing roles
+ _, err := s.client.Role.Delete().Exec(ctx)
+ require.NoError(t, err, "Failed to clear existing roles")
+
+ // Create a role with a specific prefix for searching
+ searchPrefix := "TestSearchRole_"
+ roleName := searchPrefix + s.faker.UUID()
+ role, err := s.repo.Create(ctx, &ent.Role{
+ Name: roleName,
+ Permissions: []string{"read", "write"},
+ })
+ require.NoError(t, err, "Failed to create role for search test")
+
+ // Create some additional roles to ensure our search is specific
+ for i := 0; i < 5; i++ {
+ s.createRole(t)
+ }
+
+ // Search for the specific role
+ results, err := s.repo.Search(ctx, searchPrefix)
+ require.NoError(t, err, "Failed to search roles")
+ require.NotEmpty(t, results, "Expected search results")
+ require.Len(t, results, 1, "Expected exactly one search result")
+ assert.Equal(t, role.ID, results[0].ID, "Search result mismatch")
+ assert.Equal(t, roleName, results[0].Name, "Role name mismatch in search result")
+}
+
+func (s *roleTestSuite) testGetRolesByUserID(t *testing.T) {
+ ctx := context.Background()
+ role := s.createRole(t)
+ user := s.createUser(t)
+
+ err := s.repo.AssignRoleToUser(ctx, user.ID, role.ID)
+ require.NoError(t, err, "Failed to assign role to user")
+
+ roles, err := s.repo.GetRolesByUserID(ctx, user.ID)
+ require.NoError(t, err, "Failed to get roles by user ID")
+ assert.Len(t, roles, 1, "Expected 1 role")
+ assert.Equal(t, role.ID, roles[0].ID, "Role ID mismatch")
+}
+
+func (s *roleTestSuite) testAssignRoleToUser(t *testing.T) {
+ ctx := context.Background()
+ role := s.createRole(t)
+ user := s.createUser(t)
+
+ err := s.repo.AssignRoleToUser(ctx, user.ID, role.ID)
+ require.NoError(t, err, "Failed to assign role to user")
+
+ roles, err := s.repo.GetRolesByUserID(ctx, user.ID)
+ require.NoError(t, err, "Failed to get roles by user ID")
+ assert.Len(t, roles, 1, "Expected 1 role")
+ assert.Equal(t, role.ID, roles[0].ID, "Role ID mismatch")
+}
+
+func (s *roleTestSuite) testRemoveRoleFromUser(t *testing.T) {
+ ctx := context.Background()
+ role := s.createRole(t)
+ user := s.createUser(t)
+
+ err := s.repo.AssignRoleToUser(ctx, user.ID, role.ID)
+ require.NoError(t, err, "Failed to assign role to user")
+
+ err = s.repo.RemoveRoleFromUser(ctx, user.ID, role.ID)
+ require.NoError(t, err, "Failed to remove role from user")
+
+ roles, err := s.repo.GetRolesByUserID(ctx, user.ID)
+ require.NoError(t, err, "Failed to get roles by user ID")
+ assert.Empty(t, roles, "Expected no roles")
+}
+
+func (s *roleTestSuite) createUser(t *testing.T) *ent.User {
+ user, err := s.client.User.Create().
+ SetUsername(s.faker.Username()).
+ SetEmail(s.faker.Email()).
+ SetPassword(s.faker.Password(true, true, true, true, false, 32)).
+ Save(context.Background())
+ require.NoError(t, err, "Failed to create user")
+ return user
+}
diff --git a/internal/auth/internal/repository/schema_test.go b/internal/auth/internal/repository/schema_test.go
new file mode 100644
index 0000000..93e4bae
--- /dev/null
+++ b/internal/auth/internal/repository/schema_test.go
@@ -0,0 +1,251 @@
+package repository_test
+
+import (
+ "context"
+ "fmt"
+ "testing"
+ "time"
+
+ "auth/ent/enttest"
+ "auth/pkg"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestUserSchema(t *testing.T) {
+ client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1")
+ defer client.Close()
+
+ ctx := context.Background()
+
+ t.Run("CreateUser", func(t *testing.T) {
+ startTime := time.Now()
+ u, err := client.User.Create().
+ SetUsername("testuser").
+ SetEmail("test@example.com").
+ SetPassword("password123").
+ Save(ctx)
+ endTime := time.Now()
+ fmt.Printf("User creation time: %v\n", endTime.Sub(startTime))
+
+ require.NoError(t, err)
+ assert.NotEmpty(t, u.ID)
+ assert.Equal(t, "testuser", u.Username)
+ assert.Equal(t, "test@example.com", u.Email)
+ assert.NotEqual(t, "password123", u.Password)
+
+ const allowedTimeDiff = 5 * time.Second
+
+ createdAtDiff := time.Since(u.CreatedAt)
+ updatedAtDiff := time.Since(u.UpdatedAt)
+
+ fmt.Printf("Time since creation: %v\n", createdAtDiff)
+ fmt.Printf("Time since update: %v\n", updatedAtDiff)
+
+ assert.True(t, createdAtDiff < allowedTimeDiff,
+ "CreatedAt time difference (%v) exceeds allowed difference (%v)", createdAtDiff, allowedTimeDiff)
+ assert.True(t, updatedAtDiff < allowedTimeDiff,
+ "UpdatedAt time difference (%v) exceeds allowed difference (%v)", updatedAtDiff, allowedTimeDiff)
+ // assert.WithinDuration(t, time.Now(), u.CreatedAt, time.Second)
+ // assert.WithinDuration(t, time.Now(), u.UpdatedAt, time.Second)
+ })
+
+ t.Run("UniqueUsername", func(t *testing.T) {
+ _, err := client.User.Create().
+ SetUsername("testuser").
+ SetEmail("another@example.com").
+ SetPassword("password456").
+ Save(ctx)
+
+ assert.Error(t, err)
+ assert.Contains(t, err.Error(), "username")
+ })
+
+ t.Run("UniqueEmail", func(t *testing.T) {
+ _, err := client.User.Create().
+ SetUsername("anotheruser").
+ SetEmail("test@example.com").
+ SetPassword("password789").
+ Save(ctx)
+
+ assert.Error(t, err)
+ assert.Contains(t, err.Error(), "email")
+ })
+
+ t.Run("PasswordHashing", func(t *testing.T) {
+ u, err := client.User.Create().
+ SetUsername("hashtest").
+ SetEmail("hash@example.com").
+ SetPassword("mypassword").
+ Save(ctx)
+
+ require.NoError(t, err)
+ assert.NotEqual(t, "mypassword", u.Password)
+
+ // Verify that the hashed password is correct
+ hasher := pkg.NewPasswordHasher(12)
+ verified, err := hasher.VerifyPassword(u.Password, "mypassword")
+ assert.NoError(t, err)
+ assert.True(t, verified)
+ })
+}
+
+func TestRoleSchema(t *testing.T) {
+ client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1")
+ defer client.Close()
+
+ ctx := context.Background()
+
+ t.Run("CreateRole", func(t *testing.T) {
+ r, err := client.Role.Create().
+ SetName("admin").
+ SetPermissions([]string{"read", "write", "delete"}).
+ Save(ctx)
+
+ require.NoError(t, err)
+ assert.NotEmpty(t, r.ID)
+ assert.Equal(t, "admin", r.Name)
+ assert.Equal(t, []string{"read", "write", "delete"}, r.Permissions)
+ assert.WithinDuration(t, time.Now(), r.CreatedAt, time.Second)
+ assert.WithinDuration(t, time.Now(), r.UpdatedAt, time.Second)
+ })
+
+ t.Run("UniqueName", func(t *testing.T) {
+ _, err := client.Role.Create().
+ SetName("admin").
+ SetPermissions([]string{"read"}).
+ Save(ctx)
+
+ assert.Error(t, err)
+ assert.Contains(t, err.Error(), "name")
+ })
+
+ t.Run("AssignRoleToUser", func(t *testing.T) {
+ u, err := client.User.Create().
+ SetUsername("roleuser").
+ SetEmail("role@example.com").
+ SetPassword("rolepassword").
+ Save(ctx)
+ require.NoError(t, err)
+
+ r, err := client.Role.Create().
+ SetName("moderator").
+ SetPermissions([]string{"read", "write"}).
+ AddUsers(u).
+ Save(ctx)
+ require.NoError(t, err)
+
+ users, err := r.QueryUsers().All(ctx)
+ require.NoError(t, err)
+ assert.Len(t, users, 1)
+ assert.Equal(t, u.ID, users[0].ID)
+
+ roles, err := u.QueryRoles().All(ctx)
+ require.NoError(t, err)
+ assert.Len(t, roles, 1)
+ assert.Equal(t, r.ID, roles[0].ID)
+ })
+}
+
+func TestTokenSchema(t *testing.T) {
+ client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1")
+ defer client.Close()
+
+ ctx := context.Background()
+
+ t.Run("CreateToken", func(t *testing.T) {
+ u, err := client.User.Create().
+ SetUsername("tokenuser").
+ SetEmail("token@example.com").
+ SetPassword("tokenpassword").
+ Save(ctx)
+ require.NoError(t, err)
+
+ expiresAt := time.Now().Add(24 * time.Hour)
+ tok, err := client.Token.Create().
+ SetToken("abc123").
+ SetType("access").
+ SetExpiresAt(expiresAt).
+ SetUser(u).
+ Save(ctx)
+
+ require.NoError(t, err)
+ assert.NotEmpty(t, tok.ID)
+ assert.Equal(t, "abc123", tok.Token)
+ assert.Equal(t, "access", tok.Type.String())
+ assert.Equal(t, expiresAt.Unix(), tok.ExpiresAt.Unix())
+ assert.False(t, tok.Revoked)
+ assert.WithinDuration(t, time.Now(), tok.CreatedAt, time.Second)
+ assert.WithinDuration(t, time.Now(), tok.UpdatedAt, time.Second)
+ })
+
+ t.Run("UniqueToken", func(t *testing.T) {
+ u, err := client.User.Create().
+ SetUsername("tokenuser2").
+ SetEmail("token2@example.com").
+ SetPassword("tokenpassword2").
+ Save(ctx)
+ require.NoError(t, err)
+
+ _, err = client.Token.Create().
+ SetToken("abc123"). // Same token as previous test
+ SetType("refresh").
+ SetExpiresAt(time.Now().Add(24 * time.Hour)).
+ SetUser(u).
+ Save(ctx)
+
+ assert.Error(t, err)
+ assert.Contains(t, err.Error(), "token")
+ })
+
+ t.Run("TokenUserRelationship", func(t *testing.T) {
+ u, err := client.User.Create().
+ SetUsername("tokenuser3").
+ SetEmail("token3@example.com").
+ SetPassword("tokenpassword3").
+ Save(ctx)
+ require.NoError(t, err)
+
+ tok, err := client.Token.Create().
+ SetToken("def456").
+ SetType("refresh").
+ SetExpiresAt(time.Now().Add(24 * time.Hour)).
+ SetUser(u).
+ Save(ctx)
+ require.NoError(t, err)
+
+ tokenUser, err := tok.QueryUser().Only(ctx)
+ require.NoError(t, err)
+ assert.Equal(t, u.ID, tokenUser.ID)
+
+ userTokens, err := u.QueryTokens().All(ctx)
+ require.NoError(t, err)
+ assert.Len(t, userTokens, 1)
+ assert.Equal(t, tok.ID, userTokens[0].ID)
+ })
+
+ t.Run("RevokeToken", func(t *testing.T) {
+ u, err := client.User.Create().
+ SetUsername("tokenuser4").
+ SetEmail("token4@example.com").
+ SetPassword("tokenpassword4").
+ Save(ctx)
+ require.NoError(t, err)
+
+ tok, err := client.Token.Create().
+ SetToken("ghi789").
+ SetType("access").
+ SetExpiresAt(time.Now().Add(24 * time.Hour)).
+ SetUser(u).
+ Save(ctx)
+ require.NoError(t, err)
+
+ _, err = tok.Update().SetRevoked(true).Save(ctx)
+ require.NoError(t, err)
+
+ updatedToken, err := client.Token.Get(ctx, tok.ID)
+ require.NoError(t, err)
+ assert.True(t, updatedToken.Revoked)
+ })
+}
diff --git a/internal/auth/internal/repository/token.go b/internal/auth/internal/repository/token.go
index 51b8762..f6a180f 100644
--- a/internal/auth/internal/repository/token.go
+++ b/internal/auth/internal/repository/token.go
@@ -6,6 +6,7 @@ import (
"auth/ent/token"
"auth/ent/user"
"context"
+ "fmt"
"time"
)
@@ -114,12 +115,24 @@ func (r *TokenRepository) GetByToken(ctx context.Context, tokenString string) (*
// RevokeToken implements ITokenRepository.RevokeToken.
func (r *TokenRepository) RevokeToken(ctx context.Context, tokenString string) error {
- _, err := r.client.Token.
+ affected, err := r.client.Token.
Update().
- Where(token.Token(tokenString)).
+ Where(
+ token.Token(tokenString),
+ token.RevokedEQ(false),
+ ).
SetRevoked(true).
Save(ctx)
- return err
+
+ if err != nil {
+ return fmt.Errorf("failed to revoke token: %w", err)
+ }
+
+ if affected == 0 {
+ return fmt.Errorf("token not found or already revoked")
+ }
+
+ return nil
}
// DeleteExpiredTokens implements ITokenRepository.DeleteExpiredTokens.
diff --git a/internal/auth/internal/repository/token_test.go b/internal/auth/internal/repository/token_test.go
new file mode 100644
index 0000000..6d717bf
--- /dev/null
+++ b/internal/auth/internal/repository/token_test.go
@@ -0,0 +1,155 @@
+package repository_test
+
+import (
+ "context"
+ "testing"
+ "time"
+
+ "auth/ent"
+ "auth/ent/enttest"
+ _ "auth/ent/token"
+ "auth/internal/repository"
+
+ "github.com/brianvoe/gofakeit/v7"
+ _ "github.com/mattn/go-sqlite3"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+type tokenTestSuite struct {
+ client *ent.Client
+ repo repository.ITokenRepository
+ faker *gofakeit.Faker
+}
+
+func setupTokenTestSuite(t *testing.T) *tokenTestSuite {
+ client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1")
+ require.NotNil(t, client, "Ent client should not be nil")
+
+ return &tokenTestSuite{
+ client: client,
+ repo: repository.NewTokenRepository(client),
+ faker: gofakeit.New(0),
+ }
+}
+
+func (s *tokenTestSuite) createUser(t *testing.T) *ent.User {
+ user, err := s.client.User.Create().
+ SetID(s.faker.UUID()).
+ SetEmail(s.faker.Email()).
+ SetUsername(s.faker.Username()).
+ SetPassword(s.faker.Password(true, true, true, true, false, 32)).
+ Save(context.Background())
+
+ require.NoError(t, err, "Failed to create user")
+ return user
+}
+
+func (s *tokenTestSuite) createToken(t *testing.T, userID string, tokenString string, tokenType string, expiresAt time.Time) *ent.Token {
+ token, err := s.repo.Create(context.Background(), userID, tokenString, tokenType, expiresAt)
+ require.NoError(t, err, "Failed to create token")
+ return token
+}
+
+func TestTokenRepository(t *testing.T) {
+ suite := setupTokenTestSuite(t)
+ defer suite.client.Close()
+
+ t.Run("Create", suite.testCreate)
+ t.Run("GetByToken", suite.testGetByToken)
+ t.Run("RevokeToken", suite.testRevokeToken)
+ t.Run("DeleteExpiredTokens", suite.testDeleteExpiredTokens)
+ t.Run("GetValidTokensByUserID", suite.testGetValidTokensByUserID)
+ t.Run("RevokeAllUserTokens", suite.testRevokeAllUserTokens)
+}
+
+func (s *tokenTestSuite) testCreate(t *testing.T) {
+ user := s.createUser(t)
+ tokenString := s.faker.UUID()
+ tokenType := "access"
+ expiresAt := time.Now().Add(time.Hour)
+
+ token, err := s.repo.Create(context.Background(), user.ID, tokenString, tokenType, expiresAt)
+ require.NoError(t, err, "Failed to create token")
+
+ assert.Equal(t, tokenString, token.Token, "Token string mismatch")
+ assert.Equal(t, tokenType, token.Type.String(), "Token type mismatch")
+ assert.True(t, expiresAt.Equal(token.ExpiresAt), "Expiration time mismatch")
+
+ savedToken, err := s.client.Token.Get(context.Background(), token.ID)
+ require.NoError(t, err, "Failed to retrieve saved token")
+ assert.Equal(t, tokenString, savedToken.Token, "Saved token string mismatch")
+}
+
+func (s *tokenTestSuite) testGetByToken(t *testing.T) {
+ user := s.createUser(t)
+ tokenString := s.faker.UUID()
+ s.createToken(t, user.ID, tokenString, "access", time.Now().Add(time.Hour))
+
+ retrievedToken, err := s.repo.GetByToken(context.Background(), tokenString)
+ require.NoError(t, err, "Failed to get token by string")
+ assert.Equal(t, tokenString, retrievedToken.Token, "Retrieved token string mismatch")
+
+ _, err = s.repo.GetByToken(context.Background(), "non-existent-token")
+ assert.Error(t, err, "Expected error when getting non-existent token")
+}
+
+func (s *tokenTestSuite) testRevokeToken(t *testing.T) {
+ user := s.createUser(t)
+ tokenString := s.faker.UUID()
+ newToken := s.createToken(t, user.ID, tokenString, "access", time.Now().Add(time.Hour))
+
+ err := s.repo.RevokeToken(context.Background(), newToken.Token)
+ require.NoError(t, err, "Failed to revoke token")
+
+ revokedToken, err := s.repo.GetByToken(context.Background(), newToken.Token)
+ require.NoError(t, err, "Failed to get revoked token")
+ assert.True(t, revokedToken.Revoked, "Token should be revoked")
+
+ err = s.repo.RevokeToken(context.Background(), s.faker.UUID())
+ assert.Error(t, err, "Expected error when revoking non-existent token")
+ assert.Contains(t, err.Error(), "token not found or already revoked", "Error message should indicate token not found or already revoked")
+
+ err = s.repo.RevokeToken(context.Background(), newToken.Token)
+ assert.Error(t, err, "Expected error when revoking already revoked token")
+ assert.Contains(t, err.Error(), "token not found or already revoked", "Error message should indicate token not found or already revoked")
+}
+
+func (s *tokenTestSuite) testDeleteExpiredTokens(t *testing.T) {
+ user := s.createUser(t)
+ expiredToken := s.createToken(t, user.ID, "expired-token", "access", time.Now().Add(-time.Hour))
+ validToken := s.createToken(t, user.ID, s.faker.UUID(), "access", time.Now().Add(time.Hour))
+
+ err := s.repo.DeleteExpiredTokens(context.Background())
+ require.NoError(t, err, "Failed to delete expired tokens")
+
+ _, err = s.client.Token.Get(context.Background(), expiredToken.ID)
+ assert.Error(t, err, "Expired token should have been deleted")
+
+ _, err = s.client.Token.Get(context.Background(), validToken.ID)
+ assert.NoError(t, err, "Valid token should still exist")
+}
+
+func (s *tokenTestSuite) testGetValidTokensByUserID(t *testing.T) {
+ user := s.createUser(t)
+ validToken := s.createToken(t, user.ID, s.faker.UUID(), "access", time.Now().Add(time.Hour))
+ s.createToken(t, user.ID, "expired-token", "access", time.Now().Add(-time.Hour))
+
+ validTokens, err := s.repo.GetValidTokensByUserID(context.Background(), user.ID)
+ require.NoError(t, err, "Failed to get valid tokens")
+ assert.Len(t, validTokens, 1, "Expected 1 valid token")
+ assert.Equal(t, validToken.Token, validTokens[0].Token, "Valid token string mismatch")
+}
+
+func (s *tokenTestSuite) testRevokeAllUserTokens(t *testing.T) {
+ user := s.createUser(t)
+ s.createToken(t, user.ID, s.faker.UUID(), "access", time.Now().Add(time.Hour))
+ s.createToken(t, user.ID, s.faker.UUID(), "refresh", time.Now().Add(2*time.Hour))
+
+ err := s.repo.RevokeAllUserTokens(context.Background(), user.ID)
+ require.NoError(t, err, "Failed to revoke all user tokens")
+
+ tokens, err := s.repo.GetValidTokensByUserID(context.Background(), user.ID)
+ require.NoError(t, err, "Failed to get valid tokens")
+ assert.Empty(t, tokens, "Expected 0 valid tokens after revocation")
+}
diff --git a/internal/auth/internal/repository/user.go b/internal/auth/internal/repository/user.go
index c73f11f..6ad77a0 100644
--- a/internal/auth/internal/repository/user.go
+++ b/internal/auth/internal/repository/user.go
@@ -5,10 +5,10 @@ import (
"auth/ent"
"auth/ent/role"
"auth/ent/user"
+ "auth/pkg"
"context"
+ "pkg/common/errors"
"time"
-
- "golang.org/x/crypto/bcrypt"
)
// IUserRepository defines the interface for user-related operations.
@@ -309,6 +309,7 @@ type IUserRepository interface {
//
// Parameters:
// - ctx: Context for the database operation.
+ // - username: String representing the username of the user.
// - password: String representing the password to check.
//
// Returns:
@@ -322,12 +323,13 @@ type IUserRepository interface {
// } else {
// fmt.Println("Password is incorrect")
// }
- CheckPassword(ctx context.Context, password string) bool
+ CheckPassword(ctx context.Context, username, password string) bool
// SetPassword sets a new password for a user.
//
// Parameters:
// - ctx: Context for the database operation.
+ // - username: String representing the username of the user.
// - password: String representing the new password to set.
//
// Returns:
@@ -341,7 +343,7 @@ type IUserRepository interface {
// return
// }
// fmt.Println("New password successfully set")
- SetPassword(ctx context.Context, password string) error
+ SetPassword(ctx context.Context, username, password string) error
}
type UserRepository struct {
@@ -465,28 +467,25 @@ func (r *UserRepository) GetUsersByRole(ctx context.Context, roleID string) ([]*
}
// CheckPassword verifies if the provided password is correct for a user.
-func (r *UserRepository) CheckPassword(ctx context.Context, password string) bool {
- user, err := r.client.User.Query().Where(user.Password(password)).Only(ctx)
+func (r *UserRepository) CheckPassword(ctx context.Context, username, password string) bool {
+ user, err := r.client.User.Query().Where(user.Username(username)).Only(ctx)
if err != nil {
return false
}
+ valid, err := pkg.NewPasswordHasher(12).VerifyPassword(user.Password, password)
- err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password))
- if err != nil {
- return false
- }
- return true
+ return err == nil && valid
}
// SetPassword sets a new password for a user.
-func (r *UserRepository) SetPassword(ctx context.Context, password string) error {
- user, err := r.client.User.Query().Where(user.Password(password)).Only(ctx)
+func (r *UserRepository) SetPassword(ctx context.Context, username, password string) error {
+ user, err := r.client.User.Query().Where(user.Username(username)).Only(ctx)
if err != nil {
+ if ent.IsNotFound(err) {
+ return errors.NewError(errors.ErrorTypeNotFound, "User not found", err)
+ }
return err
}
- hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
- if err != nil {
- return err
- }
- return r.client.User.UpdateOne(user).SetPassword(string(hashedPassword)).Exec(ctx)
+
+ return r.client.User.UpdateOne(user).SetPassword(password).Exec(ctx)
}
diff --git a/internal/auth/internal/repository/user_test.go b/internal/auth/internal/repository/user_test.go
new file mode 100644
index 0000000..db0d94a
--- /dev/null
+++ b/internal/auth/internal/repository/user_test.go
@@ -0,0 +1,333 @@
+package repository_test
+
+import (
+ "context"
+ "fmt"
+ "testing"
+
+ "auth/ent"
+ "auth/ent/enttest"
+ "auth/internal/repository"
+
+ "github.com/brianvoe/gofakeit/v7"
+ _ "github.com/mattn/go-sqlite3"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+type userTestSuite struct {
+ client *ent.Client
+ repo repository.IUserRepository
+ faker *gofakeit.Faker
+}
+
+func setupUserTestSuite(t *testing.T) *userTestSuite {
+ client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1")
+ require.NotNil(t, client, "Ent client should not be nil")
+
+ return &userTestSuite{
+ client: client,
+ repo: repository.NewUserRepository(client),
+ faker: gofakeit.New(0),
+ }
+}
+
+func (s *userTestSuite) createUser(t *testing.T) *ent.User {
+ user, err := s.repo.Create(context.Background(), &ent.User{
+ Username: s.faker.Username(),
+ Email: s.faker.Email(),
+ Password: s.faker.Password(true, true, true, true, false, 32),
+ })
+ require.NoError(t, err, "Failed to create user")
+ return user
+}
+
+func (s *userTestSuite) createUniqueRole(t *testing.T) *ent.Role {
+ ctx := context.Background()
+ roleName := fmt.Sprintf("role_%s", s.faker.UUID())
+ role, err := s.client.Role.Create().
+ SetName(roleName).
+ SetPermissions([]string{"read", "write"}).
+ Save(ctx)
+ require.NoError(t, err, "Failed to create role")
+ return role
+}
+
+func TestUserRepository(t *testing.T) {
+ suite := setupUserTestSuite(t)
+ defer suite.client.Close()
+
+ t.Run("Create", suite.testCreate)
+ t.Run("GetByID", suite.testGetByID)
+ t.Run("GetByUsername", suite.testGetByUsername)
+ t.Run("GetByEmail", suite.testGetByEmail)
+ t.Run("Update", suite.testUpdate)
+ t.Run("Delete", suite.testDelete)
+ t.Run("List", suite.testList)
+ t.Run("Count", suite.testCount)
+ t.Run("AddRole", suite.testAddRole)
+ t.Run("RemoveRole", suite.testRemoveRole)
+ t.Run("GetRoles", suite.testGetRoles)
+ t.Run("Search", suite.testSearch)
+ t.Run("ChangePassword", suite.testChangePassword)
+ t.Run("GetUsersByRole", suite.testGetUsersByRole)
+ t.Run("CheckPassword", suite.testCheckPassword)
+ t.Run("SetPassword", suite.testSetPassword)
+}
+
+func (s *userTestSuite) testCreate(t *testing.T) {
+ ctx := context.Background()
+ newUser := &ent.User{
+ Username: s.faker.Username(),
+ Email: s.faker.Email(),
+ Password: s.faker.Password(true, true, true, true, false, 32),
+ }
+
+ createdUser, err := s.repo.Create(ctx, newUser)
+ require.NoError(t, err, "Failed to create user")
+ assert.Equal(t, newUser.Username, createdUser.Username, "Username mismatch")
+ assert.Equal(t, newUser.Email, createdUser.Email, "Email mismatch")
+
+ savedUser, err := s.client.User.Get(ctx, createdUser.ID)
+ require.NoError(t, err, "Failed to retrieve saved user")
+ assert.Equal(t, newUser.Username, savedUser.Username, "Saved username mismatch")
+}
+
+func (s *userTestSuite) testGetByID(t *testing.T) {
+ ctx := context.Background()
+ user := s.createUser(t)
+
+ retrievedUser, err := s.repo.GetByID(ctx, user.ID)
+ require.NoError(t, err, "Failed to get user by ID")
+ assert.Equal(t, user.ID, retrievedUser.ID, "Retrieved user ID mismatch")
+
+ _, err = s.repo.GetByID(ctx, "non-existent-id")
+ assert.Error(t, err, "Expected error when getting non-existent user")
+}
+
+func (s *userTestSuite) testGetByUsername(t *testing.T) {
+ ctx := context.Background()
+ user := s.createUser(t)
+
+ retrievedUser, err := s.repo.GetByUsername(ctx, user.Username)
+ require.NoError(t, err, "Failed to get user by username")
+ assert.Equal(t, user.Username, retrievedUser.Username, "Retrieved username mismatch")
+
+ _, err = s.repo.GetByUsername(ctx, "non-existent-username")
+ assert.Error(t, err, "Expected error when getting non-existent username")
+}
+
+func (s *userTestSuite) testGetByEmail(t *testing.T) {
+ ctx := context.Background()
+ user := s.createUser(t)
+
+ retrievedUser, err := s.repo.GetByEmail(ctx, user.Email)
+ require.NoError(t, err, "Failed to get user by email")
+ assert.Equal(t, user.Email, retrievedUser.Email, "Retrieved email mismatch")
+
+ _, err = s.repo.GetByEmail(ctx, "non-existent@example.com")
+ assert.Error(t, err, "Expected error when getting non-existent email")
+}
+
+func (s *userTestSuite) testUpdate(t *testing.T) {
+ ctx := context.Background()
+ user := s.createUser(t)
+
+ updatedUser := user
+ updatedUser.Email = s.faker.Email()
+
+ result, err := s.repo.Update(ctx, updatedUser)
+ require.NoError(t, err, "Failed to update user")
+ assert.Equal(t, updatedUser.Email, result.Email, "Updated email mismatch")
+
+ retrievedUser, err := s.repo.GetByID(ctx, user.ID)
+ require.NoError(t, err, "Failed to retrieve updated user")
+ assert.Equal(t, updatedUser.Email, retrievedUser.Email, "Retrieved updated email mismatch")
+}
+
+func (s *userTestSuite) testDelete(t *testing.T) {
+ ctx := context.Background()
+ user := s.createUser(t)
+
+ err := s.repo.Delete(ctx, user.ID)
+ require.NoError(t, err, "Failed to delete user")
+
+ _, err = s.repo.GetByID(ctx, user.ID)
+ assert.Error(t, err, "Expected error when getting deleted user")
+
+ err = s.repo.Delete(ctx, "non-existent-id")
+ assert.Error(t, err, "Expected error when deleting non-existent user")
+}
+
+func (s *userTestSuite) testList(t *testing.T) {
+ ctx := context.Background()
+
+ _, err := s.client.User.Delete().Exec(ctx)
+ require.NoError(t, err, "Failed to clear existing users")
+
+ for i := 0; i < 5; i++ {
+ s.createUser(t)
+ }
+
+ users, err := s.repo.List(ctx, 0, 3)
+ require.NoError(t, err, "Failed to list users")
+ assert.Len(t, users, 3, "Expected 3 users")
+
+ users, err = s.repo.List(ctx, 3, 3)
+ require.NoError(t, err, "Failed to list users")
+ assert.Len(t, users, 2, "Expected 2 users")
+}
+
+func (s *userTestSuite) testCount(t *testing.T) {
+ ctx := context.Background()
+
+ initialCount, err := s.repo.Count(ctx)
+ require.NoError(t, err, "Failed to count users")
+
+ for i := 0; i < 5; i++ {
+ s.createUser(t)
+ }
+
+ count, err := s.repo.Count(ctx)
+ require.NoError(t, err, "Failed to count users")
+ assert.Equal(t, initialCount+5, count, "Expected count to increase by 5")
+}
+
+func (s *userTestSuite) testAddRole(t *testing.T) {
+ ctx := context.Background()
+ user := s.createUser(t)
+ role := s.createUniqueRole(t)
+
+ err := s.repo.AddRole(ctx, user.ID, role.ID)
+ require.NoError(t, err, "Failed to add role to user")
+
+ roles, err := s.repo.GetRoles(ctx, user.ID)
+ require.NoError(t, err, "Failed to get user roles")
+ assert.Len(t, roles, 1, "Expected 1 role")
+ assert.Equal(t, role.ID, roles[0].ID, "Role ID mismatch")
+}
+
+func (s *userTestSuite) testRemoveRole(t *testing.T) {
+ ctx := context.Background()
+ user := s.createUser(t)
+ role := s.createUniqueRole(t)
+
+ err := s.repo.AddRole(ctx, user.ID, role.ID)
+ require.NoError(t, err, "Failed to add role to user")
+
+ err = s.repo.RemoveRole(ctx, user.ID, role.ID)
+ require.NoError(t, err, "Failed to remove role from user")
+
+ roles, err := s.repo.GetRoles(ctx, user.ID)
+ require.NoError(t, err, "Failed to get user roles")
+ assert.Empty(t, roles, "Expected no roles")
+}
+
+func (s *userTestSuite) testGetRoles(t *testing.T) {
+ ctx := context.Background()
+ user := s.createUser(t)
+ role := s.createUniqueRole(t)
+
+ err := s.repo.AddRole(ctx, user.ID, role.ID)
+ require.NoError(t, err, "Failed to add role to user")
+
+ roles, err := s.repo.GetRoles(ctx, user.ID)
+ require.NoError(t, err, "Failed to get user roles")
+ assert.Len(t, roles, 1, "Expected 1 role")
+ assert.Equal(t, role.ID, roles[0].ID, "Role ID mismatch")
+}
+
+func (s *userTestSuite) testGetUsersByRole(t *testing.T) {
+ ctx := context.Background()
+ role := s.createUniqueRole(t)
+
+ user1 := s.createUser(t)
+ user2 := s.createUser(t)
+
+ err := s.repo.AddRole(ctx, user1.ID, role.ID)
+ require.NoError(t, err, "Failed to add role to user1")
+ err = s.repo.AddRole(ctx, user2.ID, role.ID)
+ require.NoError(t, err, "Failed to add role to user2")
+
+ usersWithRole, err := s.repo.GetUsersByRole(ctx, role.ID)
+ require.NoError(t, err, "Failed to get users by role")
+ assert.Len(t, usersWithRole, 2, "Expected 2 users with the role")
+}
+
+func (s *userTestSuite) testCheckPassword(t *testing.T) {
+ ctx := context.Background()
+ password := s.faker.Password(true, true, true, true, false, 32)
+ username := s.faker.Username()
+
+ user, err := s.repo.Create(ctx, &ent.User{
+ Username: username,
+ Email: s.faker.Email(),
+ Password: password,
+ })
+ fmt.Println("user", user)
+ require.NoError(t, err, "Failed to create user")
+
+ isCorrect := s.repo.CheckPassword(ctx, username, password)
+ assert.True(t, isCorrect, "Password check should succeed")
+
+ isCorrect = s.repo.CheckPassword(ctx, username, "wrongPassword2")
+ fmt.Println("isCorrect", isCorrect)
+ assert.False(t, isCorrect, "Password check should fail for incorrect password")
+
+ isCorrect = s.repo.CheckPassword(ctx, username, user.Password)
+ assert.False(t, isCorrect, "Password check should fail for hashed password")
+}
+
+func (s *userTestSuite) testSetPassword(t *testing.T) {
+ ctx := context.Background()
+ oldPassword := s.faker.Password(true, true, true, true, false, 32)
+ user := s.client.User.Create().
+ SetUsername(s.faker.Username()).
+ SetEmail(s.faker.Email()).
+ SetPassword(oldPassword).
+ SaveX(ctx)
+ newPassword := s.faker.Password(true, true, true, true, false, 32)
+
+ err := s.repo.SetPassword(ctx, user.Username, newPassword)
+ require.NoError(t, err, "Failed to set new password")
+
+ err = s.repo.SetPassword(ctx, "non-existent-username", newPassword)
+ assert.Error(t, err, "Expected error when setting password for non-existent user")
+
+ isCorrect := s.repo.CheckPassword(ctx, user.Username, newPassword)
+ assert.True(t, isCorrect, "New password check should succeed")
+
+ isCorrect = s.repo.CheckPassword(ctx, user.Username, oldPassword)
+ assert.False(t, isCorrect, "Old password check should fail")
+}
+
+func (s *userTestSuite) testSearch(t *testing.T) {
+ ctx := context.Background()
+ user := s.createUser(t)
+
+ results, err := s.repo.Search(ctx, user.Username[:3])
+ require.NoError(t, err, "Failed to search users")
+ assert.NotEmpty(t, results, "Expected search results")
+
+ found := false
+ for _, result := range results {
+ if result.ID == user.ID {
+ found = true
+ break
+ }
+ }
+ assert.True(t, found, "Expected to find the created user in search results")
+}
+
+func (s *userTestSuite) testChangePassword(t *testing.T) {
+ ctx := context.Background()
+ user := s.createUser(t)
+ newPassword := "newSecurePassword123"
+
+ err := s.repo.ChangePassword(ctx, user.ID, newPassword)
+ require.NoError(t, err, "Failed to change password")
+
+ updatedUser, err := s.repo.GetByID(ctx, user.ID)
+ require.NoError(t, err, "Failed to get updated user")
+ assert.NotEqual(t, user.Password, updatedUser.Password, "Password should have changed")
+}
diff --git a/internal/auth/pb/auth.pb.go b/internal/auth/pb/auth.pb.go
index 5274307..1e5bd7d 100644
--- a/internal/auth/pb/auth.pb.go
+++ b/internal/auth/pb/auth.pb.go
@@ -7,11 +7,12 @@
package grpc
import (
+ reflect "reflect"
+ sync "sync"
+
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
emptypb "google.golang.org/protobuf/types/known/emptypb"
- reflect "reflect"
- sync "sync"
)
const (
diff --git a/internal/auth/pb/auth_grpc.pb.go b/internal/auth/pb/auth_grpc.pb.go
index a75895b..f501c39 100644
--- a/internal/auth/pb/auth_grpc.pb.go
+++ b/internal/auth/pb/auth_grpc.pb.go
@@ -8,6 +8,7 @@ package grpc
import (
context "context"
+
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
diff --git a/internal/auth/pb/authorization.pb.go b/internal/auth/pb/authorization.pb.go
index a69d9ca..1ead493 100644
--- a/internal/auth/pb/authorization.pb.go
+++ b/internal/auth/pb/authorization.pb.go
@@ -7,11 +7,12 @@
package grpc
import (
+ reflect "reflect"
+ sync "sync"
+
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
emptypb "google.golang.org/protobuf/types/known/emptypb"
- reflect "reflect"
- sync "sync"
)
const (
diff --git a/internal/auth/pb/authorization_grpc.pb.go b/internal/auth/pb/authorization_grpc.pb.go
index 4339cf9..2129f19 100644
--- a/internal/auth/pb/authorization_grpc.pb.go
+++ b/internal/auth/pb/authorization_grpc.pb.go
@@ -8,6 +8,7 @@ package grpc
import (
context "context"
+
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
diff --git a/internal/auth/pb/common.pb.go b/internal/auth/pb/common.pb.go
index f6ceefa..1ae7999 100644
--- a/internal/auth/pb/common.pb.go
+++ b/internal/auth/pb/common.pb.go
@@ -7,11 +7,12 @@
package grpc
import (
+ reflect "reflect"
+ sync "sync"
+
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
- reflect "reflect"
- sync "sync"
)
const (
diff --git a/internal/auth/pkg/limiter.go b/internal/auth/pkg/limiter.go
new file mode 100644
index 0000000..263b142
--- /dev/null
+++ b/internal/auth/pkg/limiter.go
@@ -0,0 +1,89 @@
+package pkg
+
+import (
+ "math/rand"
+ "sync"
+ "time"
+
+ "golang.org/x/time/rate"
+)
+
+// PerIPRateLimiter is a helper struct for per-IP rate limiting.
+// It uses a map to store rate limiters for each IP address.
+// The rate limiter is created on the first request from an IP address.
+type PerIPRateLimiter struct {
+ ips map[string]*rate.Limiter
+ mu *sync.RWMutex
+ r rate.Limit
+ b int
+}
+
+// NewPerIPRateLimiter creates a new PerIPRateLimiter.
+// The rate is the maximum number of requests per second.
+// The burst is the maximum number of requests that can be made in a short burst.
+// Parameters:
+// - r: The rate limit.
+// - b: The burst limit.
+//
+// Usage:
+//
+// limiter := NewPerIPRateLimiter(10, 5)
+func NewPerIPRateLimiter(r rate.Limit, b int) *PerIPRateLimiter {
+ rand.New(rand.NewSource(time.Now().UnixNano()))
+ return &PerIPRateLimiter{
+ ips: make(map[string]*rate.Limiter),
+ mu: &sync.RWMutex{},
+ r: r,
+ b: b,
+ }
+}
+
+// AddIP adds an IP address to the rate limiter.
+// If the IP address already exists, it returns the existing rate limiter.
+// Otherwise, it creates a new rate limiter with a small random variation to the rate.
+// Parameters:
+// - ip: The IP address to add.
+//
+// Returns:
+// - The rate limiter for the IP address.
+//
+// Usage:
+//
+// limiter.AddIP("126.0.0.1")
+func (l *PerIPRateLimiter) AddIP(ip string) *rate.Limiter {
+ l.mu.Lock()
+ defer l.mu.Unlock()
+
+ limiter, exists := l.ips[ip]
+ if !exists {
+ // Add a small random variation to the rate
+ adjustedRate := l.r + rate.Limit(rand.Float64()*0.1*float64(l.r))
+ limiter = rate.NewLimiter(adjustedRate, l.b)
+ l.ips[ip] = limiter
+ }
+
+ return limiter
+}
+
+// GetLimiter returns the rate limiter for the given IP address.
+// If the IP address does not exist, it creates a new rate limiter.
+// Parameters:
+// - ip: The IP address to get the rate limiter for.
+//
+// Returns:
+// - The rate limiter for the IP address.
+//
+// Usage:
+//
+// limiter.GetLimiter("126.0.0.1")
+func (l *PerIPRateLimiter) GetLimiter(ip string) *rate.Limiter {
+ l.mu.RLock()
+ limiter, exists := l.ips[ip]
+ l.mu.RUnlock()
+
+ if !exists {
+ return l.AddIP(ip)
+ }
+
+ return limiter
+}
diff --git a/internal/auth/pkg/limiter_test.go b/internal/auth/pkg/limiter_test.go
new file mode 100644
index 0000000..36eedf0
--- /dev/null
+++ b/internal/auth/pkg/limiter_test.go
@@ -0,0 +1,114 @@
+package pkg_test
+
+import (
+ "auth/pkg"
+ "sync"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/assert"
+ "golang.org/x/time/rate"
+)
+
+func TestPerIPRateLimiter(t *testing.T) {
+ t.Run("NewPerIPRateLimiter", func(t *testing.T) {
+ limiter := pkg.NewPerIPRateLimiter(1, 5)
+ assert.NotNil(t, limiter, "NewPerIPRateLimiter should return a non-nil limiter")
+ })
+
+ t.Run("AddIP", func(t *testing.T) {
+ limiter := pkg.NewPerIPRateLimiter(1, 5)
+ ip := "192.168.1.1"
+ rateLimiter := limiter.AddIP(ip)
+ assert.NotNil(t, rateLimiter, "AddIP should return a non-nil rate.Limiter")
+ })
+
+ t.Run("GetLimiter", func(t *testing.T) {
+ limiter := pkg.NewPerIPRateLimiter(1, 5)
+ ip := "192.168.1.1"
+
+ // First call should add the IP
+ rateLimiter1 := limiter.GetLimiter(ip)
+ assert.NotNil(t, rateLimiter1, "GetLimiter should return a non-nil rate.Limiter")
+
+ // Second call should return the same limiter
+ rateLimiter2 := limiter.GetLimiter(ip)
+ assert.Equal(t, rateLimiter1, rateLimiter2, "GetLimiter should return the same rate.Limiter for the same IP")
+ })
+
+ t.Run("RateLimitingBehavior", func(t *testing.T) {
+ limiter := pkg.NewPerIPRateLimiter(10, 5) // 10 requests per second, burst of 5
+ ip := "192.168.1.1"
+
+ rateLimiter := limiter.GetLimiter(ip)
+
+ // Should allow burst
+ for i := 0; i < 5; i++ {
+ assert.True(t, rateLimiter.Allow(), "Should allow burst of 5 requests")
+ }
+
+ // Next request should be rate limited
+ assert.False(t, rateLimiter.Allow(), "Should not allow 6th request immediately")
+
+ // Wait for 100ms, should allow one more request
+ time.Sleep(100 * time.Millisecond)
+ assert.True(t, rateLimiter.Allow(), "Should allow request after waiting")
+ })
+
+ t.Run("ConcurrentAccess", func(t *testing.T) {
+ limiter := pkg.NewPerIPRateLimiter(100, 10) // High limit to avoid rate limiting in this test
+ ips := []string{"192.168.1.1", "192.168.1.2", "192.168.1.3", "192.168.1.4", "192.168.1.5"}
+
+ var wg sync.WaitGroup
+ for i := 0; i < 100; i++ {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ for _, ip := range ips {
+ rateLimiter := limiter.GetLimiter(ip)
+ assert.NotNil(t, rateLimiter, "GetLimiter should return a non-nil rate.Limiter")
+ }
+ }()
+ }
+
+ wg.Wait()
+ })
+
+ t.Run("DifferentIPsDifferentLimiters", func(t *testing.T) {
+ limiter := pkg.NewPerIPRateLimiter(1, 5)
+ ip1 := "192.168.1.1"
+ ip2 := "192.168.1.2"
+
+ rateLimiter1 := limiter.GetLimiter(ip1)
+ rateLimiter2 := limiter.GetLimiter(ip2)
+
+ assert.NotEqual(t, rateLimiter1, rateLimiter2, "Different IPs should have different rate limiters")
+
+ // Additional check to ensure the limiters are truly different
+ rateLimiter1.Allow() // Use up one token from the first limiter
+ assert.True(t, rateLimiter2.Allow(), "Second limiter should still allow a request")
+ })
+
+ t.Run("RespectsBurstAndRate", func(t *testing.T) {
+ r := rate.Limit(2) // 2 requests per second
+ b := 3 // burst of 3
+ limiter := pkg.NewPerIPRateLimiter(r, b)
+ ip := "192.168.1.1"
+ rateLimiter := limiter.GetLimiter(ip)
+
+ // Should allow burst
+ for i := 0; i < b; i++ {
+ assert.True(t, rateLimiter.Allow(), "Should allow burst of 3 requests")
+ }
+
+ // Next request should be rate limited
+ assert.False(t, rateLimiter.Allow(), "Should not allow 4th request immediately")
+
+ // Wait for 500ms, should allow one more request
+ time.Sleep(500 * time.Millisecond)
+ assert.True(t, rateLimiter.Allow(), "Should allow request after waiting")
+
+ // Next request should be rate limited again
+ assert.False(t, rateLimiter.Allow(), "Should not allow another request immediately")
+ })
+}
diff --git a/internal/auth/pkg/password_hash.go b/internal/auth/pkg/password_hash.go
new file mode 100644
index 0000000..c1863e3
--- /dev/null
+++ b/internal/auth/pkg/password_hash.go
@@ -0,0 +1,78 @@
+package pkg
+
+import (
+ "pkg/common/errors"
+
+ "golang.org/x/crypto/bcrypt"
+)
+
+// PasswordHasher is a helper struct for hashing and verifying passwords.
+type PasswordHasher struct {
+ cost int
+}
+
+// NewPasswordHasher creates a new PasswordHasher.
+//
+// Parameters:
+// - cost: The cost of the bcrypt algorithm (default is 10).
+//
+// Usage:
+//
+// hasher := NewPasswordHasher(12)
+func NewPasswordHasher(cost int) *PasswordHasher {
+ if cost <= 0 {
+ cost = 10
+ }
+ return &PasswordHasher{cost: cost}
+}
+
+// HashPassword hashes a password using bcrypt.
+//
+// Parameters:
+// - password: The password to hash.
+//
+// Returns:
+// - The hashed password and an error if hashing fails.
+//
+// Usage:
+//
+// hashedPassword, err := hasher.HashPassword("myPassword123")
+func (ph *PasswordHasher) HashPassword(password string) (string, error) {
+ if password == "" {
+ return "", errors.NewError(errors.ErrorTypeEmptyPassword, "Password cannot be empty", nil)
+ }
+ if ph.cost < bcrypt.MinCost || ph.cost > bcrypt.MaxCost {
+ return "", errors.NewError(errors.ErrorTypeInvalidCost, "Invalid bcrypt cost", nil)
+ }
+ bytes, err := bcrypt.GenerateFromPassword([]byte(password), ph.cost)
+ return string(bytes), err
+}
+
+// VerifyPassword verifies a password against a hashed password.
+//
+// Parameters:
+// - hashedPassword: The hashed password.
+// - password: The password to verify.
+//
+// Returns:
+// - True if the password matches the hashed password, false otherwise.
+//
+// Usage:
+//
+// valid, err := hasher.VerifyPassword(hashedPassword, "myPassword123")
+func (ph *PasswordHasher) VerifyPassword(hashedPassword, password string) (bool, error) {
+ if hashedPassword == "" {
+ return false, errors.NewError(errors.ErrorTypeEmptyPassword, "Hashed password cannot be empty", nil)
+ }
+ if password == "" {
+ return false, errors.NewError(errors.ErrorTypeEmptyPassword, "Password cannot be empty", nil)
+ }
+ err := bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password))
+ if err != nil {
+ if err == bcrypt.ErrMismatchedHashAndPassword {
+ return false, nil
+ }
+ return false, err
+ }
+ return true, nil
+}
diff --git a/internal/auth/pkg/password_hash_test.go b/internal/auth/pkg/password_hash_test.go
new file mode 100644
index 0000000..0d3dc1e
--- /dev/null
+++ b/internal/auth/pkg/password_hash_test.go
@@ -0,0 +1,81 @@
+package pkg_test
+
+import (
+ "auth/pkg"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+ "golang.org/x/crypto/bcrypt"
+)
+
+func TestPasswordHasherHashPassword(t *testing.T) {
+
+ t.Run("HashPassword", func(t *testing.T) {
+ hasher := pkg.NewPasswordHasher(12)
+ hashedPassword, err := hasher.HashPassword("myPassword123")
+ require.NoError(t, err, "HashPassword should not return an error")
+ assert.NotEmpty(t, hashedPassword, "Hashed password should not be empty")
+ })
+
+ t.Run("HashPasswordWithDefaultCost", func(t *testing.T) {
+ hasher := pkg.NewPasswordHasher(0)
+ hashedPassword, err := hasher.HashPassword("myPassword123")
+ require.NoError(t, err, "HashPassword should not return an error")
+ assert.NotEmpty(t, hashedPassword, "Hashed password should not be empty")
+ })
+
+ t.Run("HashPasswordWithEmptyPassword", func(t *testing.T) {
+ hasher := pkg.NewPasswordHasher(12)
+ hashedPassword, err := hasher.HashPassword("")
+ require.Error(t, err, "HashPassword should return an error")
+ assert.Empty(t, hashedPassword, "Hashed password should be empty")
+ })
+
+ t.Run("HashPasswordWithInvalidCost", func(t *testing.T) {
+ hasher := pkg.NewPasswordHasher(-1)
+ hashedPassword, err := hasher.HashPassword("myPassword123")
+ require.NoError(t, err, "HashPassword should not return an error even with invalid initial cost")
+ assert.NotEmpty(t, hashedPassword, "Hashed password should not be empty")
+ })
+
+ t.Run("HashPasswordWithInvalidCost", func(t *testing.T) {
+ hasher := pkg.NewPasswordHasher(bcrypt.MaxCost + 1)
+ hashedPassword, err := hasher.HashPassword("myPassword123")
+ require.Error(t, err, "HashPassword should return an error")
+ assert.Empty(t, hashedPassword, "Hashed password should be empty")
+ })
+
+ t.Run("VerifyPassword", func(t *testing.T) {
+ hasher := pkg.NewPasswordHasher(12)
+ password := "myPassword123"
+ hashedPassword, err := hasher.HashPassword(password)
+ require.NoError(t, err, "HashPassword should not return an error")
+
+ match, err := hasher.VerifyPassword(hashedPassword, password)
+ assert.NoError(t, err, "Passwords should match")
+ assert.True(t, match, "Passwords should match")
+ })
+
+ t.Run("VerifyPasswordWithInvalidPassword", func(t *testing.T) {
+ hasher := pkg.NewPasswordHasher(12)
+ hashedPassword, err := hasher.HashPassword("myPassword123")
+ require.NoError(t, err, "HashPassword should not return an error")
+
+ match, err := hasher.VerifyPassword(hashedPassword, "invalidPassword")
+ assert.False(t, match, "Passwords should not match")
+ assert.NoError(t, err, "Passwords should not match")
+
+ })
+
+ t.Run("VerifyPasswordWithEmptyPassword", func(t *testing.T) {
+ hasher := pkg.NewPasswordHasher(12)
+ hashedPassword, err := hasher.HashPassword("myPassword123")
+ require.NoError(t, err, "HashPassword should not return an error")
+
+ match, err := hasher.VerifyPassword(hashedPassword, "")
+ assert.False(t, match, "Passwords should not match")
+ assert.Error(t, err, "Passwords should not match")
+ assert.Contains(t, err.Error(), "Password cannot be empty")
+ })
+}
diff --git a/internal/auth/pkg/token_generator.go b/internal/auth/pkg/token_generator.go
new file mode 100644
index 0000000..91d3d87
--- /dev/null
+++ b/internal/auth/pkg/token_generator.go
@@ -0,0 +1,36 @@
+package pkg
+
+import (
+ "time"
+
+ "github.com/golang-jwt/jwt"
+)
+
+// TokenGenerator is a helper struct for generating JWT tokens.
+type TokenGenerator struct {
+ secretKey []byte
+ issuer string
+ duration time.Duration
+}
+
+// NewTokenGenerator creates a new TokenGenerator.
+func NewTokenGenerator(secretKey []byte, issuer string, duration time.Duration) *TokenGenerator {
+ return &TokenGenerator{
+ secretKey: secretKey,
+ issuer: issuer,
+ duration: duration,
+ }
+}
+
+// GenerateToken generates a new JWT token with the given claims.
+func (g *TokenGenerator) GenerateToken(claims jwt.MapClaims) (string, error) {
+ if claims == nil {
+ claims = jwt.MapClaims{}
+ }
+ now := time.Now()
+ claims["iss"] = g.issuer
+ claims["iat"] = now.Unix()
+ claims["exp"] = now.Add(g.duration).Unix()
+ token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
+ return token.SignedString(g.secretKey)
+}
diff --git a/internal/auth/pkg/token_generator_test.go b/internal/auth/pkg/token_generator_test.go
new file mode 100644
index 0000000..2675e22
--- /dev/null
+++ b/internal/auth/pkg/token_generator_test.go
@@ -0,0 +1,86 @@
+package pkg_test
+
+import (
+ "auth/pkg"
+ "fmt"
+ "testing"
+ "time"
+
+ "github.com/golang-jwt/jwt"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestTokenGenerator(t *testing.T) {
+ secretKey := []byte("test-secret-key")
+ issuer := "test-issuer"
+ duration := 1 * time.Hour
+
+ t.Run("NewTokenGenerator", func(t *testing.T) {
+ generator := pkg.NewTokenGenerator(secretKey, issuer, duration)
+ assert.NotNil(t, generator, "NewTokenGenerator should return a non-nil generator")
+ })
+
+ t.Run("GenerateToken", func(t *testing.T) {
+ generator := pkg.NewTokenGenerator(secretKey, issuer, duration)
+
+ t.Run("BasicToken", func(t *testing.T) {
+ claims := jwt.MapClaims{
+ "sub": "1234567890",
+ "name": "John Doe",
+ }
+
+ token, err := generator.GenerateToken(claims)
+ require.NoError(t, err, "GenerateToken should not return an error")
+ assert.NotEmpty(t, token, "Generated token should not be empty")
+
+ // Verify the token
+ parsedToken, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) {
+ return secretKey, nil
+ })
+
+ require.NoError(t, err, "Token parsing should not return an error")
+ assert.True(t, parsedToken.Valid, "Token should be valid")
+
+ parsedClaims, ok := parsedToken.Claims.(jwt.MapClaims)
+ require.True(t, ok, "Claims should be of type jwt.MapClaims")
+
+ assert.Equal(t, issuer, parsedClaims["iss"], "Issuer claim should match")
+ assert.Equal(t, "1234567890", parsedClaims["sub"], "Subject claim should match")
+ assert.Equal(t, "John Doe", parsedClaims["name"], "Name claim should match")
+
+ iat, ok := parsedClaims["iat"].(float64)
+ require.True(t, ok, "iat claim should be a number")
+ exp, ok := parsedClaims["exp"].(float64)
+ require.True(t, ok, "exp claim should be a number")
+
+ assert.InDelta(t, time.Now().Unix(), int64(iat), 5, "iat should be close to current time")
+ assert.InDelta(t, time.Now().Add(duration).Unix(), int64(exp), 5, "exp should be close to current time plus duration")
+ })
+
+ t.Run("EmptyClaims", func(t *testing.T) {
+ claims := jwt.MapClaims{}
+
+ token, err := generator.GenerateToken(claims)
+ require.NoError(t, err, "GenerateToken should not return an error with empty claims")
+ assert.NotEmpty(t, token, "Generated token should not be empty")
+ })
+
+ t.Run("NilClaims", func(t *testing.T) {
+ token, err := generator.GenerateToken(nil)
+ require.NoError(t, err, "GenerateToken should not return an error with nil claims")
+ assert.NotEmpty(t, token, "Generated token should not be empty")
+ })
+
+ t.Run("LargeClaims", func(t *testing.T) {
+ largeClaims := jwt.MapClaims{}
+ for i := 0; i < 100; i++ {
+ largeClaims[fmt.Sprintf("key%d", i)] = fmt.Sprintf("value%d", i)
+ }
+
+ token, err := generator.GenerateToken(largeClaims)
+ require.NoError(t, err, "GenerateToken should not return an error with large claims")
+ assert.NotEmpty(t, token, "Generated token should not be empty")
+ })
+ })
+}
diff --git a/internal/auth/scripts/db_migrate.sh b/internal/auth/scripts/db_migrate.sh
index bfe9f34..ef975e0 100755
--- a/internal/auth/scripts/db_migrate.sh
+++ b/internal/auth/scripts/db_migrate.sh
@@ -94,4 +94,4 @@ case $ACTION in
;;
esac
-echo "Operation completed successfully."
\ No newline at end of file
+echo "Operation completed successfully."
diff --git a/internal/auth/scripts/generate_proto.sh b/internal/auth/scripts/generate_proto.sh
index 7784eaf..ff447e7 100755
--- a/internal/auth/scripts/generate_proto.sh
+++ b/internal/auth/scripts/generate_proto.sh
@@ -27,4 +27,4 @@ echo "Proto files generated successfully in $GO_OUT_DIR"
# Optionally, run go mod tidy to ensure all dependencies are properly managed
cd $PROJECT_ROOT && go mod tidy
-echo "Proto generation complete!"
\ No newline at end of file
+echo "Proto generation complete!"
diff --git a/internal/datasource/cmd/main.go b/internal/datasource/cmd/main.go
index 7bd2847..a9fbd20 100644
--- a/internal/datasource/cmd/main.go
+++ b/internal/datasource/cmd/main.go
@@ -8,10 +8,11 @@ import (
"google.golang.org/grpc"
pb "datasource/grpc"
+
"google.golang.org/grpc/reflection"
- "datasource/managers"
"datasource/grpc/server"
+ manager "datasource/managers"
)
type ServerConfig struct {
@@ -30,7 +31,7 @@ func SetupAndServe(config ServerConfig) error {
s := grpc.NewServer()
pb.RegisterDataSourceServiceServer(s, server)
-
+
// Register reflection service on gRPC server.
reflection.Register(s)
@@ -50,4 +51,4 @@ func main() {
if err := SetupAndServe(config); err != nil {
log.Fatalf("Failed to serve: %v", err)
}
-}
\ No newline at end of file
+}
diff --git a/internal/datasource/connectors/api.go b/internal/datasource/connectors/api.go
index c85182e..07e0771 100644
--- a/internal/datasource/connectors/api.go
+++ b/internal/datasource/connectors/api.go
@@ -20,17 +20,17 @@ import (
// APIConnector implements the Connector interface for API data sources.
// It supports both RESTful HTTP APIs and WebSocket connections, as well as periodic polling.
type APIConnector struct {
- client *http.Client
- config *Config
- baseURL string
- wsConn *websocket.Conn
- wsBuffer chan []byte
- pollingTicker *time.Ticker
- stopPolling chan struct{}
- wsLock sync.Mutex
- reconnectBackoff time.Duration
- maxReconnectWait time.Duration
- stopReadWebSocket chan struct{}
+ client *http.Client
+ config *Config
+ baseURL string
+ wsConn *websocket.Conn
+ wsBuffer chan []byte
+ pollingTicker *time.Ticker
+ stopPolling chan struct{}
+ wsLock sync.Mutex
+ reconnectBackoff time.Duration
+ maxReconnectWait time.Duration
+ stopReadWebSocket chan struct{}
}
// NewAPIConnector creates a new APIConnector with the given configuration.
@@ -57,12 +57,12 @@ func NewAPIConnector(config *Config) *APIConnector {
client: &http.Client{
Timeout: time.Duration(config.TimeoutSeconds) * time.Second,
},
- baseURL: config.BaseURL,
- wsBuffer: make(chan []byte, config.WebSocketBufferSize),
- stopPolling: make(chan struct{}),
- reconnectBackoff: time.Second,
- maxReconnectWait: 2 * time.Minute,
- stopReadWebSocket: make(chan struct{}),
+ baseURL: config.BaseURL,
+ wsBuffer: make(chan []byte, config.WebSocketBufferSize),
+ stopPolling: make(chan struct{}),
+ reconnectBackoff: time.Second,
+ maxReconnectWait: 2 * time.Minute,
+ stopReadWebSocket: make(chan struct{}),
}
}
@@ -104,19 +104,19 @@ func (c *APIConnector) Connect(ctx context.Context) error {
// log.Printf("Error closing connector: %v", err)
// }
func (c *APIConnector) Close(ctx context.Context) error {
- if c.wsConn != nil {
- c.stopReadWebSocket <- struct{}{}
- err := c.wsConn.Close()
- c.wsConn = nil
- return err
- }
-
- if c.pollingTicker != nil {
- c.stopPolling <- struct{}{}
- c.pollingTicker.Stop()
- }
-
- return nil
+ if c.wsConn != nil {
+ c.stopReadWebSocket <- struct{}{}
+ err := c.wsConn.Close()
+ c.wsConn = nil
+ return err
+ }
+
+ if c.pollingTicker != nil {
+ c.stopPolling <- struct{}{}
+ c.pollingTicker.Stop()
+ }
+
+ return nil
}
// Query executes a request to the API and returns the results.
@@ -147,67 +147,67 @@ func (c *APIConnector) Query(ctx context.Context, query string, args ...interfac
// connectWebSocket establishes a WebSocket connection to the API.
func (c *APIConnector) connectWebSocket(ctx context.Context) error {
- dialer := websocket.Dialer{
- HandshakeTimeout: time.Duration(c.config.TimeoutSeconds) * time.Second,
- }
+ dialer := websocket.Dialer{
+ HandshakeTimeout: time.Duration(c.config.TimeoutSeconds) * time.Second,
+ }
- conn, _, err := dialer.DialContext(ctx, c.baseURL, nil)
- if err != nil {
- return errors.NewError(errors.ErrorTypeApiConnection, "failed to connect to WebSocket", err)
- }
+ conn, _, err := dialer.DialContext(ctx, c.baseURL, nil)
+ if err != nil {
+ return errors.NewError(errors.ErrorTypeAPIConnection, "failed to connect to WebSocket", err)
+ }
- c.wsConn = conn
- return nil
+ c.wsConn = conn
+ return nil
}
// readWebSocket continuously reads messages from the WebSocket connection
// and sends them to the wsBuffer channel.
func (c *APIConnector) readWebSocket() {
- defer func() {
- close(c.wsBuffer)
- close(c.stopReadWebSocket)
- }()
-
- for {
- _, message, err := c.wsConn.ReadMessage()
- if err != nil {
- select {
- case <-c.stopReadWebSocket:
- return
- default:
- log.Printf("WebSocket read error: %v", err)
- if err := c.reconnectWebSocket(); err != nil {
- log.Printf("Failed to reconnect WebSocket: %v", err)
- return
- }
- continue
- }
- }
- c.wsBuffer <- message
- }
+ defer func() {
+ close(c.wsBuffer)
+ close(c.stopReadWebSocket)
+ }()
+
+ for {
+ _, message, err := c.wsConn.ReadMessage()
+ if err != nil {
+ select {
+ case <-c.stopReadWebSocket:
+ return
+ default:
+ log.Printf("WebSocket read error: %v", err)
+ if err := c.reconnectWebSocket(); err != nil {
+ log.Printf("Failed to reconnect WebSocket: %v", err)
+ return
+ }
+ continue
+ }
+ }
+ c.wsBuffer <- message
+ }
}
// reconnectWebSocket attempts to reconnect the WebSocket with exponential backoff
func (c *APIConnector) reconnectWebSocket() error {
- c.wsLock.Lock()
- defer c.wsLock.Unlock()
-
- backoff := c.reconnectBackoff
- for {
- log.Printf("Attempting to reconnect WebSocket in %v", backoff)
- time.Sleep(backoff)
-
- if err := c.connectWebSocket(context.Background()); err == nil {
- log.Println("Successfully reconnected WebSocket")
- c.reconnectBackoff = time.Second // Reset backoff on successful connection
- return nil
- }
-
- backoff *= 2
- if backoff > c.maxReconnectWait {
- backoff = c.maxReconnectWait
- }
- }
+ c.wsLock.Lock()
+ defer c.wsLock.Unlock()
+
+ backoff := c.reconnectBackoff
+ for {
+ log.Printf("Attempting to reconnect WebSocket in %v", backoff)
+ time.Sleep(backoff)
+
+ if err := c.connectWebSocket(context.Background()); err == nil {
+ log.Println("Successfully reconnected WebSocket")
+ c.reconnectBackoff = time.Second // Reset backoff on successful connection
+ return nil
+ }
+
+ backoff *= 2
+ if backoff > c.maxReconnectWait {
+ backoff = c.maxReconnectWait
+ }
+ }
}
// queryWebSocket returns the latest message received from the WebSocket connection.
@@ -357,7 +357,7 @@ func (c *APIConnector) Execute(ctx context.Context, command string, args ...inte
func (c *APIConnector) Ping(ctx context.Context) error {
if c.config.IsWebSocket {
if c.wsConn == nil {
- return errors.NewError(errors.ErrorTypeApiConnection, "WebSocket connection not established", nil)
+ return errors.NewError(errors.ErrorTypeAPIConnection, "WebSocket connection not established", nil)
}
return nil
}
@@ -370,4 +370,4 @@ func (c *APIConnector) Ping(ctx context.Context) error {
// It always returns an error indicating that transactions are not supported.
func (c *APIConnector) Transaction(ctx context.Context) (TransactionConnector, error) {
return nil, errors.NewError(errors.ErrorTypeUnsupported, "transactions are not supported for API connector", nil)
-}
\ No newline at end of file
+}
diff --git a/internal/datasource/connectors/connectors.go b/internal/datasource/connectors/connectors.go
index 029b0d3..328f96f 100644
--- a/internal/datasource/connectors/connectors.go
+++ b/internal/datasource/connectors/connectors.go
@@ -43,39 +43,39 @@ type TransactionConnector interface {
// Config represents the configuration for a data connector.
type Config struct {
// Type is the type of the data connector.
- Type string
+ Type string
// Host is the hostname of the data source.
- Host string
+ Host string
// Port is the port number of the data source.
- Port int
+ Port int
// Username is the username for the data source.
- Username string
+ Username string
// Password is the password for the data source.
- Password string
+ Password string
// Database is the name of the database.
- Database string
+ Database string
// MaxOpenConns is the maximum number of open connections to the database.
- MaxOpenConns int
+ MaxOpenConns int
// MaxIdleConns is the maximum number of connections in the idle connection pool.
- MaxIdleConns int
+ MaxIdleConns int
// ConnMaxLifetimeSeconds is the maximum amount of time a connection may be reused.
- ConnMaxLifetimeSeconds int
+ ConnMaxLifetimeSeconds int
// ConnMaxIdleTimeSeconds is the maximum amount of time a connection may be idle before being closed.
- Options map[string]interface{}
+ Options map[string]interface{}
// Driver is the driver name for the data source.
- Driver string
+ Driver string
// RedisDB is the database number for Redis.
- RedisDB int
+ RedisDB int
// IsWebSocket indicates whether the connection is a WebSocket.
- IsWebSocket bool
+ IsWebSocket bool
// WebSocketPath is the path for WebSocket connections.
- PollingIntervalSeconds int
+ PollingIntervalSeconds int
// WebSocketBufferSize is the buffer size for WebSocket connections.
- WebSocketBufferSize int
+ WebSocketBufferSize int
// TimeoutSeconds is the timeout for the HTTP client.
- TimeoutSeconds int
+ TimeoutSeconds int
// BaseURL is the base URL for the API.
- BaseURL string
+ BaseURL string
// BasePath is the base path for the file connector.
- BasePath string
-}
\ No newline at end of file
+ BasePath string
+}
diff --git a/internal/datasource/connectors/factory.go b/internal/datasource/connectors/factory.go
index 213876e..4ee778c 100644
--- a/internal/datasource/connectors/factory.go
+++ b/internal/datasource/connectors/factory.go
@@ -20,5 +20,4 @@ func ConnectorFactory(config *Config) (Connector, error) {
default:
return nil, fmt.Errorf("unsupported connector type: %s", config.Type)
}
- return nil, fmt.Errorf("connector type not implemented: %s", config.Type)
-}
\ No newline at end of file
+}
diff --git a/internal/datasource/connectors/file.go b/internal/datasource/connectors/file.go
index 894444c..3dd38f0 100644
--- a/internal/datasource/connectors/file.go
+++ b/internal/datasource/connectors/file.go
@@ -177,4 +177,4 @@ func (c *FileConnector) readCSVFile(filePath string) ([]map[string]interface{},
}
return result, nil
-}
\ No newline at end of file
+}
diff --git a/internal/datasource/connectors/mongo.go b/internal/datasource/connectors/mongo.go
index 95d2646..0649450 100644
--- a/internal/datasource/connectors/mongo.go
+++ b/internal/datasource/connectors/mongo.go
@@ -29,56 +29,55 @@ func NewMongoConnector(config *Config) *MongoConnector {
// Connect establishes a connection to the MongoDB database.
func (c *MongoConnector) Connect(ctx context.Context) error {
- uri := c.buildConnectionString()
-
- clientOptions := options.Client().ApplyURI(uri)
+ uri := c.buildConnectionString()
+
+ clientOptions := options.Client().ApplyURI(uri)
log.Printf("Connecting to MongoDB: %s", uri)
- var client *mongo.Client
- err := retry.Retry(ctx, func() error {
- var err error
- client, err = mongo.Connect(ctx, clientOptions)
- if err != nil {
+ var client *mongo.Client
+ err := retry.Retry(ctx, func() error {
+ var err error
+ client, err = mongo.Connect(ctx, clientOptions)
+ if err != nil {
log.Printf("Failed to connect to MongoDB: %v", err)
- return errors.NewError(errors.ErrorTypeConnection, "failed to connect to MongoDB", err)
- }
- return client.Ping(ctx, nil)
- }, retry.DefaultConfig())
+ return errors.NewError(errors.ErrorTypeConnection, "failed to connect to MongoDB", err)
+ }
+ return client.Ping(ctx, nil)
+ }, retry.DefaultConfig())
- if err != nil {
- return err
- }
+ if err != nil {
+ return err
+ }
- c.client = client
- return nil
+ c.client = client
+ return nil
}
-
func (c *MongoConnector) buildConnectionString() string {
- query := url.Values{}
- for k, v := range c.config.Options {
- query.Add(k, fmt.Sprintf("%v", v))
- }
-
- var baseURL string
- if c.config.Port > 0 {
- // If port is provided, use standard MongoDB protocol
- baseURL = fmt.Sprintf("mongodb://%s:%s@%s:%d",
- url.QueryEscape(c.config.Username),
- url.QueryEscape(c.config.Password),
- c.config.Host,
- c.config.Port)
- } else {
- // If no port, assume it's MongoDB Atlas and use srv protocol
- baseURL = fmt.Sprintf("mongodb+srv://%s:%s@%s",
- url.QueryEscape(c.config.Username),
- url.QueryEscape(c.config.Password),
- c.config.Host)
- }
-
- // Append database and query parameters
- return fmt.Sprintf("%s/%s?%s", baseURL, c.config.Database, query.Encode())
+ query := url.Values{}
+ for k, v := range c.config.Options {
+ query.Add(k, fmt.Sprintf("%v", v))
+ }
+
+ var baseURL string
+ if c.config.Port > 0 {
+ // If port is provided, use standard MongoDB protocol
+ baseURL = fmt.Sprintf("mongodb://%s:%s@%s:%d",
+ url.QueryEscape(c.config.Username),
+ url.QueryEscape(c.config.Password),
+ c.config.Host,
+ c.config.Port)
+ } else {
+ // If no port, assume it's MongoDB Atlas and use srv protocol
+ baseURL = fmt.Sprintf("mongodb+srv://%s:%s@%s",
+ url.QueryEscape(c.config.Username),
+ url.QueryEscape(c.config.Password),
+ c.config.Host)
+ }
+
+ // Append database and query parameters
+ return fmt.Sprintf("%s/%s?%s", baseURL, c.config.Database, query.Encode())
}
// Close closes the connection to the MongoDB database.
@@ -91,101 +90,101 @@ func (c *MongoConnector) Close(ctx context.Context) error {
// Query executes a query and returns the results as a slice of maps.
func (c *MongoConnector) Query(ctx context.Context, query string, args ...interface{}) ([]map[string]interface{}, error) {
- if len(args) == 0 {
- return nil, errors.NewError(errors.ErrorTypeQuery, "missing collection name", nil)
- }
- collection, ok := args[0].(string)
- if !ok {
- return nil, errors.NewError(errors.ErrorTypeQuery, "invalid collection name", nil)
- }
-
- coll := c.client.Database(c.config.Database).Collection(collection)
-
- var filter bson.M
- err := json.Unmarshal([]byte(query), &filter)
- if err != nil {
- return nil, errors.NewError(errors.ErrorTypeQuery, "failed to parse query", err)
- }
-
- cursor, err := coll.Find(ctx, filter)
- if err != nil {
- return nil, errors.NewError(errors.ErrorTypeQuery, "failed to execute query", err)
- }
- defer cursor.Close(ctx)
-
- var results []map[string]interface{}
- if err = cursor.All(ctx, &results); err != nil {
- return nil, errors.NewError(errors.ErrorTypeQuery, "failed to decode query results", err)
- }
-
- return results, nil
+ if len(args) == 0 {
+ return nil, errors.NewError(errors.ErrorTypeQuery, "missing collection name", nil)
+ }
+ collection, ok := args[0].(string)
+ if !ok {
+ return nil, errors.NewError(errors.ErrorTypeQuery, "invalid collection name", nil)
+ }
+
+ coll := c.client.Database(c.config.Database).Collection(collection)
+
+ var filter bson.M
+ err := json.Unmarshal([]byte(query), &filter)
+ if err != nil {
+ return nil, errors.NewError(errors.ErrorTypeQuery, "failed to parse query", err)
+ }
+
+ cursor, err := coll.Find(ctx, filter)
+ if err != nil {
+ return nil, errors.NewError(errors.ErrorTypeQuery, "failed to execute query", err)
+ }
+ defer cursor.Close(ctx)
+
+ var results []map[string]interface{}
+ if err = cursor.All(ctx, &results); err != nil {
+ return nil, errors.NewError(errors.ErrorTypeQuery, "failed to decode query results", err)
+ }
+
+ return results, nil
}
// Execute executes a command and returns the number of affected documents.
func (c *MongoConnector) Execute(ctx context.Context, command string, args ...interface{}) (int64, error) {
- if len(args) == 0 {
- return 0, errors.NewError(errors.ErrorTypeExecution, "missing collection name", nil)
- }
- collectionName, ok := args[0].(string)
- if !ok {
- return 0, errors.NewError(errors.ErrorTypeExecution, "invalid collection name", nil)
- }
-
- collection := c.client.Database(c.config.Database).Collection(collectionName)
-
- var result int64
- var err error
-
- switch command {
- case "insert":
- if len(args) < 2 {
- return 0, errors.NewError(errors.ErrorTypeExecution, "missing document to insert", nil)
- }
- doc, ok := args[1].(map[string]interface{})
- if !ok {
- return 0, errors.NewError(errors.ErrorTypeExecution, "invalid document format", nil)
- }
- _, err = collection.InsertOne(ctx, doc)
- if err == nil {
- result = 1
- }
- case "update":
- if len(args) < 3 {
- return 0, errors.NewError(errors.ErrorTypeExecution, "missing update parameters", nil)
- }
- filter, ok := args[1].(map[string]interface{})
- if !ok {
- return 0, errors.NewError(errors.ErrorTypeExecution, "invalid filter format", nil)
- }
- update, ok := args[2].(map[string]interface{})
- if !ok {
- return 0, errors.NewError(errors.ErrorTypeExecution, "invalid update format", nil)
- }
- updateResult, err := collection.UpdateMany(ctx, filter, bson.M{"$set": update})
- if err == nil {
- result = updateResult.ModifiedCount
- }
- case "delete":
- if len(args) < 2 {
- return 0, errors.NewError(errors.ErrorTypeExecution, "missing delete parameters", nil)
- }
- filter, ok := args[1].(map[string]interface{})
- if !ok {
- return 0, errors.NewError(errors.ErrorTypeExecution, "invalid filter format", nil)
- }
- deleteResult, err := collection.DeleteMany(ctx, filter)
- if err == nil {
- result = deleteResult.DeletedCount
- }
- default:
- return 0, errors.NewError(errors.ErrorTypeExecution, fmt.Sprintf("unsupported command: %s", command), nil)
- }
-
- if err != nil {
- return 0, errors.NewError(errors.ErrorTypeExecution, fmt.Sprintf("failed to execute command: %s", command), err)
- }
-
- return result, nil
+ if len(args) == 0 {
+ return 0, errors.NewError(errors.ErrorTypeExecution, "missing collection name", nil)
+ }
+ collectionName, ok := args[0].(string)
+ if !ok {
+ return 0, errors.NewError(errors.ErrorTypeExecution, "invalid collection name", nil)
+ }
+
+ collection := c.client.Database(c.config.Database).Collection(collectionName)
+
+ var result int64
+ var err error
+
+ switch command {
+ case "insert":
+ if len(args) < 2 {
+ return 0, errors.NewError(errors.ErrorTypeExecution, "missing document to insert", nil)
+ }
+ doc, ok := args[1].(map[string]interface{})
+ if !ok {
+ return 0, errors.NewError(errors.ErrorTypeExecution, "invalid document format", nil)
+ }
+ _, err = collection.InsertOne(ctx, doc)
+ if err == nil {
+ result = 1
+ }
+ case "update":
+ if len(args) < 3 {
+ return 0, errors.NewError(errors.ErrorTypeExecution, "missing update parameters", nil)
+ }
+ filter, ok := args[1].(map[string]interface{})
+ if !ok {
+ return 0, errors.NewError(errors.ErrorTypeExecution, "invalid filter format", nil)
+ }
+ update, ok := args[2].(map[string]interface{})
+ if !ok {
+ return 0, errors.NewError(errors.ErrorTypeExecution, "invalid update format", nil)
+ }
+ updateResult, err := collection.UpdateMany(ctx, filter, bson.M{"$set": update})
+ if err == nil {
+ result = updateResult.ModifiedCount
+ }
+ case "delete":
+ if len(args) < 2 {
+ return 0, errors.NewError(errors.ErrorTypeExecution, "missing delete parameters", nil)
+ }
+ filter, ok := args[1].(map[string]interface{})
+ if !ok {
+ return 0, errors.NewError(errors.ErrorTypeExecution, "invalid filter format", nil)
+ }
+ deleteResult, err := collection.DeleteMany(ctx, filter)
+ if err == nil {
+ result = deleteResult.DeletedCount
+ }
+ default:
+ return 0, errors.NewError(errors.ErrorTypeExecution, fmt.Sprintf("unsupported command: %s", command), nil)
+ }
+
+ if err != nil {
+ return 0, errors.NewError(errors.ErrorTypeExecution, fmt.Sprintf("failed to execute command: %s", command), err)
+ }
+
+ return result, nil
}
// Ping checks if the database connection is still alive.
@@ -223,95 +222,95 @@ type MongoTransactionConnector struct {
// Query executes a query within the transaction and returns the results.
func (c *MongoTransactionConnector) Query(ctx context.Context, query string, args ...interface{}) ([]map[string]interface{}, error) {
- var results []map[string]interface{}
-
- _, err := c.session.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
- // Parse the query string into a BSON document
- var filter bson.D
- err := bson.UnmarshalExtJSON([]byte(query), true, &filter)
- if err != nil {
- return nil, errors.NewError(errors.ErrorTypeQuery, "failed to parse query", err)
- }
-
- // Ensure we have at least one argument for the collection name
- if len(args) == 0 {
- return nil, errors.NewError(errors.ErrorTypeQuery, "missing collection name", nil)
- }
- collectionName, ok := args[0].(string)
- if !ok {
- return nil, errors.NewError(errors.ErrorTypeQuery, "invalid collection name", nil)
- }
-
- collection := c.client.Database(c.config.Database).Collection(collectionName)
- cursor, err := collection.Find(sessCtx, filter)
- if err != nil {
- return nil, errors.NewError(errors.ErrorTypeQuery, "failed to execute query", err)
- }
- defer cursor.Close(sessCtx)
-
- for cursor.Next(sessCtx) {
- var result map[string]interface{}
- if err := cursor.Decode(&result); err != nil {
- return nil, errors.NewError(errors.ErrorTypeQuery, "failed to decode result", err)
- }
- results = append(results, result)
- }
-
- if err := cursor.Err(); err != nil {
- return nil, errors.NewError(errors.ErrorTypeQuery, "error during cursor iteration", err)
- }
-
- return results, nil
- })
-
- if err != nil {
- return nil, errors.NewError(errors.ErrorTypeTransaction, "transaction failed", err)
- }
-
- return results, nil
+ var results []map[string]interface{}
+
+ _, err := c.session.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
+ // Parse the query string into a BSON document
+ var filter bson.D
+ err := bson.UnmarshalExtJSON([]byte(query), true, &filter)
+ if err != nil {
+ return nil, errors.NewError(errors.ErrorTypeQuery, "failed to parse query", err)
+ }
+
+ // Ensure we have at least one argument for the collection name
+ if len(args) == 0 {
+ return nil, errors.NewError(errors.ErrorTypeQuery, "missing collection name", nil)
+ }
+ collectionName, ok := args[0].(string)
+ if !ok {
+ return nil, errors.NewError(errors.ErrorTypeQuery, "invalid collection name", nil)
+ }
+
+ collection := c.client.Database(c.config.Database).Collection(collectionName)
+ cursor, err := collection.Find(sessCtx, filter)
+ if err != nil {
+ return nil, errors.NewError(errors.ErrorTypeQuery, "failed to execute query", err)
+ }
+ defer cursor.Close(sessCtx)
+
+ for cursor.Next(sessCtx) {
+ var result map[string]interface{}
+ if err := cursor.Decode(&result); err != nil {
+ return nil, errors.NewError(errors.ErrorTypeQuery, "failed to decode result", err)
+ }
+ results = append(results, result)
+ }
+
+ if err := cursor.Err(); err != nil {
+ return nil, errors.NewError(errors.ErrorTypeQuery, "error during cursor iteration", err)
+ }
+
+ return results, nil
+ })
+
+ if err != nil {
+ return nil, errors.NewError(errors.ErrorTypeTransaction, "transaction failed", err)
+ }
+
+ return results, nil
}
// Execute executes a command within the transaction and returns the number of affected documents.
func (c *MongoTransactionConnector) Execute(ctx context.Context, command string, args ...interface{}) (int64, error) {
- var modifiedCount int64
-
- _, err := c.session.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
- var doc bson.D
- err := bson.UnmarshalExtJSON([]byte(command), true, &doc)
- if err != nil {
- return nil, errors.NewError(errors.ErrorTypeExecution, "failed to parse command", err)
- }
-
- // Ensure we have at least one argument for the collection name
- if len(args) == 0 {
- return nil, errors.NewError(errors.ErrorTypeExecution, "missing collection name", nil)
- }
- collectionName, ok := args[0].(string)
- if !ok {
- return nil, errors.NewError(errors.ErrorTypeExecution, "invalid collection name", nil)
- }
-
- collection := c.client.Database(c.config.Database).Collection(collectionName)
-
- // Assuming the first element is the filter and the second is the update
- if len(doc) < 2 {
- return nil, errors.NewError(errors.ErrorTypeExecution, "invalid command structure", nil)
- }
-
- result, err := collection.UpdateMany(sessCtx, doc[0].Value, doc[1].Value)
- if err != nil {
- return nil, errors.NewError(errors.ErrorTypeExecution, "failed to execute command", err)
- }
-
- modifiedCount = result.ModifiedCount
- return modifiedCount, nil
- })
-
- if err != nil {
- return 0, errors.NewError(errors.ErrorTypeTransaction, "transaction failed", err)
- }
-
- return modifiedCount, nil
+ var modifiedCount int64
+
+ _, err := c.session.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
+ var doc bson.D
+ err := bson.UnmarshalExtJSON([]byte(command), true, &doc)
+ if err != nil {
+ return nil, errors.NewError(errors.ErrorTypeExecution, "failed to parse command", err)
+ }
+
+ // Ensure we have at least one argument for the collection name
+ if len(args) == 0 {
+ return nil, errors.NewError(errors.ErrorTypeExecution, "missing collection name", nil)
+ }
+ collectionName, ok := args[0].(string)
+ if !ok {
+ return nil, errors.NewError(errors.ErrorTypeExecution, "invalid collection name", nil)
+ }
+
+ collection := c.client.Database(c.config.Database).Collection(collectionName)
+
+ // Assuming the first element is the filter and the second is the update
+ if len(doc) < 2 {
+ return nil, errors.NewError(errors.ErrorTypeExecution, "invalid command structure", nil)
+ }
+
+ result, err := collection.UpdateMany(sessCtx, doc[0].Value, doc[1].Value)
+ if err != nil {
+ return nil, errors.NewError(errors.ErrorTypeExecution, "failed to execute command", err)
+ }
+
+ modifiedCount = result.ModifiedCount
+ return modifiedCount, nil
+ })
+
+ if err != nil {
+ return 0, errors.NewError(errors.ErrorTypeTransaction, "transaction failed", err)
+ }
+
+ return modifiedCount, nil
}
// Commit commits the transaction.
@@ -322,4 +321,4 @@ func (c *MongoTransactionConnector) Commit(ctx context.Context) error {
// Rollback rolls back the transaction.
func (c *MongoTransactionConnector) Rollback(ctx context.Context) error {
return c.session.AbortTransaction(ctx)
-}
\ No newline at end of file
+}
diff --git a/internal/datasource/connectors/redis.go b/internal/datasource/connectors/redis.go
index 3ff1006..9351b8a 100644
--- a/internal/datasource/connectors/redis.go
+++ b/internal/datasource/connectors/redis.go
@@ -113,7 +113,7 @@ func (c *RedisTransactionConnector) Query(ctx context.Context, query string, arg
return nil, nil // Key does not exist
} else if err != nil {
return nil, errors.NewError(errors.ErrorTypeTransaction, "cannot query in Redis transaction, use Execute instead", nil)
- }
+ }
return []map[string]interface{}{{"value": val}}, nil
}
@@ -143,4 +143,4 @@ func (c *RedisTransactionConnector) Rollback(ctx context.Context) error {
return errors.NewError(errors.ErrorTypeTransaction, "failed to rollback transaction", err)
}
return nil
-}
\ No newline at end of file
+}
diff --git a/internal/datasource/connectors/sql.go b/internal/datasource/connectors/sql.go
index b0a4292..d1f1b57 100644
--- a/internal/datasource/connectors/sql.go
+++ b/internal/datasource/connectors/sql.go
@@ -121,7 +121,7 @@ func (c *SQLConnector) Query(ctx context.Context, query string, args ...interfac
// Execute executes a command (e.g., INSERT, UPDATE, DELETE) and returns the number of affected rows.
func (c *SQLConnector) Execute(ctx context.Context, command string, args ...interface{}) (int64, error) {
if c.db == nil {
- return 0, errors.NewError(errors.ErrorTypeDatabaseConnection,errors.ErrorMessages[errors.ErrorTypeDatabaseConnection], nil)
+ return 0, errors.NewError(errors.ErrorTypeDatabaseConnection, errors.ErrorMessages[errors.ErrorTypeDatabaseConnection], nil)
}
result, err := c.db.ExecContext(ctx, command, args...)
@@ -172,7 +172,6 @@ func (c *SQLTransactionConnector) Query(ctx context.Context, query string, args
}
defer rows.Close()
-
columns, err := rows.Columns()
if err != nil {
return nil, errors.NewError(errors.ErrorTypeQuery, "failed to get columns in transaction", err)
@@ -233,4 +232,4 @@ func (c *SQLTransactionConnector) Rollback(ctx context.Context) error {
return errors.NewError(errors.ErrorTypeTransaction, "failed to rollback transaction", err)
}
return nil
-}
\ No newline at end of file
+}
diff --git a/internal/datasource/go.mod b/internal/datasource/go.mod
index b5d2ad8..e433f95 100644
--- a/internal/datasource/go.mod
+++ b/internal/datasource/go.mod
@@ -5,29 +5,31 @@ go 1.21
require (
github.com/lib/pq v1.10.9
go.mongodb.org/mongo-driver v1.16.0
- google.golang.org/protobuf v1.33.0
+ google.golang.org/protobuf v1.34.2
)
require (
- github.com/cespare/xxhash/v2 v2.2.0 // indirect
+ github.com/cespare/xxhash/v2 v2.3.0 // indirect
+ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
- golang.org/x/net v0.23.0 // indirect
- golang.org/x/sys v0.19.0 // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect
+ github.com/fsnotify/fsnotify v1.7.0 // indirect
+ golang.org/x/net v0.25.0 // indirect
+ golang.org/x/sys v0.20.0 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 // indirect
)
require (
github.com/go-redis/redis/v8 v8.11.5
github.com/golang/snappy v0.0.4 // indirect
github.com/gorilla/websocket v1.5.3
- github.com/klauspost/compress v1.13.6 // indirect
+ github.com/klauspost/compress v1.17.2 // indirect
github.com/montanaflynn/stats v0.7.1 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.1.2 // indirect
github.com/xdg-go/stringprep v1.0.4 // indirect
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
- golang.org/x/crypto v0.22.0 // indirect
+ golang.org/x/crypto v0.23.0 // indirect
golang.org/x/sync v0.7.0 // indirect
- golang.org/x/text v0.14.0 // indirect
- google.golang.org/grpc v1.64.0
+ golang.org/x/text v0.15.0 // indirect
+ google.golang.org/grpc v1.65.0
)
diff --git a/internal/datasource/go.sum b/internal/datasource/go.sum
index a930282..9a71e68 100644
--- a/internal/datasource/go.sum
+++ b/internal/datasource/go.sum
@@ -1,11 +1,8 @@
-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/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/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
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/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
-github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
+github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
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/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
@@ -14,8 +11,7 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
-github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
-github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
+github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE=
@@ -39,14 +35,12 @@ go.mongodb.org/mongo-driver v1.16.0 h1:tpRsfBJMROVHKpdGyc1BBEzzjDUWjItxbVSZ8Ls4B
go.mongodb.org/mongo-driver v1.16.0/go.mod h1:oB6AhJQvFQL4LEHyXi6aJzQJtBiTQHiAd83l0GdFaiw=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
-golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
+golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
-golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
-golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
+golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/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.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
@@ -56,26 +50,21 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/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-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
-golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
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/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.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
-golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
-golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
-google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY=
-google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg=
-google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
-google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 h1:Zy9XzmMEflZ/MAaA7vNcoebnRAld7FsPW1EeBB7V0m8=
+google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
+google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
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.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
diff --git a/internal/datasource/grpc/connector.pb.go b/internal/datasource/grpc/connector.pb.go
index b43209b..8586875 100644
--- a/internal/datasource/grpc/connector.pb.go
+++ b/internal/datasource/grpc/connector.pb.go
@@ -7,10 +7,11 @@
package grpc
import (
- protoreflect "google.golang.org/protobuf/reflect/protoreflect"
- protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
+
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
)
const (
diff --git a/internal/datasource/grpc/connector_grpc.pb.go b/internal/datasource/grpc/connector_grpc.pb.go
index dfcdc0e..4283296 100644
--- a/internal/datasource/grpc/connector_grpc.pb.go
+++ b/internal/datasource/grpc/connector_grpc.pb.go
@@ -8,6 +8,7 @@ package grpc
import (
context "context"
+
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
diff --git a/internal/datasource/grpc/generate_grpc.sh b/internal/datasource/grpc/generate_grpc.sh
index d688c3d..694df8f 100755
--- a/internal/datasource/grpc/generate_grpc.sh
+++ b/internal/datasource/grpc/generate_grpc.sh
@@ -23,4 +23,4 @@ protoc --proto_path=${PROTO_DIR} \
--go-grpc_out=${GO_OUT_DIR} --go-grpc_opt=paths=source_relative \
${PROTO_DIR}/connector.proto
-echo "DataSource gRPC code generation completed."
\ No newline at end of file
+echo "DataSource gRPC code generation completed."
diff --git a/internal/datasource/grpc/proto/connector.proto b/internal/datasource/grpc/proto/connector.proto
index 80a8ac2..e395403 100644
--- a/internal/datasource/grpc/proto/connector.proto
+++ b/internal/datasource/grpc/proto/connector.proto
@@ -87,4 +87,4 @@ message RemoveConnectorRequest {
message RemoveConnectorResponse {
bool success = 1;
string error = 2;
-}
\ No newline at end of file
+}
diff --git a/internal/datasource/grpc/server/datasource.go b/internal/datasource/grpc/server/datasource.go
index d908db4..b8afe29 100644
--- a/internal/datasource/grpc/server/datasource.go
+++ b/internal/datasource/grpc/server/datasource.go
@@ -9,10 +9,10 @@ import (
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
+ "datasource/connectors"
"datasource/grpc"
- "datasource/managers"
+ manager "datasource/managers"
"datasource/managers/query"
- "datasource/connectors"
)
type DataSourceServer struct {
@@ -26,7 +26,7 @@ func NewDataSourceServer(manager *manager.ConnectorManager) *DataSourceServer {
func (s *DataSourceServer) Connect(ctx context.Context, req *grpc.ConnectRequest) (*grpc.ConnectResponse, error) {
log.Printf("Received Connect request for connector: %s", req.ConnectorName)
-
+
connector, err := s.manager.GetConnector(req.ConnectorName)
if err != nil {
log.Printf("Error getting connector %s: %v", req.ConnectorName, err)
@@ -45,7 +45,7 @@ func (s *DataSourceServer) Connect(ctx context.Context, req *grpc.ConnectRequest
func (s *DataSourceServer) Disconnect(ctx context.Context, req *grpc.DisconnectRequest) (*grpc.DisconnectResponse, error) {
log.Printf("Received Disconnect request for connector: %s", req.ConnectorName)
-
+
connector, err := s.manager.GetConnector(req.ConnectorName)
if err != nil {
log.Printf("Error getting connector %s: %v", req.ConnectorName, err)
@@ -64,7 +64,7 @@ func (s *DataSourceServer) Disconnect(ctx context.Context, req *grpc.DisconnectR
func (s *DataSourceServer) ExecuteQuery(ctx context.Context, req *grpc.QueryRequest) (*grpc.QueryResponse, error) {
log.Printf("Received ExecuteQuery request for connector: %s", req.ConnectorName)
-
+
connector, err := s.manager.GetConnector(req.ConnectorName)
if err != nil {
log.Printf("Error getting connector %s: %v", req.ConnectorName, err)
@@ -72,7 +72,7 @@ func (s *DataSourceServer) ExecuteQuery(ctx context.Context, req *grpc.QueryRequ
}
executor := query.NewQueryExecutor(connector)
-
+
var q query.Query
err = json.Unmarshal([]byte(req.Query), &q)
if err != nil {
@@ -102,7 +102,7 @@ func (s *DataSourceServer) ExecuteQuery(ctx context.Context, req *grpc.QueryRequ
func (s *DataSourceServer) ExecuteCommand(ctx context.Context, req *grpc.CommandRequest) (*grpc.CommandResponse, error) {
log.Printf("Received ExecuteCommand request for connector: %s", req.ConnectorName)
-
+
connector, err := s.manager.GetConnector(req.ConnectorName)
if err != nil {
log.Printf("Error getting connector %s: %v", req.ConnectorName, err)
@@ -121,7 +121,7 @@ func (s *DataSourceServer) ExecuteCommand(ctx context.Context, req *grpc.Command
// func (s *DataSourceServer) GetConnectors(ctx context.Context, req *grpc.GetConnectorsRequest) (*grpc.GetConnectorsResponse, error) {
// log.Printf("Received GetConnectors request")
-
+
// connectorNames, err := s.manager.GetConnector()
// log.Printf("Retrieved %d connectors", len(connectorNames))
// return &grpc.GetConnectorsResponse{ConnectorNames: connectorNames}, nil
@@ -129,7 +129,7 @@ func (s *DataSourceServer) ExecuteCommand(ctx context.Context, req *grpc.Command
func (s *DataSourceServer) AddConnector(ctx context.Context, req *grpc.AddConnectorRequest) (*grpc.AddConnectorResponse, error) {
log.Printf("Received AddConnector request for connector: %s", req.Name)
-
+
config := &connectors.Config{
Type: req.Config.Type,
Host: req.Config.Host,
@@ -158,7 +158,7 @@ func (s *DataSourceServer) AddConnector(ctx context.Context, req *grpc.AddConnec
func (s *DataSourceServer) RemoveConnector(ctx context.Context, req *grpc.RemoveConnectorRequest) (*grpc.RemoveConnectorResponse, error) {
log.Printf("Received RemoveConnector request for connector: %s", req.Name)
-
+
err := s.manager.RemoveConnector(req.Name)
if err != nil {
log.Printf("Error removing connector %s: %v", req.Name, err)
@@ -181,4 +181,4 @@ func (s *DataSourceServer) validateConnectorConfig(config *grpc.ConnectorConfig)
}
// Add more validation as needed
return nil
-}
\ No newline at end of file
+}
diff --git a/internal/datasource/managers/manager.go b/internal/datasource/managers/manager.go
index 81bc4d0..f294f86 100644
--- a/internal/datasource/managers/manager.go
+++ b/internal/datasource/managers/manager.go
@@ -92,4 +92,4 @@ func (m *ConnectorManager) CloseAll(ctx context.Context) error {
}
return nil
-}
\ No newline at end of file
+}
diff --git a/internal/datasource/managers/query/query.go b/internal/datasource/managers/query/query.go
index 73d1d4c..3bdf9b6 100644
--- a/internal/datasource/managers/query/query.go
+++ b/internal/datasource/managers/query/query.go
@@ -22,13 +22,13 @@ const (
// Query represents a unified query structure
type Query struct {
- Type QueryType `json:"type"`
- Collection string `json:"collection"`
- Fields []string `json:"fields,omitempty"`
- Conditions map[string]interface{} `json:"conditions,omitempty"`
- Data map[string]interface{} `json:"data,omitempty"`
- Limit int `json:"limit,omitempty"`
- Offset int `json:"offset,omitempty"`
+ Type QueryType `json:"type"`
+ Collection string `json:"collection"`
+ Fields []string `json:"fields,omitempty"`
+ Conditions map[string]interface{} `json:"conditions,omitempty"`
+ Data map[string]interface{} `json:"data,omitempty"`
+ Limit int `json:"limit,omitempty"`
+ Offset int `json:"offset,omitempty"`
}
// QueryExecutor handles query execution across different connector types
@@ -70,34 +70,34 @@ func (qe *QueryExecutor) executeSQL(ctx context.Context, connector *connectors.S
}
func (qe *QueryExecutor) executeMongo(ctx context.Context, connector *connectors.MongoConnector, query Query) ([]map[string]interface{}, error) {
- switch query.Type {
- case Select:
- filterJSON, err := json.Marshal(query.Conditions)
- if err != nil {
- return nil, errors.NewError(errors.ErrorTypeQuery, "failed to marshal query conditions", err)
- }
- return connector.Query(ctx, string(filterJSON), query.Collection)
- case Insert:
- affected, err := connector.Execute(ctx, "insert", query.Collection, query.Data)
- if err != nil {
- return nil, err
- }
- return []map[string]interface{}{{"affected_documents": affected}}, nil
- case Update:
- affected, err := connector.Execute(ctx, "update", query.Collection, query.Conditions, query.Data)
- if err != nil {
- return nil, err
- }
- return []map[string]interface{}{{"affected_documents": affected}}, nil
- case Delete:
- affected, err := connector.Execute(ctx, "delete", query.Collection, query.Conditions)
- if err != nil {
- return nil, err
- }
- return []map[string]interface{}{{"affected_documents": affected}}, nil
- default:
- return nil, errors.NewError(errors.ErrorTypeUnsupported, "unsupported query type for MongoDB", nil)
- }
+ switch query.Type {
+ case Select:
+ filterJSON, err := json.Marshal(query.Conditions)
+ if err != nil {
+ return nil, errors.NewError(errors.ErrorTypeQuery, "failed to marshal query conditions", err)
+ }
+ return connector.Query(ctx, string(filterJSON), query.Collection)
+ case Insert:
+ affected, err := connector.Execute(ctx, "insert", query.Collection, query.Data)
+ if err != nil {
+ return nil, err
+ }
+ return []map[string]interface{}{{"affected_documents": affected}}, nil
+ case Update:
+ affected, err := connector.Execute(ctx, "update", query.Collection, query.Conditions, query.Data)
+ if err != nil {
+ return nil, err
+ }
+ return []map[string]interface{}{{"affected_documents": affected}}, nil
+ case Delete:
+ affected, err := connector.Execute(ctx, "delete", query.Collection, query.Conditions)
+ if err != nil {
+ return nil, err
+ }
+ return []map[string]interface{}{{"affected_documents": affected}}, nil
+ default:
+ return nil, errors.NewError(errors.ErrorTypeUnsupported, "unsupported query type for MongoDB", nil)
+ }
}
func (qe *QueryExecutor) executeRedis(ctx context.Context, connector *connectors.RedisConnector, query Query) ([]map[string]interface{}, error) {
@@ -196,4 +196,4 @@ func buildSQLQuery(query Query) (string, []interface{}) {
}
return sqlQuery.String(), args
-}
\ No newline at end of file
+}
diff --git a/internal/datasource/managers/transform/transform.go b/internal/datasource/managers/transform/transform.go
index d08b1e8..cdb3de3 100644
--- a/internal/datasource/managers/transform/transform.go
+++ b/internal/datasource/managers/transform/transform.go
@@ -45,11 +45,12 @@ type Transformer struct{}
// fmt.Printf("Name: %v\n", resultValue.FieldByName("Name").Interface())
// fmt.Printf("Age: %v\n", resultValue.FieldByName("Age").Interface())
-// // Access nested struct
-// address := resultValue.FieldByName("Address").Interface()
-// addressValue := reflect.ValueOf(address)
-// fmt.Printf("City: %v\n", addressValue.FieldByName("City").Interface())
-// fmt.Printf("Zip: %v\n", addressValue.FieldByName("Zip").Interface())
+// // Access nested struct
+// address := resultValue.FieldByName("Address").Interface()
+// addressValue := reflect.ValueOf(address)
+// fmt.Printf("City: %v\n", addressValue.FieldByName("City").Interface())
+// fmt.Printf("Zip: %v\n", addressValue.FieldByName("Zip").Interface())
+//
// ```
func NewTransformer() *Transformer {
return &Transformer{}
@@ -73,111 +74,111 @@ func (t *Transformer) TransformData(data interface{}, targetFormat string) (inte
// toStruct converts data to a struct using reflection
func (t *Transformer) toStruct(data interface{}) (interface{}, error) {
- dataValue := reflect.ValueOf(data)
- if dataValue.Kind() == reflect.Ptr {
- dataValue = dataValue.Elem()
- }
-
- switch dataValue.Kind() {
- case reflect.Struct:
- return data, nil // Already a struct
- case reflect.Map:
- return t.mapToStruct(dataValue)
- default:
- return nil, errors.NewError(errors.ErrorTypeTransformation, "unsupported data type for struct conversion", nil)
- }
+ dataValue := reflect.ValueOf(data)
+ if dataValue.Kind() == reflect.Ptr {
+ dataValue = dataValue.Elem()
+ }
+
+ switch dataValue.Kind() {
+ case reflect.Struct:
+ return data, nil // Already a struct
+ case reflect.Map:
+ return t.mapToStruct(dataValue)
+ default:
+ return nil, errors.NewError(errors.ErrorTypeTransformation, "unsupported data type for struct conversion", nil)
+ }
}
// mapToStruct converts a map to a struct
func (t *Transformer) mapToStruct(mapValue reflect.Value) (interface{}, error) {
- if mapValue.Kind() != reflect.Map {
- return nil, errors.NewError(errors.ErrorTypeTransformation, "input is not a map", nil)
- }
+ if mapValue.Kind() != reflect.Map {
+ return nil, errors.NewError(errors.ErrorTypeTransformation, "input is not a map", nil)
+ }
- structType := reflect.StructOf(t.mapToStructFields(mapValue))
- structValue := reflect.New(structType).Elem()
+ structType := reflect.StructOf(t.mapToStructFields(mapValue))
+ structValue := reflect.New(structType).Elem()
- for _, key := range mapValue.MapKeys() {
- fieldName := t.normalizeFieldName(key.String())
- fieldValue := mapValue.MapIndex(key)
+ for _, key := range mapValue.MapKeys() {
+ fieldName := t.normalizeFieldName(key.String())
+ fieldValue := mapValue.MapIndex(key)
- if structValue.FieldByName(fieldName).IsValid() {
- if err := t.setStructField(structValue.FieldByName(fieldName), fieldValue); err != nil {
- return nil, err
- }
- }
- }
+ if structValue.FieldByName(fieldName).IsValid() {
+ if err := t.setStructField(structValue.FieldByName(fieldName), fieldValue); err != nil {
+ return nil, err
+ }
+ }
+ }
- return structValue.Interface(), nil
+ return structValue.Interface(), nil
}
// mapToStructFields creates struct fields from a map
func (t *Transformer) mapToStructFields(mapValue reflect.Value) []reflect.StructField {
- var fields []reflect.StructField
-
- for _, key := range mapValue.MapKeys() {
- fieldName := t.normalizeFieldName(key.String())
- fieldValue := mapValue.MapIndex(key)
- fieldType := fieldValue.Type()
-
- // Handle nested maps
- if fieldValue.Kind() == reflect.Map {
- nestedFields := t.mapToStructFields(fieldValue)
- fieldType = reflect.StructOf(nestedFields)
- }
-
- fields = append(fields, reflect.StructField{
- Name: fieldName,
- Type: fieldType,
- })
- }
-
- return fields
+ var fields []reflect.StructField
+
+ for _, key := range mapValue.MapKeys() {
+ fieldName := t.normalizeFieldName(key.String())
+ fieldValue := mapValue.MapIndex(key)
+ fieldType := fieldValue.Type()
+
+ // Handle nested maps
+ if fieldValue.Kind() == reflect.Map {
+ nestedFields := t.mapToStructFields(fieldValue)
+ fieldType = reflect.StructOf(nestedFields)
+ }
+
+ fields = append(fields, reflect.StructField{
+ Name: fieldName,
+ Type: fieldType,
+ })
+ }
+
+ return fields
}
// setStructField sets the value of a struct field
func (t *Transformer) setStructField(field reflect.Value, value reflect.Value) error {
- if !field.CanSet() {
- return errors.NewError(errors.ErrorTypeTransformation, "cannot set field value", nil)
- }
-
- if field.Kind() == reflect.Struct && value.Kind() == reflect.Map {
- nestedStruct, err := t.mapToStruct(value)
- if err != nil {
- return err
- }
- field.Set(reflect.ValueOf(nestedStruct))
- return nil
- }
-
- if field.Type() != value.Type() {
- if value.Type().ConvertibleTo(field.Type()) {
- value = value.Convert(field.Type())
- } else {
- return errors.NewError(errors.ErrorTypeTransformation, "incompatible types for field assignment", nil)
- }
- }
-
- field.Set(value)
- return nil
+ if !field.CanSet() {
+ return errors.NewError(errors.ErrorTypeTransformation, "cannot set field value", nil)
+ }
+
+ if field.Kind() == reflect.Struct && value.Kind() == reflect.Map {
+ nestedStruct, err := t.mapToStruct(value)
+ if err != nil {
+ return err
+ }
+ field.Set(reflect.ValueOf(nestedStruct))
+ return nil
+ }
+
+ if field.Type() != value.Type() {
+ if value.Type().ConvertibleTo(field.Type()) {
+ value = value.Convert(field.Type())
+ } else {
+ return errors.NewError(errors.ErrorTypeTransformation, "incompatible types for field assignment", nil)
+ }
+ }
+
+ field.Set(value)
+ return nil
}
// normalizeFieldName converts a string to a valid Go struct field name
func (t *Transformer) normalizeFieldName(name string) string {
- // Capitalize the first letter
- name = strings.Title(name)
- // Remove any characters that are not letters, numbers, or underscores
- name = strings.Map(func(r rune) rune {
- if (r >= 'A' && r <= 'Z') || (r >= 'a' && r <= 'z') || (r >= '0' && r <= '9') || r == '_' {
- return r
- }
- return -1
- }, name)
- // Ensure the field name starts with a letter
- if len(name) > 0 && (name[0] >= '0' && name[0] <= '9') {
- name = "F" + name
- }
- return name
+ // Capitalize the first letter
+ name = strings.Title(name)
+ // Remove any characters that are not letters, numbers, or underscores
+ name = strings.Map(func(r rune) rune {
+ if (r >= 'A' && r <= 'Z') || (r >= 'a' && r <= 'z') || (r >= '0' && r <= '9') || r == '_' {
+ return r
+ }
+ return -1
+ }, name)
+ // Ensure the field name starts with a letter
+ if len(name) > 0 && (name[0] >= '0' && name[0] <= '9') {
+ name = "F" + name
+ }
+ return name
}
// toJSON converts data to JSON format
@@ -330,4 +331,4 @@ func (t *Transformer) UnflattenMap(data map[string]interface{}) map[string]inter
m[parts[len(parts)-1]] = v
}
return result
-}
\ No newline at end of file
+}
diff --git a/internal/datasource/managers/transform/utils.go b/internal/datasource/managers/transform/utils.go
index 32a217a..5bcc960 100644
--- a/internal/datasource/managers/transform/utils.go
+++ b/internal/datasource/managers/transform/utils.go
@@ -100,4 +100,4 @@ func FilterSlice(data []map[string]interface{}, condition func(map[string]interf
}
}
return result
-}
\ No newline at end of file
+}
diff --git a/internal/realtime/main.go b/internal/realtime/main.go
new file mode 100644
index 0000000..24963e5
--- /dev/null
+++ b/internal/realtime/main.go
@@ -0,0 +1,5 @@
+package main
+
+func main() {
+ println("Hello, world!")
+}
diff --git a/internal/report/main.go b/internal/report/main.go
new file mode 100644
index 0000000..24963e5
--- /dev/null
+++ b/internal/report/main.go
@@ -0,0 +1,5 @@
+package main
+
+func main() {
+ println("Hello, world!")
+}
diff --git a/internal/visualization/Dockerfile b/internal/visualization/Dockerfile
index cd7500b..64d7734 100644
--- a/internal/visualization/Dockerfile
+++ b/internal/visualization/Dockerfile
@@ -1 +1 @@
-FROM node:20
\ No newline at end of file
+FROM node:20
diff --git a/internal/visualization/api/handlers/visualization_handler.go b/internal/visualization/api/handlers/visualization_handler.go
index 28ae6f5..5ac8282 100644
--- a/internal/visualization/api/handlers/visualization_handler.go
+++ b/internal/visualization/api/handlers/visualization_handler.go
@@ -1 +1 @@
-package handlers
\ No newline at end of file
+package handlers
diff --git a/internal/visualization/api/proto/visualization.pb.go b/internal/visualization/api/proto/visualization.pb.go
index 8e94382..10f5713 100644
--- a/internal/visualization/api/proto/visualization.pb.go
+++ b/internal/visualization/api/proto/visualization.pb.go
@@ -7,10 +7,11 @@
package grpc
import (
- protoreflect "google.golang.org/protobuf/reflect/protoreflect"
- protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
+
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
)
const (
diff --git a/internal/visualization/api/proto/visualization.proto b/internal/visualization/api/proto/visualization.proto
index 6844b8a..aa8ca34 100644
--- a/internal/visualization/api/proto/visualization.proto
+++ b/internal/visualization/api/proto/visualization.proto
@@ -63,4 +63,4 @@ message DeleteVisualizationResponse {
message ExportVisualizationResponse {
bytes exported_data = 1;
string format = 2;
-}
\ No newline at end of file
+}
diff --git a/internal/visualization/api/proto/visualization_grpc.pb.go b/internal/visualization/api/proto/visualization_grpc.pb.go
index 9a4c480..61d7a21 100644
--- a/internal/visualization/api/proto/visualization_grpc.pb.go
+++ b/internal/visualization/api/proto/visualization_grpc.pb.go
@@ -8,6 +8,7 @@ package grpc
import (
context "context"
+
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
diff --git a/internal/visualization/cmd/server/main.go b/internal/visualization/cmd/server/main.go
index 85f0393..24963e5 100644
--- a/internal/visualization/cmd/server/main.go
+++ b/internal/visualization/cmd/server/main.go
@@ -1 +1,5 @@
-package main
\ No newline at end of file
+package main
+
+func main() {
+ println("Hello, world!")
+}
diff --git a/internal/visualization/data/client.go b/internal/visualization/data/client.go
index 6e9adc2..33dc2bb 100644
--- a/internal/visualization/data/client.go
+++ b/internal/visualization/data/client.go
@@ -5,9 +5,11 @@ import (
"encoding/json"
"fmt"
- "google.golang.org/grpc"
- pb "visualization/data/client"
"datasource/managers/query"
+ pb "visualization/data/client"
+
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/credentials/insecure"
)
// DataSourceClient is a gRPC client for the DataSource service
@@ -18,7 +20,7 @@ type DataSourceClient struct {
// NewDataSourceClient creates a new DataSourceClient
func NewDataSourceClient(address string) (*DataSourceClient, error) {
- conn, err := grpc.Dial(address, grpc.WithInsecure())
+ conn, err := grpc.NewClient(address, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
return nil, fmt.Errorf("failed to connect to DataSource service: %w", err)
}
@@ -133,4 +135,4 @@ func (c *DataSourceClient) RemoveConnector(ctx context.Context, name string) err
return fmt.Errorf("failed to remove connector: %s", resp.Error)
}
return nil
-}
\ No newline at end of file
+}
diff --git a/internal/visualization/data/client/connector.pb.go b/internal/visualization/data/client/connector.pb.go
index b43209b..8586875 100644
--- a/internal/visualization/data/client/connector.pb.go
+++ b/internal/visualization/data/client/connector.pb.go
@@ -7,10 +7,11 @@
package grpc
import (
- protoreflect "google.golang.org/protobuf/reflect/protoreflect"
- protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
+
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
)
const (
diff --git a/internal/visualization/data/client/connector_grpc.pb.go b/internal/visualization/data/client/connector_grpc.pb.go
index dfcdc0e..4283296 100644
--- a/internal/visualization/data/client/connector_grpc.pb.go
+++ b/internal/visualization/data/client/connector_grpc.pb.go
@@ -8,6 +8,7 @@ package grpc
import (
context "context"
+
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
diff --git a/internal/visualization/go.mod b/internal/visualization/go.mod
index 1206a54..c005fba 100644
--- a/internal/visualization/go.mod
+++ b/internal/visualization/go.mod
@@ -2,4 +2,24 @@ module visualization
go 1.21
-require github.com/go-echarts/go-echarts/v2 v2.4.0
+require (
+ github.com/go-echarts/go-echarts/v2 v2.4.0
+ github.com/google/uuid v1.6.0
+ go.uber.org/zap v1.21.0
+ google.golang.org/grpc v1.65.0
+ google.golang.org/protobuf v1.34.2
+)
+
+require (
+ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
+ github.com/pkg/errors v0.9.1 // indirect
+ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
+ github.com/stretchr/testify v1.9.0 // indirect
+ go.uber.org/atomic v1.9.0 // indirect
+ go.uber.org/multierr v1.9.0 // indirect
+ golang.org/x/net v0.25.0 // indirect
+ golang.org/x/sys v0.20.0 // indirect
+ golang.org/x/text v0.15.0 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 // indirect
+ gopkg.in/yaml.v2 v2.4.0 // indirect
+)
diff --git a/internal/visualization/go.sum b/internal/visualization/go.sum
index ab15134..7a9d5aa 100644
--- a/internal/visualization/go.sum
+++ b/internal/visualization/go.sum
@@ -1,2 +1,21 @@
+github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/go-echarts/go-echarts/v2 v2.4.0 h1:efD46dmAvaZEWrBHAGjE8cfDK48vvFTHz5N9VqW5rYc=
github.com/go-echarts/go-echarts/v2 v2.4.0/go.mod h1:56YlvzhW/a+du15f3S2qUGNDfKnFOeJSThBIrVFHDtI=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
+github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
+go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
+go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
+go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8=
+golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
+golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
+golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 h1:Zy9XzmMEflZ/MAaA7vNcoebnRAld7FsPW1EeBB7V0m8=
+google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
+google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
diff --git a/internal/visualization/internal/processor/aggregator.go b/internal/visualization/internal/processor/aggregator.go
index 163e23d..03d94d3 100644
--- a/internal/visualization/internal/processor/aggregator.go
+++ b/internal/visualization/internal/processor/aggregator.go
@@ -163,4 +163,4 @@ func (tp *TimeSeriesProcessor) getTimeBucketKey(t time.Time, interval string) st
// Close closes the DataSourceClient connection
func (dp *DataProcessor) Close() error {
return dp.dataSourceClient.Close()
-}
\ No newline at end of file
+}
diff --git a/internal/visualization/internal/processor/data_processor.go b/internal/visualization/internal/processor/data_processor.go
index ca0b2ef..0456d5b 100644
--- a/internal/visualization/internal/processor/data_processor.go
+++ b/internal/visualization/internal/processor/data_processor.go
@@ -1,4 +1,3 @@
-
package processor
import (
@@ -6,9 +5,9 @@ import (
"fmt"
"sort"
+ "datasource/managers/query"
pb "visualization/api/proto"
client "visualization/data"
- "datasource/managers/query"
)
// DataProcessor handles the processing of data for visualizations.
diff --git a/internal/visualization/internal/service/visualization_service.go b/internal/visualization/internal/service/visualization_service.go
index 52eebbe..95c0b26 100644
--- a/internal/visualization/internal/service/visualization_service.go
+++ b/internal/visualization/internal/service/visualization_service.go
@@ -166,7 +166,6 @@ type VisualizationStore interface {
List(ctx context.Context, page, pageSize int32) ([]*pb.VisualizationResponse, int32, error)
}
-
// VisualizationService implements the VisualizationService gRPC service.
type VisualizationService struct {
pb.UnimplementedVisualizationServiceServer
@@ -344,4 +343,4 @@ func (s *VisualizationService) ExportVisualization(ctx context.Context, req *pb.
// Close closes any resources held by the VisualizationService.
func (s *VisualizationService) Close() error {
return s.processor.Close()
-}
\ No newline at end of file
+}
diff --git a/internal/visualization/makefile b/internal/visualization/makefile
index 7b38a80..3d4a804 100644
--- a/internal/visualization/makefile
+++ b/internal/visualization/makefile
@@ -12,4 +12,4 @@ test:
proto:
protoc --go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
- api/proto/visualization.proto
\ No newline at end of file
+ api/proto/visualization.proto
diff --git a/internal/visualization/models/visualization.go b/internal/visualization/models/visualization.go
index 778a4c0..2640e7f 100644
--- a/internal/visualization/models/visualization.go
+++ b/internal/visualization/models/visualization.go
@@ -1 +1 @@
-package models
\ No newline at end of file
+package models
diff --git a/internal/visualization/pkg/colors/palette.go b/internal/visualization/pkg/colors/palette.go
index e89a813..7477042 100644
--- a/internal/visualization/pkg/colors/palette.go
+++ b/internal/visualization/pkg/colors/palette.go
@@ -1 +1 @@
-package colors
\ No newline at end of file
+package colors
diff --git a/internal/visualization/pkg/export/exporter.go b/internal/visualization/pkg/export/exporter.go
index 3477fc3..0fd21d2 100644
--- a/internal/visualization/pkg/export/exporter.go
+++ b/internal/visualization/pkg/export/exporter.go
@@ -1 +1 @@
-package export
\ No newline at end of file
+package export
diff --git a/internal/visualization/renderers/chart/bar_chart.go b/internal/visualization/renderers/chart/bar_chart.go
index 5690e56..58a733f 100644
--- a/internal/visualization/renderers/chart/bar_chart.go
+++ b/internal/visualization/renderers/chart/bar_chart.go
@@ -1 +1 @@
-package chart
\ No newline at end of file
+package chart
diff --git a/internal/visualization/renderers/graph/network_graph.go b/internal/visualization/renderers/graph/network_graph.go
index 8566596..e103ddd 100644
--- a/internal/visualization/renderers/graph/network_graph.go
+++ b/internal/visualization/renderers/graph/network_graph.go
@@ -1 +1 @@
-package graph
\ No newline at end of file
+package graph
diff --git a/internal/visualization/renderers/graph/tree_graph.go b/internal/visualization/renderers/graph/tree_graph.go
index 8566596..e103ddd 100644
--- a/internal/visualization/renderers/graph/tree_graph.go
+++ b/internal/visualization/renderers/graph/tree_graph.go
@@ -1 +1 @@
-package graph
\ No newline at end of file
+package graph
diff --git a/internal/visualization/renderers/mapStrucutre/choropleth.go b/internal/visualization/renderers/mapStrucutre/choropleth.go
index 8525c41..e48ff87 100644
--- a/internal/visualization/renderers/mapStrucutre/choropleth.go
+++ b/internal/visualization/renderers/mapStrucutre/choropleth.go
@@ -1 +1 @@
-package mapStrucutre
\ No newline at end of file
+package mapStrucutre
diff --git a/internal/visualization/renderers/mapStrucutre/point_map.go b/internal/visualization/renderers/mapStrucutre/point_map.go
index 8525c41..e48ff87 100644
--- a/internal/visualization/renderers/mapStrucutre/point_map.go
+++ b/internal/visualization/renderers/mapStrucutre/point_map.go
@@ -1 +1 @@
-package mapStrucutre
\ No newline at end of file
+package mapStrucutre
diff --git a/internal/visualization/renderers/renderers.go b/internal/visualization/renderers/renderers.go
index f55adaf..3bb99b0 100644
--- a/internal/visualization/renderers/renderers.go
+++ b/internal/visualization/renderers/renderers.go
@@ -187,9 +187,9 @@ func (spr *ScatterPlotRenderer) Render(data map[string]interface{}) (string, err
scatterData := make([]opts.ScatterData, 0, len(chartData))
for _, dataPoint := range chartData {
scatterData = append(scatterData, opts.ScatterData{
- Value: []interface{}{dataPoint[xMeasure], dataPoint[yMeasure]},
- Symbol: "circle",
- SymbolSize: 10,
+ Value: []interface{}{dataPoint[xMeasure], dataPoint[yMeasure]},
+ Symbol: "circle",
+ SymbolSize: 10,
// ItemStyle: &opts.ItemStyle{Color: "blue"},
SymbolRotate: 0,
})
@@ -262,4 +262,4 @@ func RendererFactory(visualizationType string) (Renderer, error) {
default:
return nil, fmt.Errorf("unsupported visualization type: %s", visualizationType)
}
-}
\ No newline at end of file
+}
diff --git a/makefile b/makefile
index 5a04c71..a84e31e 100644
--- a/makefile
+++ b/makefile
@@ -34,4 +34,4 @@ client-ssl:
openssl x509 -req -days 3653 -sha256 \
-CA ./certs/root.crt -CAkey /tmp/root.key -CAcreateserial \
-in /tmp/postgresql.csr \
- -out ./certs/postgresql.crt
\ No newline at end of file
+ -out ./certs/postgresql.crt
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..d4f714a
--- /dev/null
+++ b/package.json
@@ -0,0 +1,8 @@
+{
+ "devDependencies": {
+ "@typescript-eslint/eslint-plugin": "6.7.0",
+ "@typescript-eslint/parser": "6.7.0",
+ "eslint": "9.6.0",
+ "typescript": "5.2.2"
+ }
+}
diff --git a/pkg/common/encoder/base64.go b/pkg/common/encoder/base64.go
new file mode 100644
index 0000000..179b949
--- /dev/null
+++ b/pkg/common/encoder/base64.go
@@ -0,0 +1,49 @@
+package encoder
+
+import "encoding/base64"
+
+// Base64Encoder is a helper struct for encoding and decoding Base64 strings.
+type Base64Encoder struct{}
+
+// NewBase64Encoder creates a new Base64Encoder.
+//
+// Usage:
+//
+// encoder := NewBase64Encoder()
+func NewBase64Encoder() *Base64Encoder {
+ return &Base64Encoder{}
+}
+
+// Encode encodes a string to Base64.
+//
+// Parameters:
+// - data: The string to encode.
+//
+// Returns:
+// - The Base64 encoded string.
+//
+// Usage:
+//
+// encoded := encoder.Encode("Hello, World!")
+func (b *Base64Encoder) Encode(data string) string {
+ return base64.StdEncoding.EncodeToString([]byte(data))
+}
+
+// Decode decodes a Base64 string.
+//
+// Parameters:
+// - encodedData: The Base64 encoded string to decode.
+//
+// Returns:
+// - The decoded string and an error if decoding fails.
+//
+// Usage:
+//
+// decoded, err := encoder.Decode(encodedString)
+func (b *Base64Encoder) Decode(encodedData string) (string, error) {
+ data, err := base64.StdEncoding.DecodeString(encodedData)
+ if err != nil {
+ return "", err
+ }
+ return string(data), nil
+}
diff --git a/pkg/common/encoder/base64_test.go b/pkg/common/encoder/base64_test.go
new file mode 100644
index 0000000..697bd4c
--- /dev/null
+++ b/pkg/common/encoder/base64_test.go
@@ -0,0 +1,82 @@
+package encoder_test
+
+import (
+ "pkg/common/encoder"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestBase64Encoder(t *testing.T) {
+ t.Run("NewBase64Encoder", func(t *testing.T) {
+ enc := encoder.NewBase64Encoder()
+ assert.NotNil(t, enc, "NewBase64Encoder should return a non-nil encoder")
+ })
+
+ t.Run("Encode", func(t *testing.T) {
+ enc := encoder.NewBase64Encoder()
+ testCases := []struct {
+ input string
+ expected string
+ }{
+ {"Hello, World!", "SGVsbG8sIFdvcmxkIQ=="},
+ {"", ""},
+ {"1234567890", "MTIzNDU2Nzg5MA=="},
+ {"!@#$%^&*()", "IUAjJCVeJiooKQ=="},
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.input, func(t *testing.T) {
+ result := enc.Encode(tc.input)
+ assert.Equal(t, tc.expected, result, "Encode(%q) = %q; want %q", tc.input, result, tc.expected)
+ })
+ }
+ })
+
+ t.Run("Decode", func(t *testing.T) {
+ enc := encoder.NewBase64Encoder()
+ testCases := []struct {
+ input string
+ expected string
+ hasError bool
+ }{
+ {"SGVsbG8sIFdvcmxkIQ==", "Hello, World!", false},
+ {"", "", false},
+ {"MTIzNDU2Nzg5MA==", "1234567890", false},
+ {"IUAjJCVeJiooKQ==", "!@#$%^&*()", false},
+ {"Invalid Base64!", "", true},
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.input, func(t *testing.T) {
+ result, err := enc.Decode(tc.input)
+ if tc.hasError {
+ assert.Error(t, err, "Decode(%q) should return an error", tc.input)
+ } else {
+ assert.NoError(t, err, "Decode(%q) should not return an error", tc.input)
+ assert.Equal(t, tc.expected, result, "Decode(%q) = %q; want %q", tc.input, result, tc.expected)
+ }
+ })
+ }
+ })
+
+ t.Run("EncodeDecode", func(t *testing.T) {
+ enc := encoder.NewBase64Encoder()
+ testCases := []string{
+ "Hello, World!",
+ "",
+ "1234567890",
+ "!@#$%^&*()",
+ "This is a longer string with spaces and punctuation.",
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc, func(t *testing.T) {
+ encoded := enc.Encode(tc)
+ decoded, err := enc.Decode(encoded)
+ assert.NoError(t, err, "Decode(Encode(%q)) should not return an error", tc)
+ assert.Equal(t, tc, decoded, "Decode(Encode(%q)) = %q; want %q", tc, decoded, tc)
+ })
+ }
+ })
+}
diff --git a/pkg/common/errors/error.go b/pkg/common/errors/error.go
index 2cc0d9f..7233962 100644
--- a/pkg/common/errors/error.go
+++ b/pkg/common/errors/error.go
@@ -1,80 +1,94 @@
-// Package errors provide custom error types and error checking functions
+// Package errors provides custom error types and error checking functions
// for common error scenarios in the DataVinci project.
package errors
import (
+ "context"
"errors"
"fmt"
"net"
+ "runtime"
"strings"
)
// ErrorType represents the type of error.
type ErrorType uint
-// ErrorMessages maps error types to human-readable messages.
-var ErrorMessages = map[ErrorType]string{
- ErrorTypeUnknown: "unknown",
- ErrorTypeDatabaseConnection: "database connection not established",
- ErrorTypeTimeout: "timeout",
- ErrorTypePermission: "permission",
- ErrorTypeQuery: "query",
- ErrorTypeExecution: "execution",
- ErrorTypeTransaction: "transaction",
- ErrorTypeConfiguration: "configuration",
- ErrorTypeApiConnection: "api connection",
- ErrorTypeUnsupported: "unsupported",
- ErrorTypeFileConnection: "file connection",
- ErrorTypeNotFound: "not found",
- ErrorTypeConnection : "connection",
- ErrorTypeTransformation: "transformation",
-}
-
const (
- // ErrorTypeUnknown represents an unknown error.
ErrorTypeUnknown ErrorType = iota
- // ErrorTypeDatabaseConnection represents a connection error.
ErrorTypeDatabaseConnection
- // ErrorTypeTimeout represents a timeout error.
ErrorTypeTimeout
- // ErrorTypePermission represents a permission error.
ErrorTypePermission
- // ErrorTypeQuery represents a query error.
ErrorTypeQuery
- // ErrorTypeExecution represents an execution error.
ErrorTypeExecution
- // ErrorTypeTransaction represents a transaction error.
ErrorTypeTransaction
- // ErrorTypeConfiguration represents a configuration error.
ErrorTypeConfiguration
- // ErrorTypeApiConnection represents an API connection error.
- ErrorTypeApiConnection
- // ErrorTypeUnsupported represents an unsupported operation error.
+ ErrorTypeAPIConnection
ErrorTypeUnsupported
- // ErrorTypeFileConnection represents a file connection error.
ErrorTypeFileConnection
- // ErrorTypeNotFound represents a not found error.
ErrorTypeNotFound
- // ErrorTypeConnection represents a connection error.
ErrorTypeConnection
- // ErrorTypeTransformation represents a transformation error.
ErrorTypeTransformation
+ ErrorTypeEmptyPassword
+ ErrorTypeInvalidCost
+ ErrorTypeValidation
+ ErrorTypeResourceExhausted
+ ErrorTypeDataIntegrity
)
+// ErrorMessages maps error types to human-readable messages.
+var ErrorMessages = map[ErrorType]string{
+ ErrorTypeUnknown: "Unknown error occurred",
+ ErrorTypeDatabaseConnection: "Database connection not established",
+ ErrorTypeTimeout: "Operation timed out",
+ ErrorTypePermission: "Permission denied",
+ ErrorTypeQuery: "Query execution failed",
+ ErrorTypeExecution: "Execution error",
+ ErrorTypeTransaction: "Transaction error",
+ ErrorTypeConfiguration: "Configuration error",
+ ErrorTypeAPIConnection: "API connection failed",
+ ErrorTypeUnsupported: "Unsupported operation",
+ ErrorTypeFileConnection: "File connection error",
+ ErrorTypeNotFound: "Resource not found",
+ ErrorTypeConnection: "Connection error",
+ ErrorTypeTransformation: "Data transformation error",
+ ErrorTypeEmptyPassword: "Empty password provided",
+ ErrorTypeInvalidCost: "Invalid bcrypt cost",
+ ErrorTypeValidation: "Validation error",
+ ErrorTypeResourceExhausted: "Resource exhausted",
+ ErrorTypeDataIntegrity: "Data integrity violation",
+}
+
+// GetErrorMessage returns the error message for a given ErrorType.
+// If the ErrorType is not found in ErrorMessages, it returns a default message.
+func GetErrorMessage(errType ErrorType) string {
+ if msg, ok := ErrorMessages[errType]; ok {
+ return msg
+ }
+ return fmt.Sprintf("Unknown error type (%d)", errType)
+}
+
// Error represents a custom error with additional context.
type Error struct {
- Type ErrorType // The type of the error
- Message string // A human-readable error message
- Err error // The underlying error, if any
+ Type ErrorType // The type of the error
+ Message string // A human-readable error message
+ Err error // The underlying error, if any
+ Cause error // The cause of the error, if any
+ Stack string // The stack trace of the error
+ Context map[string]string // Additional context for the error
}
// Error returns the error message.
// It implements the error interface.
func (e *Error) Error() string {
+ message := e.Message
+ if message == "" {
+ message = GetErrorMessage(e.Type)
+ }
if e.Err != nil {
- return fmt.Sprintf("%s: %v", e.Message, e.Err)
+ return fmt.Sprintf("%s: %v", message, e.Err)
}
- return e.Message
+ return message
}
// Unwrap returns the wrapped error.
@@ -83,49 +97,130 @@ func (e *Error) Unwrap() error {
return e.Err
}
+// Is checks if the given error is of the given type.
+// It allows Error to work with errors.Is and errors.As.
+func (e *Error) Is(target error) bool {
+ if target == nil {
+ return false
+ }
+ t, ok := target.(*Error)
+ if !ok {
+ return errors.Is(e.Err, target)
+ }
+ return e.Type == t.Type
+}
+
// NewError creates a new Error with the given type, message, and underlying error.
func NewError(errType ErrorType, message string, err error) *Error {
- return &Error{
+ return NewErrorWithContext(errType, message, err, nil)
+}
+
+// NewErrorWithContext creates a new Error with the given type, message, underlying error, and context.
+func NewErrorWithContext(errType ErrorType, message string, err error, context map[string]string) *Error {
+ if message == "" {
+ message = GetErrorMessage(errType)
+ }
+ newError := &Error{
Type: errType,
Message: message,
Err: err,
+ Cause: err,
+ Context: context,
}
+
+ var sb strings.Builder
+ for i := 1; ; i++ {
+ pc, file, line, ok := runtime.Caller(i)
+ if !ok {
+ break
+ }
+ fn := runtime.FuncForPC(pc)
+ sb.WriteString(fmt.Sprintf("%s:%d %s\n", file, line, fn.Name()))
+ }
+ newError.Stack = sb.String()
+
+ return newError
+}
+
+// IsErrorType checks if the error is of the given type.
+func IsErrorType(err error, errType ErrorType) bool {
+ var customErr *Error
+ if errors.As(err, &customErr) {
+ return customErr.Type == errType
+ }
+ return false
}
// IsConnectionError checks if the given error is a connection error.
-// It returns true for custom Error types with ErrorTypeConnection,
-// or for standard library network errors.
func IsConnectionError(err error) bool {
+ if err == nil {
+ return false
+ }
var e *Error
if errors.As(err, &e) {
- return e.Type == ErrorTypeDatabaseConnection
+ return e.Type == ErrorTypeDatabaseConnection || e.Type == ErrorTypeConnection || e.Type == ErrorTypeAPIConnection
}
- return isNetworkError(err)
+ var netErr *net.OpError
+ var dnsErr *net.DNSError
+ return errors.As(err, &netErr) || errors.As(err, &dnsErr) || isNetworkError(err)
}
// IsTimeoutError checks if the given error is a timeout error.
-// It returns true for custom Error types with ErrorTypeTimeout,
-// or for errors that contain "timeout" in their message.
func IsTimeoutError(err error) bool {
+ if err == nil {
+ return false
+ }
var e *Error
if errors.As(err, &e) {
return e.Type == ErrorTypeTimeout
}
- return isNetworkError(err) && strings.Contains(strings.ToLower(err.Error()), ErrorMessages[ErrorTypeTimeout])
+ var netErr *net.OpError
+ if errors.As(err, &netErr) {
+ return netErr.Timeout()
+ }
+ return errors.Is(err, context.DeadlineExceeded) ||
+ strings.Contains(strings.ToLower(err.Error()), "timeout") ||
+ strings.Contains(strings.ToLower(err.Error()), "deadline exceeded")
}
// IsPermissionError checks if the given error is a permission error.
-// It returns true for custom Error types with ErrorTypePermission,
-// or for errors that contain "permission" in their message.
func IsPermissionError(err error) bool {
+ if err == nil {
+ return false
+ }
var e *Error
if errors.As(err, &e) {
return e.Type == ErrorTypePermission
}
- return strings.Contains(strings.ToLower(err.Error()), ErrorMessages[ErrorTypePermission])
+ errLower := strings.ToLower(err.Error())
+ return strings.Contains(errLower, "permission") ||
+ strings.Contains(errLower, "access denied")
}
// isNetworkError checks if the error is a known network error.
func isNetworkError(err error) bool {
return errors.Is(err, net.ErrClosed) || errors.Is(err, net.ErrWriteToConnected)
}
+
+// AddErrorContext adds additional context to an existing Error.
+func AddErrorContext(err *Error, key, value string) *Error {
+ if err.Context == nil {
+ err.Context = make(map[string]string)
+ }
+ err.Context[key] = value
+ return err
+}
+
+// GetErrorContext retrieves the context from an Error.
+func GetErrorContext(err error) map[string]string {
+ var e *Error
+ if errors.As(err, &e) {
+ return e.Context
+ }
+ return nil
+}
+
+// WrapError wraps an existing error with a new Error type and message.
+func WrapError(err error, errType ErrorType, message string) *Error {
+ return NewError(errType, message, err)
+}
diff --git a/pkg/common/errors/error_test.go b/pkg/common/errors/error_test.go
index d8a8898..6b48710 100644
--- a/pkg/common/errors/error_test.go
+++ b/pkg/common/errors/error_test.go
@@ -1,9 +1,17 @@
-package errors
+package errors_test
import (
+ "context"
"errors"
+ "fmt"
"net"
+ "os"
"testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ . "pkg/common/errors"
)
func TestIsConnectionError(t *testing.T) {
@@ -14,14 +22,18 @@ func TestIsConnectionError(t *testing.T) {
}{
{"Connection error", NewError(ErrorTypeDatabaseConnection, "connection failed", nil), true},
{"Network error", net.ErrClosed, true},
+ {"DNS error", &net.DNSError{Err: "no such host", Name: "example.com"}, true},
+ {"Dial error", &net.OpError{Op: "dial", Err: fmt.Errorf("connection refused")}, true},
+ {"Timeout error", NewError(ErrorTypeTimeout, "operation timed out", nil), false},
+ {"Permission error", NewError(ErrorTypePermission, "access denied", nil), false},
{"Other error", errors.New("some error"), false},
+ {"Nil error", nil, false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- if got := IsConnectionError(tt.err); got != tt.want {
- t.Errorf("IsConnectionError() = %v, want %v", got, tt.want)
- }
+ got := IsConnectionError(tt.err)
+ assert.Equal(t, tt.want, got, "IsConnectionError() = %v, want %v", got, tt.want)
})
}
}
@@ -33,15 +45,19 @@ func TestIsTimeoutError(t *testing.T) {
want bool
}{
{"Timeout error", NewError(ErrorTypeTimeout, "operation timed out", nil), true},
- {"Network timeout", errors.New("i/o timeout"), true},
+ {"Network timeout", &net.OpError{Op: "read", Err: os.ErrDeadlineExceeded}, true},
+ {"Context deadline exceeded", context.DeadlineExceeded, true},
+ {"I/O timeout string", errors.New("i/o timeout"), true},
+ {"Connection error", NewError(ErrorTypeDatabaseConnection, "connection failed", nil), false},
+ {"Permission error", NewError(ErrorTypePermission, "access denied", nil), false},
{"Other error", errors.New("some error"), false},
+ {"Nil error", nil, false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- if got := IsTimeoutError(tt.err); got != tt.want {
- t.Errorf("IsTimeoutError() = %v, want %v", got, tt.want)
- }
+ got := IsTimeoutError(tt.err)
+ assert.Equal(t, tt.want, got, "IsTimeoutError() = %v, want %v", got, tt.want)
})
}
}
@@ -54,14 +70,248 @@ func TestIsPermissionError(t *testing.T) {
}{
{"Permission error", NewError(ErrorTypePermission, "access denied", nil), true},
{"Permission string", errors.New("permission denied"), true},
+ {"OS permission denied", os.ErrPermission, true},
+ {"Access denied string", errors.New("access denied"), true},
+ {"Connection error", NewError(ErrorTypeDatabaseConnection, "connection failed", nil), false},
+ {"Timeout error", NewError(ErrorTypeTimeout, "operation timed out", nil), false},
{"Other error", errors.New("some error"), false},
+ {"Nil error", nil, false},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got := IsPermissionError(tt.err)
+ assert.Equal(t, tt.want, got, "IsPermissionError() = %v, want %v", got, tt.want)
+ })
+ }
+}
+
+func TestErrorIs(t *testing.T) {
+ baseErr := errors.New("base error")
+ tests := []struct {
+ name string
+ err *Error
+ target error
+ want bool
+ }{
+ {"Equal error", NewError(ErrorTypeDatabaseConnection, "connection failed", nil), NewError(ErrorTypeDatabaseConnection, "connection failed", nil), true},
+ {"Different error", NewError(ErrorTypeDatabaseConnection, "connection failed", nil), NewError(ErrorTypePermission, "access denied", nil), false},
+ {"Same type, different message", NewError(ErrorTypeDatabaseConnection, "connection failed", nil), NewError(ErrorTypeDatabaseConnection, "connection error", nil), true},
+ {"With wrapped error", NewError(ErrorTypeDatabaseConnection, "connection failed", baseErr), baseErr, true},
+ {"Different wrapped error", NewError(ErrorTypeDatabaseConnection, "connection failed", baseErr), errors.New("other error"), false},
+ {"Nil target", NewError(ErrorTypeDatabaseConnection, "connection failed", nil), nil, false},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got := errors.Is(tt.err, tt.target)
+ assert.Equal(t, tt.want, got, "errors.Is() = %v, want %v", got, tt.want)
+ })
+ }
+}
+
+func TestErrorUnwrap(t *testing.T) {
+ baseErr := errors.New("base error")
+ tests := []struct {
+ name string
+ err *Error
+ want error
+ }{
+ {"Nil wrapped error", NewError(ErrorTypeDatabaseConnection, "connection failed", nil), nil},
+ {"With wrapped error", NewError(ErrorTypeDatabaseConnection, "connection failed", baseErr), baseErr},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got := tt.err.Unwrap()
+ assert.Equal(t, tt.want, got, "Error.Unwrap() = %v, want %v", got, tt.want)
+ })
+ }
+}
+
+func TestErrorError(t *testing.T) {
+ tests := []struct {
+ name string
+ err *Error
+ want string
+ wantErr bool
+ }{
+ {"Simple error", NewError(ErrorTypeDatabaseConnection, "connection failed", nil), "connection failed", false},
+ {"Error with type, no custom message", NewError(ErrorTypePermission, "", nil), "Permission denied", false},
+ {"Error with wrapped error", NewError(ErrorTypeTimeout, "operation timed out", errors.New("underlying error")), "operation timed out: underlying error", false},
+ {"Error with type, no custom message, with wrapped error", NewError(ErrorTypeTimeout, "", errors.New("underlying error")), "Operation timed out: underlying error", false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- if got := IsPermissionError(tt.err); got != tt.want {
- t.Errorf("IsPermissionError() = %v, want %v", got, tt.want)
+ got := tt.err.Error()
+ assert.Equal(t, tt.want, got, "Error.Error() = %v, want %v", got, tt.want)
+ })
+ }
+}
+
+func TestNewError(t *testing.T) {
+ baseErr := errors.New("base error")
+ tests := []struct {
+ name string
+ errType ErrorType
+ message string
+ cause error
+ }{
+ {"Connection error with custom message", ErrorTypeDatabaseConnection, "custom connection failed", nil},
+ {"Timeout error with cause, no custom message", ErrorTypeTimeout, "", baseErr},
+ {"Permission error with default message", ErrorTypePermission, "", nil},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ err := NewError(tt.errType, tt.message, tt.cause)
+ require.NotNil(t, err)
+ assert.Equal(t, tt.errType, err.Type)
+ if tt.message != "" {
+ assert.Equal(t, tt.message, err.Message)
+ } else {
+ assert.Equal(t, GetErrorMessage(tt.errType), err.Message)
}
+ assert.Equal(t, tt.cause, err.Cause)
+ })
+ }
+}
+
+func TestErrorWithStack(t *testing.T) {
+ err := NewError(ErrorTypeDatabaseConnection, "connection failed", nil)
+ assert.NotEmpty(t, err.Stack, "Error stack should not be empty")
+}
+
+func TestErrorAs(t *testing.T) {
+ var target *Error
+ err := NewError(ErrorTypeDatabaseConnection, "connection failed", nil)
+
+ assert.True(t, errors.As(err, &target))
+ assert.Equal(t, err, target)
+
+ var notTarget *net.OpError
+ assert.False(t, errors.As(err, ¬Target))
+}
+
+func TestIsErrorType(t *testing.T) {
+ tests := []struct {
+ name string
+ err error
+ errType ErrorType
+ expected bool
+ }{
+ {"Matching type", NewError(ErrorTypeDatabaseConnection, "connection failed", nil), ErrorTypeDatabaseConnection, true},
+ {"Non-matching type", NewError(ErrorTypeTimeout, "operation timed out", nil), ErrorTypeDatabaseConnection, false},
+ {"Non-custom error", errors.New("some error"), ErrorTypeDatabaseConnection, false},
+ {"Nil error", nil, ErrorTypeDatabaseConnection, false},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ result := IsErrorType(tt.err, tt.errType)
+ assert.Equal(t, tt.expected, result)
+ })
+ }
+}
+
+func TestGetErrorContext(t *testing.T) {
+ context := map[string]string{"server": "db01", "retry": "3"}
+ err := NewErrorWithContext(ErrorTypeDatabaseConnection, "connection failed", nil, context)
+
+ tests := []struct {
+ name string
+ err error
+ want map[string]string
+ }{
+ {"Get context from Error", err, context},
+ {"Get context from non-Error", errors.New("some error"), nil},
+ {"Get context from nil", nil, nil},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got := GetErrorContext(tt.err)
+ assert.Equal(t, tt.want, got)
+ })
+ }
+}
+
+func TestWrapError(t *testing.T) {
+ baseErr := errors.New("base error")
+
+ tests := []struct {
+ name string
+ err error
+ errType ErrorType
+ message string
+ }{
+ {"Wrap base error", baseErr, ErrorTypeDatabaseConnection, "connection failed"},
+ {"Wrap nil error", nil, ErrorTypeTimeout, "operation timed out"},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ wrapped := WrapError(tt.err, tt.errType, tt.message)
+ assert.Equal(t, tt.errType, wrapped.Type)
+ assert.Equal(t, tt.message, wrapped.Message)
+ assert.Equal(t, tt.err, wrapped.Cause)
+ })
+ }
+}
+
+func TestErrorTypeString(t *testing.T) {
+ tests := []struct {
+ name string
+ errType ErrorType
+ expected string
+ }{
+ {"Unknown error", ErrorTypeUnknown, "Unknown error occurred"},
+ {"Database connection error", ErrorTypeDatabaseConnection, "Database connection not established"},
+ {"Timeout error", ErrorTypeTimeout, "Operation timed out"},
+ {"Non-existent error type", ErrorType(9999), "Unknown error type (9999)"},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ assert.Equal(t, tt.expected, GetErrorMessage(tt.errType))
+ })
+ }
+}
+func TestErrorStack(t *testing.T) {
+ err := NewError(ErrorTypeDatabaseConnection, "connection failed", nil)
+
+ assert.NotEmpty(t, err.Stack)
+ assert.Contains(t, err.Stack, "errors_test.TestErrorStack")
+ assert.Contains(t, err.Stack, "error_test.go")
+}
+
+func TestErrorString(t *testing.T) {
+ tests := []struct {
+ name string
+ err *Error
+ expected string
+ }{
+ {
+ name: "Error without underlying error",
+ err: NewError(ErrorTypeTimeout, "", nil),
+ expected: "Operation timed out",
+ },
+ {
+ name: "Error with underlying error",
+ err: NewError(ErrorTypeDatabaseConnection, "", fmt.Errorf("connection refused")),
+ expected: "Database connection not established: connection refused",
+ },
+ {
+ name: "Unknown error type",
+ err: NewError(ErrorType(9999), "", nil),
+ expected: "Unknown error type (9999)",
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ assert.Equal(t, tt.expected, tt.err.Error())
})
}
}
diff --git a/pkg/config/config.go b/pkg/config/config.go
index 73de0a7..7aa4a44 100644
--- a/pkg/config/config.go
+++ b/pkg/config/config.go
@@ -1,30 +1,30 @@
package config
import (
- "github.com/spf13/viper"
+ "github.com/spf13/viper"
)
type Config struct {
- DatabaseURL string
- AuthServiceAddr string
- AuthzServiceAddr string
- JWTSecret string
+ DatabaseURL string
+ AuthServiceAddr string
+ AuthzServiceAddr string
+ JWTSecret string
}
func Load() (*Config, error) {
- viper.SetConfigName("config")
- viper.SetConfigType("yaml")
- viper.AddConfigPath(".")
- viper.AddConfigPath("./config")
+ viper.SetConfigName("config")
+ viper.SetConfigType("yaml")
+ viper.AddConfigPath(".")
+ viper.AddConfigPath("./config")
- if err := viper.ReadInConfig(); err != nil {
- return nil, err
- }
+ if err := viper.ReadInConfig(); err != nil {
+ return nil, err
+ }
- var cfg Config
- if err := viper.Unmarshal(&cfg); err != nil {
- return nil, err
- }
+ var cfg Config
+ if err := viper.Unmarshal(&cfg); err != nil {
+ return nil, err
+ }
- return &cfg, nil
-}
\ No newline at end of file
+ return &cfg, nil
+}
diff --git a/pkg/config/config.yaml b/pkg/config/config.yaml
new file mode 100644
index 0000000..fdd6fe7
--- /dev/null
+++ b/pkg/config/config.yaml
@@ -0,0 +1,8 @@
+JWTSecret:
+ value: "secret"
+DatabaseURL:
+ value: "postgres://postgres:password@localhost:5432/postgres"
+AuthServiceAddress:
+ value: "localhost:8080"
+AuthzServiceAddress:
+ value: "localhost:8081"
diff --git a/pkg/coverage.txt b/pkg/coverage.txt
new file mode 100644
index 0000000..c2de1cd
--- /dev/null
+++ b/pkg/coverage.txt
@@ -0,0 +1,7270 @@
+mode: atomic
+auth/ent/client.go:38.40,42.2 3 0
+auth/ent/client.go:44.25,49.2 4 0
+auth/ent/client.go:70.39,74.2 3 0
+auth/ent/client.go:77.42,78.27 1 0
+auth/ent/client.go:78.27,80.3 1 0
+auth/ent/client.go:81.2,81.13 1 0
+auth/ent/client.go:81.13,83.3 1 0
+auth/ent/client.go:87.21,88.25 1 0
+auth/ent/client.go:88.25,90.3 1 0
+auth/ent/client.go:94.34,95.25 1 0
+auth/ent/client.go:95.25,97.3 1 0
+auth/ent/client.go:101.43,102.25 1 0
+auth/ent/client.go:102.25,104.3 1 0
+auth/ent/client.go:110.82,111.20 1 0
+auth/ent/client.go:112.55,114.17 2 0
+auth/ent/client.go:114.17,116.4 1 0
+auth/ent/client.go:117.3,117.57 1 0
+auth/ent/client.go:118.10,119.63 1 0
+auth/ent/client.go:128.55,129.39 1 0
+auth/ent/client.go:129.39,131.3 1 0
+auth/ent/client.go:132.2,133.16 2 0
+auth/ent/client.go:133.16,135.3 1 0
+auth/ent/client.go:136.2,144.8 3 0
+auth/ent/client.go:148.81,149.39 1 0
+auth/ent/client.go:149.39,151.3 1 0
+auth/ent/client.go:152.2,155.16 2 0
+auth/ent/client.go:155.16,157.3 1 0
+auth/ent/client.go:158.2,166.8 3 0
+auth/ent/client.go:175.34,176.13 1 0
+auth/ent/client.go:176.13,178.3 1 0
+auth/ent/client.go:179.2,183.15 5 0
+auth/ent/client.go:187.32,189.2 1 0
+auth/ent/client.go:193.37,197.2 3 0
+auth/ent/client.go:201.57,205.2 3 0
+auth/ent/client.go:208.73,209.23 1 0
+auth/ent/client.go:210.21,211.31 1 0
+auth/ent/client.go:212.22,213.32 1 0
+auth/ent/client.go:214.21,215.31 1 0
+auth/ent/client.go:216.10,217.61 1 0
+auth/ent/client.go:227.42,229.2 1 0
+auth/ent/client.go:233.41,235.2 1 0
+auth/ent/client.go:239.61,241.2 1 0
+auth/ent/client.go:244.43,247.2 2 0
+auth/ent/client.go:250.74,252.2 1 0
+auth/ent/client.go:256.95,258.32 2 0
+auth/ent/client.go:258.32,260.3 1 0
+auth/ent/client.go:261.2,262.32 2 0
+auth/ent/client.go:262.32,265.3 2 0
+auth/ent/client.go:266.2,266.62 1 0
+auth/ent/client.go:270.43,273.2 2 0
+auth/ent/client.go:276.56,279.2 2 0
+auth/ent/client.go:282.60,285.2 2 0
+auth/ent/client.go:288.43,291.2 2 0
+auth/ent/client.go:294.56,296.2 1 0
+auth/ent/client.go:299.60,304.2 4 0
+auth/ent/client.go:307.41,313.2 1 0
+auth/ent/client.go:316.73,318.2 1 0
+auth/ent/client.go:321.65,323.16 2 0
+auth/ent/client.go:323.16,324.13 1 0
+auth/ent/client.go:326.2,326.12 1 0
+auth/ent/client.go:330.53,332.68 2 0
+auth/ent/client.go:332.68,341.3 4 0
+auth/ent/client.go:342.2,342.14 1 0
+auth/ent/client.go:346.37,348.2 1 0
+auth/ent/client.go:351.51,353.2 1 0
+auth/ent/client.go:355.82,356.16 1 0
+auth/ent/client.go:357.16,358.82 1 0
+auth/ent/client.go:359.16,360.82 1 0
+auth/ent/client.go:361.19,362.85 1 0
+auth/ent/client.go:363.29,364.82 1 0
+auth/ent/client.go:365.10,366.70 1 0
+auth/ent/client.go:376.44,378.2 1 0
+auth/ent/client.go:382.42,384.2 1 0
+auth/ent/client.go:388.62,390.2 1 0
+auth/ent/client.go:393.45,396.2 2 0
+auth/ent/client.go:399.77,401.2 1 0
+auth/ent/client.go:405.98,407.32 2 0
+auth/ent/client.go:407.32,409.3 1 0
+auth/ent/client.go:410.2,411.32 2 0
+auth/ent/client.go:411.32,414.3 2 0
+auth/ent/client.go:415.2,415.63 1 0
+auth/ent/client.go:419.45,422.2 2 0
+auth/ent/client.go:425.59,428.2 2 0
+auth/ent/client.go:431.62,434.2 2 0
+auth/ent/client.go:437.45,440.2 2 0
+auth/ent/client.go:443.59,445.2 1 0
+auth/ent/client.go:448.62,453.2 4 0
+auth/ent/client.go:456.43,462.2 1 0
+auth/ent/client.go:465.75,467.2 1 0
+auth/ent/client.go:470.67,472.16 2 0
+auth/ent/client.go:472.16,473.13 1 0
+auth/ent/client.go:475.2,475.12 1 0
+auth/ent/client.go:479.54,481.68 2 0
+auth/ent/client.go:481.68,490.3 4 0
+auth/ent/client.go:491.2,491.14 1 0
+auth/ent/client.go:495.38,497.2 1 0
+auth/ent/client.go:500.52,502.2 1 0
+auth/ent/client.go:504.84,505.16 1 0
+auth/ent/client.go:506.16,507.83 1 0
+auth/ent/client.go:508.16,509.83 1 0
+auth/ent/client.go:510.19,511.86 1 0
+auth/ent/client.go:512.29,513.83 1 0
+auth/ent/client.go:514.10,515.71 1 0
+auth/ent/client.go:525.42,527.2 1 0
+auth/ent/client.go:531.41,533.2 1 0
+auth/ent/client.go:537.61,539.2 1 0
+auth/ent/client.go:542.43,545.2 2 0
+auth/ent/client.go:548.74,550.2 1 0
+auth/ent/client.go:554.95,556.32 2 0
+auth/ent/client.go:556.32,558.3 1 0
+auth/ent/client.go:559.2,560.32 2 0
+auth/ent/client.go:560.32,563.3 2 0
+auth/ent/client.go:564.2,564.62 1 0
+auth/ent/client.go:568.43,571.2 2 0
+auth/ent/client.go:574.56,577.2 2 0
+auth/ent/client.go:580.60,583.2 2 0
+auth/ent/client.go:586.43,589.2 2 0
+auth/ent/client.go:592.56,594.2 1 0
+auth/ent/client.go:597.60,602.2 4 0
+auth/ent/client.go:605.41,611.2 1 0
+auth/ent/client.go:614.73,616.2 1 0
+auth/ent/client.go:619.65,621.16 2 0
+auth/ent/client.go:621.16,622.13 1 0
+auth/ent/client.go:624.2,624.12 1 0
+auth/ent/client.go:628.53,630.68 2 0
+auth/ent/client.go:630.68,639.3 4 0
+auth/ent/client.go:640.2,640.14 1 0
+auth/ent/client.go:644.55,646.68 2 0
+auth/ent/client.go:646.68,655.3 4 0
+auth/ent/client.go:656.2,656.14 1 0
+auth/ent/client.go:660.37,663.2 2 0
+auth/ent/client.go:666.51,668.2 1 0
+auth/ent/client.go:670.82,671.16 1 0
+auth/ent/client.go:672.16,673.82 1 0
+auth/ent/client.go:674.16,675.82 1 0
+auth/ent/client.go:676.19,677.85 1 0
+auth/ent/client.go:678.29,679.82 1 0
+auth/ent/client.go:680.10,681.70 1 0
+auth/ent/ent.go:42.47,45.2 2 0
+auth/ent/ent.go:48.68,50.2 1 0
+auth/ent/ent.go:55.45,58.2 2 0
+auth/ent/ent.go:61.67,63.2 1 0
+auth/ent/ent.go:75.46,76.22 1 0
+auth/ent/ent.go:76.22,82.3 1 0
+auth/ent/ent.go:83.2,83.35 1 0
+auth/ent/ent.go:87.48,88.31 1 0
+auth/ent/ent.go:88.31,89.28 1 0
+auth/ent/ent.go:89.28,90.56 1 0
+auth/ent/ent.go:90.56,92.5 1 0
+auth/ent/ent.go:93.4,93.30 1 0
+auth/ent/ent.go:99.49,100.31 1 0
+auth/ent/ent.go:100.31,101.28 1 0
+auth/ent/ent.go:101.28,102.56 1 0
+auth/ent/ent.go:102.56,104.5 1 0
+auth/ent/ent.go:105.4,105.31 1 0
+auth/ent/ent.go:118.53,119.38 1 0
+auth/ent/ent.go:119.38,121.3 1 0
+auth/ent/ent.go:125.28,126.38 1 0
+auth/ent/ent.go:126.38,128.3 1 0
+auth/ent/ent.go:132.38,133.38 1 0
+auth/ent/ent.go:133.38,134.59 1 0
+auth/ent/ent.go:134.59,137.4 2 0
+auth/ent/ent.go:138.3,138.29 1 0
+auth/ent/ent.go:143.39,144.38 1 0
+auth/ent/ent.go:144.38,145.59 1 0
+auth/ent/ent.go:145.59,148.4 2 0
+auth/ent/ent.go:149.3,149.29 1 0
+auth/ent/ent.go:154.38,155.38 1 0
+auth/ent/ent.go:155.38,156.59 1 0
+auth/ent/ent.go:156.59,159.4 2 0
+auth/ent/ent.go:160.3,160.29 1 0
+auth/ent/ent.go:165.38,166.38 1 0
+auth/ent/ent.go:166.38,167.59 1 0
+auth/ent/ent.go:167.59,170.4 2 0
+auth/ent/ent.go:171.3,171.29 1 0
+auth/ent/ent.go:182.42,184.2 1 0
+auth/ent/ent.go:187.42,189.2 1 0
+auth/ent/ent.go:192.40,193.16 1 0
+auth/ent/ent.go:193.16,195.3 1 0
+auth/ent/ent.go:196.2,197.27 2 0
+auth/ent/ent.go:206.40,208.2 1 0
+auth/ent/ent.go:211.33,212.16 1 0
+auth/ent/ent.go:212.16,214.3 1 0
+auth/ent/ent.go:215.2,216.27 2 0
+auth/ent/ent.go:220.36,221.21 1 0
+auth/ent/ent.go:221.21,223.3 1 0
+auth/ent/ent.go:224.2,224.12 1 0
+auth/ent/ent.go:233.43,235.2 1 0
+auth/ent/ent.go:238.36,239.16 1 0
+auth/ent/ent.go:239.16,241.3 1 0
+auth/ent/ent.go:242.2,243.27 2 0
+auth/ent/ent.go:252.41,254.2 1 0
+auth/ent/ent.go:257.34,258.16 1 0
+auth/ent/ent.go:258.16,260.3 1 0
+auth/ent/ent.go:261.2,262.27 2 0
+auth/ent/ent.go:274.41,276.2 1 0
+auth/ent/ent.go:279.42,281.2 1 0
+auth/ent/ent.go:284.40,285.16 1 0
+auth/ent/ent.go:285.16,287.3 1 0
+auth/ent/ent.go:288.2,289.27 2 0
+auth/ent/ent.go:301.54,302.39 1 0
+auth/ent/ent.go:302.39,303.13 1 0
+auth/ent/ent.go:308.67,309.22 1 0
+auth/ent/ent.go:309.22,311.3 1 0
+auth/ent/ent.go:312.2,313.40 2 0
+auth/ent/ent.go:313.40,315.3 1 0
+auth/ent/ent.go:316.2,316.15 1 0
+auth/ent/ent.go:320.59,322.16 2 0
+auth/ent/ent.go:322.16,323.13 1 0
+auth/ent/ent.go:325.2,325.10 1 0
+auth/ent/ent.go:329.70,331.41 2 0
+auth/ent/ent.go:331.41,333.3 1 0
+auth/ent/ent.go:334.2,334.16 1 0
+auth/ent/ent.go:335.9,336.19 1 0
+auth/ent/ent.go:337.9,338.32 1 0
+auth/ent/ent.go:339.10,340.85 1 0
+auth/ent/ent.go:342.2,342.8 1 0
+auth/ent/ent.go:346.56,348.16 2 0
+auth/ent/ent.go:348.16,349.13 1 0
+auth/ent/ent.go:351.2,351.10 1 0
+auth/ent/ent.go:355.61,356.22 1 0
+auth/ent/ent.go:356.22,358.3 1 0
+auth/ent/ent.go:359.2,360.40 2 0
+auth/ent/ent.go:360.40,362.3 1 0
+auth/ent/ent.go:363.2,363.15 1 0
+auth/ent/ent.go:367.53,369.16 2 0
+auth/ent/ent.go:369.16,370.13 1 0
+auth/ent/ent.go:372.2,372.10 1 0
+auth/ent/ent.go:376.64,378.38 2 0
+auth/ent/ent.go:378.38,380.3 1 0
+auth/ent/ent.go:381.2,381.16 1 0
+auth/ent/ent.go:382.9,383.19 1 0
+auth/ent/ent.go:384.9,385.32 1 0
+auth/ent/ent.go:386.10,387.82 1 0
+auth/ent/ent.go:389.2,389.8 1 0
+auth/ent/ent.go:393.50,395.16 2 0
+auth/ent/ent.go:395.16,396.13 1 0
+auth/ent/ent.go:398.2,398.10 1 0
+auth/ent/ent.go:402.69,403.22 1 0
+auth/ent/ent.go:403.22,405.3 1 0
+auth/ent/ent.go:406.2,407.40 2 0
+auth/ent/ent.go:407.40,409.3 1 0
+auth/ent/ent.go:410.2,410.15 1 0
+auth/ent/ent.go:414.61,416.16 2 0
+auth/ent/ent.go:416.16,417.13 1 0
+auth/ent/ent.go:419.2,419.10 1 0
+auth/ent/ent.go:423.72,425.42 2 0
+auth/ent/ent.go:425.42,427.3 1 0
+auth/ent/ent.go:428.2,428.16 1 0
+auth/ent/ent.go:429.9,430.19 1 0
+auth/ent/ent.go:431.9,432.32 1 0
+auth/ent/ent.go:433.10,434.86 1 0
+auth/ent/ent.go:436.2,436.8 1 0
+auth/ent/ent.go:440.58,442.16 2 0
+auth/ent/ent.go:442.16,443.13 1 0
+auth/ent/ent.go:445.2,445.10 1 0
+auth/ent/ent.go:449.63,450.22 1 0
+auth/ent/ent.go:450.22,452.3 1 0
+auth/ent/ent.go:453.2,454.40 2 0
+auth/ent/ent.go:454.40,456.3 1 0
+auth/ent/ent.go:457.2,457.15 1 0
+auth/ent/ent.go:461.55,463.16 2 0
+auth/ent/ent.go:463.16,464.13 1 0
+auth/ent/ent.go:466.2,466.10 1 0
+auth/ent/ent.go:470.66,472.39 2 0
+auth/ent/ent.go:472.39,474.3 1 0
+auth/ent/ent.go:475.2,475.16 1 0
+auth/ent/ent.go:476.9,477.19 1 0
+auth/ent/ent.go:478.9,479.32 1 0
+auth/ent/ent.go:480.10,481.83 1 0
+auth/ent/ent.go:483.2,483.8 1 0
+auth/ent/ent.go:487.52,489.16 2 0
+auth/ent/ent.go:489.16,490.13 1 0
+auth/ent/ent.go:492.2,492.10 1 0
+auth/ent/ent.go:499.112,500.21 1 0
+auth/ent/ent.go:500.21,502.3 1 0
+auth/ent/ent.go:503.2,503.84 1 0
+auth/ent/ent.go:503.84,505.10 2 0
+auth/ent/ent.go:505.10,507.4 1 0
+auth/ent/ent.go:509.3,510.19 2 0
+auth/ent/ent.go:512.2,512.39 1 0
+auth/ent/ent.go:512.39,513.22 1 0
+auth/ent/ent.go:513.22,515.4 1 0
+auth/ent/ent.go:516.3,516.22 1 0
+auth/ent/ent.go:518.2,519.16 2 0
+auth/ent/ent.go:519.16,521.3 1 0
+auth/ent/ent.go:522.2,523.9 2 0
+auth/ent/ent.go:523.9,525.3 1 0
+auth/ent/ent.go:526.2,526.16 1 0
+auth/ent/ent.go:530.85,531.38 1 0
+auth/ent/ent.go:531.38,534.3 2 0
+auth/ent/ent.go:535.2,535.12 1 0
+auth/ent/ent.go:540.14,541.71 1 0
+auth/ent/ent.go:541.71,543.10 2 0
+auth/ent/ent.go:543.10,545.4 1 0
+auth/ent/ent.go:546.3,546.27 1 0
+auth/ent/ent.go:552.14,553.71 1 0
+auth/ent/ent.go:553.71,555.10 2 0
+auth/ent/ent.go:555.10,557.4 1 0
+auth/ent/ent.go:558.3,558.29 1 0
+auth/ent/ent.go:562.113,563.40 1 0
+auth/ent/ent.go:563.40,565.3 1 0
+auth/ent/ent.go:566.2,567.16 2 0
+auth/ent/ent.go:567.16,569.3 1 0
+auth/ent/ent.go:570.2,571.9 2 0
+auth/ent/ent.go:571.9,573.3 1 0
+auth/ent/ent.go:574.2,574.16 1 0
+auth/ent/ent.go:579.92,581.81 2 0
+auth/ent/ent.go:581.81,583.10 2 0
+auth/ent/ent.go:583.10,585.4 1 0
+auth/ent/ent.go:586.3,586.62 1 0
+auth/ent/ent.go:586.62,588.4 1 0
+auth/ent/ent.go:589.3,589.71 1 0
+auth/ent/ent.go:589.71,591.4 1 0
+auth/ent/ent.go:592.3,592.16 1 0
+auth/ent/ent.go:594.2,594.40 1 0
+auth/ent/ent.go:594.40,596.3 1 0
+auth/ent/ent.go:597.2,598.16 2 0
+auth/ent/ent.go:598.16,600.3 1 0
+auth/ent/ent.go:601.2,601.37 1 0
+auth/ent/ent.go:602.61,602.61 0 0
+auth/ent/ent.go:603.31,604.28 1 0
+auth/ent/ent.go:605.38,606.21 1 0
+auth/ent/ent.go:608.2,608.12 1 0
+auth/ent/mutation.go:60.73,67.27 2 0
+auth/ent/mutation.go:67.27,69.3 1 0
+auth/ent/mutation.go:70.2,70.10 1 0
+auth/ent/mutation.go:74.39,75.31 1 0
+auth/ent/mutation.go:75.31,81.57 2 0
+auth/ent/mutation.go:81.57,82.19 1 0
+auth/ent/mutation.go:82.19,83.15 1 0
+auth/ent/mutation.go:83.15,85.6 1 0
+auth/ent/mutation.go:85.11,87.6 1 0
+auth/ent/mutation.go:89.4,89.21 1 0
+auth/ent/mutation.go:91.3,91.13 1 0
+auth/ent/mutation.go:96.38,97.31 1 0
+auth/ent/mutation.go:97.31,98.53 1 0
+auth/ent/mutation.go:98.53,100.4 1 0
+auth/ent/mutation.go:101.3,101.18 1 0
+auth/ent/mutation.go:107.40,111.2 3 0
+auth/ent/mutation.go:115.41,116.40 1 0
+auth/ent/mutation.go:116.40,118.3 1 0
+auth/ent/mutation.go:119.2,121.16 3 0
+auth/ent/mutation.go:126.41,128.2 1 0
+auth/ent/mutation.go:132.54,133.17 1 0
+auth/ent/mutation.go:133.17,135.3 1 0
+auth/ent/mutation.go:136.2,136.20 1 0
+auth/ent/mutation.go:143.67,144.9 1 0
+auth/ent/mutation.go:145.42,147.13 2 0
+auth/ent/mutation.go:147.13,149.4 1 0
+auth/ent/mutation.go:150.3,150.14 1 0
+auth/ent/mutation.go:151.36,152.65 1 0
+auth/ent/mutation.go:153.10,154.70 1 0
+auth/ent/mutation.go:159.42,161.2 1 0
+auth/ent/mutation.go:164.55,166.14 2 0
+auth/ent/mutation.go:166.14,168.3 1 0
+auth/ent/mutation.go:169.2,169.17 1 0
+auth/ent/mutation.go:175.75,176.27 1 0
+auth/ent/mutation.go:176.27,178.3 1 0
+auth/ent/mutation.go:179.2,179.38 1 0
+auth/ent/mutation.go:179.38,181.3 1 0
+auth/ent/mutation.go:182.2,183.16 2 0
+auth/ent/mutation.go:183.16,185.3 1 0
+auth/ent/mutation.go:186.2,186.27 1 0
+auth/ent/mutation.go:190.36,192.2 1 0
+auth/ent/mutation.go:195.51,198.2 2 0
+auth/ent/mutation.go:201.64,203.14 2 0
+auth/ent/mutation.go:203.14,205.3 1 0
+auth/ent/mutation.go:206.2,206.17 1 0
+auth/ent/mutation.go:212.84,213.27 1 0
+auth/ent/mutation.go:213.27,215.3 1 0
+auth/ent/mutation.go:216.2,216.38 1 0
+auth/ent/mutation.go:216.38,218.3 1 0
+auth/ent/mutation.go:219.2,220.16 2 0
+auth/ent/mutation.go:220.16,222.3 1 0
+auth/ent/mutation.go:223.2,223.34 1 0
+auth/ent/mutation.go:227.54,229.2 1 0
+auth/ent/mutation.go:232.63,233.35 1 0
+auth/ent/mutation.go:233.35,235.3 1 0
+auth/ent/mutation.go:236.2,236.34 1 0
+auth/ent/mutation.go:240.43,243.2 2 0
+auth/ent/mutation.go:246.50,248.2 1 0
+auth/ent/mutation.go:251.63,253.14 2 0
+auth/ent/mutation.go:253.14,255.3 1 0
+auth/ent/mutation.go:256.2,256.17 1 0
+auth/ent/mutation.go:262.83,263.27 1 0
+auth/ent/mutation.go:263.27,265.3 1 0
+auth/ent/mutation.go:266.2,266.38 1 0
+auth/ent/mutation.go:266.38,268.3 1 0
+auth/ent/mutation.go:269.2,270.16 2 0
+auth/ent/mutation.go:270.16,272.3 1 0
+auth/ent/mutation.go:273.2,273.32 1 0
+auth/ent/mutation.go:277.41,279.2 1 0
+auth/ent/mutation.go:282.50,284.2 1 0
+auth/ent/mutation.go:287.63,289.14 2 0
+auth/ent/mutation.go:289.14,291.3 1 0
+auth/ent/mutation.go:292.2,292.17 1 0
+auth/ent/mutation.go:298.83,299.27 1 0
+auth/ent/mutation.go:299.27,301.3 1 0
+auth/ent/mutation.go:302.2,302.38 1 0
+auth/ent/mutation.go:302.38,304.3 1 0
+auth/ent/mutation.go:305.2,306.16 2 0
+auth/ent/mutation.go:306.16,308.3 1 0
+auth/ent/mutation.go:309.2,309.32 1 0
+auth/ent/mutation.go:313.41,315.2 1 0
+auth/ent/mutation.go:318.50,319.20 1 0
+auth/ent/mutation.go:319.20,321.3 1 0
+auth/ent/mutation.go:322.2,322.21 1 0
+auth/ent/mutation.go:322.21,324.3 1 0
+auth/ent/mutation.go:328.37,330.2 1 0
+auth/ent/mutation.go:333.44,335.2 1 0
+auth/ent/mutation.go:338.53,339.27 1 0
+auth/ent/mutation.go:339.27,341.3 1 0
+auth/ent/mutation.go:342.2,342.21 1 0
+auth/ent/mutation.go:342.21,345.3 2 0
+auth/ent/mutation.go:349.57,350.33 1 0
+auth/ent/mutation.go:350.33,352.3 1 0
+auth/ent/mutation.go:353.2,353.8 1 0
+auth/ent/mutation.go:357.50,358.26 1 0
+auth/ent/mutation.go:358.26,360.3 1 0
+auth/ent/mutation.go:361.2,361.8 1 0
+auth/ent/mutation.go:365.37,369.2 3 0
+auth/ent/mutation.go:372.52,374.2 1 0
+auth/ent/mutation.go:378.58,380.20 2 0
+auth/ent/mutation.go:380.20,382.3 1 0
+auth/ent/mutation.go:383.2,383.15 1 0
+auth/ent/mutation.go:387.32,389.2 1 0
+auth/ent/mutation.go:392.37,394.2 1 0
+auth/ent/mutation.go:397.38,399.2 1 0
+auth/ent/mutation.go:404.42,406.19 2 0
+auth/ent/mutation.go:406.19,408.3 1 0
+auth/ent/mutation.go:409.2,409.26 1 0
+auth/ent/mutation.go:409.26,411.3 1 0
+auth/ent/mutation.go:412.2,412.25 1 0
+auth/ent/mutation.go:412.25,414.3 1 0
+auth/ent/mutation.go:415.2,415.25 1 0
+auth/ent/mutation.go:415.25,417.3 1 0
+auth/ent/mutation.go:418.2,418.15 1 0
+auth/ent/mutation.go:424.61,425.14 1 0
+auth/ent/mutation.go:426.22,427.18 1 0
+auth/ent/mutation.go:428.29,429.25 1 0
+auth/ent/mutation.go:430.27,431.23 1 0
+auth/ent/mutation.go:432.27,433.23 1 0
+auth/ent/mutation.go:435.2,435.19 1 0
+auth/ent/mutation.go:441.86,442.14 1 0
+auth/ent/mutation.go:443.22,444.24 1 0
+auth/ent/mutation.go:445.29,446.31 1 0
+auth/ent/mutation.go:447.27,448.29 1 0
+auth/ent/mutation.go:449.27,450.29 1 0
+auth/ent/mutation.go:452.2,452.55 1 0
+auth/ent/mutation.go:458.69,459.14 1 0
+auth/ent/mutation.go:460.22,462.10 2 0
+auth/ent/mutation.go:462.10,464.4 1 0
+auth/ent/mutation.go:465.3,466.13 2 0
+auth/ent/mutation.go:467.29,469.10 2 0
+auth/ent/mutation.go:469.10,471.4 1 0
+auth/ent/mutation.go:472.3,473.13 2 0
+auth/ent/mutation.go:474.27,476.10 2 0
+auth/ent/mutation.go:476.10,478.4 1 0
+auth/ent/mutation.go:479.3,480.13 2 0
+auth/ent/mutation.go:481.27,483.10 2 0
+auth/ent/mutation.go:483.10,485.4 1 0
+auth/ent/mutation.go:486.3,487.13 2 0
+auth/ent/mutation.go:489.2,489.50 1 0
+auth/ent/mutation.go:494.47,496.2 1 0
+auth/ent/mutation.go:501.66,503.2 1 0
+auth/ent/mutation.go:508.69,509.14 1 0
+auth/ent/mutation.go:511.2,511.58 1 0
+auth/ent/mutation.go:516.49,518.2 1 0
+auth/ent/mutation.go:522.55,525.2 2 0
+auth/ent/mutation.go:529.54,531.2 1 0
+auth/ent/mutation.go:535.54,536.14 1 0
+auth/ent/mutation.go:537.22,539.13 2 0
+auth/ent/mutation.go:540.29,542.13 2 0
+auth/ent/mutation.go:543.27,545.13 2 0
+auth/ent/mutation.go:546.27,548.13 2 0
+auth/ent/mutation.go:550.2,550.50 1 0
+auth/ent/mutation.go:554.46,556.20 2 0
+auth/ent/mutation.go:556.20,558.3 1 0
+auth/ent/mutation.go:559.2,559.14 1 0
+auth/ent/mutation.go:564.58,565.14 1 0
+auth/ent/mutation.go:566.22,568.27 2 0
+auth/ent/mutation.go:568.27,570.4 1 0
+auth/ent/mutation.go:571.3,571.13 1 0
+auth/ent/mutation.go:573.2,573.12 1 0
+auth/ent/mutation.go:577.48,579.27 2 0
+auth/ent/mutation.go:579.27,581.3 1 0
+auth/ent/mutation.go:582.2,582.14 1 0
+auth/ent/mutation.go:587.60,588.14 1 0
+auth/ent/mutation.go:589.22,591.34 2 0
+auth/ent/mutation.go:591.34,593.4 1 0
+auth/ent/mutation.go:594.3,594.13 1 0
+auth/ent/mutation.go:596.2,596.12 1 0
+auth/ent/mutation.go:600.48,602.20 2 0
+auth/ent/mutation.go:602.20,604.3 1 0
+auth/ent/mutation.go:605.2,605.14 1 0
+auth/ent/mutation.go:610.54,611.14 1 0
+auth/ent/mutation.go:612.22,613.24 1 0
+auth/ent/mutation.go:615.2,615.14 1 0
+auth/ent/mutation.go:620.53,621.14 1 0
+auth/ent/mutation.go:623.2,623.56 1 0
+auth/ent/mutation.go:628.53,629.14 1 0
+auth/ent/mutation.go:630.22,632.13 2 0
+auth/ent/mutation.go:634.2,634.49 1 0
+auth/ent/mutation.go:663.76,670.27 2 0
+auth/ent/mutation.go:670.27,672.3 1 0
+auth/ent/mutation.go:673.2,673.10 1 0
+auth/ent/mutation.go:677.41,678.32 1 0
+auth/ent/mutation.go:678.32,684.58 2 0
+auth/ent/mutation.go:684.58,685.19 1 0
+auth/ent/mutation.go:685.19,686.15 1 0
+auth/ent/mutation.go:686.15,688.6 1 0
+auth/ent/mutation.go:688.11,690.6 1 0
+auth/ent/mutation.go:692.4,692.21 1 0
+auth/ent/mutation.go:694.3,694.13 1 0
+auth/ent/mutation.go:699.41,700.32 1 0
+auth/ent/mutation.go:700.32,701.54 1 0
+auth/ent/mutation.go:701.54,703.4 1 0
+auth/ent/mutation.go:704.3,704.18 1 0
+auth/ent/mutation.go:710.41,714.2 3 0
+auth/ent/mutation.go:718.42,719.40 1 0
+auth/ent/mutation.go:719.40,721.3 1 0
+auth/ent/mutation.go:722.2,724.16 3 0
+auth/ent/mutation.go:729.42,731.2 1 0
+auth/ent/mutation.go:735.55,736.17 1 0
+auth/ent/mutation.go:736.17,738.3 1 0
+auth/ent/mutation.go:739.2,739.20 1 0
+auth/ent/mutation.go:746.68,747.9 1 0
+auth/ent/mutation.go:748.42,750.13 2 0
+auth/ent/mutation.go:750.13,752.4 1 0
+auth/ent/mutation.go:753.3,753.14 1 0
+auth/ent/mutation.go:754.36,755.66 1 0
+auth/ent/mutation.go:756.10,757.70 1 0
+auth/ent/mutation.go:762.44,764.2 1 0
+auth/ent/mutation.go:767.57,769.14 2 0
+auth/ent/mutation.go:769.14,771.3 1 0
+auth/ent/mutation.go:772.2,772.17 1 0
+auth/ent/mutation.go:778.77,779.27 1 0
+auth/ent/mutation.go:779.27,781.3 1 0
+auth/ent/mutation.go:782.2,782.38 1 0
+auth/ent/mutation.go:782.38,784.3 1 0
+auth/ent/mutation.go:785.2,786.16 2 0
+auth/ent/mutation.go:786.16,788.3 1 0
+auth/ent/mutation.go:789.2,789.28 1 0
+auth/ent/mutation.go:793.38,795.2 1 0
+auth/ent/mutation.go:798.47,800.2 1 0
+auth/ent/mutation.go:803.63,805.14 2 0
+auth/ent/mutation.go:805.14,807.3 1 0
+auth/ent/mutation.go:808.2,808.17 1 0
+auth/ent/mutation.go:814.80,815.27 1 0
+auth/ent/mutation.go:815.27,817.3 1 0
+auth/ent/mutation.go:818.2,818.38 1 0
+auth/ent/mutation.go:818.38,820.3 1 0
+auth/ent/mutation.go:821.2,822.16 2 0
+auth/ent/mutation.go:822.16,824.3 1 0
+auth/ent/mutation.go:825.2,825.27 1 0
+auth/ent/mutation.go:829.37,831.2 1 0
+auth/ent/mutation.go:834.51,836.2 1 0
+auth/ent/mutation.go:839.64,841.14 2 0
+auth/ent/mutation.go:841.14,843.3 1 0
+auth/ent/mutation.go:844.2,844.17 1 0
+auth/ent/mutation.go:850.84,851.27 1 0
+auth/ent/mutation.go:851.27,853.3 1 0
+auth/ent/mutation.go:854.2,854.38 1 0
+auth/ent/mutation.go:854.38,856.3 1 0
+auth/ent/mutation.go:857.2,858.16 2 0
+auth/ent/mutation.go:858.16,860.3 1 0
+auth/ent/mutation.go:861.2,861.32 1 0
+auth/ent/mutation.go:865.42,867.2 1 0
+auth/ent/mutation.go:870.44,872.2 1 0
+auth/ent/mutation.go:875.57,877.14 2 0
+auth/ent/mutation.go:877.14,879.3 1 0
+auth/ent/mutation.go:880.2,880.17 1 0
+auth/ent/mutation.go:886.77,887.27 1 0
+auth/ent/mutation.go:887.27,889.3 1 0
+auth/ent/mutation.go:890.2,890.38 1 0
+auth/ent/mutation.go:890.38,892.3 1 0
+auth/ent/mutation.go:893.2,894.16 2 0
+auth/ent/mutation.go:894.16,896.3 1 0
+auth/ent/mutation.go:897.2,897.30 1 0
+auth/ent/mutation.go:901.40,903.2 1 0
+auth/ent/mutation.go:906.51,908.2 1 0
+auth/ent/mutation.go:911.64,913.14 2 0
+auth/ent/mutation.go:913.14,915.3 1 0
+auth/ent/mutation.go:916.2,916.17 1 0
+auth/ent/mutation.go:922.84,923.27 1 0
+auth/ent/mutation.go:923.27,925.3 1 0
+auth/ent/mutation.go:926.2,926.38 1 0
+auth/ent/mutation.go:926.38,928.3 1 0
+auth/ent/mutation.go:929.2,930.16 2 0
+auth/ent/mutation.go:930.16,932.3 1 0
+auth/ent/mutation.go:933.2,933.32 1 0
+auth/ent/mutation.go:937.42,939.2 1 0
+auth/ent/mutation.go:942.51,944.2 1 0
+auth/ent/mutation.go:947.64,949.14 2 0
+auth/ent/mutation.go:949.14,951.3 1 0
+auth/ent/mutation.go:952.2,952.17 1 0
+auth/ent/mutation.go:958.84,959.27 1 0
+auth/ent/mutation.go:959.27,961.3 1 0
+auth/ent/mutation.go:962.2,962.38 1 0
+auth/ent/mutation.go:962.38,964.3 1 0
+auth/ent/mutation.go:965.2,966.16 2 0
+auth/ent/mutation.go:966.16,968.3 1 0
+auth/ent/mutation.go:969.2,969.32 1 0
+auth/ent/mutation.go:973.42,975.2 1 0
+auth/ent/mutation.go:978.46,980.2 1 0
+auth/ent/mutation.go:983.37,985.2 1 0
+auth/ent/mutation.go:988.44,990.2 1 0
+auth/ent/mutation.go:993.59,994.19 1 0
+auth/ent/mutation.go:994.19,996.3 1 0
+auth/ent/mutation.go:997.2,997.8 1 0
+auth/ent/mutation.go:1003.50,1004.29 1 0
+auth/ent/mutation.go:1004.29,1006.3 1 0
+auth/ent/mutation.go:1007.2,1007.8 1 0
+auth/ent/mutation.go:1011.37,1014.2 2 0
+auth/ent/mutation.go:1017.54,1019.2 1 0
+auth/ent/mutation.go:1023.59,1025.20 2 0
+auth/ent/mutation.go:1025.20,1027.3 1 0
+auth/ent/mutation.go:1028.2,1028.15 1 0
+auth/ent/mutation.go:1032.33,1034.2 1 0
+auth/ent/mutation.go:1037.38,1039.2 1 0
+auth/ent/mutation.go:1042.39,1044.2 1 0
+auth/ent/mutation.go:1049.43,1051.20 2 0
+auth/ent/mutation.go:1051.20,1053.3 1 0
+auth/ent/mutation.go:1054.2,1054.20 1 0
+auth/ent/mutation.go:1054.20,1056.3 1 0
+auth/ent/mutation.go:1057.2,1057.25 1 0
+auth/ent/mutation.go:1057.25,1059.3 1 0
+auth/ent/mutation.go:1060.2,1060.22 1 0
+auth/ent/mutation.go:1060.22,1062.3 1 0
+auth/ent/mutation.go:1063.2,1063.25 1 0
+auth/ent/mutation.go:1063.25,1065.3 1 0
+auth/ent/mutation.go:1066.2,1066.25 1 0
+auth/ent/mutation.go:1066.25,1068.3 1 0
+auth/ent/mutation.go:1069.2,1069.15 1 0
+auth/ent/mutation.go:1075.62,1076.14 1 0
+auth/ent/mutation.go:1077.24,1078.19 1 0
+auth/ent/mutation.go:1079.23,1080.21 1 0
+auth/ent/mutation.go:1081.28,1082.23 1 0
+auth/ent/mutation.go:1083.26,1084.21 1 0
+auth/ent/mutation.go:1085.28,1086.23 1 0
+auth/ent/mutation.go:1087.28,1088.23 1 0
+auth/ent/mutation.go:1090.2,1090.19 1 0
+auth/ent/mutation.go:1096.87,1097.14 1 0
+auth/ent/mutation.go:1098.24,1099.25 1 0
+auth/ent/mutation.go:1100.23,1101.24 1 0
+auth/ent/mutation.go:1102.28,1103.29 1 0
+auth/ent/mutation.go:1104.26,1105.27 1 0
+auth/ent/mutation.go:1106.28,1107.29 1 0
+auth/ent/mutation.go:1108.28,1109.29 1 0
+auth/ent/mutation.go:1111.2,1111.56 1 0
+auth/ent/mutation.go:1117.70,1118.14 1 0
+auth/ent/mutation.go:1119.24,1121.10 2 0
+auth/ent/mutation.go:1121.10,1123.4 1 0
+auth/ent/mutation.go:1124.3,1125.13 2 0
+auth/ent/mutation.go:1126.23,1128.10 2 0
+auth/ent/mutation.go:1128.10,1130.4 1 0
+auth/ent/mutation.go:1131.3,1132.13 2 0
+auth/ent/mutation.go:1133.28,1135.10 2 0
+auth/ent/mutation.go:1135.10,1137.4 1 0
+auth/ent/mutation.go:1138.3,1139.13 2 0
+auth/ent/mutation.go:1140.26,1142.10 2 0
+auth/ent/mutation.go:1142.10,1144.4 1 0
+auth/ent/mutation.go:1145.3,1146.13 2 0
+auth/ent/mutation.go:1147.28,1149.10 2 0
+auth/ent/mutation.go:1149.10,1151.4 1 0
+auth/ent/mutation.go:1152.3,1153.13 2 0
+auth/ent/mutation.go:1154.28,1156.10 2 0
+auth/ent/mutation.go:1156.10,1158.4 1 0
+auth/ent/mutation.go:1159.3,1160.13 2 0
+auth/ent/mutation.go:1162.2,1162.51 1 0
+auth/ent/mutation.go:1167.48,1169.2 1 0
+auth/ent/mutation.go:1174.67,1176.2 1 0
+auth/ent/mutation.go:1181.70,1182.14 1 0
+auth/ent/mutation.go:1184.2,1184.59 1 0
+auth/ent/mutation.go:1189.50,1191.2 1 0
+auth/ent/mutation.go:1195.56,1198.2 2 0
+auth/ent/mutation.go:1202.55,1204.2 1 0
+auth/ent/mutation.go:1208.55,1209.14 1 0
+auth/ent/mutation.go:1210.24,1212.13 2 0
+auth/ent/mutation.go:1213.23,1215.13 2 0
+auth/ent/mutation.go:1216.28,1218.13 2 0
+auth/ent/mutation.go:1219.26,1221.13 2 0
+auth/ent/mutation.go:1222.28,1224.13 2 0
+auth/ent/mutation.go:1225.28,1227.13 2 0
+auth/ent/mutation.go:1229.2,1229.51 1 0
+auth/ent/mutation.go:1233.47,1235.19 2 0
+auth/ent/mutation.go:1235.19,1237.3 1 0
+auth/ent/mutation.go:1238.2,1238.14 1 0
+auth/ent/mutation.go:1243.59,1244.14 1 0
+auth/ent/mutation.go:1245.22,1246.30 1 0
+auth/ent/mutation.go:1246.30,1248.4 1 0
+auth/ent/mutation.go:1250.2,1250.12 1 0
+auth/ent/mutation.go:1254.49,1257.2 2 0
+auth/ent/mutation.go:1261.61,1263.2 1 0
+auth/ent/mutation.go:1266.49,1268.19 2 0
+auth/ent/mutation.go:1268.19,1270.3 1 0
+auth/ent/mutation.go:1271.2,1271.14 1 0
+auth/ent/mutation.go:1276.55,1277.14 1 0
+auth/ent/mutation.go:1278.22,1279.23 1 0
+auth/ent/mutation.go:1281.2,1281.14 1 0
+auth/ent/mutation.go:1286.54,1287.14 1 0
+auth/ent/mutation.go:1288.22,1290.13 2 0
+auth/ent/mutation.go:1292.2,1292.57 1 0
+auth/ent/mutation.go:1297.54,1298.14 1 0
+auth/ent/mutation.go:1299.22,1301.13 2 0
+auth/ent/mutation.go:1303.2,1303.50 1 0
+auth/ent/mutation.go:1335.73,1342.27 2 0
+auth/ent/mutation.go:1342.27,1344.3 1 0
+auth/ent/mutation.go:1345.2,1345.10 1 0
+auth/ent/mutation.go:1349.39,1350.31 1 0
+auth/ent/mutation.go:1350.31,1356.57 2 0
+auth/ent/mutation.go:1356.57,1357.19 1 0
+auth/ent/mutation.go:1357.19,1358.15 1 0
+auth/ent/mutation.go:1358.15,1360.6 1 0
+auth/ent/mutation.go:1360.11,1362.6 1 0
+auth/ent/mutation.go:1364.4,1364.21 1 0
+auth/ent/mutation.go:1366.3,1366.13 1 0
+auth/ent/mutation.go:1371.38,1372.31 1 0
+auth/ent/mutation.go:1372.31,1373.53 1 0
+auth/ent/mutation.go:1373.53,1375.4 1 0
+auth/ent/mutation.go:1376.3,1376.18 1 0
+auth/ent/mutation.go:1382.40,1386.2 3 0
+auth/ent/mutation.go:1390.41,1391.40 1 0
+auth/ent/mutation.go:1391.40,1393.3 1 0
+auth/ent/mutation.go:1394.2,1396.16 3 0
+auth/ent/mutation.go:1401.41,1403.2 1 0
+auth/ent/mutation.go:1407.54,1408.17 1 0
+auth/ent/mutation.go:1408.17,1410.3 1 0
+auth/ent/mutation.go:1411.2,1411.20 1 0
+auth/ent/mutation.go:1418.67,1419.9 1 0
+auth/ent/mutation.go:1420.42,1422.13 2 0
+auth/ent/mutation.go:1422.13,1424.4 1 0
+auth/ent/mutation.go:1425.3,1425.14 1 0
+auth/ent/mutation.go:1426.36,1427.65 1 0
+auth/ent/mutation.go:1428.10,1429.70 1 0
+auth/ent/mutation.go:1434.46,1436.2 1 0
+auth/ent/mutation.go:1439.59,1441.14 2 0
+auth/ent/mutation.go:1441.14,1443.3 1 0
+auth/ent/mutation.go:1444.2,1444.17 1 0
+auth/ent/mutation.go:1450.79,1451.27 1 0
+auth/ent/mutation.go:1451.27,1453.3 1 0
+auth/ent/mutation.go:1454.2,1454.38 1 0
+auth/ent/mutation.go:1454.38,1456.3 1 0
+auth/ent/mutation.go:1457.2,1458.16 2 0
+auth/ent/mutation.go:1458.16,1460.3 1 0
+auth/ent/mutation.go:1461.2,1461.31 1 0
+auth/ent/mutation.go:1465.40,1467.2 1 0
+auth/ent/mutation.go:1470.43,1472.2 1 0
+auth/ent/mutation.go:1475.56,1477.14 2 0
+auth/ent/mutation.go:1477.14,1479.3 1 0
+auth/ent/mutation.go:1480.2,1480.17 1 0
+auth/ent/mutation.go:1486.76,1487.27 1 0
+auth/ent/mutation.go:1487.27,1489.3 1 0
+auth/ent/mutation.go:1490.2,1490.38 1 0
+auth/ent/mutation.go:1490.38,1492.3 1 0
+auth/ent/mutation.go:1493.2,1494.16 2 0
+auth/ent/mutation.go:1494.16,1496.3 1 0
+auth/ent/mutation.go:1497.2,1497.28 1 0
+auth/ent/mutation.go:1501.37,1503.2 1 0
+auth/ent/mutation.go:1506.46,1508.2 1 0
+auth/ent/mutation.go:1511.59,1513.14 2 0
+auth/ent/mutation.go:1513.14,1515.3 1 0
+auth/ent/mutation.go:1516.2,1516.17 1 0
+auth/ent/mutation.go:1522.79,1523.27 1 0
+auth/ent/mutation.go:1523.27,1525.3 1 0
+auth/ent/mutation.go:1526.2,1526.38 1 0
+auth/ent/mutation.go:1526.38,1528.3 1 0
+auth/ent/mutation.go:1529.2,1530.16 2 0
+auth/ent/mutation.go:1530.16,1532.3 1 0
+auth/ent/mutation.go:1533.2,1533.31 1 0
+auth/ent/mutation.go:1537.40,1539.2 1 0
+auth/ent/mutation.go:1542.50,1544.2 1 0
+auth/ent/mutation.go:1547.63,1549.14 2 0
+auth/ent/mutation.go:1549.14,1551.3 1 0
+auth/ent/mutation.go:1552.2,1552.17 1 0
+auth/ent/mutation.go:1558.83,1559.27 1 0
+auth/ent/mutation.go:1559.27,1561.3 1 0
+auth/ent/mutation.go:1562.2,1562.38 1 0
+auth/ent/mutation.go:1562.38,1564.3 1 0
+auth/ent/mutation.go:1565.2,1566.16 2 0
+auth/ent/mutation.go:1566.16,1568.3 1 0
+auth/ent/mutation.go:1569.2,1569.32 1 0
+auth/ent/mutation.go:1573.41,1575.2 1 0
+auth/ent/mutation.go:1578.50,1580.2 1 0
+auth/ent/mutation.go:1583.63,1585.14 2 0
+auth/ent/mutation.go:1585.14,1587.3 1 0
+auth/ent/mutation.go:1588.2,1588.17 1 0
+auth/ent/mutation.go:1594.83,1595.27 1 0
+auth/ent/mutation.go:1595.27,1597.3 1 0
+auth/ent/mutation.go:1598.2,1598.38 1 0
+auth/ent/mutation.go:1598.38,1600.3 1 0
+auth/ent/mutation.go:1601.2,1602.16 2 0
+auth/ent/mutation.go:1602.16,1604.3 1 0
+auth/ent/mutation.go:1605.2,1605.32 1 0
+auth/ent/mutation.go:1609.41,1611.2 1 0
+auth/ent/mutation.go:1614.50,1615.20 1 0
+auth/ent/mutation.go:1615.20,1617.3 1 0
+auth/ent/mutation.go:1618.2,1618.21 1 0
+auth/ent/mutation.go:1618.21,1620.3 1 0
+auth/ent/mutation.go:1624.37,1626.2 1 0
+auth/ent/mutation.go:1629.44,1631.2 1 0
+auth/ent/mutation.go:1634.53,1635.27 1 0
+auth/ent/mutation.go:1635.27,1637.3 1 0
+auth/ent/mutation.go:1638.2,1638.21 1 0
+auth/ent/mutation.go:1638.21,1641.3 2 0
+auth/ent/mutation.go:1645.57,1646.33 1 0
+auth/ent/mutation.go:1646.33,1648.3 1 0
+auth/ent/mutation.go:1649.2,1649.8 1 0
+auth/ent/mutation.go:1653.50,1654.26 1 0
+auth/ent/mutation.go:1654.26,1656.3 1 0
+auth/ent/mutation.go:1657.2,1657.8 1 0
+auth/ent/mutation.go:1661.37,1665.2 3 0
+auth/ent/mutation.go:1668.51,1669.21 1 0
+auth/ent/mutation.go:1669.21,1671.3 1 0
+auth/ent/mutation.go:1672.2,1672.21 1 0
+auth/ent/mutation.go:1672.21,1674.3 1 0
+auth/ent/mutation.go:1678.38,1680.2 1 0
+auth/ent/mutation.go:1683.45,1685.2 1 0
+auth/ent/mutation.go:1688.54,1689.28 1 0
+auth/ent/mutation.go:1689.28,1691.3 1 0
+auth/ent/mutation.go:1692.2,1692.21 1 0
+auth/ent/mutation.go:1692.21,1695.3 2 0
+auth/ent/mutation.go:1699.58,1700.34 1 0
+auth/ent/mutation.go:1700.34,1702.3 1 0
+auth/ent/mutation.go:1703.2,1703.8 1 0
+auth/ent/mutation.go:1707.51,1708.27 1 0
+auth/ent/mutation.go:1708.27,1710.3 1 0
+auth/ent/mutation.go:1711.2,1711.8 1 0
+auth/ent/mutation.go:1715.38,1719.2 3 0
+auth/ent/mutation.go:1722.52,1724.2 1 0
+auth/ent/mutation.go:1728.58,1730.20 2 0
+auth/ent/mutation.go:1730.20,1732.3 1 0
+auth/ent/mutation.go:1733.2,1733.15 1 0
+auth/ent/mutation.go:1737.32,1739.2 1 0
+auth/ent/mutation.go:1742.37,1744.2 1 0
+auth/ent/mutation.go:1747.38,1749.2 1 0
+auth/ent/mutation.go:1754.42,1756.23 2 0
+auth/ent/mutation.go:1756.23,1758.3 1 0
+auth/ent/mutation.go:1759.2,1759.20 1 0
+auth/ent/mutation.go:1759.20,1761.3 1 0
+auth/ent/mutation.go:1762.2,1762.23 1 0
+auth/ent/mutation.go:1762.23,1764.3 1 0
+auth/ent/mutation.go:1765.2,1765.25 1 0
+auth/ent/mutation.go:1765.25,1767.3 1 0
+auth/ent/mutation.go:1768.2,1768.25 1 0
+auth/ent/mutation.go:1768.25,1770.3 1 0
+auth/ent/mutation.go:1771.2,1771.15 1 0
+auth/ent/mutation.go:1777.61,1778.14 1 0
+auth/ent/mutation.go:1779.26,1780.22 1 0
+auth/ent/mutation.go:1781.23,1782.19 1 0
+auth/ent/mutation.go:1783.26,1784.22 1 0
+auth/ent/mutation.go:1785.27,1786.23 1 0
+auth/ent/mutation.go:1787.27,1788.23 1 0
+auth/ent/mutation.go:1790.2,1790.19 1 0
+auth/ent/mutation.go:1796.86,1797.14 1 0
+auth/ent/mutation.go:1798.26,1799.28 1 0
+auth/ent/mutation.go:1800.23,1801.25 1 0
+auth/ent/mutation.go:1802.26,1803.28 1 0
+auth/ent/mutation.go:1804.27,1805.29 1 0
+auth/ent/mutation.go:1806.27,1807.29 1 0
+auth/ent/mutation.go:1809.2,1809.55 1 0
+auth/ent/mutation.go:1815.69,1816.14 1 0
+auth/ent/mutation.go:1817.26,1819.10 2 0
+auth/ent/mutation.go:1819.10,1821.4 1 0
+auth/ent/mutation.go:1822.3,1823.13 2 0
+auth/ent/mutation.go:1824.23,1826.10 2 0
+auth/ent/mutation.go:1826.10,1828.4 1 0
+auth/ent/mutation.go:1829.3,1830.13 2 0
+auth/ent/mutation.go:1831.26,1833.10 2 0
+auth/ent/mutation.go:1833.10,1835.4 1 0
+auth/ent/mutation.go:1836.3,1837.13 2 0
+auth/ent/mutation.go:1838.27,1840.10 2 0
+auth/ent/mutation.go:1840.10,1842.4 1 0
+auth/ent/mutation.go:1843.3,1844.13 2 0
+auth/ent/mutation.go:1845.27,1847.10 2 0
+auth/ent/mutation.go:1847.10,1849.4 1 0
+auth/ent/mutation.go:1850.3,1851.13 2 0
+auth/ent/mutation.go:1853.2,1853.50 1 0
+auth/ent/mutation.go:1858.47,1860.2 1 0
+auth/ent/mutation.go:1865.66,1867.2 1 0
+auth/ent/mutation.go:1872.69,1873.14 1 0
+auth/ent/mutation.go:1875.2,1875.58 1 0
+auth/ent/mutation.go:1880.49,1882.2 1 0
+auth/ent/mutation.go:1886.55,1889.2 2 0
+auth/ent/mutation.go:1893.54,1895.2 1 0
+auth/ent/mutation.go:1899.54,1900.14 1 0
+auth/ent/mutation.go:1901.26,1903.13 2 0
+auth/ent/mutation.go:1904.23,1906.13 2 0
+auth/ent/mutation.go:1907.26,1909.13 2 0
+auth/ent/mutation.go:1910.27,1912.13 2 0
+auth/ent/mutation.go:1913.27,1915.13 2 0
+auth/ent/mutation.go:1917.2,1917.50 1 0
+auth/ent/mutation.go:1921.46,1923.20 2 0
+auth/ent/mutation.go:1923.20,1925.3 1 0
+auth/ent/mutation.go:1926.2,1926.21 1 0
+auth/ent/mutation.go:1926.21,1928.3 1 0
+auth/ent/mutation.go:1929.2,1929.14 1 0
+auth/ent/mutation.go:1934.58,1935.14 1 0
+auth/ent/mutation.go:1936.22,1938.27 2 0
+auth/ent/mutation.go:1938.27,1940.4 1 0
+auth/ent/mutation.go:1941.3,1941.13 1 0
+auth/ent/mutation.go:1942.23,1944.28 2 0
+auth/ent/mutation.go:1944.28,1946.4 1 0
+auth/ent/mutation.go:1947.3,1947.13 1 0
+auth/ent/mutation.go:1949.2,1949.12 1 0
+auth/ent/mutation.go:1953.48,1955.27 2 0
+auth/ent/mutation.go:1955.27,1957.3 1 0
+auth/ent/mutation.go:1958.2,1958.28 1 0
+auth/ent/mutation.go:1958.28,1960.3 1 0
+auth/ent/mutation.go:1961.2,1961.14 1 0
+auth/ent/mutation.go:1966.60,1967.14 1 0
+auth/ent/mutation.go:1968.22,1970.34 2 0
+auth/ent/mutation.go:1970.34,1972.4 1 0
+auth/ent/mutation.go:1973.3,1973.13 1 0
+auth/ent/mutation.go:1974.23,1976.35 2 0
+auth/ent/mutation.go:1976.35,1978.4 1 0
+auth/ent/mutation.go:1979.3,1979.13 1 0
+auth/ent/mutation.go:1981.2,1981.12 1 0
+auth/ent/mutation.go:1985.48,1987.20 2 0
+auth/ent/mutation.go:1987.20,1989.3 1 0
+auth/ent/mutation.go:1990.2,1990.21 1 0
+auth/ent/mutation.go:1990.21,1992.3 1 0
+auth/ent/mutation.go:1993.2,1993.14 1 0
+auth/ent/mutation.go:1998.54,1999.14 1 0
+auth/ent/mutation.go:2000.22,2001.24 1 0
+auth/ent/mutation.go:2002.23,2003.25 1 0
+auth/ent/mutation.go:2005.2,2005.14 1 0
+auth/ent/mutation.go:2010.53,2011.14 1 0
+auth/ent/mutation.go:2013.2,2013.56 1 0
+auth/ent/mutation.go:2018.53,2019.14 1 0
+auth/ent/mutation.go:2020.22,2022.13 2 0
+auth/ent/mutation.go:2023.23,2025.13 2 0
+auth/ent/mutation.go:2027.2,2027.49 1 0
+auth/ent/role.go:46.50,47.22 1 0
+auth/ent/role.go:47.22,49.3 1 0
+auth/ent/role.go:50.2,50.44 1 0
+auth/ent/role.go:54.58,56.25 2 0
+auth/ent/role.go:56.25,57.21 1 0
+auth/ent/role.go:58.30,59.27 1 0
+auth/ent/role.go:60.37,61.35 1 0
+auth/ent/role.go:62.49,63.33 1 0
+auth/ent/role.go:64.11,65.36 1 0
+auth/ent/role.go:68.2,68.20 1 0
+auth/ent/role.go:73.67,74.46 1 0
+auth/ent/role.go:74.46,76.3 1 0
+auth/ent/role.go:77.2,77.25 1 0
+auth/ent/role.go:77.25,78.21 1 0
+auth/ent/role.go:79.21,80.53 1 0
+auth/ent/role.go:80.53,82.5 1 0
+auth/ent/role.go:82.10,82.26 1 0
+auth/ent/role.go:82.26,84.5 1 0
+auth/ent/role.go:85.23,86.53 1 0
+auth/ent/role.go:86.53,88.5 1 0
+auth/ent/role.go:88.10,88.26 1 0
+auth/ent/role.go:88.26,90.5 1 0
+auth/ent/role.go:91.30,92.45 1 0
+auth/ent/role.go:92.45,94.5 1 0
+auth/ent/role.go:94.10,94.46 1 0
+auth/ent/role.go:94.46,95.66 1 0
+auth/ent/role.go:95.66,97.6 1 0
+auth/ent/role.go:99.28,100.51 1 0
+auth/ent/role.go:100.51,102.5 1 0
+auth/ent/role.go:102.10,102.26 1 0
+auth/ent/role.go:102.26,104.5 1 0
+auth/ent/role.go:105.28,106.51 1 0
+auth/ent/role.go:106.51,108.5 1 0
+auth/ent/role.go:108.10,108.26 1 0
+auth/ent/role.go:108.26,110.5 1 0
+auth/ent/role.go:111.11,112.45 1 0
+auth/ent/role.go:115.2,115.12 1 0
+auth/ent/role.go:120.54,122.2 1 0
+auth/ent/role.go:125.40,127.2 1 0
+auth/ent/role.go:132.40,134.2 1 0
+auth/ent/role.go:138.31,140.9 2 0
+auth/ent/role.go:140.9,141.51 1 0
+auth/ent/role.go:143.2,144.10 2 0
+auth/ent/role.go:148.32,165.2 16 0
+auth/ent/role_create.go:25.53,28.2 2 0
+auth/ent/role_create.go:31.62,34.2 2 0
+auth/ent/role_create.go:37.61,40.2 2 0
+auth/ent/role_create.go:43.70,44.14 1 0
+auth/ent/role_create.go:44.14,46.3 1 0
+auth/ent/role_create.go:47.2,47.11 1 0
+auth/ent/role_create.go:51.61,54.2 2 0
+auth/ent/role_create.go:57.70,58.14 1 0
+auth/ent/role_create.go:58.14,60.3 1 0
+auth/ent/role_create.go:61.2,61.11 1 0
+auth/ent/role_create.go:65.51,68.2 2 0
+auth/ent/role_create.go:71.60,72.14 1 0
+auth/ent/role_create.go:72.14,74.3 1 0
+auth/ent/role_create.go:75.2,75.11 1 0
+auth/ent/role_create.go:79.61,82.2 2 0
+auth/ent/role_create.go:85.56,87.19 2 0
+auth/ent/role_create.go:87.19,89.3 1 0
+auth/ent/role_create.go:90.2,90.30 1 0
+auth/ent/role_create.go:94.48,96.2 1 0
+auth/ent/role_create.go:99.64,102.2 2 0
+auth/ent/role_create.go:105.56,107.16 2 0
+auth/ent/role_create.go:107.16,108.13 1 0
+auth/ent/role_create.go:110.2,110.10 1 0
+auth/ent/role_create.go:114.55,117.2 2 0
+auth/ent/role_create.go:120.50,121.37 1 0
+auth/ent/role_create.go:121.37,122.13 1 0
+auth/ent/role_create.go:127.34,128.43 1 0
+auth/ent/role_create.go:128.43,131.3 2 0
+auth/ent/role_create.go:132.2,132.43 1 0
+auth/ent/role_create.go:132.43,135.3 2 0
+auth/ent/role_create.go:136.2,136.36 1 0
+auth/ent/role_create.go:136.36,139.3 2 0
+auth/ent/role_create.go:143.37,144.38 1 0
+auth/ent/role_create.go:144.38,146.3 1 0
+auth/ent/role_create.go:147.2,147.45 1 0
+auth/ent/role_create.go:147.45,149.3 1 0
+auth/ent/role_create.go:150.2,150.43 1 0
+auth/ent/role_create.go:150.43,152.3 1 0
+auth/ent/role_create.go:153.2,153.43 1 0
+auth/ent/role_create.go:153.43,155.3 1 0
+auth/ent/role_create.go:156.2,156.12 1 0
+auth/ent/role_create.go:159.67,160.35 1 0
+auth/ent/role_create.go:160.35,162.3 1 0
+auth/ent/role_create.go:163.2,164.67 2 0
+auth/ent/role_create.go:164.67,165.38 1 0
+auth/ent/role_create.go:165.38,167.4 1 0
+auth/ent/role_create.go:168.3,168.18 1 0
+auth/ent/role_create.go:170.2,170.27 1 0
+auth/ent/role_create.go:170.27,171.44 1 0
+auth/ent/role_create.go:171.44,173.4 1 0
+auth/ent/role_create.go:173.9,175.4 1 0
+auth/ent/role_create.go:177.2,179.19 3 0
+auth/ent/role_create.go:182.66,187.36 2 0
+auth/ent/role_create.go:187.36,190.3 2 0
+auth/ent/role_create.go:191.2,191.41 1 0
+auth/ent/role_create.go:191.41,194.3 2 0
+auth/ent/role_create.go:195.2,195.48 1 0
+auth/ent/role_create.go:195.48,198.3 2 0
+auth/ent/role_create.go:199.2,199.46 1 0
+auth/ent/role_create.go:199.46,202.3 2 0
+auth/ent/role_create.go:203.2,203.46 1 0
+auth/ent/role_create.go:203.46,206.3 2 0
+auth/ent/role_create.go:207.2,207.53 1 0
+auth/ent/role_create.go:207.53,218.27 2 0
+auth/ent/role_create.go:218.27,220.4 1 0
+auth/ent/role_create.go:221.3,221.42 1 0
+auth/ent/role_create.go:223.2,223.21 1 0
+auth/ent/role_create.go:234.71,235.20 1 0
+auth/ent/role_create.go:235.20,237.3 1 0
+auth/ent/role_create.go:238.2,241.30 4 0
+auth/ent/role_create.go:241.30,242.37 1 0
+auth/ent/role_create.go:242.37,245.86 3 0
+auth/ent/role_create.go:245.86,247.12 2 0
+auth/ent/role_create.go:247.12,249.6 1 0
+auth/ent/role_create.go:250.5,250.43 1 0
+auth/ent/role_create.go:250.43,252.6 1 0
+auth/ent/role_create.go:253.5,256.28 4 0
+auth/ent/role_create.go:256.28,258.6 1 0
+auth/ent/role_create.go:258.11,261.71 2 0
+auth/ent/role_create.go:261.71,262.42 1 0
+auth/ent/role_create.go:262.42,264.8 1 0
+auth/ent/role_create.go:267.5,267.19 1 0
+auth/ent/role_create.go:267.19,269.6 1 0
+auth/ent/role_create.go:270.5,272.25 3 0
+auth/ent/role_create.go:274.4,274.49 1 0
+auth/ent/role_create.go:274.49,276.5 1 0
+auth/ent/role_create.go:277.4,277.21 1 0
+auth/ent/role_create.go:280.2,280.23 1 0
+auth/ent/role_create.go:280.23,281.78 1 0
+auth/ent/role_create.go:281.78,283.4 1 0
+auth/ent/role_create.go:285.2,285.19 1 0
+auth/ent/role_create.go:289.63,291.16 2 0
+auth/ent/role_create.go:291.16,292.13 1 0
+auth/ent/role_create.go:294.2,294.10 1 0
+auth/ent/role_create.go:298.60,301.2 2 0
+auth/ent/role_create.go:304.55,305.38 1 0
+auth/ent/role_create.go:305.38,306.13 1 0
+auth/ent/role_delete.go:23.63,26.2 2 0
+auth/ent/role_delete.go:29.62,31.2 1 0
+auth/ent/role_delete.go:34.54,36.16 2 0
+auth/ent/role_delete.go:36.16,37.13 1 0
+auth/ent/role_delete.go:39.2,39.10 1 0
+auth/ent/role_delete.go:42.65,44.47 2 0
+auth/ent/role_delete.go:44.47,45.50 1 0
+auth/ent/role_delete.go:45.50,46.22 1 0
+auth/ent/role_delete.go:46.22,48.5 1 0
+auth/ent/role_delete.go:51.2,52.51 2 0
+auth/ent/role_delete.go:52.51,54.3 1 0
+auth/ent/role_delete.go:55.2,56.22 2 0
+auth/ent/role_delete.go:65.70,68.2 2 0
+auth/ent/role_delete.go:71.59,73.9 2 0
+auth/ent/role_delete.go:74.18,75.13 1 0
+auth/ent/role_delete.go:76.14,77.36 1 0
+auth/ent/role_delete.go:78.10,79.13 1 0
+auth/ent/role_delete.go:84.54,85.38 1 0
+auth/ent/role_delete.go:85.38,86.13 1 0
+auth/ent/role_query.go:33.61,36.2 2 0
+auth/ent/role_query.go:39.50,42.2 2 0
+auth/ent/role_query.go:45.52,48.2 2 0
+auth/ent/role_query.go:52.53,55.2 2 0
+auth/ent/role_query.go:58.62,61.2 2 0
+auth/ent/role_query.go:64.46,66.74 2 0
+auth/ent/role_query.go:66.74,67.46 1 0
+auth/ent/role_query.go:67.46,69.4 1 0
+auth/ent/role_query.go:70.3,71.40 2 0
+auth/ent/role_query.go:71.40,73.4 1 0
+auth/ent/role_query.go:74.3,80.20 3 0
+auth/ent/role_query.go:82.2,82.14 1 0
+auth/ent/role_query.go:87.64,89.16 2 0
+auth/ent/role_query.go:89.16,91.3 1 0
+auth/ent/role_query.go:92.2,92.21 1 0
+auth/ent/role_query.go:92.21,94.3 1 0
+auth/ent/role_query.go:95.2,95.22 1 0
+auth/ent/role_query.go:99.56,101.36 2 0
+auth/ent/role_query.go:101.36,102.13 1 0
+auth/ent/role_query.go:104.2,104.13 1 0
+auth/ent/role_query.go:109.74,111.82 2 0
+auth/ent/role_query.go:111.82,113.3 1 0
+auth/ent/role_query.go:114.2,114.19 1 0
+auth/ent/role_query.go:114.19,117.3 2 0
+auth/ent/role_query.go:118.2,118.20 1 0
+auth/ent/role_query.go:122.59,124.36 2 0
+auth/ent/role_query.go:124.36,125.13 1 0
+auth/ent/role_query.go:127.2,127.11 1 0
+auth/ent/role_query.go:133.63,135.16 2 0
+auth/ent/role_query.go:135.16,137.3 1 0
+auth/ent/role_query.go:138.2,138.20 1 0
+auth/ent/role_query.go:139.9,140.23 1 0
+auth/ent/role_query.go:141.9,142.41 1 0
+auth/ent/role_query.go:143.10,144.44 1 0
+auth/ent/role_query.go:149.55,151.16 2 0
+auth/ent/role_query.go:151.16,152.13 1 0
+auth/ent/role_query.go:154.2,154.13 1 0
+auth/ent/role_query.go:160.73,162.81 2 0
+auth/ent/role_query.go:162.81,164.3 1 0
+auth/ent/role_query.go:165.2,165.18 1 0
+auth/ent/role_query.go:166.9,167.14 1 0
+auth/ent/role_query.go:168.9,169.35 1 0
+auth/ent/role_query.go:170.10,171.38 1 0
+auth/ent/role_query.go:173.2,173.8 1 0
+auth/ent/role_query.go:177.58,179.16 2 0
+auth/ent/role_query.go:179.16,180.13 1 0
+auth/ent/role_query.go:182.2,182.11 1 0
+auth/ent/role_query.go:186.64,188.45 2 0
+auth/ent/role_query.go:188.45,190.3 1 0
+auth/ent/role_query.go:191.2,192.58 2 0
+auth/ent/role_query.go:196.56,198.16 2 0
+auth/ent/role_query.go:198.16,199.13 1 0
+auth/ent/role_query.go:201.2,201.14 1 0
+auth/ent/role_query.go:205.73,206.44 1 0
+auth/ent/role_query.go:206.44,208.3 1 0
+auth/ent/role_query.go:209.2,210.63 2 0
+auth/ent/role_query.go:210.63,212.3 1 0
+auth/ent/role_query.go:213.2,213.17 1 0
+auth/ent/role_query.go:217.57,219.16 2 0
+auth/ent/role_query.go:219.16,220.13 1 0
+auth/ent/role_query.go:222.2,222.12 1 0
+auth/ent/role_query.go:226.62,228.45 2 0
+auth/ent/role_query.go:228.45,230.3 1 0
+auth/ent/role_query.go:231.2,231.78 1 0
+auth/ent/role_query.go:235.54,237.16 2 0
+auth/ent/role_query.go:237.16,238.13 1 0
+auth/ent/role_query.go:240.2,240.14 1 0
+auth/ent/role_query.go:244.63,246.36 2 0
+auth/ent/role_query.go:247.23,248.20 1 0
+auth/ent/role_query.go:249.18,250.60 1 0
+auth/ent/role_query.go:251.10,252.19 1 0
+auth/ent/role_query.go:257.55,259.16 2 0
+auth/ent/role_query.go:259.16,260.13 1 0
+auth/ent/role_query.go:262.2,262.14 1 0
+auth/ent/role_query.go:267.41,268.15 1 0
+auth/ent/role_query.go:268.15,270.3 1 0
+auth/ent/role_query.go:271.2,281.3 1 0
+auth/ent/role_query.go:286.69,288.27 2 0
+auth/ent/role_query.go:288.27,290.3 1 0
+auth/ent/role_query.go:291.2,292.11 2 0
+auth/ent/role_query.go:309.75,316.2 6 0
+auth/ent/role_query.go:330.59,336.2 5 0
+auth/ent/role_query.go:339.66,341.2 1 0
+auth/ent/role_query.go:343.62,344.34 1 0
+auth/ent/role_query.go:344.34,345.19 1 0
+auth/ent/role_query.go:345.19,347.4 1 0
+auth/ent/role_query.go:348.3,348.39 1 0
+auth/ent/role_query.go:348.39,349.48 1 0
+auth/ent/role_query.go:349.48,351.5 1 0
+auth/ent/role_query.go:354.2,354.34 1 0
+auth/ent/role_query.go:354.34,355.27 1 0
+auth/ent/role_query.go:355.27,357.4 1 0
+auth/ent/role_query.go:359.2,359.20 1 0
+auth/ent/role_query.go:359.20,361.17 2 0
+auth/ent/role_query.go:361.17,363.4 1 0
+auth/ent/role_query.go:364.3,364.16 1 0
+auth/ent/role_query.go:366.2,366.12 1 0
+auth/ent/role_query.go:369.87,377.59 2 0
+auth/ent/role_query.go:377.59,379.3 1 0
+auth/ent/role_query.go:380.2,380.60 1 0
+auth/ent/role_query.go:380.60,385.3 4 0
+auth/ent/role_query.go:386.2,386.23 1 0
+auth/ent/role_query.go:386.23,388.3 1 0
+auth/ent/role_query.go:389.2,389.67 1 0
+auth/ent/role_query.go:389.67,391.3 1 0
+auth/ent/role_query.go:392.2,392.21 1 0
+auth/ent/role_query.go:392.21,394.3 1 0
+auth/ent/role_query.go:395.2,395.41 1 0
+auth/ent/role_query.go:395.41,397.18 1 0
+auth/ent/role_query.go:397.18,397.47 1 0
+auth/ent/role_query.go:398.27,398.71 1 0
+auth/ent/role_query.go:398.85,400.4 1 0
+auth/ent/role_query.go:402.2,402.19 1 0
+auth/ent/role_query.go:405.137,409.29 4 0
+auth/ent/role_query.go:409.29,412.18 3 0
+auth/ent/role_query.go:412.18,414.4 1 0
+auth/ent/role_query.go:416.2,416.36 1 0
+auth/ent/role_query.go:416.36,424.3 7 0
+auth/ent/role_query.go:425.2,425.48 1 0
+auth/ent/role_query.go:425.48,427.3 1 0
+auth/ent/role_query.go:428.2,428.70 1 0
+auth/ent/role_query.go:428.70,429.78 1 0
+auth/ent/role_query.go:429.78,432.60 3 0
+auth/ent/role_query.go:432.60,434.19 2 0
+auth/ent/role_query.go:434.19,436.6 1 0
+auth/ent/role_query.go:437.5,437.62 1 0
+auth/ent/role_query.go:439.4,439.61 1 0
+auth/ent/role_query.go:439.61,442.29 3 0
+auth/ent/role_query.go:442.29,445.6 2 0
+auth/ent/role_query.go:446.5,447.15 2 0
+auth/ent/role_query.go:451.2,452.16 2 0
+auth/ent/role_query.go:452.16,454.3 1 0
+auth/ent/role_query.go:455.2,455.30 1 0
+auth/ent/role_query.go:455.30,457.10 2 0
+auth/ent/role_query.go:457.10,459.4 1 0
+auth/ent/role_query.go:460.3,460.25 1 0
+auth/ent/role_query.go:460.25,462.4 1 0
+auth/ent/role_query.go:464.2,464.12 1 0
+auth/ent/role_query.go:467.65,470.28 3 0
+auth/ent/role_query.go:470.28,472.3 1 0
+auth/ent/role_query.go:473.2,473.51 1 0
+auth/ent/role_query.go:476.54,479.44 3 0
+auth/ent/role_query.go:479.44,481.3 1 0
+auth/ent/role_query.go:481.8,481.27 1 0
+auth/ent/role_query.go:481.27,483.3 1 0
+auth/ent/role_query.go:484.2,484.46 1 0
+auth/ent/role_query.go:484.46,487.25 3 0
+auth/ent/role_query.go:487.25,488.33 1 0
+auth/ent/role_query.go:488.33,490.5 1 0
+auth/ent/role_query.go:493.2,493.38 1 0
+auth/ent/role_query.go:493.38,494.50 1 0
+auth/ent/role_query.go:494.50,495.22 1 0
+auth/ent/role_query.go:495.22,497.5 1 0
+auth/ent/role_query.go:500.2,500.41 1 0
+auth/ent/role_query.go:500.41,502.3 1 0
+auth/ent/role_query.go:503.2,503.44 1 0
+auth/ent/role_query.go:503.44,505.3 1 0
+auth/ent/role_query.go:506.2,506.33 1 0
+auth/ent/role_query.go:506.33,507.46 1 0
+auth/ent/role_query.go:507.46,508.22 1 0
+auth/ent/role_query.go:508.22,510.5 1 0
+auth/ent/role_query.go:513.2,513.14 1 0
+auth/ent/role_query.go:516.66,520.23 4 0
+auth/ent/role_query.go:520.23,522.3 1 0
+auth/ent/role_query.go:523.2,524.19 2 0
+auth/ent/role_query.go:524.19,527.3 2 0
+auth/ent/role_query.go:528.2,528.44 1 0
+auth/ent/role_query.go:528.44,530.3 1 0
+auth/ent/role_query.go:531.2,531.34 1 0
+auth/ent/role_query.go:531.34,533.3 1 0
+auth/ent/role_query.go:534.2,534.29 1 0
+auth/ent/role_query.go:534.29,536.3 1 0
+auth/ent/role_query.go:537.2,537.44 1 0
+auth/ent/role_query.go:537.44,541.3 1 0
+auth/ent/role_query.go:542.2,542.41 1 0
+auth/ent/role_query.go:542.41,544.3 1 0
+auth/ent/role_query.go:545.2,545.17 1 0
+auth/ent/role_query.go:555.70,558.2 2 0
+auth/ent/role_query.go:561.64,563.52 2 0
+auth/ent/role_query.go:563.52,565.3 1 0
+auth/ent/role_query.go:566.2,566.97 1 0
+auth/ent/role_query.go:569.84,572.29 3 0
+auth/ent/role_query.go:572.29,574.3 1 0
+auth/ent/role_query.go:575.2,575.42 1 0
+auth/ent/role_query.go:575.42,577.31 2 0
+auth/ent/role_query.go:577.31,579.4 1 0
+auth/ent/role_query.go:580.3,581.30 2 0
+auth/ent/role_query.go:583.2,584.39 2 0
+auth/ent/role_query.go:584.39,586.3 1 0
+auth/ent/role_query.go:587.2,589.71 3 0
+auth/ent/role_query.go:589.71,591.3 1 0
+auth/ent/role_query.go:592.2,593.31 2 0
+auth/ent/role_query.go:603.67,606.2 2 0
+auth/ent/role_query.go:609.62,611.45 2 0
+auth/ent/role_query.go:611.45,613.3 1 0
+auth/ent/role_query.go:614.2,614.91 1 0
+auth/ent/role_query.go:617.82,620.28 3 0
+auth/ent/role_query.go:620.28,622.3 1 0
+auth/ent/role_query.go:623.2,623.38 1 0
+auth/ent/role_query.go:624.38,625.34 1 0
+auth/ent/role_query.go:626.38,627.40 1 0
+auth/ent/role_query.go:629.2,631.64 3 0
+auth/ent/role_query.go:631.64,633.3 1 0
+auth/ent/role_query.go:634.2,635.31 2 0
+auth/ent/role_update.go:28.63,31.2 2 0
+auth/ent/role_update.go:34.53,37.2 2 0
+auth/ent/role_update.go:40.62,41.14 1 0
+auth/ent/role_update.go:41.14,43.3 1 0
+auth/ent/role_update.go:44.2,44.11 1 0
+auth/ent/role_update.go:48.62,51.2 2 0
+auth/ent/role_update.go:54.65,57.2 2 0
+auth/ent/role_update.go:60.61,63.2 2 0
+auth/ent/role_update.go:66.70,67.14 1 0
+auth/ent/role_update.go:67.14,69.3 1 0
+auth/ent/role_update.go:70.2,70.11 1 0
+auth/ent/role_update.go:74.61,77.2 2 0
+auth/ent/role_update.go:80.61,83.2 2 0
+auth/ent/role_update.go:86.56,88.19 2 0
+auth/ent/role_update.go:88.19,90.3 1 0
+auth/ent/role_update.go:91.2,91.30 1 0
+auth/ent/role_update.go:95.48,97.2 1 0
+auth/ent/role_update.go:100.48,103.2 2 0
+auth/ent/role_update.go:106.64,109.2 2 0
+auth/ent/role_update.go:112.59,114.19 2 0
+auth/ent/role_update.go:114.19,116.3 1 0
+auth/ent/role_update.go:117.2,117.33 1 0
+auth/ent/role_update.go:121.62,124.2 2 0
+auth/ent/role_update.go:127.54,129.16 2 0
+auth/ent/role_update.go:129.16,130.13 1 0
+auth/ent/role_update.go:132.2,132.17 1 0
+auth/ent/role_update.go:136.55,139.2 2 0
+auth/ent/role_update.go:142.50,143.37 1 0
+auth/ent/role_update.go:143.37,144.13 1 0
+auth/ent/role_update.go:149.34,150.43 1 0
+auth/ent/role_update.go:150.43,153.3 2 0
+auth/ent/role_update.go:156.71,158.47 2 0
+auth/ent/role_update.go:158.47,159.50 1 0
+auth/ent/role_update.go:159.50,160.22 1 0
+auth/ent/role_update.go:160.22,162.5 1 0
+auth/ent/role_update.go:165.2,165.41 1 0
+auth/ent/role_update.go:165.41,167.3 1 0
+auth/ent/role_update.go:168.2,168.48 1 0
+auth/ent/role_update.go:168.48,170.3 1 0
+auth/ent/role_update.go:171.2,171.56 1 0
+auth/ent/role_update.go:171.56,172.48 1 0
+auth/ent/role_update.go:172.48,174.4 1 0
+auth/ent/role_update.go:176.2,176.46 1 0
+auth/ent/role_update.go:176.46,178.3 1 0
+auth/ent/role_update.go:179.2,179.46 1 0
+auth/ent/role_update.go:179.46,181.3 1 0
+auth/ent/role_update.go:182.2,182.32 1 0
+auth/ent/role_update.go:182.32,194.3 2 0
+auth/ent/role_update.go:195.2,195.91 1 0
+auth/ent/role_update.go:195.91,206.27 2 0
+auth/ent/role_update.go:206.27,208.4 1 0
+auth/ent/role_update.go:209.3,209.54 1 0
+auth/ent/role_update.go:211.2,211.53 1 0
+auth/ent/role_update.go:211.53,222.27 2 0
+auth/ent/role_update.go:222.27,224.4 1 0
+auth/ent/role_update.go:225.3,225.50 1 0
+auth/ent/role_update.go:227.2,227.70 1 0
+auth/ent/role_update.go:227.70,228.49 1 0
+auth/ent/role_update.go:228.49,230.4 1 0
+auth/ent/role_update.go:230.9,230.45 1 0
+auth/ent/role_update.go:230.45,232.4 1 0
+auth/ent/role_update.go:233.3,233.16 1 0
+auth/ent/role_update.go:235.2,236.15 2 0
+auth/ent/role_update.go:248.60,251.2 2 0
+auth/ent/role_update.go:254.69,255.14 1 0
+auth/ent/role_update.go:255.14,257.3 1 0
+auth/ent/role_update.go:258.2,258.12 1 0
+auth/ent/role_update.go:262.69,265.2 2 0
+auth/ent/role_update.go:268.72,271.2 2 0
+auth/ent/role_update.go:274.68,277.2 2 0
+auth/ent/role_update.go:280.77,281.14 1 0
+auth/ent/role_update.go:281.14,283.3 1 0
+auth/ent/role_update.go:284.2,284.12 1 0
+auth/ent/role_update.go:288.68,291.2 2 0
+auth/ent/role_update.go:294.68,297.2 2 0
+auth/ent/role_update.go:300.63,302.19 2 0
+auth/ent/role_update.go:302.19,304.3 1 0
+auth/ent/role_update.go:305.2,305.31 1 0
+auth/ent/role_update.go:309.52,311.2 1 0
+auth/ent/role_update.go:314.55,317.2 2 0
+auth/ent/role_update.go:320.71,323.2 2 0
+auth/ent/role_update.go:326.66,328.19 2 0
+auth/ent/role_update.go:328.19,330.3 1 0
+auth/ent/role_update.go:331.2,331.34 1 0
+auth/ent/role_update.go:335.70,338.2 2 0
+auth/ent/role_update.go:342.81,345.2 2 0
+auth/ent/role_update.go:348.68,351.2 2 0
+auth/ent/role_update.go:354.60,356.16 2 0
+auth/ent/role_update.go:356.16,357.13 1 0
+auth/ent/role_update.go:359.2,359.13 1 0
+auth/ent/role_update.go:363.59,366.2 2 0
+auth/ent/role_update.go:369.54,370.38 1 0
+auth/ent/role_update.go:370.38,371.13 1 0
+auth/ent/role_update.go:376.38,377.44 1 0
+auth/ent/role_update.go:377.44,380.3 2 0
+auth/ent/role_update.go:383.81,386.9 3 0
+auth/ent/role_update.go:386.9,388.3 1 0
+auth/ent/role_update.go:389.2,390.43 2 0
+auth/ent/role_update.go:390.43,393.28 3 0
+auth/ent/role_update.go:393.28,394.28 1 0
+auth/ent/role_update.go:394.28,396.5 1 0
+auth/ent/role_update.go:397.4,397.25 1 0
+auth/ent/role_update.go:397.25,399.5 1 0
+auth/ent/role_update.go:402.2,402.48 1 0
+auth/ent/role_update.go:402.48,403.50 1 0
+auth/ent/role_update.go:403.50,404.22 1 0
+auth/ent/role_update.go:404.22,406.5 1 0
+auth/ent/role_update.go:409.2,409.42 1 0
+auth/ent/role_update.go:409.42,411.3 1 0
+auth/ent/role_update.go:412.2,412.49 1 0
+auth/ent/role_update.go:412.49,414.3 1 0
+auth/ent/role_update.go:415.2,415.57 1 0
+auth/ent/role_update.go:415.57,416.48 1 0
+auth/ent/role_update.go:416.48,418.4 1 0
+auth/ent/role_update.go:420.2,420.47 1 0
+auth/ent/role_update.go:420.47,422.3 1 0
+auth/ent/role_update.go:423.2,423.47 1 0
+auth/ent/role_update.go:423.47,425.3 1 0
+auth/ent/role_update.go:426.2,426.33 1 0
+auth/ent/role_update.go:426.33,438.3 2 0
+auth/ent/role_update.go:439.2,439.93 1 0
+auth/ent/role_update.go:439.93,450.27 2 0
+auth/ent/role_update.go:450.27,452.4 1 0
+auth/ent/role_update.go:453.3,453.54 1 0
+auth/ent/role_update.go:455.2,455.54 1 0
+auth/ent/role_update.go:455.54,466.27 2 0
+auth/ent/role_update.go:466.27,468.4 1 0
+auth/ent/role_update.go:469.3,469.50 1 0
+auth/ent/role_update.go:471.2,474.67 4 0
+auth/ent/role_update.go:474.67,475.49 1 0
+auth/ent/role_update.go:475.49,477.4 1 0
+auth/ent/role_update.go:477.9,477.45 1 0
+auth/ent/role_update.go:477.45,479.4 1 0
+auth/ent/role_update.go:480.3,480.18 1 0
+auth/ent/role_update.go:482.2,483.19 2 0
+auth/ent/token.go:51.48,52.19 1 0
+auth/ent/token.go:52.19,54.3 1 0
+auth/ent/token.go:54.8,54.29 1 0
+auth/ent/token.go:54.29,56.3 1 0
+auth/ent/token.go:57.2,57.43 1 0
+auth/ent/token.go:61.59,63.25 2 0
+auth/ent/token.go:63.25,64.21 1 0
+auth/ent/token.go:65.27,66.33 1 0
+auth/ent/token.go:67.57,68.35 1 0
+auth/ent/token.go:69.73,70.33 1 0
+auth/ent/token.go:71.29,72.35 1 0
+auth/ent/token.go:73.11,74.36 1 0
+auth/ent/token.go:77.2,77.20 1 0
+auth/ent/token.go:82.68,83.46 1 0
+auth/ent/token.go:83.46,85.3 1 0
+auth/ent/token.go:86.2,86.25 1 0
+auth/ent/token.go:86.25,87.21 1 0
+auth/ent/token.go:88.22,89.53 1 0
+auth/ent/token.go:89.53,91.5 1 0
+auth/ent/token.go:91.10,91.26 1 0
+auth/ent/token.go:91.26,93.5 1 0
+auth/ent/token.go:94.25,95.53 1 0
+auth/ent/token.go:95.53,97.5 1 0
+auth/ent/token.go:97.10,97.26 1 0
+auth/ent/token.go:97.26,99.5 1 0
+auth/ent/token.go:100.24,101.53 1 0
+auth/ent/token.go:101.53,103.5 1 0
+auth/ent/token.go:103.10,103.26 1 0
+auth/ent/token.go:103.26,105.5 1 0
+auth/ent/token.go:106.29,107.51 1 0
+auth/ent/token.go:107.51,109.5 1 0
+auth/ent/token.go:109.10,109.26 1 0
+auth/ent/token.go:109.26,111.5 1 0
+auth/ent/token.go:112.27,113.51 1 0
+auth/ent/token.go:113.51,115.5 1 0
+auth/ent/token.go:115.10,115.26 1 0
+auth/ent/token.go:115.26,117.5 1 0
+auth/ent/token.go:118.29,119.51 1 0
+auth/ent/token.go:119.51,121.5 1 0
+auth/ent/token.go:121.10,121.26 1 0
+auth/ent/token.go:121.26,123.5 1 0
+auth/ent/token.go:124.29,125.51 1 0
+auth/ent/token.go:125.51,127.5 1 0
+auth/ent/token.go:127.10,127.26 1 0
+auth/ent/token.go:127.26,129.5 1 0
+auth/ent/token.go:130.29,131.53 1 0
+auth/ent/token.go:131.53,133.5 1 0
+auth/ent/token.go:133.10,133.26 1 0
+auth/ent/token.go:133.26,136.5 2 0
+auth/ent/token.go:137.11,138.45 1 0
+auth/ent/token.go:141.2,141.12 1 0
+auth/ent/token.go:146.55,148.2 1 0
+auth/ent/token.go:151.40,153.2 1 0
+auth/ent/token.go:158.42,160.2 1 0
+auth/ent/token.go:164.33,166.9 2 0
+auth/ent/token.go:166.9,167.52 1 0
+auth/ent/token.go:169.2,170.10 2 0
+auth/ent/token.go:174.33,197.2 22 0
+auth/ent/token_create.go:25.56,28.2 2 0
+auth/ent/token_create.go:31.59,34.2 2 0
+auth/ent/token_create.go:37.63,40.2 2 0
+auth/ent/token_create.go:43.56,46.2 2 0
+auth/ent/token_create.go:49.65,50.14 1 0
+auth/ent/token_create.go:50.14,52.3 1 0
+auth/ent/token_create.go:53.2,53.11 1 0
+auth/ent/token_create.go:57.63,60.2 2 0
+auth/ent/token_create.go:63.72,64.14 1 0
+auth/ent/token_create.go:64.14,66.3 1 0
+auth/ent/token_create.go:67.2,67.11 1 0
+auth/ent/token_create.go:71.63,74.2 2 0
+auth/ent/token_create.go:77.72,78.14 1 0
+auth/ent/token_create.go:78.14,80.3 1 0
+auth/ent/token_create.go:81.2,81.11 1 0
+auth/ent/token_create.go:85.53,88.2 2 0
+auth/ent/token_create.go:91.62,92.14 1 0
+auth/ent/token_create.go:92.14,94.3 1 0
+auth/ent/token_create.go:95.2,95.11 1 0
+auth/ent/token_create.go:99.58,102.2 2 0
+auth/ent/token_create.go:105.54,107.2 1 0
+auth/ent/token_create.go:110.50,112.2 1 0
+auth/ent/token_create.go:115.66,118.2 2 0
+auth/ent/token_create.go:121.58,123.16 2 0
+auth/ent/token_create.go:123.16,124.13 1 0
+auth/ent/token_create.go:126.2,126.10 1 0
+auth/ent/token_create.go:130.56,133.2 2 0
+auth/ent/token_create.go:136.51,137.37 1 0
+auth/ent/token_create.go:137.37,138.13 1 0
+auth/ent/token_create.go:143.35,144.41 1 0
+auth/ent/token_create.go:144.41,147.3 2 0
+auth/ent/token_create.go:148.2,148.43 1 0
+auth/ent/token_create.go:148.43,151.3 2 0
+auth/ent/token_create.go:152.2,152.43 1 0
+auth/ent/token_create.go:152.43,155.3 2 0
+auth/ent/token_create.go:156.2,156.36 1 0
+auth/ent/token_create.go:156.36,159.3 2 0
+auth/ent/token_create.go:163.38,164.39 1 0
+auth/ent/token_create.go:164.39,166.3 1 0
+auth/ent/token_create.go:167.2,167.41 1 0
+auth/ent/token_create.go:167.41,169.3 1 0
+auth/ent/token_create.go:170.2,170.40 1 0
+auth/ent/token_create.go:170.40,171.48 1 0
+auth/ent/token_create.go:171.48,173.4 1 0
+auth/ent/token_create.go:175.2,175.43 1 0
+auth/ent/token_create.go:175.43,177.3 1 0
+auth/ent/token_create.go:178.2,178.41 1 0
+auth/ent/token_create.go:178.41,180.3 1 0
+auth/ent/token_create.go:181.2,181.43 1 0
+auth/ent/token_create.go:181.43,183.3 1 0
+auth/ent/token_create.go:184.2,184.43 1 0
+auth/ent/token_create.go:184.43,186.3 1 0
+auth/ent/token_create.go:187.2,187.40 1 0
+auth/ent/token_create.go:187.40,189.3 1 0
+auth/ent/token_create.go:190.2,190.12 1 0
+auth/ent/token_create.go:193.69,194.35 1 0
+auth/ent/token_create.go:194.35,196.3 1 0
+auth/ent/token_create.go:197.2,198.67 2 0
+auth/ent/token_create.go:198.67,199.38 1 0
+auth/ent/token_create.go:199.38,201.4 1 0
+auth/ent/token_create.go:202.3,202.18 1 0
+auth/ent/token_create.go:204.2,204.27 1 0
+auth/ent/token_create.go:204.27,205.44 1 0
+auth/ent/token_create.go:205.44,207.4 1 0
+auth/ent/token_create.go:207.9,209.4 1 0
+auth/ent/token_create.go:211.2,213.19 3 0
+auth/ent/token_create.go:216.68,221.36 2 0
+auth/ent/token_create.go:221.36,224.3 2 0
+auth/ent/token_create.go:225.2,225.42 1 0
+auth/ent/token_create.go:225.42,228.3 2 0
+auth/ent/token_create.go:229.2,229.44 1 0
+auth/ent/token_create.go:229.44,232.3 2 0
+auth/ent/token_create.go:233.2,233.46 1 0
+auth/ent/token_create.go:233.46,236.3 2 0
+auth/ent/token_create.go:237.2,237.44 1 0
+auth/ent/token_create.go:237.44,240.3 2 0
+auth/ent/token_create.go:241.2,241.46 1 0
+auth/ent/token_create.go:241.46,244.3 2 0
+auth/ent/token_create.go:245.2,245.46 1 0
+auth/ent/token_create.go:245.46,248.3 2 0
+auth/ent/token_create.go:249.2,249.52 1 0
+auth/ent/token_create.go:249.52,260.27 2 0
+auth/ent/token_create.go:260.27,262.4 1 0
+auth/ent/token_create.go:263.3,264.42 2 0
+auth/ent/token_create.go:266.2,266.21 1 0
+auth/ent/token_create.go:277.73,278.20 1 0
+auth/ent/token_create.go:278.20,280.3 1 0
+auth/ent/token_create.go:281.2,284.30 4 0
+auth/ent/token_create.go:284.30,285.37 1 0
+auth/ent/token_create.go:285.37,288.86 3 0
+auth/ent/token_create.go:288.86,290.12 2 0
+auth/ent/token_create.go:290.12,292.6 1 0
+auth/ent/token_create.go:293.5,293.43 1 0
+auth/ent/token_create.go:293.43,295.6 1 0
+auth/ent/token_create.go:296.5,299.28 4 0
+auth/ent/token_create.go:299.28,301.6 1 0
+auth/ent/token_create.go:301.11,304.71 2 0
+auth/ent/token_create.go:304.71,305.42 1 0
+auth/ent/token_create.go:305.42,307.8 1 0
+auth/ent/token_create.go:310.5,310.19 1 0
+auth/ent/token_create.go:310.19,312.6 1 0
+auth/ent/token_create.go:313.5,315.25 3 0
+auth/ent/token_create.go:317.4,317.49 1 0
+auth/ent/token_create.go:317.49,319.5 1 0
+auth/ent/token_create.go:320.4,320.21 1 0
+auth/ent/token_create.go:323.2,323.23 1 0
+auth/ent/token_create.go:323.23,324.78 1 0
+auth/ent/token_create.go:324.78,326.4 1 0
+auth/ent/token_create.go:328.2,328.19 1 0
+auth/ent/token_create.go:332.65,334.16 2 0
+auth/ent/token_create.go:334.16,335.13 1 0
+auth/ent/token_create.go:337.2,337.10 1 0
+auth/ent/token_create.go:341.61,344.2 2 0
+auth/ent/token_create.go:347.56,348.38 1 0
+auth/ent/token_create.go:348.38,349.13 1 0
+auth/ent/token_delete.go:23.66,26.2 2 0
+auth/ent/token_delete.go:29.63,31.2 1 0
+auth/ent/token_delete.go:34.55,36.16 2 0
+auth/ent/token_delete.go:36.16,37.13 1 0
+auth/ent/token_delete.go:39.2,39.10 1 0
+auth/ent/token_delete.go:42.66,44.47 2 0
+auth/ent/token_delete.go:44.47,45.50 1 0
+auth/ent/token_delete.go:45.50,46.22 1 0
+auth/ent/token_delete.go:46.22,48.5 1 0
+auth/ent/token_delete.go:51.2,52.51 2 0
+auth/ent/token_delete.go:52.51,54.3 1 0
+auth/ent/token_delete.go:55.2,56.22 2 0
+auth/ent/token_delete.go:65.73,68.2 2 0
+auth/ent/token_delete.go:71.60,73.9 2 0
+auth/ent/token_delete.go:74.18,75.13 1 0
+auth/ent/token_delete.go:76.14,77.37 1 0
+auth/ent/token_delete.go:78.10,79.13 1 0
+auth/ent/token_delete.go:84.55,85.38 1 0
+auth/ent/token_delete.go:85.38,86.13 1 0
+auth/ent/token_query.go:33.64,36.2 2 0
+auth/ent/token_query.go:39.52,42.2 2 0
+auth/ent/token_query.go:45.54,48.2 2 0
+auth/ent/token_query.go:52.55,55.2 2 0
+auth/ent/token_query.go:58.65,61.2 2 0
+auth/ent/token_query.go:64.46,66.74 2 0
+auth/ent/token_query.go:66.74,67.46 1 0
+auth/ent/token_query.go:67.46,69.4 1 0
+auth/ent/token_query.go:70.3,71.40 2 0
+auth/ent/token_query.go:71.40,73.4 1 0
+auth/ent/token_query.go:74.3,80.20 3 0
+auth/ent/token_query.go:82.2,82.14 1 0
+auth/ent/token_query.go:87.66,89.16 2 0
+auth/ent/token_query.go:89.16,91.3 1 0
+auth/ent/token_query.go:92.2,92.21 1 0
+auth/ent/token_query.go:92.21,94.3 1 0
+auth/ent/token_query.go:95.2,95.22 1 0
+auth/ent/token_query.go:99.58,101.36 2 0
+auth/ent/token_query.go:101.36,102.13 1 0
+auth/ent/token_query.go:104.2,104.13 1 0
+auth/ent/token_query.go:109.75,111.82 2 0
+auth/ent/token_query.go:111.82,113.3 1 0
+auth/ent/token_query.go:114.2,114.19 1 0
+auth/ent/token_query.go:114.19,117.3 2 0
+auth/ent/token_query.go:118.2,118.20 1 0
+auth/ent/token_query.go:122.60,124.36 2 0
+auth/ent/token_query.go:124.36,125.13 1 0
+auth/ent/token_query.go:127.2,127.11 1 0
+auth/ent/token_query.go:133.65,135.16 2 0
+auth/ent/token_query.go:135.16,137.3 1 0
+auth/ent/token_query.go:138.2,138.20 1 0
+auth/ent/token_query.go:139.9,140.23 1 0
+auth/ent/token_query.go:141.9,142.42 1 0
+auth/ent/token_query.go:143.10,144.45 1 0
+auth/ent/token_query.go:149.57,151.16 2 0
+auth/ent/token_query.go:151.16,152.13 1 0
+auth/ent/token_query.go:154.2,154.13 1 0
+auth/ent/token_query.go:160.74,162.81 2 0
+auth/ent/token_query.go:162.81,164.3 1 0
+auth/ent/token_query.go:165.2,165.18 1 0
+auth/ent/token_query.go:166.9,167.14 1 0
+auth/ent/token_query.go:168.9,169.36 1 0
+auth/ent/token_query.go:170.10,171.39 1 0
+auth/ent/token_query.go:173.2,173.8 1 0
+auth/ent/token_query.go:177.59,179.16 2 0
+auth/ent/token_query.go:179.16,180.13 1 0
+auth/ent/token_query.go:182.2,182.11 1 0
+auth/ent/token_query.go:186.66,188.45 2 0
+auth/ent/token_query.go:188.45,190.3 1 0
+auth/ent/token_query.go:191.2,192.59 2 0
+auth/ent/token_query.go:196.58,198.16 2 0
+auth/ent/token_query.go:198.16,199.13 1 0
+auth/ent/token_query.go:201.2,201.14 1 0
+auth/ent/token_query.go:205.74,206.44 1 0
+auth/ent/token_query.go:206.44,208.3 1 0
+auth/ent/token_query.go:209.2,210.64 2 0
+auth/ent/token_query.go:210.64,212.3 1 0
+auth/ent/token_query.go:213.2,213.17 1 0
+auth/ent/token_query.go:217.58,219.16 2 0
+auth/ent/token_query.go:219.16,220.13 1 0
+auth/ent/token_query.go:222.2,222.12 1 0
+auth/ent/token_query.go:226.63,228.45 2 0
+auth/ent/token_query.go:228.45,230.3 1 0
+auth/ent/token_query.go:231.2,231.79 1 0
+auth/ent/token_query.go:235.55,237.16 2 0
+auth/ent/token_query.go:237.16,238.13 1 0
+auth/ent/token_query.go:240.2,240.14 1 0
+auth/ent/token_query.go:244.64,246.36 2 0
+auth/ent/token_query.go:247.23,248.20 1 0
+auth/ent/token_query.go:249.18,250.60 1 0
+auth/ent/token_query.go:251.10,252.19 1 0
+auth/ent/token_query.go:257.56,259.16 2 0
+auth/ent/token_query.go:259.16,260.13 1 0
+auth/ent/token_query.go:262.2,262.14 1 0
+auth/ent/token_query.go:267.43,268.15 1 0
+auth/ent/token_query.go:268.15,270.3 1 0
+auth/ent/token_query.go:271.2,281.3 1 0
+auth/ent/token_query.go:286.70,288.27 2 0
+auth/ent/token_query.go:288.27,290.3 1 0
+auth/ent/token_query.go:291.2,292.11 2 0
+auth/ent/token_query.go:309.77,316.2 6 0
+auth/ent/token_query.go:330.61,336.2 5 0
+auth/ent/token_query.go:339.68,341.2 1 0
+auth/ent/token_query.go:343.63,344.34 1 0
+auth/ent/token_query.go:344.34,345.19 1 0
+auth/ent/token_query.go:345.19,347.4 1 0
+auth/ent/token_query.go:348.3,348.39 1 0
+auth/ent/token_query.go:348.39,349.48 1 0
+auth/ent/token_query.go:349.48,351.5 1 0
+auth/ent/token_query.go:354.2,354.34 1 0
+auth/ent/token_query.go:354.34,355.28 1 0
+auth/ent/token_query.go:355.28,357.4 1 0
+auth/ent/token_query.go:359.2,359.20 1 0
+auth/ent/token_query.go:359.20,361.17 2 0
+auth/ent/token_query.go:361.17,363.4 1 0
+auth/ent/token_query.go:364.3,364.16 1 0
+auth/ent/token_query.go:366.2,366.12 1 0
+auth/ent/token_query.go:369.89,378.24 2 0
+auth/ent/token_query.go:378.24,380.3 1 0
+auth/ent/token_query.go:381.2,381.13 1 0
+auth/ent/token_query.go:381.13,383.3 1 0
+auth/ent/token_query.go:384.2,384.59 1 0
+auth/ent/token_query.go:384.59,386.3 1 0
+auth/ent/token_query.go:387.2,387.60 1 0
+auth/ent/token_query.go:387.60,392.3 4 0
+auth/ent/token_query.go:393.2,393.23 1 0
+auth/ent/token_query.go:393.23,395.3 1 0
+auth/ent/token_query.go:396.2,396.67 1 0
+auth/ent/token_query.go:396.67,398.3 1 0
+auth/ent/token_query.go:399.2,399.21 1 0
+auth/ent/token_query.go:399.21,401.3 1 0
+auth/ent/token_query.go:402.2,402.40 1 0
+auth/ent/token_query.go:402.40,404.28 1 0
+auth/ent/token_query.go:404.28,404.48 1 0
+auth/ent/token_query.go:404.62,406.4 1 0
+auth/ent/token_query.go:408.2,408.19 1 0
+auth/ent/token_query.go:411.140,414.23 3 0
+auth/ent/token_query.go:414.23,415.34 1 0
+auth/ent/token_query.go:415.34,416.12 1 0
+auth/ent/token_query.go:418.3,419.32 2 0
+auth/ent/token_query.go:419.32,421.4 1 0
+auth/ent/token_query.go:422.3,422.46 1 0
+auth/ent/token_query.go:424.2,424.19 1 0
+auth/ent/token_query.go:424.19,426.3 1 0
+auth/ent/token_query.go:427.2,429.16 3 0
+auth/ent/token_query.go:429.16,431.3 1 0
+auth/ent/token_query.go:432.2,432.30 1 0
+auth/ent/token_query.go:432.30,434.10 2 0
+auth/ent/token_query.go:434.10,436.4 1 0
+auth/ent/token_query.go:437.3,437.24 1 0
+auth/ent/token_query.go:437.24,439.4 1 0
+auth/ent/token_query.go:441.2,441.12 1 0
+auth/ent/token_query.go:444.66,447.28 3 0
+auth/ent/token_query.go:447.28,449.3 1 0
+auth/ent/token_query.go:450.2,450.51 1 0
+auth/ent/token_query.go:453.55,456.44 3 0
+auth/ent/token_query.go:456.44,458.3 1 0
+auth/ent/token_query.go:458.8,458.27 1 0
+auth/ent/token_query.go:458.27,460.3 1 0
+auth/ent/token_query.go:461.2,461.46 1 0
+auth/ent/token_query.go:461.46,464.25 3 0
+auth/ent/token_query.go:464.25,465.34 1 0
+auth/ent/token_query.go:465.34,467.5 1 0
+auth/ent/token_query.go:470.2,470.38 1 0
+auth/ent/token_query.go:470.38,471.50 1 0
+auth/ent/token_query.go:471.50,472.22 1 0
+auth/ent/token_query.go:472.22,474.5 1 0
+auth/ent/token_query.go:477.2,477.41 1 0
+auth/ent/token_query.go:477.41,479.3 1 0
+auth/ent/token_query.go:480.2,480.44 1 0
+auth/ent/token_query.go:480.44,482.3 1 0
+auth/ent/token_query.go:483.2,483.33 1 0
+auth/ent/token_query.go:483.33,484.46 1 0
+auth/ent/token_query.go:484.46,485.22 1 0
+auth/ent/token_query.go:485.22,487.5 1 0
+auth/ent/token_query.go:490.2,490.14 1 0
+auth/ent/token_query.go:493.67,497.23 4 0
+auth/ent/token_query.go:497.23,499.3 1 0
+auth/ent/token_query.go:500.2,501.19 2 0
+auth/ent/token_query.go:501.19,504.3 2 0
+auth/ent/token_query.go:505.2,505.44 1 0
+auth/ent/token_query.go:505.44,507.3 1 0
+auth/ent/token_query.go:508.2,508.34 1 0
+auth/ent/token_query.go:508.34,510.3 1 0
+auth/ent/token_query.go:511.2,511.29 1 0
+auth/ent/token_query.go:511.29,513.3 1 0
+auth/ent/token_query.go:514.2,514.44 1 0
+auth/ent/token_query.go:514.44,518.3 1 0
+auth/ent/token_query.go:519.2,519.41 1 0
+auth/ent/token_query.go:519.41,521.3 1 0
+auth/ent/token_query.go:522.2,522.17 1 0
+auth/ent/token_query.go:532.72,535.2 2 0
+auth/ent/token_query.go:538.65,540.52 2 0
+auth/ent/token_query.go:540.52,542.3 1 0
+auth/ent/token_query.go:543.2,543.99 1 0
+auth/ent/token_query.go:546.86,549.29 3 0
+auth/ent/token_query.go:549.29,551.3 1 0
+auth/ent/token_query.go:552.2,552.42 1 0
+auth/ent/token_query.go:552.42,554.31 2 0
+auth/ent/token_query.go:554.31,556.4 1 0
+auth/ent/token_query.go:557.3,558.30 2 0
+auth/ent/token_query.go:560.2,561.39 2 0
+auth/ent/token_query.go:561.39,563.3 1 0
+auth/ent/token_query.go:564.2,566.71 3 0
+auth/ent/token_query.go:566.71,568.3 1 0
+auth/ent/token_query.go:569.2,570.31 2 0
+auth/ent/token_query.go:580.69,583.2 2 0
+auth/ent/token_query.go:586.63,588.45 2 0
+auth/ent/token_query.go:588.45,590.3 1 0
+auth/ent/token_query.go:591.2,591.94 1 0
+auth/ent/token_query.go:594.84,597.28 3 0
+auth/ent/token_query.go:597.28,599.3 1 0
+auth/ent/token_query.go:600.2,600.38 1 0
+auth/ent/token_query.go:601.38,602.34 1 0
+auth/ent/token_query.go:603.38,604.40 1 0
+auth/ent/token_query.go:606.2,608.64 3 0
+auth/ent/token_query.go:608.64,610.3 1 0
+auth/ent/token_query.go:611.2,612.31 2 0
+auth/ent/token_update.go:27.66,30.2 2 0
+auth/ent/token_update.go:33.56,36.2 2 0
+auth/ent/token_update.go:39.65,40.14 1 0
+auth/ent/token_update.go:40.14,42.3 1 0
+auth/ent/token_update.go:43.2,43.11 1 0
+auth/ent/token_update.go:47.59,50.2 2 0
+auth/ent/token_update.go:53.68,54.14 1 0
+auth/ent/token_update.go:54.14,56.3 1 0
+auth/ent/token_update.go:57.2,57.11 1 0
+auth/ent/token_update.go:61.63,64.2 2 0
+auth/ent/token_update.go:67.72,68.14 1 0
+auth/ent/token_update.go:68.14,70.3 1 0
+auth/ent/token_update.go:71.2,71.11 1 0
+auth/ent/token_update.go:75.56,78.2 2 0
+auth/ent/token_update.go:81.65,82.14 1 0
+auth/ent/token_update.go:82.14,84.3 1 0
+auth/ent/token_update.go:85.2,85.11 1 0
+auth/ent/token_update.go:89.63,92.2 2 0
+auth/ent/token_update.go:95.72,96.14 1 0
+auth/ent/token_update.go:96.14,98.3 1 0
+auth/ent/token_update.go:99.2,99.11 1 0
+auth/ent/token_update.go:103.63,106.2 2 0
+auth/ent/token_update.go:109.58,112.2 2 0
+auth/ent/token_update.go:115.54,117.2 1 0
+auth/ent/token_update.go:120.50,122.2 1 0
+auth/ent/token_update.go:125.49,128.2 2 0
+auth/ent/token_update.go:131.63,134.2 2 0
+auth/ent/token_update.go:137.55,139.16 2 0
+auth/ent/token_update.go:139.16,140.13 1 0
+auth/ent/token_update.go:142.2,142.17 1 0
+auth/ent/token_update.go:146.56,149.2 2 0
+auth/ent/token_update.go:152.51,153.37 1 0
+auth/ent/token_update.go:153.37,154.13 1 0
+auth/ent/token_update.go:159.35,160.43 1 0
+auth/ent/token_update.go:160.43,163.3 2 0
+auth/ent/token_update.go:167.38,168.40 1 0
+auth/ent/token_update.go:168.40,169.48 1 0
+auth/ent/token_update.go:169.48,171.4 1 0
+auth/ent/token_update.go:173.2,173.69 1 0
+auth/ent/token_update.go:173.69,175.3 1 0
+auth/ent/token_update.go:176.2,176.12 1 0
+auth/ent/token_update.go:179.72,180.35 1 0
+auth/ent/token_update.go:180.35,182.3 1 0
+auth/ent/token_update.go:183.2,184.47 2 0
+auth/ent/token_update.go:184.47,185.50 1 0
+auth/ent/token_update.go:185.50,186.22 1 0
+auth/ent/token_update.go:186.22,188.5 1 0
+auth/ent/token_update.go:191.2,191.42 1 0
+auth/ent/token_update.go:191.42,193.3 1 0
+auth/ent/token_update.go:194.2,194.44 1 0
+auth/ent/token_update.go:194.44,196.3 1 0
+auth/ent/token_update.go:197.2,197.46 1 0
+auth/ent/token_update.go:197.46,199.3 1 0
+auth/ent/token_update.go:200.2,200.44 1 0
+auth/ent/token_update.go:200.44,202.3 1 0
+auth/ent/token_update.go:203.2,203.46 1 0
+auth/ent/token_update.go:203.46,205.3 1 0
+auth/ent/token_update.go:206.2,206.46 1 0
+auth/ent/token_update.go:206.46,208.3 1 0
+auth/ent/token_update.go:209.2,209.31 1 0
+auth/ent/token_update.go:209.31,221.3 2 0
+auth/ent/token_update.go:222.2,222.52 1 0
+auth/ent/token_update.go:222.52,233.27 2 0
+auth/ent/token_update.go:233.27,235.4 1 0
+auth/ent/token_update.go:236.3,236.50 1 0
+auth/ent/token_update.go:238.2,238.70 1 0
+auth/ent/token_update.go:238.70,239.49 1 0
+auth/ent/token_update.go:239.49,241.4 1 0
+auth/ent/token_update.go:241.9,241.45 1 0
+auth/ent/token_update.go:241.45,243.4 1 0
+auth/ent/token_update.go:244.3,244.16 1 0
+auth/ent/token_update.go:246.2,247.15 2 0
+auth/ent/token_update.go:259.63,262.2 2 0
+auth/ent/token_update.go:265.72,266.14 1 0
+auth/ent/token_update.go:266.14,268.3 1 0
+auth/ent/token_update.go:269.2,269.12 1 0
+auth/ent/token_update.go:273.66,276.2 2 0
+auth/ent/token_update.go:279.75,280.14 1 0
+auth/ent/token_update.go:280.14,282.3 1 0
+auth/ent/token_update.go:283.2,283.12 1 0
+auth/ent/token_update.go:287.70,290.2 2 0
+auth/ent/token_update.go:293.79,294.14 1 0
+auth/ent/token_update.go:294.14,296.3 1 0
+auth/ent/token_update.go:297.2,297.12 1 0
+auth/ent/token_update.go:301.63,304.2 2 0
+auth/ent/token_update.go:307.72,308.14 1 0
+auth/ent/token_update.go:308.14,310.3 1 0
+auth/ent/token_update.go:311.2,311.12 1 0
+auth/ent/token_update.go:315.70,318.2 2 0
+auth/ent/token_update.go:321.79,322.14 1 0
+auth/ent/token_update.go:322.14,324.3 1 0
+auth/ent/token_update.go:325.2,325.12 1 0
+auth/ent/token_update.go:329.70,332.2 2 0
+auth/ent/token_update.go:335.65,338.2 2 0
+auth/ent/token_update.go:341.61,343.2 1 0
+auth/ent/token_update.go:346.54,348.2 1 0
+auth/ent/token_update.go:351.56,354.2 2 0
+auth/ent/token_update.go:357.73,360.2 2 0
+auth/ent/token_update.go:364.83,367.2 2 0
+auth/ent/token_update.go:370.70,373.2 2 0
+auth/ent/token_update.go:376.62,378.16 2 0
+auth/ent/token_update.go:378.16,379.13 1 0
+auth/ent/token_update.go:381.2,381.13 1 0
+auth/ent/token_update.go:385.60,388.2 2 0
+auth/ent/token_update.go:391.55,392.38 1 0
+auth/ent/token_update.go:392.38,393.13 1 0
+auth/ent/token_update.go:398.39,399.44 1 0
+auth/ent/token_update.go:399.44,402.3 2 0
+auth/ent/token_update.go:406.42,407.41 1 0
+auth/ent/token_update.go:407.41,408.48 1 0
+auth/ent/token_update.go:408.48,410.4 1 0
+auth/ent/token_update.go:412.2,412.71 1 0
+auth/ent/token_update.go:412.71,414.3 1 0
+auth/ent/token_update.go:415.2,415.12 1 0
+auth/ent/token_update.go:418.83,419.36 1 0
+auth/ent/token_update.go:419.36,421.3 1 0
+auth/ent/token_update.go:422.2,424.9 3 0
+auth/ent/token_update.go:424.9,426.3 1 0
+auth/ent/token_update.go:427.2,428.43 2 0
+auth/ent/token_update.go:428.43,431.28 3 0
+auth/ent/token_update.go:431.28,432.29 1 0
+auth/ent/token_update.go:432.29,434.5 1 0
+auth/ent/token_update.go:435.4,435.26 1 0
+auth/ent/token_update.go:435.26,437.5 1 0
+auth/ent/token_update.go:440.2,440.48 1 0
+auth/ent/token_update.go:440.48,441.50 1 0
+auth/ent/token_update.go:441.50,442.22 1 0
+auth/ent/token_update.go:442.22,444.5 1 0
+auth/ent/token_update.go:447.2,447.43 1 0
+auth/ent/token_update.go:447.43,449.3 1 0
+auth/ent/token_update.go:450.2,450.45 1 0
+auth/ent/token_update.go:450.45,452.3 1 0
+auth/ent/token_update.go:453.2,453.47 1 0
+auth/ent/token_update.go:453.47,455.3 1 0
+auth/ent/token_update.go:456.2,456.45 1 0
+auth/ent/token_update.go:456.45,458.3 1 0
+auth/ent/token_update.go:459.2,459.47 1 0
+auth/ent/token_update.go:459.47,461.3 1 0
+auth/ent/token_update.go:462.2,462.47 1 0
+auth/ent/token_update.go:462.47,464.3 1 0
+auth/ent/token_update.go:465.2,465.32 1 0
+auth/ent/token_update.go:465.32,477.3 2 0
+auth/ent/token_update.go:478.2,478.53 1 0
+auth/ent/token_update.go:478.53,489.27 2 0
+auth/ent/token_update.go:489.27,491.4 1 0
+auth/ent/token_update.go:492.3,492.50 1 0
+auth/ent/token_update.go:494.2,497.67 4 0
+auth/ent/token_update.go:497.67,498.49 1 0
+auth/ent/token_update.go:498.49,500.4 1 0
+auth/ent/token_update.go:500.9,500.45 1 0
+auth/ent/token_update.go:500.45,502.4 1 0
+auth/ent/token_update.go:503.3,503.18 1 0
+auth/ent/token_update.go:505.2,506.19 2 0
+auth/ent/tx.go:59.63,61.2 1 0
+auth/ent/tx.go:64.30,66.65 2 0
+auth/ent/tx.go:66.65,68.3 1 0
+auth/ent/tx.go:69.2,72.39 4 0
+auth/ent/tx.go:72.39,74.3 1 0
+auth/ent/tx.go:75.2,75.30 1 0
+auth/ent/tx.go:79.38,84.2 4 0
+auth/ent/tx.go:115.67,117.2 1 0
+auth/ent/tx.go:120.32,122.68 2 0
+auth/ent/tx.go:122.68,124.3 1 0
+auth/ent/tx.go:125.2,128.39 4 0
+auth/ent/tx.go:128.39,130.3 1 0
+auth/ent/tx.go:131.2,131.32 1 0
+auth/ent/tx.go:135.42,140.2 4 0
+auth/ent/tx.go:143.32,144.26 1 0
+auth/ent/tx.go:144.26,147.3 2 0
+auth/ent/tx.go:148.2,148.18 1 0
+auth/ent/tx.go:151.22,155.2 3 0
+auth/ent/tx.go:180.72,182.16 2 0
+auth/ent/tx.go:182.16,184.3 1 0
+auth/ent/tx.go:185.2,185.41 1 0
+auth/ent/tx.go:190.61,190.79 1 0
+auth/ent/tx.go:193.38,193.65 1 0
+auth/ent/tx.go:196.32,196.46 1 0
+auth/ent/tx.go:200.33,200.47 1 0
+auth/ent/tx.go:204.35,204.49 1 0
+auth/ent/tx.go:207.80,209.2 1 0
+auth/ent/tx.go:212.81,214.2 1 0
+auth/ent/user.go:49.50,50.22 1 0
+auth/ent/user.go:50.22,52.3 1 0
+auth/ent/user.go:53.2,53.44 1 0
+auth/ent/user.go:58.52,59.22 1 0
+auth/ent/user.go:59.22,61.3 1 0
+auth/ent/user.go:62.2,62.45 1 0
+auth/ent/user.go:66.58,68.25 2 0
+auth/ent/user.go:68.25,69.21 1 0
+auth/ent/user.go:70.78,71.35 1 0
+auth/ent/user.go:72.49,73.33 1 0
+auth/ent/user.go:74.11,75.36 1 0
+auth/ent/user.go:78.2,78.20 1 0
+auth/ent/user.go:83.67,84.46 1 0
+auth/ent/user.go:84.46,86.3 1 0
+auth/ent/user.go:87.2,87.25 1 0
+auth/ent/user.go:87.25,88.21 1 0
+auth/ent/user.go:89.21,90.53 1 0
+auth/ent/user.go:90.53,92.5 1 0
+auth/ent/user.go:92.10,92.26 1 0
+auth/ent/user.go:92.26,94.5 1 0
+auth/ent/user.go:95.27,96.53 1 0
+auth/ent/user.go:96.53,98.5 1 0
+auth/ent/user.go:98.10,98.26 1 0
+auth/ent/user.go:98.26,100.5 1 0
+auth/ent/user.go:101.24,102.53 1 0
+auth/ent/user.go:102.53,104.5 1 0
+auth/ent/user.go:104.10,104.26 1 0
+auth/ent/user.go:104.26,106.5 1 0
+auth/ent/user.go:107.27,108.53 1 0
+auth/ent/user.go:108.53,110.5 1 0
+auth/ent/user.go:110.10,110.26 1 0
+auth/ent/user.go:110.26,112.5 1 0
+auth/ent/user.go:113.28,114.51 1 0
+auth/ent/user.go:114.51,116.5 1 0
+auth/ent/user.go:116.10,116.26 1 0
+auth/ent/user.go:116.26,118.5 1 0
+auth/ent/user.go:119.28,120.51 1 0
+auth/ent/user.go:120.51,122.5 1 0
+auth/ent/user.go:122.10,122.26 1 0
+auth/ent/user.go:122.26,124.5 1 0
+auth/ent/user.go:125.11,126.45 1 0
+auth/ent/user.go:129.2,129.12 1 0
+auth/ent/user.go:134.54,136.2 1 0
+auth/ent/user.go:139.40,141.2 1 0
+auth/ent/user.go:144.42,146.2 1 0
+auth/ent/user.go:151.40,153.2 1 0
+auth/ent/user.go:157.31,159.9 2 0
+auth/ent/user.go:159.9,160.51 1 0
+auth/ent/user.go:162.2,163.10 2 0
+auth/ent/user.go:167.32,187.2 19 0
+auth/ent/user_create.go:26.57,29.2 2 0
+auth/ent/user_create.go:32.54,35.2 2 0
+auth/ent/user_create.go:38.57,41.2 2 0
+auth/ent/user_create.go:44.61,47.2 2 0
+auth/ent/user_create.go:50.70,51.14 1 0
+auth/ent/user_create.go:51.14,53.3 1 0
+auth/ent/user_create.go:54.2,54.11 1 0
+auth/ent/user_create.go:58.61,61.2 2 0
+auth/ent/user_create.go:64.70,65.14 1 0
+auth/ent/user_create.go:65.14,67.3 1 0
+auth/ent/user_create.go:68.2,68.11 1 0
+auth/ent/user_create.go:72.51,75.2 2 0
+auth/ent/user_create.go:78.60,79.14 1 0
+auth/ent/user_create.go:79.14,81.3 1 0
+auth/ent/user_create.go:82.2,82.11 1 0
+auth/ent/user_create.go:86.61,89.2 2 0
+auth/ent/user_create.go:92.56,94.19 2 0
+auth/ent/user_create.go:94.19,96.3 1 0
+auth/ent/user_create.go:97.2,97.30 1 0
+auth/ent/user_create.go:101.62,104.2 2 0
+auth/ent/user_create.go:107.58,109.19 2 0
+auth/ent/user_create.go:109.19,111.3 1 0
+auth/ent/user_create.go:112.2,112.31 1 0
+auth/ent/user_create.go:116.48,118.2 1 0
+auth/ent/user_create.go:121.64,122.38 1 0
+auth/ent/user_create.go:122.38,124.3 1 0
+auth/ent/user_create.go:125.2,125.58 1 0
+auth/ent/user_create.go:129.56,131.16 2 0
+auth/ent/user_create.go:131.16,132.13 1 0
+auth/ent/user_create.go:134.2,134.10 1 0
+auth/ent/user_create.go:138.55,141.2 2 0
+auth/ent/user_create.go:144.50,145.37 1 0
+auth/ent/user_create.go:145.37,146.13 1 0
+auth/ent/user_create.go:151.40,152.43 1 0
+auth/ent/user_create.go:152.43,153.35 1 0
+auth/ent/user_create.go:153.35,155.4 1 0
+auth/ent/user_create.go:156.3,157.30 2 0
+auth/ent/user_create.go:159.2,159.43 1 0
+auth/ent/user_create.go:159.43,160.35 1 0
+auth/ent/user_create.go:160.35,162.4 1 0
+auth/ent/user_create.go:163.3,164.30 2 0
+auth/ent/user_create.go:166.2,166.36 1 0
+auth/ent/user_create.go:166.36,167.28 1 0
+auth/ent/user_create.go:167.28,169.4 1 0
+auth/ent/user_create.go:170.3,171.23 2 0
+auth/ent/user_create.go:173.2,173.12 1 0
+auth/ent/user_create.go:177.37,178.42 1 0
+auth/ent/user_create.go:178.42,180.3 1 0
+auth/ent/user_create.go:181.2,181.39 1 0
+auth/ent/user_create.go:181.39,183.3 1 0
+auth/ent/user_create.go:184.2,184.42 1 0
+auth/ent/user_create.go:184.42,186.3 1 0
+auth/ent/user_create.go:187.2,187.43 1 0
+auth/ent/user_create.go:187.43,189.3 1 0
+auth/ent/user_create.go:190.2,190.43 1 0
+auth/ent/user_create.go:190.43,192.3 1 0
+auth/ent/user_create.go:193.2,193.12 1 0
+auth/ent/user_create.go:196.67,197.35 1 0
+auth/ent/user_create.go:197.35,199.3 1 0
+auth/ent/user_create.go:200.2,201.67 2 0
+auth/ent/user_create.go:201.67,202.38 1 0
+auth/ent/user_create.go:202.38,204.4 1 0
+auth/ent/user_create.go:205.3,205.18 1 0
+auth/ent/user_create.go:207.2,207.27 1 0
+auth/ent/user_create.go:207.27,208.44 1 0
+auth/ent/user_create.go:208.44,210.4 1 0
+auth/ent/user_create.go:210.9,212.4 1 0
+auth/ent/user_create.go:214.2,216.19 3 0
+auth/ent/user_create.go:219.66,224.36 2 0
+auth/ent/user_create.go:224.36,227.3 2 0
+auth/ent/user_create.go:228.2,228.45 1 0
+auth/ent/user_create.go:228.45,231.3 2 0
+auth/ent/user_create.go:232.2,232.42 1 0
+auth/ent/user_create.go:232.42,235.3 2 0
+auth/ent/user_create.go:236.2,236.45 1 0
+auth/ent/user_create.go:236.45,239.3 2 0
+auth/ent/user_create.go:240.2,240.46 1 0
+auth/ent/user_create.go:240.46,243.3 2 0
+auth/ent/user_create.go:244.2,244.46 1 0
+auth/ent/user_create.go:244.46,247.3 2 0
+auth/ent/user_create.go:248.2,248.53 1 0
+auth/ent/user_create.go:248.53,259.27 2 0
+auth/ent/user_create.go:259.27,261.4 1 0
+auth/ent/user_create.go:262.3,262.42 1 0
+auth/ent/user_create.go:264.2,264.54 1 0
+auth/ent/user_create.go:264.54,275.27 2 0
+auth/ent/user_create.go:275.27,277.4 1 0
+auth/ent/user_create.go:278.3,278.42 1 0
+auth/ent/user_create.go:280.2,280.21 1 0
+auth/ent/user_create.go:291.71,292.20 1 0
+auth/ent/user_create.go:292.20,294.3 1 0
+auth/ent/user_create.go:295.2,298.30 4 0
+auth/ent/user_create.go:298.30,299.37 1 0
+auth/ent/user_create.go:299.37,302.86 3 0
+auth/ent/user_create.go:302.86,304.12 2 0
+auth/ent/user_create.go:304.12,306.6 1 0
+auth/ent/user_create.go:307.5,307.43 1 0
+auth/ent/user_create.go:307.43,309.6 1 0
+auth/ent/user_create.go:310.5,313.28 4 0
+auth/ent/user_create.go:313.28,315.6 1 0
+auth/ent/user_create.go:315.11,318.71 2 0
+auth/ent/user_create.go:318.71,319.42 1 0
+auth/ent/user_create.go:319.42,321.8 1 0
+auth/ent/user_create.go:324.5,324.19 1 0
+auth/ent/user_create.go:324.19,326.6 1 0
+auth/ent/user_create.go:327.5,329.25 3 0
+auth/ent/user_create.go:331.4,331.49 1 0
+auth/ent/user_create.go:331.49,333.5 1 0
+auth/ent/user_create.go:334.4,334.21 1 0
+auth/ent/user_create.go:337.2,337.23 1 0
+auth/ent/user_create.go:337.23,338.78 1 0
+auth/ent/user_create.go:338.78,340.4 1 0
+auth/ent/user_create.go:342.2,342.19 1 0
+auth/ent/user_create.go:346.63,348.16 2 0
+auth/ent/user_create.go:348.16,349.13 1 0
+auth/ent/user_create.go:351.2,351.10 1 0
+auth/ent/user_create.go:355.60,358.2 2 0
+auth/ent/user_create.go:361.55,362.38 1 0
+auth/ent/user_create.go:362.38,363.13 1 0
+auth/ent/user_delete.go:23.63,26.2 2 0
+auth/ent/user_delete.go:29.62,31.2 1 0
+auth/ent/user_delete.go:34.54,36.16 2 0
+auth/ent/user_delete.go:36.16,37.13 1 0
+auth/ent/user_delete.go:39.2,39.10 1 0
+auth/ent/user_delete.go:42.65,44.47 2 0
+auth/ent/user_delete.go:44.47,45.50 1 0
+auth/ent/user_delete.go:45.50,46.22 1 0
+auth/ent/user_delete.go:46.22,48.5 1 0
+auth/ent/user_delete.go:51.2,52.51 2 0
+auth/ent/user_delete.go:52.51,54.3 1 0
+auth/ent/user_delete.go:55.2,56.22 2 0
+auth/ent/user_delete.go:65.70,68.2 2 0
+auth/ent/user_delete.go:71.59,73.9 2 0
+auth/ent/user_delete.go:74.18,75.13 1 0
+auth/ent/user_delete.go:76.14,77.36 1 0
+auth/ent/user_delete.go:78.10,79.13 1 0
+auth/ent/user_delete.go:84.54,85.38 1 0
+auth/ent/user_delete.go:85.38,86.13 1 0
+auth/ent/user_query.go:35.61,38.2 2 0
+auth/ent/user_query.go:41.50,44.2 2 0
+auth/ent/user_query.go:47.52,50.2 2 0
+auth/ent/user_query.go:54.53,57.2 2 0
+auth/ent/user_query.go:60.62,63.2 2 0
+auth/ent/user_query.go:66.46,68.74 2 0
+auth/ent/user_query.go:68.74,69.46 1 0
+auth/ent/user_query.go:69.46,71.4 1 0
+auth/ent/user_query.go:72.3,73.40 2 0
+auth/ent/user_query.go:73.40,75.4 1 0
+auth/ent/user_query.go:76.3,82.20 3 0
+auth/ent/user_query.go:84.2,84.14 1 0
+auth/ent/user_query.go:88.48,90.74 2 0
+auth/ent/user_query.go:90.74,91.46 1 0
+auth/ent/user_query.go:91.46,93.4 1 0
+auth/ent/user_query.go:94.3,95.40 2 0
+auth/ent/user_query.go:95.40,97.4 1 0
+auth/ent/user_query.go:98.3,104.20 3 0
+auth/ent/user_query.go:106.2,106.14 1 0
+auth/ent/user_query.go:111.64,113.16 2 0
+auth/ent/user_query.go:113.16,115.3 1 0
+auth/ent/user_query.go:116.2,116.21 1 0
+auth/ent/user_query.go:116.21,118.3 1 0
+auth/ent/user_query.go:119.2,119.22 1 0
+auth/ent/user_query.go:123.56,125.36 2 0
+auth/ent/user_query.go:125.36,126.13 1 0
+auth/ent/user_query.go:128.2,128.13 1 0
+auth/ent/user_query.go:133.74,135.82 2 0
+auth/ent/user_query.go:135.82,137.3 1 0
+auth/ent/user_query.go:138.2,138.19 1 0
+auth/ent/user_query.go:138.19,141.3 2 0
+auth/ent/user_query.go:142.2,142.20 1 0
+auth/ent/user_query.go:146.59,148.36 2 0
+auth/ent/user_query.go:148.36,149.13 1 0
+auth/ent/user_query.go:151.2,151.11 1 0
+auth/ent/user_query.go:157.63,159.16 2 0
+auth/ent/user_query.go:159.16,161.3 1 0
+auth/ent/user_query.go:162.2,162.20 1 0
+auth/ent/user_query.go:163.9,164.23 1 0
+auth/ent/user_query.go:165.9,166.41 1 0
+auth/ent/user_query.go:167.10,168.44 1 0
+auth/ent/user_query.go:173.55,175.16 2 0
+auth/ent/user_query.go:175.16,176.13 1 0
+auth/ent/user_query.go:178.2,178.13 1 0
+auth/ent/user_query.go:184.73,186.81 2 0
+auth/ent/user_query.go:186.81,188.3 1 0
+auth/ent/user_query.go:189.2,189.18 1 0
+auth/ent/user_query.go:190.9,191.14 1 0
+auth/ent/user_query.go:192.9,193.35 1 0
+auth/ent/user_query.go:194.10,195.38 1 0
+auth/ent/user_query.go:197.2,197.8 1 0
+auth/ent/user_query.go:201.58,203.16 2 0
+auth/ent/user_query.go:203.16,204.13 1 0
+auth/ent/user_query.go:206.2,206.11 1 0
+auth/ent/user_query.go:210.64,212.45 2 0
+auth/ent/user_query.go:212.45,214.3 1 0
+auth/ent/user_query.go:215.2,216.58 2 0
+auth/ent/user_query.go:220.56,222.16 2 0
+auth/ent/user_query.go:222.16,223.13 1 0
+auth/ent/user_query.go:225.2,225.14 1 0
+auth/ent/user_query.go:229.73,230.44 1 0
+auth/ent/user_query.go:230.44,232.3 1 0
+auth/ent/user_query.go:233.2,234.63 2 0
+auth/ent/user_query.go:234.63,236.3 1 0
+auth/ent/user_query.go:237.2,237.17 1 0
+auth/ent/user_query.go:241.57,243.16 2 0
+auth/ent/user_query.go:243.16,244.13 1 0
+auth/ent/user_query.go:246.2,246.12 1 0
+auth/ent/user_query.go:250.62,252.45 2 0
+auth/ent/user_query.go:252.45,254.3 1 0
+auth/ent/user_query.go:255.2,255.78 1 0
+auth/ent/user_query.go:259.54,261.16 2 0
+auth/ent/user_query.go:261.16,262.13 1 0
+auth/ent/user_query.go:264.2,264.14 1 0
+auth/ent/user_query.go:268.63,270.36 2 0
+auth/ent/user_query.go:271.23,272.20 1 0
+auth/ent/user_query.go:273.18,274.60 1 0
+auth/ent/user_query.go:275.10,276.19 1 0
+auth/ent/user_query.go:281.55,283.16 2 0
+auth/ent/user_query.go:283.16,284.13 1 0
+auth/ent/user_query.go:286.2,286.14 1 0
+auth/ent/user_query.go:291.41,292.15 1 0
+auth/ent/user_query.go:292.15,294.3 1 0
+auth/ent/user_query.go:295.2,306.3 1 0
+auth/ent/user_query.go:311.69,313.27 2 0
+auth/ent/user_query.go:313.27,315.3 1 0
+auth/ent/user_query.go:316.2,317.11 2 0
+auth/ent/user_query.go:322.71,324.27 2 0
+auth/ent/user_query.go:324.27,326.3 1 0
+auth/ent/user_query.go:327.2,328.11 2 0
+auth/ent/user_query.go:345.75,352.2 6 0
+auth/ent/user_query.go:366.59,372.2 5 0
+auth/ent/user_query.go:375.66,377.2 1 0
+auth/ent/user_query.go:379.62,380.34 1 0
+auth/ent/user_query.go:380.34,381.19 1 0
+auth/ent/user_query.go:381.19,383.4 1 0
+auth/ent/user_query.go:384.3,384.39 1 0
+auth/ent/user_query.go:384.39,385.48 1 0
+auth/ent/user_query.go:385.48,387.5 1 0
+auth/ent/user_query.go:390.2,390.34 1 0
+auth/ent/user_query.go:390.34,391.27 1 0
+auth/ent/user_query.go:391.27,393.4 1 0
+auth/ent/user_query.go:395.2,395.20 1 0
+auth/ent/user_query.go:395.20,397.17 2 0
+auth/ent/user_query.go:397.17,399.4 1 0
+auth/ent/user_query.go:400.3,400.16 1 0
+auth/ent/user_query.go:402.2,402.12 1 0
+auth/ent/user_query.go:405.87,414.59 2 0
+auth/ent/user_query.go:414.59,416.3 1 0
+auth/ent/user_query.go:417.2,417.60 1 0
+auth/ent/user_query.go:417.60,422.3 4 0
+auth/ent/user_query.go:423.2,423.23 1 0
+auth/ent/user_query.go:423.23,425.3 1 0
+auth/ent/user_query.go:426.2,426.67 1 0
+auth/ent/user_query.go:426.67,428.3 1 0
+auth/ent/user_query.go:429.2,429.21 1 0
+auth/ent/user_query.go:429.21,431.3 1 0
+auth/ent/user_query.go:432.2,432.41 1 0
+auth/ent/user_query.go:432.41,434.18 1 0
+auth/ent/user_query.go:434.18,434.47 1 0
+auth/ent/user_query.go:435.27,435.71 1 0
+auth/ent/user_query.go:435.85,437.4 1 0
+auth/ent/user_query.go:439.2,439.42 1 0
+auth/ent/user_query.go:439.42,441.18 1 0
+auth/ent/user_query.go:441.18,441.49 1 0
+auth/ent/user_query.go:442.28,442.74 1 0
+auth/ent/user_query.go:442.88,444.4 1 0
+auth/ent/user_query.go:446.2,446.19 1 0
+auth/ent/user_query.go:449.137,453.29 4 0
+auth/ent/user_query.go:453.29,456.18 3 0
+auth/ent/user_query.go:456.18,458.4 1 0
+auth/ent/user_query.go:460.2,460.36 1 0
+auth/ent/user_query.go:460.36,468.3 7 0
+auth/ent/user_query.go:469.2,469.48 1 0
+auth/ent/user_query.go:469.48,471.3 1 0
+auth/ent/user_query.go:472.2,472.70 1 0
+auth/ent/user_query.go:472.70,473.78 1 0
+auth/ent/user_query.go:473.78,476.60 3 0
+auth/ent/user_query.go:476.60,478.19 2 0
+auth/ent/user_query.go:478.19,480.6 1 0
+auth/ent/user_query.go:481.5,481.62 1 0
+auth/ent/user_query.go:483.4,483.61 1 0
+auth/ent/user_query.go:483.61,486.29 3 0
+auth/ent/user_query.go:486.29,489.6 2 0
+auth/ent/user_query.go:490.5,491.15 2 0
+auth/ent/user_query.go:495.2,496.16 2 0
+auth/ent/user_query.go:496.16,498.3 1 0
+auth/ent/user_query.go:499.2,499.30 1 0
+auth/ent/user_query.go:499.30,501.10 2 0
+auth/ent/user_query.go:501.10,503.4 1 0
+auth/ent/user_query.go:504.3,504.25 1 0
+auth/ent/user_query.go:504.25,506.4 1 0
+auth/ent/user_query.go:508.2,508.12 1 0
+auth/ent/user_query.go:510.140,513.23 3 0
+auth/ent/user_query.go:513.23,516.18 3 0
+auth/ent/user_query.go:516.18,518.4 1 0
+auth/ent/user_query.go:520.2,521.52 2 0
+auth/ent/user_query.go:521.52,523.3 1 0
+auth/ent/user_query.go:524.2,525.16 2 0
+auth/ent/user_query.go:525.16,527.3 1 0
+auth/ent/user_query.go:528.2,528.30 1 0
+auth/ent/user_query.go:528.30,530.16 2 0
+auth/ent/user_query.go:530.16,532.4 1 0
+auth/ent/user_query.go:533.3,534.10 2 0
+auth/ent/user_query.go:534.10,536.4 1 0
+auth/ent/user_query.go:537.3,537.18 1 0
+auth/ent/user_query.go:539.2,539.12 1 0
+auth/ent/user_query.go:542.65,545.28 3 0
+auth/ent/user_query.go:545.28,547.3 1 0
+auth/ent/user_query.go:548.2,548.51 1 0
+auth/ent/user_query.go:551.54,554.44 3 0
+auth/ent/user_query.go:554.44,556.3 1 0
+auth/ent/user_query.go:556.8,556.27 1 0
+auth/ent/user_query.go:556.27,558.3 1 0
+auth/ent/user_query.go:559.2,559.46 1 0
+auth/ent/user_query.go:559.46,562.25 3 0
+auth/ent/user_query.go:562.25,563.33 1 0
+auth/ent/user_query.go:563.33,565.5 1 0
+auth/ent/user_query.go:568.2,568.38 1 0
+auth/ent/user_query.go:568.38,569.50 1 0
+auth/ent/user_query.go:569.50,570.22 1 0
+auth/ent/user_query.go:570.22,572.5 1 0
+auth/ent/user_query.go:575.2,575.41 1 0
+auth/ent/user_query.go:575.41,577.3 1 0
+auth/ent/user_query.go:578.2,578.44 1 0
+auth/ent/user_query.go:578.44,580.3 1 0
+auth/ent/user_query.go:581.2,581.33 1 0
+auth/ent/user_query.go:581.33,582.46 1 0
+auth/ent/user_query.go:582.46,583.22 1 0
+auth/ent/user_query.go:583.22,585.5 1 0
+auth/ent/user_query.go:588.2,588.14 1 0
+auth/ent/user_query.go:591.66,595.23 4 0
+auth/ent/user_query.go:595.23,597.3 1 0
+auth/ent/user_query.go:598.2,599.19 2 0
+auth/ent/user_query.go:599.19,602.3 2 0
+auth/ent/user_query.go:603.2,603.44 1 0
+auth/ent/user_query.go:603.44,605.3 1 0
+auth/ent/user_query.go:606.2,606.34 1 0
+auth/ent/user_query.go:606.34,608.3 1 0
+auth/ent/user_query.go:609.2,609.29 1 0
+auth/ent/user_query.go:609.29,611.3 1 0
+auth/ent/user_query.go:612.2,612.44 1 0
+auth/ent/user_query.go:612.44,616.3 1 0
+auth/ent/user_query.go:617.2,617.41 1 0
+auth/ent/user_query.go:617.41,619.3 1 0
+auth/ent/user_query.go:620.2,620.17 1 0
+auth/ent/user_query.go:630.70,633.2 2 0
+auth/ent/user_query.go:636.64,638.52 2 0
+auth/ent/user_query.go:638.52,640.3 1 0
+auth/ent/user_query.go:641.2,641.97 1 0
+auth/ent/user_query.go:644.84,647.29 3 0
+auth/ent/user_query.go:647.29,649.3 1 0
+auth/ent/user_query.go:650.2,650.42 1 0
+auth/ent/user_query.go:650.42,652.31 2 0
+auth/ent/user_query.go:652.31,654.4 1 0
+auth/ent/user_query.go:655.3,656.30 2 0
+auth/ent/user_query.go:658.2,659.39 2 0
+auth/ent/user_query.go:659.39,661.3 1 0
+auth/ent/user_query.go:662.2,664.71 3 0
+auth/ent/user_query.go:664.71,666.3 1 0
+auth/ent/user_query.go:667.2,668.31 2 0
+auth/ent/user_query.go:678.67,681.2 2 0
+auth/ent/user_query.go:684.62,686.45 2 0
+auth/ent/user_query.go:686.45,688.3 1 0
+auth/ent/user_query.go:689.2,689.91 1 0
+auth/ent/user_query.go:692.82,695.28 3 0
+auth/ent/user_query.go:695.28,697.3 1 0
+auth/ent/user_query.go:698.2,698.38 1 0
+auth/ent/user_query.go:699.38,700.34 1 0
+auth/ent/user_query.go:701.38,702.40 1 0
+auth/ent/user_query.go:704.2,706.64 3 0
+auth/ent/user_query.go:706.64,708.3 1 0
+auth/ent/user_query.go:709.2,710.31 2 0
+auth/ent/user_update.go:28.63,31.2 2 0
+auth/ent/user_update.go:34.57,37.2 2 0
+auth/ent/user_update.go:40.66,41.14 1 0
+auth/ent/user_update.go:41.14,43.3 1 0
+auth/ent/user_update.go:44.2,44.11 1 0
+auth/ent/user_update.go:48.54,51.2 2 0
+auth/ent/user_update.go:54.63,55.14 1 0
+auth/ent/user_update.go:55.14,57.3 1 0
+auth/ent/user_update.go:58.2,58.11 1 0
+auth/ent/user_update.go:62.57,65.2 2 0
+auth/ent/user_update.go:68.66,69.14 1 0
+auth/ent/user_update.go:69.14,71.3 1 0
+auth/ent/user_update.go:72.2,72.11 1 0
+auth/ent/user_update.go:76.61,79.2 2 0
+auth/ent/user_update.go:82.70,83.14 1 0
+auth/ent/user_update.go:83.14,85.3 1 0
+auth/ent/user_update.go:86.2,86.11 1 0
+auth/ent/user_update.go:90.61,93.2 2 0
+auth/ent/user_update.go:96.61,99.2 2 0
+auth/ent/user_update.go:102.56,104.19 2 0
+auth/ent/user_update.go:104.19,106.3 1 0
+auth/ent/user_update.go:107.2,107.30 1 0
+auth/ent/user_update.go:111.62,114.2 2 0
+auth/ent/user_update.go:117.58,119.19 2 0
+auth/ent/user_update.go:119.19,121.3 1 0
+auth/ent/user_update.go:122.2,122.31 1 0
+auth/ent/user_update.go:126.48,128.2 1 0
+auth/ent/user_update.go:131.48,134.2 2 0
+auth/ent/user_update.go:137.64,140.2 2 0
+auth/ent/user_update.go:143.59,145.19 2 0
+auth/ent/user_update.go:145.19,147.3 1 0
+auth/ent/user_update.go:148.2,148.33 1 0
+auth/ent/user_update.go:152.49,155.2 2 0
+auth/ent/user_update.go:158.65,161.2 2 0
+auth/ent/user_update.go:164.61,166.19 2 0
+auth/ent/user_update.go:166.19,168.3 1 0
+auth/ent/user_update.go:169.2,169.34 1 0
+auth/ent/user_update.go:173.62,174.38 1 0
+auth/ent/user_update.go:174.38,176.3 1 0
+auth/ent/user_update.go:177.2,177.58 1 0
+auth/ent/user_update.go:181.54,183.16 2 0
+auth/ent/user_update.go:183.16,184.13 1 0
+auth/ent/user_update.go:186.2,186.17 1 0
+auth/ent/user_update.go:190.55,193.2 2 0
+auth/ent/user_update.go:196.50,197.37 1 0
+auth/ent/user_update.go:197.37,198.13 1 0
+auth/ent/user_update.go:203.40,204.43 1 0
+auth/ent/user_update.go:204.43,205.41 1 0
+auth/ent/user_update.go:205.41,207.4 1 0
+auth/ent/user_update.go:208.3,209.30 2 0
+auth/ent/user_update.go:211.2,211.12 1 0
+auth/ent/user_update.go:214.71,216.47 2 0
+auth/ent/user_update.go:216.47,217.50 1 0
+auth/ent/user_update.go:217.50,218.22 1 0
+auth/ent/user_update.go:218.22,220.5 1 0
+auth/ent/user_update.go:223.2,223.45 1 0
+auth/ent/user_update.go:223.45,225.3 1 0
+auth/ent/user_update.go:226.2,226.42 1 0
+auth/ent/user_update.go:226.42,228.3 1 0
+auth/ent/user_update.go:229.2,229.45 1 0
+auth/ent/user_update.go:229.45,231.3 1 0
+auth/ent/user_update.go:232.2,232.46 1 0
+auth/ent/user_update.go:232.46,234.3 1 0
+auth/ent/user_update.go:235.2,235.46 1 0
+auth/ent/user_update.go:235.46,237.3 1 0
+auth/ent/user_update.go:238.2,238.32 1 0
+auth/ent/user_update.go:238.32,250.3 2 0
+auth/ent/user_update.go:251.2,251.91 1 0
+auth/ent/user_update.go:251.91,262.27 2 0
+auth/ent/user_update.go:262.27,264.4 1 0
+auth/ent/user_update.go:265.3,265.54 1 0
+auth/ent/user_update.go:267.2,267.53 1 0
+auth/ent/user_update.go:267.53,278.27 2 0
+auth/ent/user_update.go:278.27,280.4 1 0
+auth/ent/user_update.go:281.3,281.50 1 0
+auth/ent/user_update.go:283.2,283.33 1 0
+auth/ent/user_update.go:283.33,295.3 2 0
+auth/ent/user_update.go:296.2,296.93 1 0
+auth/ent/user_update.go:296.93,307.27 2 0
+auth/ent/user_update.go:307.27,309.4 1 0
+auth/ent/user_update.go:310.3,310.54 1 0
+auth/ent/user_update.go:312.2,312.54 1 0
+auth/ent/user_update.go:312.54,323.27 2 0
+auth/ent/user_update.go:323.27,325.4 1 0
+auth/ent/user_update.go:326.3,326.50 1 0
+auth/ent/user_update.go:328.2,328.70 1 0
+auth/ent/user_update.go:328.70,329.49 1 0
+auth/ent/user_update.go:329.49,331.4 1 0
+auth/ent/user_update.go:331.9,331.45 1 0
+auth/ent/user_update.go:331.45,333.4 1 0
+auth/ent/user_update.go:334.3,334.16 1 0
+auth/ent/user_update.go:336.2,337.15 2 0
+auth/ent/user_update.go:349.64,352.2 2 0
+auth/ent/user_update.go:355.73,356.14 1 0
+auth/ent/user_update.go:356.14,358.3 1 0
+auth/ent/user_update.go:359.2,359.12 1 0
+auth/ent/user_update.go:363.61,366.2 2 0
+auth/ent/user_update.go:369.70,370.14 1 0
+auth/ent/user_update.go:370.14,372.3 1 0
+auth/ent/user_update.go:373.2,373.12 1 0
+auth/ent/user_update.go:377.64,380.2 2 0
+auth/ent/user_update.go:383.73,384.14 1 0
+auth/ent/user_update.go:384.14,386.3 1 0
+auth/ent/user_update.go:387.2,387.12 1 0
+auth/ent/user_update.go:391.68,394.2 2 0
+auth/ent/user_update.go:397.77,398.14 1 0
+auth/ent/user_update.go:398.14,400.3 1 0
+auth/ent/user_update.go:401.2,401.12 1 0
+auth/ent/user_update.go:405.68,408.2 2 0
+auth/ent/user_update.go:411.68,414.2 2 0
+auth/ent/user_update.go:417.63,419.19 2 0
+auth/ent/user_update.go:419.19,421.3 1 0
+auth/ent/user_update.go:422.2,422.31 1 0
+auth/ent/user_update.go:426.69,429.2 2 0
+auth/ent/user_update.go:432.65,434.19 2 0
+auth/ent/user_update.go:434.19,436.3 1 0
+auth/ent/user_update.go:437.2,437.32 1 0
+auth/ent/user_update.go:441.52,443.2 1 0
+auth/ent/user_update.go:446.55,449.2 2 0
+auth/ent/user_update.go:452.71,455.2 2 0
+auth/ent/user_update.go:458.66,460.19 2 0
+auth/ent/user_update.go:460.19,462.3 1 0
+auth/ent/user_update.go:463.2,463.34 1 0
+auth/ent/user_update.go:467.56,470.2 2 0
+auth/ent/user_update.go:473.72,476.2 2 0
+auth/ent/user_update.go:479.68,481.19 2 0
+auth/ent/user_update.go:481.19,483.3 1 0
+auth/ent/user_update.go:484.2,484.35 1 0
+auth/ent/user_update.go:488.70,491.2 2 0
+auth/ent/user_update.go:495.81,498.2 2 0
+auth/ent/user_update.go:501.68,502.39 1 0
+auth/ent/user_update.go:502.39,504.3 1 0
+auth/ent/user_update.go:505.2,505.61 1 0
+auth/ent/user_update.go:509.60,511.16 2 0
+auth/ent/user_update.go:511.16,512.13 1 0
+auth/ent/user_update.go:514.2,514.13 1 0
+auth/ent/user_update.go:518.59,521.2 2 0
+auth/ent/user_update.go:524.54,525.38 1 0
+auth/ent/user_update.go:525.38,526.13 1 0
+auth/ent/user_update.go:531.44,532.44 1 0
+auth/ent/user_update.go:532.44,533.41 1 0
+auth/ent/user_update.go:533.41,535.4 1 0
+auth/ent/user_update.go:536.3,537.31 2 0
+auth/ent/user_update.go:539.2,539.12 1 0
+auth/ent/user_update.go:542.81,545.9 3 0
+auth/ent/user_update.go:545.9,547.3 1 0
+auth/ent/user_update.go:548.2,549.43 2 0
+auth/ent/user_update.go:549.43,552.28 3 0
+auth/ent/user_update.go:552.28,553.28 1 0
+auth/ent/user_update.go:553.28,555.5 1 0
+auth/ent/user_update.go:556.4,556.25 1 0
+auth/ent/user_update.go:556.25,558.5 1 0
+auth/ent/user_update.go:561.2,561.48 1 0
+auth/ent/user_update.go:561.48,562.50 1 0
+auth/ent/user_update.go:562.50,563.22 1 0
+auth/ent/user_update.go:563.22,565.5 1 0
+auth/ent/user_update.go:568.2,568.46 1 0
+auth/ent/user_update.go:568.46,570.3 1 0
+auth/ent/user_update.go:571.2,571.43 1 0
+auth/ent/user_update.go:571.43,573.3 1 0
+auth/ent/user_update.go:574.2,574.46 1 0
+auth/ent/user_update.go:574.46,576.3 1 0
+auth/ent/user_update.go:577.2,577.47 1 0
+auth/ent/user_update.go:577.47,579.3 1 0
+auth/ent/user_update.go:580.2,580.47 1 0
+auth/ent/user_update.go:580.47,582.3 1 0
+auth/ent/user_update.go:583.2,583.33 1 0
+auth/ent/user_update.go:583.33,595.3 2 0
+auth/ent/user_update.go:596.2,596.93 1 0
+auth/ent/user_update.go:596.93,607.27 2 0
+auth/ent/user_update.go:607.27,609.4 1 0
+auth/ent/user_update.go:610.3,610.54 1 0
+auth/ent/user_update.go:612.2,612.54 1 0
+auth/ent/user_update.go:612.54,623.27 2 0
+auth/ent/user_update.go:623.27,625.4 1 0
+auth/ent/user_update.go:626.3,626.50 1 0
+auth/ent/user_update.go:628.2,628.34 1 0
+auth/ent/user_update.go:628.34,640.3 2 0
+auth/ent/user_update.go:641.2,641.95 1 0
+auth/ent/user_update.go:641.95,652.27 2 0
+auth/ent/user_update.go:652.27,654.4 1 0
+auth/ent/user_update.go:655.3,655.54 1 0
+auth/ent/user_update.go:657.2,657.55 1 0
+auth/ent/user_update.go:657.55,668.27 2 0
+auth/ent/user_update.go:668.27,670.4 1 0
+auth/ent/user_update.go:671.3,671.50 1 0
+auth/ent/user_update.go:673.2,676.67 4 0
+auth/ent/user_update.go:676.67,677.49 1 0
+auth/ent/user_update.go:677.49,679.4 1 0
+auth/ent/user_update.go:679.9,679.45 1 0
+auth/ent/user_update.go:679.45,681.4 1 0
+auth/ent/user_update.go:682.3,682.18 1 0
+auth/ent/user_update.go:684.2,685.19 2 0
+auth/ent/enttest/enttest.go:35.45,36.26 1 0
+auth/ent/enttest/enttest.go:36.26,38.3 1 0
+auth/ent/enttest/enttest.go:42.62,43.26 1 0
+auth/ent/enttest/enttest.go:43.26,45.3 1 0
+auth/ent/enttest/enttest.go:48.41,50.27 2 0
+auth/ent/enttest/enttest.go:50.27,52.3 1 0
+auth/ent/enttest/enttest.go:53.2,53.10 1 0
+auth/ent/enttest/enttest.go:57.86,60.16 3 0
+auth/ent/enttest/enttest.go:60.16,63.3 2 0
+auth/ent/enttest/enttest.go:64.2,65.10 2 0
+auth/ent/enttest/enttest.go:69.56,74.2 4 0
+auth/ent/enttest/enttest.go:75.59,77.16 2 0
+auth/ent/enttest/enttest.go:77.16,80.3 2 0
+auth/ent/enttest/enttest.go:81.2,81.97 1 0
+auth/ent/enttest/enttest.go:81.97,84.3 2 0
+auth/ent/schema/role.go:18.34,21.30 1 0
+auth/ent/schema/role.go:21.30,23.5 1 0
+auth/ent/schema/role.go:35.32,40.2 1 0
+auth/ent/schema/token.go:18.35,21.30 1 0
+auth/ent/schema/token.go:21.30,23.5 1 0
+auth/ent/schema/token.go:39.33,46.2 1 0
+auth/ent/schema/user.go:20.34,23.30 1 0
+auth/ent/schema/user.go:23.30,25.5 1 0
+auth/ent/schema/user.go:38.32,43.2 1 0
+auth/ent/schema/user.go:46.32,50.2 1 0
+auth/ent/schema/user.go:53.30,54.44 1 0
+auth/ent/schema/user.go:54.44,55.86 1 0
+auth/ent/schema/user.go:55.86,56.47 1 0
+auth/ent/schema/user.go:56.47,58.19 2 0
+auth/ent/schema/user.go:58.19,60.6 1 0
+auth/ent/schema/user.go:61.5,61.41 1 0
+auth/ent/schema/user.go:63.4,63.30 1 0
+auth/ent/hook/hook.go:16.82,17.41 1 0
+auth/ent/hook/hook.go:17.41,19.3 1 0
+auth/ent/hook/hook.go:20.2,20.84 1 0
+auth/ent/hook/hook.go:28.83,29.42 1 0
+auth/ent/hook/hook.go:29.42,31.3 1 0
+auth/ent/hook/hook.go:32.2,32.85 1 0
+auth/ent/hook/hook.go:40.82,41.41 1 0
+auth/ent/hook/hook.go:41.41,43.3 1 0
+auth/ent/hook/hook.go:44.2,44.84 1 0
+auth/ent/hook/hook.go:51.64,52.56 1 0
+auth/ent/hook/hook.go:52.56,53.40 1 0
+auth/ent/hook/hook.go:53.40,55.4 1 0
+auth/ent/hook/hook.go:56.3,56.29 1 0
+auth/ent/hook/hook.go:56.29,57.21 1 0
+auth/ent/hook/hook.go:57.21,59.5 1 0
+auth/ent/hook/hook.go:61.3,61.14 1 0
+auth/ent/hook/hook.go:66.63,67.56 1 0
+auth/ent/hook/hook.go:67.56,68.38 1 0
+auth/ent/hook/hook.go:68.38,70.4 1 0
+auth/ent/hook/hook.go:71.3,71.29 1 0
+auth/ent/hook/hook.go:71.29,72.20 1 0
+auth/ent/hook/hook.go:72.20,74.5 1 0
+auth/ent/hook/hook.go:76.3,76.15 1 0
+auth/ent/hook/hook.go:81.36,82.56 1 0
+auth/ent/hook/hook.go:82.56,84.3 1 0
+auth/ent/hook/hook.go:88.33,89.54 1 0
+auth/ent/hook/hook.go:89.54,91.3 1 0
+auth/ent/hook/hook.go:95.63,96.54 1 0
+auth/ent/hook/hook.go:96.54,97.48 1 0
+auth/ent/hook/hook.go:97.48,99.4 1 0
+auth/ent/hook/hook.go:100.3,100.32 1 0
+auth/ent/hook/hook.go:100.32,101.49 1 0
+auth/ent/hook/hook.go:101.49,103.5 1 0
+auth/ent/hook/hook.go:105.3,105.14 1 0
+auth/ent/hook/hook.go:110.65,111.54 1 0
+auth/ent/hook/hook.go:111.54,112.47 1 0
+auth/ent/hook/hook.go:112.47,114.4 1 0
+auth/ent/hook/hook.go:115.3,115.32 1 0
+auth/ent/hook/hook.go:115.32,116.48 1 0
+auth/ent/hook/hook.go:116.48,118.5 1 0
+auth/ent/hook/hook.go:120.3,120.14 1 0
+auth/ent/hook/hook.go:125.58,126.54 1 0
+auth/ent/hook/hook.go:126.54,127.43 1 0
+auth/ent/hook/hook.go:127.43,129.4 1 0
+auth/ent/hook/hook.go:130.3,130.32 1 0
+auth/ent/hook/hook.go:130.32,131.44 1 0
+auth/ent/hook/hook.go:131.44,133.5 1 0
+auth/ent/hook/hook.go:135.3,135.14 1 0
+auth/ent/hook/hook.go:142.47,143.44 1 0
+auth/ent/hook/hook.go:143.44,144.86 1 0
+auth/ent/hook/hook.go:144.86,145.20 1 0
+auth/ent/hook/hook.go:145.20,147.5 1 0
+auth/ent/hook/hook.go:148.4,148.30 1 0
+auth/ent/hook/hook.go:156.42,158.2 1 0
+auth/ent/hook/hook.go:163.46,165.2 1 0
+auth/ent/hook/hook.go:168.37,169.39 1 0
+auth/ent/hook/hook.go:169.39,170.80 1 0
+auth/ent/hook/hook.go:170.80,172.4 1 0
+auth/ent/hook/hook.go:183.33,186.2 2 0
+auth/ent/hook/hook.go:195.40,197.2 1 0
+auth/ent/hook/hook.go:200.32,201.47 1 0
+auth/ent/hook/hook.go:201.47,202.42 1 0
+auth/ent/hook/hook.go:202.42,204.4 1 0
+auth/ent/hook/hook.go:205.3,205.17 1 0
+auth/ent/hook/hook.go:211.48,216.2 4 0
+auth/ent/hook/hook.go:220.42,222.2 1 0
+auth/ent/runtime/runtime.go:16.13,71.2 31 0
+auth/ent/migrate/migrate.go:41.44,41.72 1 0
+auth/ent/migrate/migrate.go:44.82,46.2 1 0
+auth/ent/migrate/migrate.go:49.105,51.16 2 0
+auth/ent/migrate/migrate.go:51.16,53.3 1 0
+auth/ent/migrate/migrate.go:54.2,54.39 1 0
+auth/ent/migrate/migrate.go:62.96,64.2 1 0
+auth/ent/migrate/schema.go:99.13,103.2 3 0
+auth/ent/token/token.go:61.38,62.25 1 0
+auth/ent/token/token.go:62.25,63.27 1 0
+auth/ent/token/token.go:63.27,65.4 1 0
+auth/ent/token/token.go:67.2,67.29 1 0
+auth/ent/token/token.go:67.29,68.31 1 0
+auth/ent/token/token.go:68.31,70.4 1 0
+auth/ent/token/token.go:72.2,72.14 1 0
+auth/ent/token/token.go:97.35,99.2 1 0
+auth/ent/token/token.go:102.38,103.15 1 0
+auth/ent/token/token.go:104.31,105.13 1 0
+auth/ent/token/token.go:106.10,107.75 1 0
+auth/ent/token/token.go:115.52,117.2 1 0
+auth/ent/token/token.go:120.55,122.2 1 0
+auth/ent/token/token.go:125.54,127.2 1 0
+auth/ent/token/token.go:130.59,132.2 1 0
+auth/ent/token/token.go:135.57,137.2 1 0
+auth/ent/token/token.go:140.59,142.2 1 0
+auth/ent/token/token.go:145.59,147.2 1 0
+auth/ent/token/token.go:150.73,151.31 1 0
+auth/ent/token/token.go:151.31,153.3 1 0
+auth/ent/token/token.go:155.35,161.2 1 0
+auth/ent/token/where.go:14.36,16.2 1 0
+auth/ent/token/where.go:19.38,21.2 1 0
+auth/ent/token/where.go:24.39,26.2 1 0
+auth/ent/token/where.go:29.42,31.2 1 0
+auth/ent/token/where.go:34.45,36.2 1 0
+auth/ent/token/where.go:39.38,41.2 1 0
+auth/ent/token/where.go:44.39,46.2 1 0
+auth/ent/token/where.go:49.38,51.2 1 0
+auth/ent/token/where.go:54.39,56.2 1 0
+auth/ent/token/where.go:59.45,61.2 1 0
+auth/ent/token/where.go:64.48,66.2 1 0
+auth/ent/token/where.go:69.38,71.2 1 0
+auth/ent/token/where.go:74.45,76.2 1 0
+auth/ent/token/where.go:79.38,81.2 1 0
+auth/ent/token/where.go:84.45,86.2 1 0
+auth/ent/token/where.go:89.45,91.2 1 0
+auth/ent/token/where.go:94.40,96.2 1 0
+auth/ent/token/where.go:99.41,101.2 1 0
+auth/ent/token/where.go:104.44,106.2 1 0
+auth/ent/token/where.go:109.47,111.2 1 0
+auth/ent/token/where.go:114.40,116.2 1 0
+auth/ent/token/where.go:119.41,121.2 1 0
+auth/ent/token/where.go:124.40,126.2 1 0
+auth/ent/token/where.go:129.41,131.2 1 0
+auth/ent/token/where.go:134.46,136.2 1 0
+auth/ent/token/where.go:139.47,141.2 1 0
+auth/ent/token/where.go:144.47,146.2 1 0
+auth/ent/token/where.go:149.47,151.2 1 0
+auth/ent/token/where.go:154.50,156.2 1 0
+auth/ent/token/where.go:159.37,161.2 1 0
+auth/ent/token/where.go:164.38,166.2 1 0
+auth/ent/token/where.go:169.41,171.2 1 0
+auth/ent/token/where.go:174.44,176.2 1 0
+auth/ent/token/where.go:179.47,181.2 1 0
+auth/ent/token/where.go:184.48,186.2 1 0
+auth/ent/token/where.go:189.51,191.2 1 0
+auth/ent/token/where.go:194.54,196.2 1 0
+auth/ent/token/where.go:199.47,201.2 1 0
+auth/ent/token/where.go:204.48,206.2 1 0
+auth/ent/token/where.go:209.47,211.2 1 0
+auth/ent/token/where.go:214.48,216.2 1 0
+auth/ent/token/where.go:219.40,221.2 1 0
+auth/ent/token/where.go:224.41,226.2 1 0
+auth/ent/token/where.go:229.47,231.2 1 0
+auth/ent/token/where.go:234.48,236.2 1 0
+auth/ent/token/where.go:239.51,241.2 1 0
+auth/ent/token/where.go:244.54,246.2 1 0
+auth/ent/token/where.go:249.47,251.2 1 0
+auth/ent/token/where.go:254.48,256.2 1 0
+auth/ent/token/where.go:259.47,261.2 1 0
+auth/ent/token/where.go:264.48,266.2 1 0
+auth/ent/token/where.go:269.47,271.2 1 0
+auth/ent/token/where.go:274.48,276.2 1 0
+auth/ent/token/where.go:279.51,281.2 1 0
+auth/ent/token/where.go:284.54,286.2 1 0
+auth/ent/token/where.go:289.47,291.2 1 0
+auth/ent/token/where.go:294.48,296.2 1 0
+auth/ent/token/where.go:299.47,301.2 1 0
+auth/ent/token/where.go:304.48,306.2 1 0
+auth/ent/token/where.go:309.32,310.47 1 0
+auth/ent/token/where.go:310.47,316.3 2 0
+auth/ent/token/where.go:320.59,321.47 1 0
+auth/ent/token/where.go:321.47,323.60 2 0
+auth/ent/token/where.go:323.60,324.28 1 0
+auth/ent/token/where.go:324.28,326.5 1 0
+auth/ent/token/where.go:332.57,334.2 1 0
+auth/ent/token/where.go:337.56,339.2 1 0
+auth/ent/token/where.go:342.45,344.2 1 0
+auth/ent/user/user.go:65.38,66.25 1 0
+auth/ent/user/user.go:66.25,67.27 1 0
+auth/ent/user/user.go:67.27,69.4 1 0
+auth/ent/user/user.go:71.2,71.14 1 0
+auth/ent/user/user.go:95.52,97.2 1 0
+auth/ent/user/user.go:100.58,102.2 1 0
+auth/ent/user/user.go:105.55,107.2 1 0
+auth/ent/user/user.go:110.58,112.2 1 0
+auth/ent/user/user.go:115.59,117.2 1 0
+auth/ent/user/user.go:120.59,122.2 1 0
+auth/ent/user/user.go:125.60,126.31 1 0
+auth/ent/user/user.go:126.31,128.3 1 0
+auth/ent/user/user.go:132.70,133.31 1 0
+auth/ent/user/user.go:133.31,135.3 1 0
+auth/ent/user/user.go:139.61,140.31 1 0
+auth/ent/user/user.go:140.31,142.3 1 0
+auth/ent/user/user.go:146.71,147.31 1 0
+auth/ent/user/user.go:147.31,149.3 1 0
+auth/ent/user/user.go:151.36,157.2 1 0
+auth/ent/user/user.go:158.37,164.2 1 0
+auth/ent/user/where.go:14.35,16.2 1 0
+auth/ent/user/where.go:19.37,21.2 1 0
+auth/ent/user/where.go:24.38,26.2 1 0
+auth/ent/user/where.go:29.41,31.2 1 0
+auth/ent/user/where.go:34.44,36.2 1 0
+auth/ent/user/where.go:39.37,41.2 1 0
+auth/ent/user/where.go:44.38,46.2 1 0
+auth/ent/user/where.go:49.37,51.2 1 0
+auth/ent/user/where.go:54.38,56.2 1 0
+auth/ent/user/where.go:59.44,61.2 1 0
+auth/ent/user/where.go:64.47,66.2 1 0
+auth/ent/user/where.go:69.40,71.2 1 0
+auth/ent/user/where.go:74.37,76.2 1 0
+auth/ent/user/where.go:79.40,81.2 1 0
+auth/ent/user/where.go:84.44,86.2 1 0
+auth/ent/user/where.go:89.44,91.2 1 0
+auth/ent/user/where.go:94.42,96.2 1 0
+auth/ent/user/where.go:99.43,101.2 1 0
+auth/ent/user/where.go:104.46,106.2 1 0
+auth/ent/user/where.go:109.49,111.2 1 0
+auth/ent/user/where.go:114.42,116.2 1 0
+auth/ent/user/where.go:119.43,121.2 1 0
+auth/ent/user/where.go:124.42,126.2 1 0
+auth/ent/user/where.go:129.43,131.2 1 0
+auth/ent/user/where.go:134.48,136.2 1 0
+auth/ent/user/where.go:139.49,141.2 1 0
+auth/ent/user/where.go:144.49,146.2 1 0
+auth/ent/user/where.go:149.49,151.2 1 0
+auth/ent/user/where.go:154.52,156.2 1 0
+auth/ent/user/where.go:159.39,161.2 1 0
+auth/ent/user/where.go:164.40,166.2 1 0
+auth/ent/user/where.go:169.43,171.2 1 0
+auth/ent/user/where.go:174.46,176.2 1 0
+auth/ent/user/where.go:179.39,181.2 1 0
+auth/ent/user/where.go:184.40,186.2 1 0
+auth/ent/user/where.go:189.39,191.2 1 0
+auth/ent/user/where.go:194.40,196.2 1 0
+auth/ent/user/where.go:199.45,201.2 1 0
+auth/ent/user/where.go:204.46,206.2 1 0
+auth/ent/user/where.go:209.46,211.2 1 0
+auth/ent/user/where.go:214.46,216.2 1 0
+auth/ent/user/where.go:219.49,221.2 1 0
+auth/ent/user/where.go:224.42,226.2 1 0
+auth/ent/user/where.go:229.43,231.2 1 0
+auth/ent/user/where.go:234.46,236.2 1 0
+auth/ent/user/where.go:239.49,241.2 1 0
+auth/ent/user/where.go:244.42,246.2 1 0
+auth/ent/user/where.go:249.43,251.2 1 0
+auth/ent/user/where.go:254.42,256.2 1 0
+auth/ent/user/where.go:259.43,261.2 1 0
+auth/ent/user/where.go:264.48,266.2 1 0
+auth/ent/user/where.go:269.49,271.2 1 0
+auth/ent/user/where.go:274.49,276.2 1 0
+auth/ent/user/where.go:279.49,281.2 1 0
+auth/ent/user/where.go:284.52,286.2 1 0
+auth/ent/user/where.go:289.46,291.2 1 0
+auth/ent/user/where.go:294.47,296.2 1 0
+auth/ent/user/where.go:299.50,301.2 1 0
+auth/ent/user/where.go:304.53,306.2 1 0
+auth/ent/user/where.go:309.46,311.2 1 0
+auth/ent/user/where.go:314.47,316.2 1 0
+auth/ent/user/where.go:319.46,321.2 1 0
+auth/ent/user/where.go:324.47,326.2 1 0
+auth/ent/user/where.go:329.46,331.2 1 0
+auth/ent/user/where.go:334.47,336.2 1 0
+auth/ent/user/where.go:339.50,341.2 1 0
+auth/ent/user/where.go:344.53,346.2 1 0
+auth/ent/user/where.go:349.46,351.2 1 0
+auth/ent/user/where.go:354.47,356.2 1 0
+auth/ent/user/where.go:359.46,361.2 1 0
+auth/ent/user/where.go:364.47,366.2 1 0
+auth/ent/user/where.go:369.32,370.46 1 0
+auth/ent/user/where.go:370.46,376.3 2 0
+auth/ent/user/where.go:380.59,381.46 1 0
+auth/ent/user/where.go:381.46,383.60 2 0
+auth/ent/user/where.go:383.60,384.28 1 0
+auth/ent/user/where.go:384.28,386.5 1 0
+auth/ent/user/where.go:392.33,393.46 1 0
+auth/ent/user/where.go:393.46,399.3 2 0
+auth/ent/user/where.go:403.61,404.46 1 0
+auth/ent/user/where.go:404.46,406.60 2 0
+auth/ent/user/where.go:406.60,407.28 1 0
+auth/ent/user/where.go:407.28,409.5 1 0
+auth/ent/user/where.go:415.55,417.2 1 0
+auth/ent/user/where.go:420.54,422.2 1 0
+auth/ent/user/where.go:425.43,427.2 1 0
+auth/ent/role/role.go:52.38,53.25 1 0
+auth/ent/role/role.go:53.25,54.27 1 0
+auth/ent/role/role.go:54.27,56.4 1 0
+auth/ent/role/role.go:58.2,58.14 1 0
+auth/ent/role/role.go:76.52,78.2 1 0
+auth/ent/role/role.go:81.54,83.2 1 0
+auth/ent/role/role.go:86.59,88.2 1 0
+auth/ent/role/role.go:91.59,93.2 1 0
+auth/ent/role/role.go:96.60,97.31 1 0
+auth/ent/role/role.go:97.31,99.3 1 0
+auth/ent/role/role.go:103.70,104.31 1 0
+auth/ent/role/role.go:104.31,106.3 1 0
+auth/ent/role/role.go:108.36,114.2 1 0
+auth/ent/role/where.go:14.35,16.2 1 0
+auth/ent/role/where.go:19.37,21.2 1 0
+auth/ent/role/where.go:24.38,26.2 1 0
+auth/ent/role/where.go:29.41,31.2 1 0
+auth/ent/role/where.go:34.44,36.2 1 0
+auth/ent/role/where.go:39.37,41.2 1 0
+auth/ent/role/where.go:44.38,46.2 1 0
+auth/ent/role/where.go:49.37,51.2 1 0
+auth/ent/role/where.go:54.38,56.2 1 0
+auth/ent/role/where.go:59.44,61.2 1 0
+auth/ent/role/where.go:64.47,66.2 1 0
+auth/ent/role/where.go:69.36,71.2 1 0
+auth/ent/role/where.go:74.44,76.2 1 0
+auth/ent/role/where.go:79.44,81.2 1 0
+auth/ent/role/where.go:84.38,86.2 1 0
+auth/ent/role/where.go:89.39,91.2 1 0
+auth/ent/role/where.go:94.42,96.2 1 0
+auth/ent/role/where.go:99.45,101.2 1 0
+auth/ent/role/where.go:104.38,106.2 1 0
+auth/ent/role/where.go:109.39,111.2 1 0
+auth/ent/role/where.go:114.38,116.2 1 0
+auth/ent/role/where.go:119.39,121.2 1 0
+auth/ent/role/where.go:124.44,126.2 1 0
+auth/ent/role/where.go:129.45,131.2 1 0
+auth/ent/role/where.go:134.45,136.2 1 0
+auth/ent/role/where.go:139.45,141.2 1 0
+auth/ent/role/where.go:144.48,146.2 1 0
+auth/ent/role/where.go:149.46,151.2 1 0
+auth/ent/role/where.go:154.47,156.2 1 0
+auth/ent/role/where.go:159.50,161.2 1 0
+auth/ent/role/where.go:164.53,166.2 1 0
+auth/ent/role/where.go:169.46,171.2 1 0
+auth/ent/role/where.go:174.47,176.2 1 0
+auth/ent/role/where.go:179.46,181.2 1 0
+auth/ent/role/where.go:184.47,186.2 1 0
+auth/ent/role/where.go:189.46,191.2 1 0
+auth/ent/role/where.go:194.47,196.2 1 0
+auth/ent/role/where.go:199.50,201.2 1 0
+auth/ent/role/where.go:204.53,206.2 1 0
+auth/ent/role/where.go:209.46,211.2 1 0
+auth/ent/role/where.go:214.47,216.2 1 0
+auth/ent/role/where.go:219.46,221.2 1 0
+auth/ent/role/where.go:224.47,226.2 1 0
+auth/ent/role/where.go:229.32,230.46 1 0
+auth/ent/role/where.go:230.46,236.3 2 0
+auth/ent/role/where.go:240.59,241.46 1 0
+auth/ent/role/where.go:241.46,243.60 2 0
+auth/ent/role/where.go:243.60,244.28 1 0
+auth/ent/role/where.go:244.28,246.5 1 0
+auth/ent/role/where.go:252.55,254.2 1 0
+auth/ent/role/where.go:257.54,259.2 1 0
+auth/ent/role/where.go:262.43,264.2 1 0
+auth/internal/auth/main.go:19.13,21.16 2 0
+auth/internal/auth/main.go:21.16,23.3 1 0
+auth/internal/auth/main.go:26.2,29.16 2 0
+auth/internal/auth/main.go:29.16,31.3 1 0
+auth/internal/auth/main.go:32.2,39.16 6 0
+auth/internal/auth/main.go:39.16,41.3 1 0
+auth/internal/auth/main.go:43.2,60.46 7 0
+auth/internal/auth/main.go:60.46,62.3 1 0
+auth/internal/authz/main.go:18.13,20.16 2 0
+auth/internal/authz/main.go:20.16,22.3 1 0
+auth/internal/authz/main.go:25.2,28.16 2 0
+auth/internal/authz/main.go:28.16,30.3 1 0
+auth/internal/authz/main.go:31.2,38.16 6 0
+auth/internal/authz/main.go:38.16,40.3 1 0
+auth/internal/authz/main.go:41.2,57.46 7 0
+auth/internal/authz/main.go:57.46,59.3 1 0
+auth/internal/auth/service/auth_service.go:143.155,150.2 1 0
+auth/internal/auth/service/auth_service.go:152.99,154.16 2 0
+auth/internal/auth/service/auth_service.go:154.16,156.3 1 0
+auth/internal/auth/service/auth_service.go:158.2,158.80 1 0
+auth/internal/auth/service/auth_service.go:158.80,160.3 1 0
+auth/internal/auth/service/auth_service.go:162.2,163.16 2 0
+auth/internal/auth/service/auth_service.go:163.16,165.3 1 0
+auth/internal/auth/service/auth_service.go:167.2,168.16 2 0
+auth/internal/auth/service/auth_service.go:168.16,170.3 1 0
+auth/internal/auth/service/auth_service.go:173.2,174.16 2 0
+auth/internal/auth/service/auth_service.go:174.16,176.3 1 0
+auth/internal/auth/service/auth_service.go:178.2,179.16 2 0
+auth/internal/auth/service/auth_service.go:179.16,181.3 1 0
+auth/internal/auth/service/auth_service.go:183.2,187.8 1 0
+auth/internal/auth/service/auth_service.go:190.98,191.70 1 0
+auth/internal/auth/service/auth_service.go:191.70,193.3 1 0
+auth/internal/auth/service/auth_service.go:194.2,194.30 1 0
+auth/internal/auth/service/auth_service.go:197.120,199.16 2 0
+auth/internal/auth/service/auth_service.go:199.16,201.3 1 0
+auth/internal/auth/service/auth_service.go:203.2,203.84 1 0
+auth/internal/auth/service/auth_service.go:203.84,205.3 1 0
+auth/internal/auth/service/auth_service.go:207.2,208.16 2 0
+auth/internal/auth/service/auth_service.go:208.16,210.3 1 0
+auth/internal/auth/service/auth_service.go:212.2,213.16 2 0
+auth/internal/auth/service/auth_service.go:213.16,215.3 1 0
+auth/internal/auth/service/auth_service.go:217.2,218.16 2 0
+auth/internal/auth/service/auth_service.go:218.16,220.3 1 0
+auth/internal/auth/service/auth_service.go:223.2,223.71 1 0
+auth/internal/auth/service/auth_service.go:223.71,225.3 1 0
+auth/internal/auth/service/auth_service.go:228.2,229.16 2 0
+auth/internal/auth/service/auth_service.go:229.16,231.3 1 0
+auth/internal/auth/service/auth_service.go:233.2,234.16 2 0
+auth/internal/auth/service/auth_service.go:234.16,236.3 1 0
+auth/internal/auth/service/auth_service.go:238.2,242.8 1 0
+auth/internal/auth/service/auth_service.go:245.123,247.16 2 0
+auth/internal/auth/service/auth_service.go:247.16,249.3 1 0
+auth/internal/auth/service/auth_service.go:251.2,251.57 1 0
+auth/internal/auth/service/auth_service.go:251.57,253.3 1 0
+auth/internal/auth/service/auth_service.go:255.2,256.16 2 0
+auth/internal/auth/service/auth_service.go:256.16,258.3 1 0
+auth/internal/auth/service/auth_service.go:260.2,266.8 1 0
+auth/internal/auth/service/auth_service.go:269.120,271.25 2 0
+auth/internal/auth/service/auth_service.go:271.25,273.3 1 0
+auth/internal/auth/service/auth_service.go:275.2,276.25 2 0
+auth/internal/auth/service/auth_service.go:276.25,278.3 1 0
+auth/internal/auth/service/auth_service.go:280.2,281.16 2 0
+auth/internal/auth/service/auth_service.go:281.16,283.3 1 0
+auth/internal/auth/service/auth_service.go:285.2,291.58 2 0
+auth/internal/auth/service/auth_service.go:291.58,293.3 1 0
+auth/internal/auth/service/auth_service.go:295.2,301.8 1 0
+auth/internal/auth/service/auth_service.go:304.114,306.16 2 0
+auth/internal/auth/service/auth_service.go:306.16,308.3 1 0
+auth/internal/auth/service/auth_service.go:310.2,310.25 1 0
+auth/internal/auth/service/auth_service.go:310.25,312.3 1 0
+auth/internal/auth/service/auth_service.go:313.2,313.22 1 0
+auth/internal/auth/service/auth_service.go:313.22,315.3 1 0
+auth/internal/auth/service/auth_service.go:316.2,316.25 1 0
+auth/internal/auth/service/auth_service.go:316.25,318.17 2 0
+auth/internal/auth/service/auth_service.go:318.17,320.4 1 0
+auth/internal/auth/service/auth_service.go:321.3,321.41 1 0
+auth/internal/auth/service/auth_service.go:324.2,324.58 1 0
+auth/internal/auth/service/auth_service.go:324.58,326.3 1 0
+auth/internal/auth/service/auth_service.go:329.2,329.70 1 0
+auth/internal/auth/service/auth_service.go:329.70,331.3 1 0
+auth/internal/auth/service/auth_service.go:333.2,339.8 1 0
+auth/internal/auth/service/auth_service.go:342.106,344.73 1 0
+auth/internal/auth/service/auth_service.go:344.73,346.3 1 0
+auth/internal/auth/service/auth_service.go:348.2,348.59 1 0
+auth/internal/auth/service/auth_service.go:348.59,350.3 1 0
+auth/internal/auth/service/auth_service.go:352.2,352.30 1 0
+auth/internal/auth/service/auth_service.go:355.105,357.16 2 0
+auth/internal/auth/service/auth_service.go:357.16,359.3 1 0
+auth/internal/auth/service/auth_service.go:361.2,367.8 1 0
+auth/internal/auth/service/auth_service.go:370.67,379.2 3 0
+auth/internal/auth/service/auth_service.go:381.76,389.2 3 0
+auth/internal/authz/service/authz_service.go:179.110,184.2 1 0
+auth/internal/authz/service/authz_service.go:186.130,188.16 2 0
+auth/internal/authz/service/authz_service.go:188.16,190.3 1 0
+auth/internal/authz/service/authz_service.go:192.2,192.29 1 0
+auth/internal/authz/service/authz_service.go:192.29,193.74 1 0
+auth/internal/authz/service/authz_service.go:193.74,195.4 1 0
+auth/internal/authz/service/authz_service.go:198.2,198.63 1 0
+auth/internal/authz/service/authz_service.go:201.121,203.16 2 0
+auth/internal/authz/service/authz_service.go:203.16,205.3 1 0
+auth/internal/authz/service/authz_service.go:207.2,208.29 2 0
+auth/internal/authz/service/authz_service.go:208.29,214.3 1 0
+auth/internal/authz/service/authz_service.go:216.2,216.54 1 0
+auth/internal/authz/service/authz_service.go:219.119,220.81 1 0
+auth/internal/authz/service/authz_service.go:220.81,222.3 1 0
+auth/internal/authz/service/authz_service.go:223.2,223.30 1 0
+auth/internal/authz/service/authz_service.go:226.123,227.83 1 0
+auth/internal/authz/service/authz_service.go:227.83,229.3 1 0
+auth/internal/authz/service/authz_service.go:230.2,230.30 1 0
+auth/internal/authz/service/authz_service.go:233.115,238.39 2 0
+auth/internal/authz/service/authz_service.go:238.39,240.3 1 0
+auth/internal/authz/service/authz_service.go:242.2,244.58 2 0
+auth/internal/authz/service/authz_service.go:244.58,246.3 1 0
+auth/internal/authz/service/authz_service.go:248.2,254.8 1 0
+auth/internal/authz/service/authz_service.go:257.115,259.16 2 0
+auth/internal/authz/service/authz_service.go:259.16,261.3 1 0
+auth/internal/authz/service/authz_service.go:263.2,263.21 1 0
+auth/internal/authz/service/authz_service.go:263.21,265.3 1 0
+auth/internal/authz/service/authz_service.go:266.2,266.28 1 0
+auth/internal/authz/service/authz_service.go:266.28,268.40 2 0
+auth/internal/authz/service/authz_service.go:268.40,270.4 1 0
+auth/internal/authz/service/authz_service.go:273.2,273.58 1 0
+auth/internal/authz/service/authz_service.go:273.58,275.3 1 0
+auth/internal/authz/service/authz_service.go:277.2,283.8 1 0
+auth/internal/authz/service/authz_service.go:286.107,287.59 1 0
+auth/internal/authz/service/authz_service.go:287.59,290.3 1 0
+auth/internal/authz/service/authz_service.go:292.2,292.30 1 0
+auth/internal/authz/service/authz_service.go:295.106,297.16 2 0
+auth/internal/authz/service/authz_service.go:297.16,299.3 1 0
+auth/internal/authz/service/authz_service.go:301.2,307.8 1 0
+auth/internal/authz/service/authz_service.go:310.112,312.16 2 0
+auth/internal/authz/service/authz_service.go:312.16,314.3 1 0
+auth/internal/authz/service/authz_service.go:315.2,317.16 3 0
+auth/internal/authz/service/authz_service.go:317.16,319.3 1 0
+auth/internal/authz/service/authz_service.go:321.2,322.29 2 0
+auth/internal/authz/service/authz_service.go:322.29,328.3 1 0
+auth/internal/authz/service/authz_service.go:330.2,333.8 1 0
+auth/internal/authz/service/authz_service.go:336.125,338.78 2 0
+auth/internal/authz/service/authz_service.go:338.78,340.3 1 0
+auth/internal/authz/service/authz_service.go:341.2,341.30 1 0
+auth/internal/authz/service/authz_service.go:344.135,346.81 2 0
+auth/internal/authz/service/authz_service.go:346.81,348.3 1 0
+auth/internal/authz/service/authz_service.go:349.2,349.30 1 0
+auth/internal/authz/service/authz_service.go:352.66,354.40 2 0
+auth/internal/authz/service/authz_service.go:354.40,355.25 1 0
+auth/internal/authz/service/authz_service.go:355.25,357.4 1 0
+auth/internal/authz/service/authz_service.go:359.2,359.14 1 0
+auth/internal/db/db.go:36.50,39.16 2 0
+auth/internal/db/db.go:39.16,41.3 1 0
+auth/internal/db/db.go:44.2,45.16 2 0
+auth/internal/db/db.go:45.16,47.3 1 0
+auth/internal/db/db.go:49.2,57.20 2 0
+auth/internal/db/db.go:68.57,70.16 2 0
+auth/internal/db/db.go:70.16,72.3 1 0
+auth/internal/db/db.go:74.2,75.29 2 0
+auth/internal/db/db.go:75.29,76.59 1 0
+auth/internal/db/db.go:76.59,77.60 1 0
+auth/internal/db/db.go:77.60,79.5 1 0
+auth/internal/db/db.go:83.2,83.23 1 0
+auth/internal/db/db.go:83.23,85.3 1 0
+auth/internal/db/db.go:87.2,88.16 2 0
+auth/internal/db/db.go:88.16,90.3 1 0
+auth/internal/db/db.go:92.2,92.29 1 0
+auth/internal/db/db.go:103.59,106.16 2 0
+auth/internal/db/db.go:106.16,108.3 1 0
+auth/internal/db/db.go:111.2,114.64 2 0
+auth/internal/db/db.go:114.64,116.3 1 0
+auth/internal/db/db.go:118.2,118.20 1 0
+auth/pb/auth.pb.go:34.32,36.29 2 0
+auth/pb/auth.pb.go:36.29,40.3 3 0
+auth/pb/auth.pb.go:43.40,45.2 1 0
+auth/pb/auth.pb.go:47.38,47.39 0 0
+auth/pb/auth.pb.go:49.60,51.41 2 0
+auth/pb/auth.pb.go:51.41,53.34 2 0
+auth/pb/auth.pb.go:53.34,55.4 1 0
+auth/pb/auth.pb.go:56.3,56.12 1 0
+auth/pb/auth.pb.go:58.2,58.24 1 0
+auth/pb/auth.pb.go:62.51,64.2 1 0
+auth/pb/auth.pb.go:66.45,67.14 1 0
+auth/pb/auth.pb.go:67.14,69.3 1 0
+auth/pb/auth.pb.go:70.2,70.11 1 0
+auth/pb/auth.pb.go:73.45,74.14 1 0
+auth/pb/auth.pb.go:74.14,76.3 1 0
+auth/pb/auth.pb.go:77.2,77.11 1 0
+auth/pb/auth.pb.go:90.33,92.29 2 0
+auth/pb/auth.pb.go:92.29,96.3 3 0
+auth/pb/auth.pb.go:99.41,101.2 1 0
+auth/pb/auth.pb.go:103.39,103.40 0 0
+auth/pb/auth.pb.go:105.61,107.41 2 0
+auth/pb/auth.pb.go:107.41,109.34 2 0
+auth/pb/auth.pb.go:109.34,111.4 1 0
+auth/pb/auth.pb.go:112.3,112.12 1 0
+auth/pb/auth.pb.go:114.2,114.24 1 0
+auth/pb/auth.pb.go:118.52,120.2 1 0
+auth/pb/auth.pb.go:122.49,123.14 1 0
+auth/pb/auth.pb.go:123.14,125.3 1 0
+auth/pb/auth.pb.go:126.2,126.11 1 0
+auth/pb/auth.pb.go:129.50,130.14 1 0
+auth/pb/auth.pb.go:130.14,132.3 1 0
+auth/pb/auth.pb.go:133.2,133.11 1 0
+auth/pb/auth.pb.go:136.46,137.14 1 0
+auth/pb/auth.pb.go:137.14,139.3 1 0
+auth/pb/auth.pb.go:140.2,140.10 1 0
+auth/pb/auth.pb.go:151.33,153.29 2 0
+auth/pb/auth.pb.go:153.29,157.3 3 0
+auth/pb/auth.pb.go:160.41,162.2 1 0
+auth/pb/auth.pb.go:164.39,164.40 0 0
+auth/pb/auth.pb.go:166.61,168.41 2 0
+auth/pb/auth.pb.go:168.41,170.34 2 0
+auth/pb/auth.pb.go:170.34,172.4 1 0
+auth/pb/auth.pb.go:173.3,173.12 1 0
+auth/pb/auth.pb.go:175.2,175.24 1 0
+auth/pb/auth.pb.go:179.52,181.2 1 0
+auth/pb/auth.pb.go:183.49,184.14 1 0
+auth/pb/auth.pb.go:184.14,186.3 1 0
+auth/pb/auth.pb.go:187.2,187.11 1 0
+auth/pb/auth.pb.go:198.39,200.29 2 0
+auth/pb/auth.pb.go:200.29,204.3 3 0
+auth/pb/auth.pb.go:207.47,209.2 1 0
+auth/pb/auth.pb.go:211.45,211.46 0 0
+auth/pb/auth.pb.go:213.67,215.41 2 0
+auth/pb/auth.pb.go:215.41,217.34 2 0
+auth/pb/auth.pb.go:217.34,219.4 1 0
+auth/pb/auth.pb.go:220.3,220.12 1 0
+auth/pb/auth.pb.go:222.2,222.24 1 0
+auth/pb/auth.pb.go:226.58,228.2 1 0
+auth/pb/auth.pb.go:230.56,231.14 1 0
+auth/pb/auth.pb.go:231.14,233.3 1 0
+auth/pb/auth.pb.go:234.2,234.11 1 0
+auth/pb/auth.pb.go:247.40,249.29 2 0
+auth/pb/auth.pb.go:249.29,253.3 3 0
+auth/pb/auth.pb.go:256.48,258.2 1 0
+auth/pb/auth.pb.go:260.46,260.47 0 0
+auth/pb/auth.pb.go:262.68,264.41 2 0
+auth/pb/auth.pb.go:264.41,266.34 2 0
+auth/pb/auth.pb.go:266.34,268.4 1 0
+auth/pb/auth.pb.go:269.3,269.12 1 0
+auth/pb/auth.pb.go:271.2,271.24 1 0
+auth/pb/auth.pb.go:275.59,277.2 1 0
+auth/pb/auth.pb.go:279.56,280.14 1 0
+auth/pb/auth.pb.go:280.14,282.3 1 0
+auth/pb/auth.pb.go:283.2,283.11 1 0
+auth/pb/auth.pb.go:286.57,287.14 1 0
+auth/pb/auth.pb.go:287.14,289.3 1 0
+auth/pb/auth.pb.go:290.2,290.11 1 0
+auth/pb/auth.pb.go:293.53,294.14 1 0
+auth/pb/auth.pb.go:294.14,296.3 1 0
+auth/pb/auth.pb.go:297.2,297.10 1 0
+auth/pb/auth.pb.go:308.40,310.29 2 0
+auth/pb/auth.pb.go:310.29,314.3 3 0
+auth/pb/auth.pb.go:317.48,319.2 1 0
+auth/pb/auth.pb.go:321.46,321.47 0 0
+auth/pb/auth.pb.go:323.68,325.41 2 0
+auth/pb/auth.pb.go:325.41,327.34 2 0
+auth/pb/auth.pb.go:327.34,329.4 1 0
+auth/pb/auth.pb.go:330.3,330.12 1 0
+auth/pb/auth.pb.go:332.2,332.24 1 0
+auth/pb/auth.pb.go:336.59,338.2 1 0
+auth/pb/auth.pb.go:340.50,341.14 1 0
+auth/pb/auth.pb.go:341.14,343.3 1 0
+auth/pb/auth.pb.go:344.2,344.11 1 0
+auth/pb/auth.pb.go:355.41,357.29 2 0
+auth/pb/auth.pb.go:357.29,361.3 3 0
+auth/pb/auth.pb.go:364.49,366.2 1 0
+auth/pb/auth.pb.go:368.47,368.48 0 0
+auth/pb/auth.pb.go:370.69,372.41 2 0
+auth/pb/auth.pb.go:372.41,374.34 2 0
+auth/pb/auth.pb.go:374.34,376.4 1 0
+auth/pb/auth.pb.go:377.3,377.12 1 0
+auth/pb/auth.pb.go:379.2,379.24 1 0
+auth/pb/auth.pb.go:383.60,385.2 1 0
+auth/pb/auth.pb.go:387.49,388.14 1 0
+auth/pb/auth.pb.go:388.14,390.3 1 0
+auth/pb/auth.pb.go:391.2,391.12 1 0
+auth/pb/auth.pb.go:404.39,406.29 2 0
+auth/pb/auth.pb.go:406.29,410.3 3 0
+auth/pb/auth.pb.go:413.47,415.2 1 0
+auth/pb/auth.pb.go:417.45,417.46 0 0
+auth/pb/auth.pb.go:419.67,421.41 2 0
+auth/pb/auth.pb.go:421.41,423.34 2 0
+auth/pb/auth.pb.go:423.34,425.4 1 0
+auth/pb/auth.pb.go:426.3,426.12 1 0
+auth/pb/auth.pb.go:428.2,428.24 1 0
+auth/pb/auth.pb.go:432.58,434.2 1 0
+auth/pb/auth.pb.go:436.52,437.14 1 0
+auth/pb/auth.pb.go:437.14,439.3 1 0
+auth/pb/auth.pb.go:440.2,440.11 1 0
+auth/pb/auth.pb.go:443.49,444.14 1 0
+auth/pb/auth.pb.go:444.14,446.3 1 0
+auth/pb/auth.pb.go:447.2,447.11 1 0
+auth/pb/auth.pb.go:450.52,451.14 1 0
+auth/pb/auth.pb.go:451.14,453.3 1 0
+auth/pb/auth.pb.go:454.2,454.11 1 0
+auth/pb/auth.pb.go:465.40,467.29 2 0
+auth/pb/auth.pb.go:467.29,471.3 3 0
+auth/pb/auth.pb.go:474.48,476.2 1 0
+auth/pb/auth.pb.go:478.46,478.47 0 0
+auth/pb/auth.pb.go:480.68,482.41 2 0
+auth/pb/auth.pb.go:482.41,484.34 2 0
+auth/pb/auth.pb.go:484.34,486.4 1 0
+auth/pb/auth.pb.go:487.3,487.12 1 0
+auth/pb/auth.pb.go:489.2,489.24 1 0
+auth/pb/auth.pb.go:493.59,495.2 1 0
+auth/pb/auth.pb.go:497.48,498.14 1 0
+auth/pb/auth.pb.go:498.14,500.3 1 0
+auth/pb/auth.pb.go:501.2,501.12 1 0
+auth/pb/auth.pb.go:515.37,517.29 2 0
+auth/pb/auth.pb.go:517.29,521.3 3 0
+auth/pb/auth.pb.go:524.45,526.2 1 0
+auth/pb/auth.pb.go:528.43,528.44 0 0
+auth/pb/auth.pb.go:530.65,532.41 2 0
+auth/pb/auth.pb.go:532.41,534.34 2 0
+auth/pb/auth.pb.go:534.34,536.4 1 0
+auth/pb/auth.pb.go:537.3,537.12 1 0
+auth/pb/auth.pb.go:539.2,539.24 1 0
+auth/pb/auth.pb.go:543.56,545.2 1 0
+auth/pb/auth.pb.go:547.48,548.14 1 0
+auth/pb/auth.pb.go:548.14,550.3 1 0
+auth/pb/auth.pb.go:551.2,551.11 1 0
+auth/pb/auth.pb.go:554.50,555.35 1 0
+auth/pb/auth.pb.go:555.35,557.3 1 0
+auth/pb/auth.pb.go:558.2,558.11 1 0
+auth/pb/auth.pb.go:561.47,562.32 1 0
+auth/pb/auth.pb.go:562.32,564.3 1 0
+auth/pb/auth.pb.go:565.2,565.11 1 0
+auth/pb/auth.pb.go:568.50,569.35 1 0
+auth/pb/auth.pb.go:569.35,571.3 1 0
+auth/pb/auth.pb.go:572.2,572.11 1 0
+auth/pb/auth.pb.go:583.38,585.29 2 0
+auth/pb/auth.pb.go:585.29,589.3 3 0
+auth/pb/auth.pb.go:592.46,594.2 1 0
+auth/pb/auth.pb.go:596.44,596.45 0 0
+auth/pb/auth.pb.go:598.66,600.41 2 0
+auth/pb/auth.pb.go:600.41,602.34 2 0
+auth/pb/auth.pb.go:602.34,604.4 1 0
+auth/pb/auth.pb.go:605.3,605.12 1 0
+auth/pb/auth.pb.go:607.2,607.24 1 0
+auth/pb/auth.pb.go:611.57,613.2 1 0
+auth/pb/auth.pb.go:615.46,616.14 1 0
+auth/pb/auth.pb.go:616.14,618.3 1 0
+auth/pb/auth.pb.go:619.2,619.12 1 0
+auth/pb/auth.pb.go:630.37,632.29 2 0
+auth/pb/auth.pb.go:632.29,636.3 3 0
+auth/pb/auth.pb.go:639.45,641.2 1 0
+auth/pb/auth.pb.go:643.43,643.44 0 0
+auth/pb/auth.pb.go:645.65,647.41 2 0
+auth/pb/auth.pb.go:647.41,649.34 2 0
+auth/pb/auth.pb.go:649.34,651.4 1 0
+auth/pb/auth.pb.go:652.3,652.12 1 0
+auth/pb/auth.pb.go:654.2,654.24 1 0
+auth/pb/auth.pb.go:658.56,660.2 1 0
+auth/pb/auth.pb.go:662.48,663.14 1 0
+auth/pb/auth.pb.go:663.14,665.3 1 0
+auth/pb/auth.pb.go:666.2,666.11 1 0
+auth/pb/auth.pb.go:677.34,679.29 2 0
+auth/pb/auth.pb.go:679.29,683.3 3 0
+auth/pb/auth.pb.go:686.42,688.2 1 0
+auth/pb/auth.pb.go:690.40,690.41 0 0
+auth/pb/auth.pb.go:692.62,694.41 2 0
+auth/pb/auth.pb.go:694.41,696.34 2 0
+auth/pb/auth.pb.go:696.34,698.4 1 0
+auth/pb/auth.pb.go:699.3,699.12 1 0
+auth/pb/auth.pb.go:701.2,701.24 1 0
+auth/pb/auth.pb.go:705.53,707.2 1 0
+auth/pb/auth.pb.go:709.45,710.14 1 0
+auth/pb/auth.pb.go:710.14,712.3 1 0
+auth/pb/auth.pb.go:713.2,713.11 1 0
+auth/pb/auth.pb.go:724.35,726.29 2 0
+auth/pb/auth.pb.go:726.29,730.3 3 0
+auth/pb/auth.pb.go:733.43,735.2 1 0
+auth/pb/auth.pb.go:737.41,737.42 0 0
+auth/pb/auth.pb.go:739.63,741.41 2 0
+auth/pb/auth.pb.go:741.41,743.34 2 0
+auth/pb/auth.pb.go:743.34,745.4 1 0
+auth/pb/auth.pb.go:746.3,746.12 1 0
+auth/pb/auth.pb.go:748.2,748.24 1 0
+auth/pb/auth.pb.go:752.54,754.2 1 0
+auth/pb/auth.pb.go:756.43,757.14 1 0
+auth/pb/auth.pb.go:757.14,759.3 1 0
+auth/pb/auth.pb.go:760.2,760.12 1 0
+auth/pb/auth.pb.go:892.43,893.40 1 0
+auth/pb/auth.pb.go:893.40,895.3 1 0
+auth/pb/auth.pb.go:896.2,896.36 1 0
+auth/pb/auth.pb.go:946.13,946.39 1 0
+auth/pb/auth.pb.go:947.29,948.28 1 0
+auth/pb/auth.pb.go:948.28,950.3 1 0
+auth/pb/auth.pb.go:951.2,952.30 2 0
+auth/pb/auth.pb.go:952.30,953.65 1 0
+auth/pb/auth.pb.go:953.65,954.37 1 0
+auth/pb/auth.pb.go:955.11,956.20 1 0
+auth/pb/auth.pb.go:957.11,958.24 1 0
+auth/pb/auth.pb.go:959.11,960.28 1 0
+auth/pb/auth.pb.go:961.12,962.15 1 0
+auth/pb/auth.pb.go:965.3,965.65 1 0
+auth/pb/auth.pb.go:965.65,966.38 1 0
+auth/pb/auth.pb.go:967.11,968.20 1 0
+auth/pb/auth.pb.go:969.11,970.24 1 0
+auth/pb/auth.pb.go:971.11,972.28 1 0
+auth/pb/auth.pb.go:973.12,974.15 1 0
+auth/pb/auth.pb.go:977.3,977.65 1 0
+auth/pb/auth.pb.go:977.65,978.38 1 0
+auth/pb/auth.pb.go:979.11,980.20 1 0
+auth/pb/auth.pb.go:981.11,982.24 1 0
+auth/pb/auth.pb.go:983.11,984.28 1 0
+auth/pb/auth.pb.go:985.12,986.15 1 0
+auth/pb/auth.pb.go:989.3,989.65 1 0
+auth/pb/auth.pb.go:989.65,990.44 1 0
+auth/pb/auth.pb.go:991.11,992.20 1 0
+auth/pb/auth.pb.go:993.11,994.24 1 0
+auth/pb/auth.pb.go:995.11,996.28 1 0
+auth/pb/auth.pb.go:997.12,998.15 1 0
+auth/pb/auth.pb.go:1001.3,1001.65 1 0
+auth/pb/auth.pb.go:1001.65,1002.45 1 0
+auth/pb/auth.pb.go:1003.11,1004.20 1 0
+auth/pb/auth.pb.go:1005.11,1006.24 1 0
+auth/pb/auth.pb.go:1007.11,1008.28 1 0
+auth/pb/auth.pb.go:1009.12,1010.15 1 0
+auth/pb/auth.pb.go:1013.3,1013.65 1 0
+auth/pb/auth.pb.go:1013.65,1014.45 1 0
+auth/pb/auth.pb.go:1015.11,1016.20 1 0
+auth/pb/auth.pb.go:1017.11,1018.24 1 0
+auth/pb/auth.pb.go:1019.11,1020.28 1 0
+auth/pb/auth.pb.go:1021.12,1022.15 1 0
+auth/pb/auth.pb.go:1025.3,1025.65 1 0
+auth/pb/auth.pb.go:1025.65,1026.46 1 0
+auth/pb/auth.pb.go:1027.11,1028.20 1 0
+auth/pb/auth.pb.go:1029.11,1030.24 1 0
+auth/pb/auth.pb.go:1031.11,1032.28 1 0
+auth/pb/auth.pb.go:1033.12,1034.15 1 0
+auth/pb/auth.pb.go:1037.3,1037.65 1 0
+auth/pb/auth.pb.go:1037.65,1038.44 1 0
+auth/pb/auth.pb.go:1039.11,1040.20 1 0
+auth/pb/auth.pb.go:1041.11,1042.24 1 0
+auth/pb/auth.pb.go:1043.11,1044.28 1 0
+auth/pb/auth.pb.go:1045.12,1046.15 1 0
+auth/pb/auth.pb.go:1049.3,1049.65 1 0
+auth/pb/auth.pb.go:1049.65,1050.45 1 0
+auth/pb/auth.pb.go:1051.11,1052.20 1 0
+auth/pb/auth.pb.go:1053.11,1054.24 1 0
+auth/pb/auth.pb.go:1055.11,1056.28 1 0
+auth/pb/auth.pb.go:1057.12,1058.15 1 0
+auth/pb/auth.pb.go:1061.3,1061.65 1 0
+auth/pb/auth.pb.go:1061.65,1062.42 1 0
+auth/pb/auth.pb.go:1063.11,1064.20 1 0
+auth/pb/auth.pb.go:1065.11,1066.24 1 0
+auth/pb/auth.pb.go:1067.11,1068.28 1 0
+auth/pb/auth.pb.go:1069.12,1070.15 1 0
+auth/pb/auth.pb.go:1073.3,1073.66 1 0
+auth/pb/auth.pb.go:1073.66,1074.43 1 0
+auth/pb/auth.pb.go:1075.11,1076.20 1 0
+auth/pb/auth.pb.go:1077.11,1078.24 1 0
+auth/pb/auth.pb.go:1079.11,1080.28 1 0
+auth/pb/auth.pb.go:1081.12,1082.15 1 0
+auth/pb/auth.pb.go:1085.3,1085.66 1 0
+auth/pb/auth.pb.go:1085.66,1086.42 1 0
+auth/pb/auth.pb.go:1087.11,1088.20 1 0
+auth/pb/auth.pb.go:1089.11,1090.24 1 0
+auth/pb/auth.pb.go:1091.11,1092.28 1 0
+auth/pb/auth.pb.go:1093.12,1094.15 1 0
+auth/pb/auth.pb.go:1097.3,1097.66 1 0
+auth/pb/auth.pb.go:1097.66,1098.39 1 0
+auth/pb/auth.pb.go:1099.11,1100.20 1 0
+auth/pb/auth.pb.go:1101.11,1102.24 1 0
+auth/pb/auth.pb.go:1103.11,1104.28 1 0
+auth/pb/auth.pb.go:1105.12,1106.15 1 0
+auth/pb/auth.pb.go:1109.3,1109.66 1 0
+auth/pb/auth.pb.go:1109.66,1110.40 1 0
+auth/pb/auth.pb.go:1111.11,1112.20 1 0
+auth/pb/auth.pb.go:1113.11,1114.24 1 0
+auth/pb/auth.pb.go:1115.11,1116.28 1 0
+auth/pb/auth.pb.go:1117.12,1118.15 1 0
+auth/pb/auth.pb.go:1122.2,1140.31 7 0
+auth/pb/auth_grpc.pb.go:60.74,62.2 1 0
+auth/pb/auth_grpc.pb.go:64.123,68.16 4 0
+auth/pb/auth_grpc.pb.go:68.16,70.3 1 0
+auth/pb/auth_grpc.pb.go:71.2,71.17 1 0
+auth/pb/auth_grpc.pb.go:74.125,78.16 4 0
+auth/pb/auth_grpc.pb.go:78.16,80.3 1 0
+auth/pb/auth_grpc.pb.go:81.2,81.17 1 0
+auth/pb/auth_grpc.pb.go:84.144,88.16 4 0
+auth/pb/auth_grpc.pb.go:88.16,90.3 1 0
+auth/pb/auth_grpc.pb.go:91.2,91.17 1 0
+auth/pb/auth_grpc.pb.go:94.147,98.16 4 0
+auth/pb/auth_grpc.pb.go:98.16,100.3 1 0
+auth/pb/auth_grpc.pb.go:101.2,101.17 1 0
+auth/pb/auth_grpc.pb.go:104.144,108.16 4 0
+auth/pb/auth_grpc.pb.go:108.16,110.3 1 0
+auth/pb/auth_grpc.pb.go:111.2,111.17 1 0
+auth/pb/auth_grpc.pb.go:114.138,118.16 4 0
+auth/pb/auth_grpc.pb.go:118.16,120.3 1 0
+auth/pb/auth_grpc.pb.go:121.2,121.17 1 0
+auth/pb/auth_grpc.pb.go:124.133,128.16 4 0
+auth/pb/auth_grpc.pb.go:128.16,130.3 1 0
+auth/pb/auth_grpc.pb.go:131.2,131.17 1 0
+auth/pb/auth_grpc.pb.go:134.129,138.16 4 0
+auth/pb/auth_grpc.pb.go:138.16,140.3 1 0
+auth/pb/auth_grpc.pb.go:141.2,141.17 1 0
+auth/pb/auth_grpc.pb.go:171.101,173.2 1 0
+auth/pb/auth_grpc.pb.go:174.103,176.2 1 0
+auth/pb/auth_grpc.pb.go:177.122,179.2 1 0
+auth/pb/auth_grpc.pb.go:180.125,182.2 1 0
+auth/pb/auth_grpc.pb.go:183.122,185.2 1 0
+auth/pb/auth_grpc.pb.go:186.116,188.2 1 0
+auth/pb/auth_grpc.pb.go:189.111,191.2 1 0
+auth/pb/auth_grpc.pb.go:192.107,194.2 1 0
+auth/pb/auth_grpc.pb.go:195.82,195.83 0 0
+auth/pb/auth_grpc.pb.go:204.80,206.2 1 0
+auth/pb/auth_grpc.pb.go:208.162,210.32 2 0
+auth/pb/auth_grpc.pb.go:210.32,212.3 1 0
+auth/pb/auth_grpc.pb.go:213.2,213.24 1 0
+auth/pb/auth_grpc.pb.go:213.24,215.3 1 0
+auth/pb/auth_grpc.pb.go:216.2,220.77 2 0
+auth/pb/auth_grpc.pb.go:220.77,222.3 1 0
+auth/pb/auth_grpc.pb.go:223.2,223.44 1 0
+auth/pb/auth_grpc.pb.go:226.163,228.32 2 0
+auth/pb/auth_grpc.pb.go:228.32,230.3 1 0
+auth/pb/auth_grpc.pb.go:231.2,231.24 1 0
+auth/pb/auth_grpc.pb.go:231.24,233.3 1 0
+auth/pb/auth_grpc.pb.go:234.2,238.77 2 0
+auth/pb/auth_grpc.pb.go:238.77,240.3 1 0
+auth/pb/auth_grpc.pb.go:241.2,241.44 1 0
+auth/pb/auth_grpc.pb.go:244.169,246.32 2 0
+auth/pb/auth_grpc.pb.go:246.32,248.3 1 0
+auth/pb/auth_grpc.pb.go:249.2,249.24 1 0
+auth/pb/auth_grpc.pb.go:249.24,251.3 1 0
+auth/pb/auth_grpc.pb.go:252.2,256.77 2 0
+auth/pb/auth_grpc.pb.go:256.77,258.3 1 0
+auth/pb/auth_grpc.pb.go:259.2,259.44 1 0
+auth/pb/auth_grpc.pb.go:262.170,264.32 2 0
+auth/pb/auth_grpc.pb.go:264.32,266.3 1 0
+auth/pb/auth_grpc.pb.go:267.2,267.24 1 0
+auth/pb/auth_grpc.pb.go:267.24,269.3 1 0
+auth/pb/auth_grpc.pb.go:270.2,274.77 2 0
+auth/pb/auth_grpc.pb.go:274.77,276.3 1 0
+auth/pb/auth_grpc.pb.go:277.2,277.44 1 0
+auth/pb/auth_grpc.pb.go:280.169,282.32 2 0
+auth/pb/auth_grpc.pb.go:282.32,284.3 1 0
+auth/pb/auth_grpc.pb.go:285.2,285.24 1 0
+auth/pb/auth_grpc.pb.go:285.24,287.3 1 0
+auth/pb/auth_grpc.pb.go:288.2,292.77 2 0
+auth/pb/auth_grpc.pb.go:292.77,294.3 1 0
+auth/pb/auth_grpc.pb.go:295.2,295.44 1 0
+auth/pb/auth_grpc.pb.go:298.167,300.32 2 0
+auth/pb/auth_grpc.pb.go:300.32,302.3 1 0
+auth/pb/auth_grpc.pb.go:303.2,303.24 1 0
+auth/pb/auth_grpc.pb.go:303.24,305.3 1 0
+auth/pb/auth_grpc.pb.go:306.2,310.77 2 0
+auth/pb/auth_grpc.pb.go:310.77,312.3 1 0
+auth/pb/auth_grpc.pb.go:313.2,313.44 1 0
+auth/pb/auth_grpc.pb.go:316.167,318.32 2 0
+auth/pb/auth_grpc.pb.go:318.32,320.3 1 0
+auth/pb/auth_grpc.pb.go:321.2,321.24 1 0
+auth/pb/auth_grpc.pb.go:321.24,323.3 1 0
+auth/pb/auth_grpc.pb.go:324.2,328.77 2 0
+auth/pb/auth_grpc.pb.go:328.77,330.3 1 0
+auth/pb/auth_grpc.pb.go:331.2,331.44 1 0
+auth/pb/auth_grpc.pb.go:334.164,336.32 2 0
+auth/pb/auth_grpc.pb.go:336.32,338.3 1 0
+auth/pb/auth_grpc.pb.go:339.2,339.24 1 0
+auth/pb/auth_grpc.pb.go:339.24,341.3 1 0
+auth/pb/auth_grpc.pb.go:342.2,346.77 2 0
+auth/pb/auth_grpc.pb.go:346.77,348.3 1 0
+auth/pb/auth_grpc.pb.go:349.2,349.44 1 0
+auth/pb/authorization.pb.go:34.42,36.29 2 0
+auth/pb/authorization.pb.go:36.29,40.3 3 0
+auth/pb/authorization.pb.go:43.50,45.2 1 0
+auth/pb/authorization.pb.go:47.48,47.49 0 0
+auth/pb/authorization.pb.go:49.70,51.41 2 0
+auth/pb/authorization.pb.go:51.41,53.34 2 0
+auth/pb/authorization.pb.go:53.34,55.4 1 0
+auth/pb/authorization.pb.go:56.3,56.12 1 0
+auth/pb/authorization.pb.go:58.2,58.24 1 0
+auth/pb/authorization.pb.go:62.61,64.2 1 0
+auth/pb/authorization.pb.go:66.53,67.14 1 0
+auth/pb/authorization.pb.go:67.14,69.3 1 0
+auth/pb/authorization.pb.go:70.2,70.11 1 0
+auth/pb/authorization.pb.go:73.62,74.14 1 0
+auth/pb/authorization.pb.go:74.14,76.3 1 0
+auth/pb/authorization.pb.go:77.2,77.12 1 0
+auth/pb/authorization.pb.go:88.43,90.29 2 0
+auth/pb/authorization.pb.go:90.29,94.3 3 0
+auth/pb/authorization.pb.go:97.51,99.2 1 0
+auth/pb/authorization.pb.go:101.49,101.50 0 0
+auth/pb/authorization.pb.go:103.71,105.41 2 0
+auth/pb/authorization.pb.go:105.41,107.34 2 0
+auth/pb/authorization.pb.go:107.34,109.4 1 0
+auth/pb/authorization.pb.go:110.3,110.12 1 0
+auth/pb/authorization.pb.go:112.2,112.24 1 0
+auth/pb/authorization.pb.go:116.62,118.2 1 0
+auth/pb/authorization.pb.go:120.59,121.14 1 0
+auth/pb/authorization.pb.go:121.14,123.3 1 0
+auth/pb/authorization.pb.go:124.2,124.14 1 0
+auth/pb/authorization.pb.go:135.39,137.29 2 0
+auth/pb/authorization.pb.go:137.29,141.3 3 0
+auth/pb/authorization.pb.go:144.47,146.2 1 0
+auth/pb/authorization.pb.go:148.45,148.46 0 0
+auth/pb/authorization.pb.go:150.67,152.41 2 0
+auth/pb/authorization.pb.go:152.41,154.34 2 0
+auth/pb/authorization.pb.go:154.34,156.4 1 0
+auth/pb/authorization.pb.go:157.3,157.12 1 0
+auth/pb/authorization.pb.go:159.2,159.24 1 0
+auth/pb/authorization.pb.go:163.58,165.2 1 0
+auth/pb/authorization.pb.go:167.50,168.14 1 0
+auth/pb/authorization.pb.go:168.14,170.3 1 0
+auth/pb/authorization.pb.go:171.2,171.11 1 0
+auth/pb/authorization.pb.go:182.40,184.29 2 0
+auth/pb/authorization.pb.go:184.29,188.3 3 0
+auth/pb/authorization.pb.go:191.48,193.2 1 0
+auth/pb/authorization.pb.go:195.46,195.47 0 0
+auth/pb/authorization.pb.go:197.68,199.41 2 0
+auth/pb/authorization.pb.go:199.41,201.34 2 0
+auth/pb/authorization.pb.go:201.34,203.4 1 0
+auth/pb/authorization.pb.go:204.3,204.12 1 0
+auth/pb/authorization.pb.go:206.2,206.24 1 0
+auth/pb/authorization.pb.go:210.59,212.2 1 0
+auth/pb/authorization.pb.go:214.51,215.14 1 0
+auth/pb/authorization.pb.go:215.14,217.3 1 0
+auth/pb/authorization.pb.go:218.2,218.12 1 0
+auth/pb/authorization.pb.go:230.43,232.29 2 0
+auth/pb/authorization.pb.go:232.29,236.3 3 0
+auth/pb/authorization.pb.go:239.51,241.2 1 0
+auth/pb/authorization.pb.go:243.49,243.50 0 0
+auth/pb/authorization.pb.go:245.71,247.41 2 0
+auth/pb/authorization.pb.go:247.41,249.34 2 0
+auth/pb/authorization.pb.go:249.34,251.4 1 0
+auth/pb/authorization.pb.go:252.3,252.12 1 0
+auth/pb/authorization.pb.go:254.2,254.24 1 0
+auth/pb/authorization.pb.go:258.62,260.2 1 0
+auth/pb/authorization.pb.go:262.54,263.14 1 0
+auth/pb/authorization.pb.go:263.14,265.3 1 0
+auth/pb/authorization.pb.go:266.2,266.11 1 0
+auth/pb/authorization.pb.go:269.54,270.14 1 0
+auth/pb/authorization.pb.go:270.14,272.3 1 0
+auth/pb/authorization.pb.go:273.2,273.11 1 0
+auth/pb/authorization.pb.go:285.45,287.29 2 0
+auth/pb/authorization.pb.go:287.29,291.3 3 0
+auth/pb/authorization.pb.go:294.53,296.2 1 0
+auth/pb/authorization.pb.go:298.51,298.52 0 0
+auth/pb/authorization.pb.go:300.73,302.41 2 0
+auth/pb/authorization.pb.go:302.41,304.34 2 0
+auth/pb/authorization.pb.go:304.34,306.4 1 0
+auth/pb/authorization.pb.go:307.3,307.12 1 0
+auth/pb/authorization.pb.go:309.2,309.24 1 0
+auth/pb/authorization.pb.go:313.64,315.2 1 0
+auth/pb/authorization.pb.go:317.56,318.14 1 0
+auth/pb/authorization.pb.go:318.14,320.3 1 0
+auth/pb/authorization.pb.go:321.2,321.11 1 0
+auth/pb/authorization.pb.go:324.56,325.14 1 0
+auth/pb/authorization.pb.go:325.14,327.3 1 0
+auth/pb/authorization.pb.go:328.2,328.11 1 0
+auth/pb/authorization.pb.go:340.37,342.29 2 0
+auth/pb/authorization.pb.go:342.29,346.3 3 0
+auth/pb/authorization.pb.go:349.45,351.2 1 0
+auth/pb/authorization.pb.go:353.43,353.44 0 0
+auth/pb/authorization.pb.go:355.65,357.41 2 0
+auth/pb/authorization.pb.go:357.41,359.34 2 0
+auth/pb/authorization.pb.go:359.34,361.4 1 0
+auth/pb/authorization.pb.go:362.3,362.12 1 0
+auth/pb/authorization.pb.go:364.2,364.24 1 0
+auth/pb/authorization.pb.go:368.56,370.2 1 0
+auth/pb/authorization.pb.go:372.46,373.14 1 0
+auth/pb/authorization.pb.go:373.14,375.3 1 0
+auth/pb/authorization.pb.go:376.2,376.11 1 0
+auth/pb/authorization.pb.go:379.60,380.14 1 0
+auth/pb/authorization.pb.go:380.14,382.3 1 0
+auth/pb/authorization.pb.go:383.2,383.12 1 0
+auth/pb/authorization.pb.go:394.38,396.29 2 0
+auth/pb/authorization.pb.go:396.29,400.3 3 0
+auth/pb/authorization.pb.go:403.46,405.2 1 0
+auth/pb/authorization.pb.go:407.44,407.45 0 0
+auth/pb/authorization.pb.go:409.66,411.41 2 0
+auth/pb/authorization.pb.go:411.41,413.34 2 0
+auth/pb/authorization.pb.go:413.34,415.4 1 0
+auth/pb/authorization.pb.go:416.3,416.12 1 0
+auth/pb/authorization.pb.go:418.2,418.24 1 0
+auth/pb/authorization.pb.go:422.57,424.2 1 0
+auth/pb/authorization.pb.go:426.46,427.14 1 0
+auth/pb/authorization.pb.go:427.14,429.3 1 0
+auth/pb/authorization.pb.go:430.2,430.12 1 0
+auth/pb/authorization.pb.go:443.37,445.29 2 0
+auth/pb/authorization.pb.go:445.29,449.3 3 0
+auth/pb/authorization.pb.go:452.45,454.2 1 0
+auth/pb/authorization.pb.go:456.43,456.44 0 0
+auth/pb/authorization.pb.go:458.65,460.41 2 0
+auth/pb/authorization.pb.go:460.41,462.34 2 0
+auth/pb/authorization.pb.go:462.34,464.4 1 0
+auth/pb/authorization.pb.go:465.3,465.12 1 0
+auth/pb/authorization.pb.go:467.2,467.24 1 0
+auth/pb/authorization.pb.go:471.56,473.2 1 0
+auth/pb/authorization.pb.go:475.48,476.14 1 0
+auth/pb/authorization.pb.go:476.14,478.3 1 0
+auth/pb/authorization.pb.go:479.2,479.11 1 0
+auth/pb/authorization.pb.go:482.46,483.31 1 0
+auth/pb/authorization.pb.go:483.31,485.3 1 0
+auth/pb/authorization.pb.go:486.2,486.11 1 0
+auth/pb/authorization.pb.go:489.60,490.14 1 0
+auth/pb/authorization.pb.go:490.14,492.3 1 0
+auth/pb/authorization.pb.go:493.2,493.12 1 0
+auth/pb/authorization.pb.go:504.38,506.29 2 0
+auth/pb/authorization.pb.go:506.29,510.3 3 0
+auth/pb/authorization.pb.go:513.46,515.2 1 0
+auth/pb/authorization.pb.go:517.44,517.45 0 0
+auth/pb/authorization.pb.go:519.66,521.41 2 0
+auth/pb/authorization.pb.go:521.41,523.34 2 0
+auth/pb/authorization.pb.go:523.34,525.4 1 0
+auth/pb/authorization.pb.go:526.3,526.12 1 0
+auth/pb/authorization.pb.go:528.2,528.24 1 0
+auth/pb/authorization.pb.go:532.57,534.2 1 0
+auth/pb/authorization.pb.go:536.46,537.14 1 0
+auth/pb/authorization.pb.go:537.14,539.3 1 0
+auth/pb/authorization.pb.go:540.2,540.12 1 0
+auth/pb/authorization.pb.go:551.37,553.29 2 0
+auth/pb/authorization.pb.go:553.29,557.3 3 0
+auth/pb/authorization.pb.go:560.45,562.2 1 0
+auth/pb/authorization.pb.go:564.43,564.44 0 0
+auth/pb/authorization.pb.go:566.65,568.41 2 0
+auth/pb/authorization.pb.go:568.41,570.34 2 0
+auth/pb/authorization.pb.go:570.34,572.4 1 0
+auth/pb/authorization.pb.go:573.3,573.12 1 0
+auth/pb/authorization.pb.go:575.2,575.24 1 0
+auth/pb/authorization.pb.go:579.56,581.2 1 0
+auth/pb/authorization.pb.go:583.48,584.14 1 0
+auth/pb/authorization.pb.go:584.14,586.3 1 0
+auth/pb/authorization.pb.go:587.2,587.11 1 0
+auth/pb/authorization.pb.go:598.34,600.29 2 0
+auth/pb/authorization.pb.go:600.29,604.3 3 0
+auth/pb/authorization.pb.go:607.42,609.2 1 0
+auth/pb/authorization.pb.go:611.40,611.41 0 0
+auth/pb/authorization.pb.go:613.62,615.41 2 0
+auth/pb/authorization.pb.go:615.41,617.34 2 0
+auth/pb/authorization.pb.go:617.34,619.4 1 0
+auth/pb/authorization.pb.go:620.3,620.12 1 0
+auth/pb/authorization.pb.go:622.2,622.24 1 0
+auth/pb/authorization.pb.go:626.53,628.2 1 0
+auth/pb/authorization.pb.go:630.45,631.14 1 0
+auth/pb/authorization.pb.go:631.14,633.3 1 0
+auth/pb/authorization.pb.go:634.2,634.11 1 0
+auth/pb/authorization.pb.go:645.35,647.29 2 0
+auth/pb/authorization.pb.go:647.29,651.3 3 0
+auth/pb/authorization.pb.go:654.43,656.2 1 0
+auth/pb/authorization.pb.go:658.41,658.42 0 0
+auth/pb/authorization.pb.go:660.63,662.41 2 0
+auth/pb/authorization.pb.go:662.41,664.34 2 0
+auth/pb/authorization.pb.go:664.34,666.4 1 0
+auth/pb/authorization.pb.go:667.3,667.12 1 0
+auth/pb/authorization.pb.go:669.2,669.24 1 0
+auth/pb/authorization.pb.go:673.54,675.2 1 0
+auth/pb/authorization.pb.go:677.43,678.14 1 0
+auth/pb/authorization.pb.go:678.14,680.3 1 0
+auth/pb/authorization.pb.go:681.2,681.12 1 0
+auth/pb/authorization.pb.go:693.36,695.29 2 0
+auth/pb/authorization.pb.go:695.29,699.3 3 0
+auth/pb/authorization.pb.go:702.44,704.2 1 0
+auth/pb/authorization.pb.go:706.42,706.43 0 0
+auth/pb/authorization.pb.go:708.64,710.41 2 0
+auth/pb/authorization.pb.go:710.41,712.34 2 0
+auth/pb/authorization.pb.go:712.34,714.4 1 0
+auth/pb/authorization.pb.go:715.3,715.12 1 0
+auth/pb/authorization.pb.go:717.2,717.24 1 0
+auth/pb/authorization.pb.go:721.55,723.2 1 0
+auth/pb/authorization.pb.go:725.48,726.14 1 0
+auth/pb/authorization.pb.go:726.14,728.3 1 0
+auth/pb/authorization.pb.go:729.2,729.10 1 0
+auth/pb/authorization.pb.go:732.50,733.14 1 0
+auth/pb/authorization.pb.go:733.14,735.3 1 0
+auth/pb/authorization.pb.go:736.2,736.11 1 0
+auth/pb/authorization.pb.go:748.37,750.29 2 0
+auth/pb/authorization.pb.go:750.29,754.3 3 0
+auth/pb/authorization.pb.go:757.45,759.2 1 0
+auth/pb/authorization.pb.go:761.43,761.44 0 0
+auth/pb/authorization.pb.go:763.65,765.41 2 0
+auth/pb/authorization.pb.go:765.41,767.34 2 0
+auth/pb/authorization.pb.go:767.34,769.4 1 0
+auth/pb/authorization.pb.go:770.3,770.12 1 0
+auth/pb/authorization.pb.go:772.2,772.24 1 0
+auth/pb/authorization.pb.go:776.56,778.2 1 0
+auth/pb/authorization.pb.go:780.48,781.14 1 0
+auth/pb/authorization.pb.go:781.14,783.3 1 0
+auth/pb/authorization.pb.go:784.2,784.12 1 0
+auth/pb/authorization.pb.go:787.55,788.14 1 0
+auth/pb/authorization.pb.go:788.14,790.3 1 0
+auth/pb/authorization.pb.go:791.2,791.11 1 0
+auth/pb/authorization.pb.go:803.46,805.29 2 0
+auth/pb/authorization.pb.go:805.29,809.3 3 0
+auth/pb/authorization.pb.go:812.54,814.2 1 0
+auth/pb/authorization.pb.go:816.52,816.53 0 0
+auth/pb/authorization.pb.go:818.74,820.41 2 0
+auth/pb/authorization.pb.go:820.41,822.34 2 0
+auth/pb/authorization.pb.go:822.34,824.4 1 0
+auth/pb/authorization.pb.go:825.3,825.12 1 0
+auth/pb/authorization.pb.go:827.2,827.24 1 0
+auth/pb/authorization.pb.go:831.65,833.2 1 0
+auth/pb/authorization.pb.go:835.57,836.14 1 0
+auth/pb/authorization.pb.go:836.14,838.3 1 0
+auth/pb/authorization.pb.go:839.2,839.11 1 0
+auth/pb/authorization.pb.go:842.66,843.14 1 0
+auth/pb/authorization.pb.go:843.14,845.3 1 0
+auth/pb/authorization.pb.go:846.2,846.12 1 0
+auth/pb/authorization.pb.go:858.51,860.29 2 0
+auth/pb/authorization.pb.go:860.29,864.3 3 0
+auth/pb/authorization.pb.go:867.59,869.2 1 0
+auth/pb/authorization.pb.go:871.57,871.58 0 0
+auth/pb/authorization.pb.go:873.79,875.41 2 0
+auth/pb/authorization.pb.go:875.41,877.34 2 0
+auth/pb/authorization.pb.go:877.34,879.4 1 0
+auth/pb/authorization.pb.go:880.3,880.12 1 0
+auth/pb/authorization.pb.go:882.2,882.24 1 0
+auth/pb/authorization.pb.go:886.70,888.2 1 0
+auth/pb/authorization.pb.go:890.62,891.14 1 0
+auth/pb/authorization.pb.go:891.14,893.3 1 0
+auth/pb/authorization.pb.go:894.2,894.11 1 0
+auth/pb/authorization.pb.go:897.71,898.14 1 0
+auth/pb/authorization.pb.go:898.14,900.3 1 0
+auth/pb/authorization.pb.go:901.2,901.12 1 0
+auth/pb/authorization.pb.go:1072.52,1073.49 1 0
+auth/pb/authorization.pb.go:1073.49,1075.3 1 0
+auth/pb/authorization.pb.go:1076.2,1076.45 1 0
+auth/pb/authorization.pb.go:1142.13,1142.48 1 0
+auth/pb/authorization.pb.go:1143.38,1144.37 1 0
+auth/pb/authorization.pb.go:1144.37,1146.3 1 0
+auth/pb/authorization.pb.go:1147.2,1148.30 2 0
+auth/pb/authorization.pb.go:1148.30,1149.74 1 0
+auth/pb/authorization.pb.go:1149.74,1150.47 1 0
+auth/pb/authorization.pb.go:1151.11,1152.20 1 0
+auth/pb/authorization.pb.go:1153.11,1154.24 1 0
+auth/pb/authorization.pb.go:1155.11,1156.28 1 0
+auth/pb/authorization.pb.go:1157.12,1158.15 1 0
+auth/pb/authorization.pb.go:1161.3,1161.74 1 0
+auth/pb/authorization.pb.go:1161.74,1162.48 1 0
+auth/pb/authorization.pb.go:1163.11,1164.20 1 0
+auth/pb/authorization.pb.go:1165.11,1166.24 1 0
+auth/pb/authorization.pb.go:1167.11,1168.28 1 0
+auth/pb/authorization.pb.go:1169.12,1170.15 1 0
+auth/pb/authorization.pb.go:1173.3,1173.74 1 0
+auth/pb/authorization.pb.go:1173.74,1174.44 1 0
+auth/pb/authorization.pb.go:1175.11,1176.20 1 0
+auth/pb/authorization.pb.go:1177.11,1178.24 1 0
+auth/pb/authorization.pb.go:1179.11,1180.28 1 0
+auth/pb/authorization.pb.go:1181.12,1182.15 1 0
+auth/pb/authorization.pb.go:1185.3,1185.74 1 0
+auth/pb/authorization.pb.go:1185.74,1186.45 1 0
+auth/pb/authorization.pb.go:1187.11,1188.20 1 0
+auth/pb/authorization.pb.go:1189.11,1190.24 1 0
+auth/pb/authorization.pb.go:1191.11,1192.28 1 0
+auth/pb/authorization.pb.go:1193.12,1194.15 1 0
+auth/pb/authorization.pb.go:1197.3,1197.74 1 0
+auth/pb/authorization.pb.go:1197.74,1198.48 1 0
+auth/pb/authorization.pb.go:1199.11,1200.20 1 0
+auth/pb/authorization.pb.go:1201.11,1202.24 1 0
+auth/pb/authorization.pb.go:1203.11,1204.28 1 0
+auth/pb/authorization.pb.go:1205.12,1206.15 1 0
+auth/pb/authorization.pb.go:1209.3,1209.74 1 0
+auth/pb/authorization.pb.go:1209.74,1210.50 1 0
+auth/pb/authorization.pb.go:1211.11,1212.20 1 0
+auth/pb/authorization.pb.go:1213.11,1214.24 1 0
+auth/pb/authorization.pb.go:1215.11,1216.28 1 0
+auth/pb/authorization.pb.go:1217.12,1218.15 1 0
+auth/pb/authorization.pb.go:1221.3,1221.74 1 0
+auth/pb/authorization.pb.go:1221.74,1222.42 1 0
+auth/pb/authorization.pb.go:1223.11,1224.20 1 0
+auth/pb/authorization.pb.go:1225.11,1226.24 1 0
+auth/pb/authorization.pb.go:1227.11,1228.28 1 0
+auth/pb/authorization.pb.go:1229.12,1230.15 1 0
+auth/pb/authorization.pb.go:1233.3,1233.74 1 0
+auth/pb/authorization.pb.go:1233.74,1234.43 1 0
+auth/pb/authorization.pb.go:1235.11,1236.20 1 0
+auth/pb/authorization.pb.go:1237.11,1238.24 1 0
+auth/pb/authorization.pb.go:1239.11,1240.28 1 0
+auth/pb/authorization.pb.go:1241.12,1242.15 1 0
+auth/pb/authorization.pb.go:1245.3,1245.74 1 0
+auth/pb/authorization.pb.go:1245.74,1246.42 1 0
+auth/pb/authorization.pb.go:1247.11,1248.20 1 0
+auth/pb/authorization.pb.go:1249.11,1250.24 1 0
+auth/pb/authorization.pb.go:1251.11,1252.28 1 0
+auth/pb/authorization.pb.go:1253.12,1254.15 1 0
+auth/pb/authorization.pb.go:1257.3,1257.74 1 0
+auth/pb/authorization.pb.go:1257.74,1258.43 1 0
+auth/pb/authorization.pb.go:1259.11,1260.20 1 0
+auth/pb/authorization.pb.go:1261.11,1262.24 1 0
+auth/pb/authorization.pb.go:1263.11,1264.28 1 0
+auth/pb/authorization.pb.go:1265.12,1266.15 1 0
+auth/pb/authorization.pb.go:1269.3,1269.75 1 0
+auth/pb/authorization.pb.go:1269.75,1270.42 1 0
+auth/pb/authorization.pb.go:1271.11,1272.20 1 0
+auth/pb/authorization.pb.go:1273.11,1274.24 1 0
+auth/pb/authorization.pb.go:1275.11,1276.28 1 0
+auth/pb/authorization.pb.go:1277.12,1278.15 1 0
+auth/pb/authorization.pb.go:1281.3,1281.75 1 0
+auth/pb/authorization.pb.go:1281.75,1282.39 1 0
+auth/pb/authorization.pb.go:1283.11,1284.20 1 0
+auth/pb/authorization.pb.go:1285.11,1286.24 1 0
+auth/pb/authorization.pb.go:1287.11,1288.28 1 0
+auth/pb/authorization.pb.go:1289.12,1290.15 1 0
+auth/pb/authorization.pb.go:1293.3,1293.75 1 0
+auth/pb/authorization.pb.go:1293.75,1294.40 1 0
+auth/pb/authorization.pb.go:1295.11,1296.20 1 0
+auth/pb/authorization.pb.go:1297.11,1298.24 1 0
+auth/pb/authorization.pb.go:1299.11,1300.28 1 0
+auth/pb/authorization.pb.go:1301.12,1302.15 1 0
+auth/pb/authorization.pb.go:1305.3,1305.75 1 0
+auth/pb/authorization.pb.go:1305.75,1306.41 1 0
+auth/pb/authorization.pb.go:1307.11,1308.20 1 0
+auth/pb/authorization.pb.go:1309.11,1310.24 1 0
+auth/pb/authorization.pb.go:1311.11,1312.28 1 0
+auth/pb/authorization.pb.go:1313.12,1314.15 1 0
+auth/pb/authorization.pb.go:1317.3,1317.75 1 0
+auth/pb/authorization.pb.go:1317.75,1318.42 1 0
+auth/pb/authorization.pb.go:1319.11,1320.20 1 0
+auth/pb/authorization.pb.go:1321.11,1322.24 1 0
+auth/pb/authorization.pb.go:1323.11,1324.28 1 0
+auth/pb/authorization.pb.go:1325.12,1326.15 1 0
+auth/pb/authorization.pb.go:1329.3,1329.75 1 0
+auth/pb/authorization.pb.go:1329.75,1330.51 1 0
+auth/pb/authorization.pb.go:1331.11,1332.20 1 0
+auth/pb/authorization.pb.go:1333.11,1334.24 1 0
+auth/pb/authorization.pb.go:1335.11,1336.28 1 0
+auth/pb/authorization.pb.go:1337.12,1338.15 1 0
+auth/pb/authorization.pb.go:1341.3,1341.75 1 0
+auth/pb/authorization.pb.go:1341.75,1342.56 1 0
+auth/pb/authorization.pb.go:1343.11,1344.20 1 0
+auth/pb/authorization.pb.go:1345.11,1346.24 1 0
+auth/pb/authorization.pb.go:1347.11,1348.28 1 0
+auth/pb/authorization.pb.go:1349.12,1350.15 1 0
+auth/pb/authorization.pb.go:1354.2,1372.40 7 0
+auth/pb/authorization_grpc.pb.go:69.92,71.2 1 0
+auth/pb/authorization_grpc.pb.go:73.162,77.16 4 0
+auth/pb/authorization_grpc.pb.go:77.16,79.3 1 0
+auth/pb/authorization_grpc.pb.go:80.2,80.17 1 0
+auth/pb/authorization_grpc.pb.go:83.153,87.16 4 0
+auth/pb/authorization_grpc.pb.go:87.16,89.3 1 0
+auth/pb/authorization_grpc.pb.go:90.2,90.17 1 0
+auth/pb/authorization_grpc.pb.go:93.154,97.16 4 0
+auth/pb/authorization_grpc.pb.go:97.16,99.3 1 0
+auth/pb/authorization_grpc.pb.go:100.2,100.17 1 0
+auth/pb/authorization_grpc.pb.go:103.158,107.16 4 0
+auth/pb/authorization_grpc.pb.go:107.16,109.3 1 0
+auth/pb/authorization_grpc.pb.go:110.2,110.17 1 0
+auth/pb/authorization_grpc.pb.go:113.147,117.16 4 0
+auth/pb/authorization_grpc.pb.go:117.16,119.3 1 0
+auth/pb/authorization_grpc.pb.go:120.2,120.17 1 0
+auth/pb/authorization_grpc.pb.go:123.147,127.16 4 0
+auth/pb/authorization_grpc.pb.go:127.16,129.3 1 0
+auth/pb/authorization_grpc.pb.go:130.2,130.17 1 0
+auth/pb/authorization_grpc.pb.go:133.142,137.16 4 0
+auth/pb/authorization_grpc.pb.go:137.16,139.3 1 0
+auth/pb/authorization_grpc.pb.go:140.2,140.17 1 0
+auth/pb/authorization_grpc.pb.go:143.138,147.16 4 0
+auth/pb/authorization_grpc.pb.go:147.16,149.3 1 0
+auth/pb/authorization_grpc.pb.go:150.2,150.17 1 0
+auth/pb/authorization_grpc.pb.go:153.144,157.16 4 0
+auth/pb/authorization_grpc.pb.go:157.16,159.3 1 0
+auth/pb/authorization_grpc.pb.go:160.2,160.17 1 0
+auth/pb/authorization_grpc.pb.go:163.160,167.16 4 0
+auth/pb/authorization_grpc.pb.go:167.16,169.3 1 0
+auth/pb/authorization_grpc.pb.go:170.2,170.17 1 0
+auth/pb/authorization_grpc.pb.go:173.170,177.16 4 0
+auth/pb/authorization_grpc.pb.go:177.16,179.3 1 0
+auth/pb/authorization_grpc.pb.go:180.2,180.17 1 0
+auth/pb/authorization_grpc.pb.go:216.140,218.2 1 0
+auth/pb/authorization_grpc.pb.go:219.131,221.2 1 0
+auth/pb/authorization_grpc.pb.go:222.132,224.2 1 0
+auth/pb/authorization_grpc.pb.go:225.136,227.2 1 0
+auth/pb/authorization_grpc.pb.go:228.125,230.2 1 0
+auth/pb/authorization_grpc.pb.go:231.125,233.2 1 0
+auth/pb/authorization_grpc.pb.go:234.120,236.2 1 0
+auth/pb/authorization_grpc.pb.go:237.116,239.2 1 0
+auth/pb/authorization_grpc.pb.go:240.122,242.2 1 0
+auth/pb/authorization_grpc.pb.go:243.138,245.2 1 0
+auth/pb/authorization_grpc.pb.go:246.148,248.2 1 0
+auth/pb/authorization_grpc.pb.go:249.100,249.101 0 0
+auth/pb/authorization_grpc.pb.go:258.98,260.2 1 0
+auth/pb/authorization_grpc.pb.go:262.181,264.32 2 0
+auth/pb/authorization_grpc.pb.go:264.32,266.3 1 0
+auth/pb/authorization_grpc.pb.go:267.2,267.24 1 0
+auth/pb/authorization_grpc.pb.go:267.24,269.3 1 0
+auth/pb/authorization_grpc.pb.go:270.2,274.77 2 0
+auth/pb/authorization_grpc.pb.go:274.77,276.3 1 0
+auth/pb/authorization_grpc.pb.go:277.2,277.44 1 0
+auth/pb/authorization_grpc.pb.go:280.178,282.32 2 0
+auth/pb/authorization_grpc.pb.go:282.32,284.3 1 0
+auth/pb/authorization_grpc.pb.go:285.2,285.24 1 0
+auth/pb/authorization_grpc.pb.go:285.24,287.3 1 0
+auth/pb/authorization_grpc.pb.go:288.2,292.77 2 0
+auth/pb/authorization_grpc.pb.go:292.77,294.3 1 0
+auth/pb/authorization_grpc.pb.go:295.2,295.44 1 0
+auth/pb/authorization_grpc.pb.go:298.182,300.32 2 0
+auth/pb/authorization_grpc.pb.go:300.32,302.3 1 0
+auth/pb/authorization_grpc.pb.go:303.2,303.24 1 0
+auth/pb/authorization_grpc.pb.go:303.24,305.3 1 0
+auth/pb/authorization_grpc.pb.go:306.2,310.77 2 0
+auth/pb/authorization_grpc.pb.go:310.77,312.3 1 0
+auth/pb/authorization_grpc.pb.go:313.2,313.44 1 0
+auth/pb/authorization_grpc.pb.go:316.184,318.32 2 0
+auth/pb/authorization_grpc.pb.go:318.32,320.3 1 0
+auth/pb/authorization_grpc.pb.go:321.2,321.24 1 0
+auth/pb/authorization_grpc.pb.go:321.24,323.3 1 0
+auth/pb/authorization_grpc.pb.go:324.2,328.77 2 0
+auth/pb/authorization_grpc.pb.go:328.77,330.3 1 0
+auth/pb/authorization_grpc.pb.go:331.2,331.44 1 0
+auth/pb/authorization_grpc.pb.go:334.176,336.32 2 0
+auth/pb/authorization_grpc.pb.go:336.32,338.3 1 0
+auth/pb/authorization_grpc.pb.go:339.2,339.24 1 0
+auth/pb/authorization_grpc.pb.go:339.24,341.3 1 0
+auth/pb/authorization_grpc.pb.go:342.2,346.77 2 0
+auth/pb/authorization_grpc.pb.go:346.77,348.3 1 0
+auth/pb/authorization_grpc.pb.go:349.2,349.44 1 0
+auth/pb/authorization_grpc.pb.go:352.176,354.32 2 0
+auth/pb/authorization_grpc.pb.go:354.32,356.3 1 0
+auth/pb/authorization_grpc.pb.go:357.2,357.24 1 0
+auth/pb/authorization_grpc.pb.go:357.24,359.3 1 0
+auth/pb/authorization_grpc.pb.go:360.2,364.77 2 0
+auth/pb/authorization_grpc.pb.go:364.77,366.3 1 0
+auth/pb/authorization_grpc.pb.go:367.2,367.44 1 0
+auth/pb/authorization_grpc.pb.go:370.176,372.32 2 0
+auth/pb/authorization_grpc.pb.go:372.32,374.3 1 0
+auth/pb/authorization_grpc.pb.go:375.2,375.24 1 0
+auth/pb/authorization_grpc.pb.go:375.24,377.3 1 0
+auth/pb/authorization_grpc.pb.go:378.2,382.77 2 0
+auth/pb/authorization_grpc.pb.go:382.77,384.3 1 0
+auth/pb/authorization_grpc.pb.go:385.2,385.44 1 0
+auth/pb/authorization_grpc.pb.go:388.173,390.32 2 0
+auth/pb/authorization_grpc.pb.go:390.32,392.3 1 0
+auth/pb/authorization_grpc.pb.go:393.2,393.24 1 0
+auth/pb/authorization_grpc.pb.go:393.24,395.3 1 0
+auth/pb/authorization_grpc.pb.go:396.2,400.77 2 0
+auth/pb/authorization_grpc.pb.go:400.77,402.3 1 0
+auth/pb/authorization_grpc.pb.go:403.2,403.44 1 0
+auth/pb/authorization_grpc.pb.go:406.175,408.32 2 0
+auth/pb/authorization_grpc.pb.go:408.32,410.3 1 0
+auth/pb/authorization_grpc.pb.go:411.2,411.24 1 0
+auth/pb/authorization_grpc.pb.go:411.24,413.3 1 0
+auth/pb/authorization_grpc.pb.go:414.2,418.77 2 0
+auth/pb/authorization_grpc.pb.go:418.77,420.3 1 0
+auth/pb/authorization_grpc.pb.go:421.2,421.44 1 0
+auth/pb/authorization_grpc.pb.go:424.185,426.32 2 0
+auth/pb/authorization_grpc.pb.go:426.32,428.3 1 0
+auth/pb/authorization_grpc.pb.go:429.2,429.24 1 0
+auth/pb/authorization_grpc.pb.go:429.24,431.3 1 0
+auth/pb/authorization_grpc.pb.go:432.2,436.77 2 0
+auth/pb/authorization_grpc.pb.go:436.77,438.3 1 0
+auth/pb/authorization_grpc.pb.go:439.2,439.44 1 0
+auth/pb/authorization_grpc.pb.go:442.190,444.32 2 0
+auth/pb/authorization_grpc.pb.go:444.32,446.3 1 0
+auth/pb/authorization_grpc.pb.go:447.2,447.24 1 0
+auth/pb/authorization_grpc.pb.go:447.24,449.3 1 0
+auth/pb/authorization_grpc.pb.go:450.2,454.77 2 0
+auth/pb/authorization_grpc.pb.go:454.77,456.3 1 0
+auth/pb/authorization_grpc.pb.go:457.2,457.44 1 0
+auth/pb/common.pb.go:39.24,41.29 2 0
+auth/pb/common.pb.go:41.29,45.3 3 0
+auth/pb/common.pb.go:48.32,50.2 1 0
+auth/pb/common.pb.go:52.30,52.31 0 0
+auth/pb/common.pb.go:54.52,56.41 2 0
+auth/pb/common.pb.go:56.41,58.34 2 0
+auth/pb/common.pb.go:58.34,60.4 1 0
+auth/pb/common.pb.go:61.3,61.12 1 0
+auth/pb/common.pb.go:63.2,63.24 1 0
+auth/pb/common.pb.go:67.43,69.2 1 0
+auth/pb/common.pb.go:71.31,72.14 1 0
+auth/pb/common.pb.go:72.14,74.3 1 0
+auth/pb/common.pb.go:75.2,75.11 1 0
+auth/pb/common.pb.go:78.37,79.14 1 0
+auth/pb/common.pb.go:79.14,81.3 1 0
+auth/pb/common.pb.go:82.2,82.11 1 0
+auth/pb/common.pb.go:85.34,86.14 1 0
+auth/pb/common.pb.go:86.14,88.3 1 0
+auth/pb/common.pb.go:89.2,89.11 1 0
+auth/pb/common.pb.go:92.36,93.14 1 0
+auth/pb/common.pb.go:93.14,95.3 1 0
+auth/pb/common.pb.go:96.2,96.12 1 0
+auth/pb/common.pb.go:99.54,100.14 1 0
+auth/pb/common.pb.go:100.14,102.3 1 0
+auth/pb/common.pb.go:103.2,103.12 1 0
+auth/pb/common.pb.go:106.54,107.14 1 0
+auth/pb/common.pb.go:107.14,109.3 1 0
+auth/pb/common.pb.go:110.2,110.12 1 0
+auth/pb/common.pb.go:126.24,128.29 2 0
+auth/pb/common.pb.go:128.29,132.3 3 0
+auth/pb/common.pb.go:135.32,137.2 1 0
+auth/pb/common.pb.go:139.30,139.31 0 0
+auth/pb/common.pb.go:141.52,143.41 2 0
+auth/pb/common.pb.go:143.41,145.34 2 0
+auth/pb/common.pb.go:145.34,147.4 1 0
+auth/pb/common.pb.go:148.3,148.12 1 0
+auth/pb/common.pb.go:150.2,150.24 1 0
+auth/pb/common.pb.go:154.43,156.2 1 0
+auth/pb/common.pb.go:158.31,159.14 1 0
+auth/pb/common.pb.go:159.14,161.3 1 0
+auth/pb/common.pb.go:162.2,162.11 1 0
+auth/pb/common.pb.go:165.33,166.14 1 0
+auth/pb/common.pb.go:166.14,168.3 1 0
+auth/pb/common.pb.go:169.2,169.11 1 0
+auth/pb/common.pb.go:172.42,173.14 1 0
+auth/pb/common.pb.go:173.14,175.3 1 0
+auth/pb/common.pb.go:176.2,176.12 1 0
+auth/pb/common.pb.go:179.54,180.14 1 0
+auth/pb/common.pb.go:180.14,182.3 1 0
+auth/pb/common.pb.go:183.2,183.12 1 0
+auth/pb/common.pb.go:186.54,187.14 1 0
+auth/pb/common.pb.go:187.14,189.3 1 0
+auth/pb/common.pb.go:190.2,190.12 1 0
+auth/pb/common.pb.go:203.30,205.29 2 0
+auth/pb/common.pb.go:205.29,209.3 3 0
+auth/pb/common.pb.go:212.38,214.2 1 0
+auth/pb/common.pb.go:216.36,216.37 0 0
+auth/pb/common.pb.go:218.58,220.41 2 0
+auth/pb/common.pb.go:220.41,222.34 2 0
+auth/pb/common.pb.go:222.34,224.4 1 0
+auth/pb/common.pb.go:225.3,225.12 1 0
+auth/pb/common.pb.go:227.2,227.24 1 0
+auth/pb/common.pb.go:231.49,233.2 1 0
+auth/pb/common.pb.go:235.43,236.14 1 0
+auth/pb/common.pb.go:236.14,238.3 1 0
+auth/pb/common.pb.go:239.2,239.11 1 0
+auth/pb/common.pb.go:242.41,243.14 1 0
+auth/pb/common.pb.go:243.14,245.3 1 0
+auth/pb/common.pb.go:246.2,246.11 1 0
+auth/pb/common.pb.go:259.25,261.29 2 0
+auth/pb/common.pb.go:261.29,265.3 3 0
+auth/pb/common.pb.go:268.33,270.2 1 0
+auth/pb/common.pb.go:272.31,272.32 0 0
+auth/pb/common.pb.go:274.53,276.41 2 0
+auth/pb/common.pb.go:276.41,278.34 2 0
+auth/pb/common.pb.go:278.34,280.4 1 0
+auth/pb/common.pb.go:281.3,281.12 1 0
+auth/pb/common.pb.go:283.2,283.24 1 0
+auth/pb/common.pb.go:287.44,289.2 1 0
+auth/pb/common.pb.go:291.34,292.14 1 0
+auth/pb/common.pb.go:292.14,294.3 1 0
+auth/pb/common.pb.go:295.2,295.11 1 0
+auth/pb/common.pb.go:298.37,299.14 1 0
+auth/pb/common.pb.go:299.14,301.3 1 0
+auth/pb/common.pb.go:302.2,302.11 1 0
+auth/pb/common.pb.go:355.45,356.42 1 0
+auth/pb/common.pb.go:356.42,358.3 1 0
+auth/pb/common.pb.go:359.2,359.38 1 0
+auth/pb/common.pb.go:382.13,382.41 1 0
+auth/pb/common.pb.go:383.31,384.30 1 0
+auth/pb/common.pb.go:384.30,386.3 1 0
+auth/pb/common.pb.go:387.2,387.30 1 0
+auth/pb/common.pb.go:387.30,388.67 1 0
+auth/pb/common.pb.go:388.67,389.29 1 0
+auth/pb/common.pb.go:390.11,391.20 1 0
+auth/pb/common.pb.go:392.11,393.24 1 0
+auth/pb/common.pb.go:394.11,395.28 1 0
+auth/pb/common.pb.go:396.12,397.15 1 0
+auth/pb/common.pb.go:400.3,400.67 1 0
+auth/pb/common.pb.go:400.67,401.29 1 0
+auth/pb/common.pb.go:402.11,403.20 1 0
+auth/pb/common.pb.go:404.11,405.24 1 0
+auth/pb/common.pb.go:406.11,407.28 1 0
+auth/pb/common.pb.go:408.12,409.15 1 0
+auth/pb/common.pb.go:412.3,412.67 1 0
+auth/pb/common.pb.go:412.67,413.35 1 0
+auth/pb/common.pb.go:414.11,415.20 1 0
+auth/pb/common.pb.go:416.11,417.24 1 0
+auth/pb/common.pb.go:418.11,419.28 1 0
+auth/pb/common.pb.go:420.12,421.15 1 0
+auth/pb/common.pb.go:424.3,424.67 1 0
+auth/pb/common.pb.go:424.67,425.30 1 0
+auth/pb/common.pb.go:426.11,427.20 1 0
+auth/pb/common.pb.go:428.11,429.24 1 0
+auth/pb/common.pb.go:430.11,431.28 1 0
+auth/pb/common.pb.go:432.12,433.15 1 0
+auth/pb/common.pb.go:437.2,454.33 6 0
+auth/internal/interceptor/interceptor.go:53.94,54.45 1 1
+auth/internal/interceptor/interceptor.go:54.45,56.3 1 1
+auth/internal/interceptor/interceptor.go:60.86,61.45 1 1
+auth/internal/interceptor/interceptor.go:61.45,63.3 1 1
+auth/internal/interceptor/interceptor.go:67.56,68.45 1 1
+auth/internal/interceptor/interceptor.go:68.45,70.3 1 1
+auth/internal/interceptor/interceptor.go:74.59,75.45 1 1
+auth/internal/interceptor/interceptor.go:75.45,77.3 1 1
+auth/internal/interceptor/interceptor.go:81.67,82.45 1 1
+auth/internal/interceptor/interceptor.go:82.45,84.3 1 1
+auth/internal/interceptor/interceptor.go:88.91,89.45 1 1
+auth/internal/interceptor/interceptor.go:89.45,91.3 1 1
+auth/internal/interceptor/interceptor.go:95.72,96.45 1 1
+auth/internal/interceptor/interceptor.go:96.45,98.3 1 1
+auth/internal/interceptor/interceptor.go:102.73,103.45 1 1
+auth/internal/interceptor/interceptor.go:103.45,105.3 1 1
+auth/internal/interceptor/interceptor.go:109.64,110.45 1 1
+auth/internal/interceptor/interceptor.go:110.45,112.3 1 1
+auth/internal/interceptor/interceptor.go:125.84,138.27 2 2
+auth/internal/interceptor/interceptor.go:138.27,140.3 1 9
+auth/internal/interceptor/interceptor.go:142.2,142.128 1 2
+auth/internal/interceptor/interceptor.go:142.128,144.3 1 0
+auth/internal/interceptor/interceptor.go:148.167,149.47 1 4
+auth/internal/interceptor/interceptor.go:149.47,151.3 1 0
+auth/internal/interceptor/interceptor.go:153.2,153.55 1 4
+auth/internal/interceptor/interceptor.go:153.55,155.3 1 0
+auth/internal/interceptor/interceptor.go:157.2,158.16 2 4
+auth/internal/interceptor/interceptor.go:158.16,160.3 1 1
+auth/internal/interceptor/interceptor.go:162.2,163.16 2 3
+auth/internal/interceptor/interceptor.go:163.16,165.3 1 1
+auth/internal/interceptor/interceptor.go:167.2,170.29 3 2
+auth/internal/interceptor/utils.go:20.58,21.19 1 7
+auth/internal/interceptor/utils.go:21.19,23.3 1 1
+auth/internal/interceptor/utils.go:24.2,24.26 1 6
+auth/internal/interceptor/utils.go:24.26,26.3 1 1
+auth/internal/interceptor/utils.go:27.2,27.12 1 6
+auth/internal/interceptor/utils.go:31.82,32.31 1 5
+auth/internal/interceptor/utils.go:32.31,33.54 1 0
+auth/internal/interceptor/utils.go:33.54,36.4 2 0
+auth/internal/interceptor/utils.go:38.2,38.12 1 5
+auth/internal/interceptor/utils.go:42.102,44.9 2 9
+auth/internal/interceptor/utils.go:44.9,47.3 2 2
+auth/internal/interceptor/utils.go:49.2,50.33 2 7
+auth/internal/interceptor/utils.go:50.33,53.3 2 1
+auth/internal/interceptor/utils.go:55.2,56.25 2 6
+auth/internal/interceptor/utils.go:56.25,59.3 2 1
+auth/internal/interceptor/utils.go:61.2,61.52 1 5
+auth/internal/interceptor/utils.go:65.142,66.20 1 6
+auth/internal/interceptor/utils.go:67.11,68.49 1 2
+auth/internal/interceptor/utils.go:69.14,70.47 1 2
+auth/internal/interceptor/utils.go:71.10,73.88 2 2
+auth/internal/interceptor/utils.go:78.115,79.34 1 8
+auth/internal/interceptor/utils.go:79.34,81.3 1 0
+auth/internal/interceptor/utils.go:83.2,84.16 2 8
+auth/internal/interceptor/utils.go:84.16,87.3 2 1
+auth/internal/interceptor/utils.go:89.2,90.16 2 7
+auth/internal/interceptor/utils.go:90.16,92.3 1 1
+auth/internal/interceptor/utils.go:92.8,92.27 1 6
+auth/internal/interceptor/utils.go:92.27,94.10 2 2
+auth/internal/interceptor/utils.go:94.10,96.4 1 0
+auth/internal/interceptor/utils.go:97.3,100.28 4 2
+auth/internal/interceptor/utils.go:103.2,103.20 1 7
+auth/internal/interceptor/utils.go:107.135,108.44 1 7
+auth/internal/interceptor/utils.go:108.44,110.88 2 5
+auth/internal/interceptor/utils.go:110.88,112.18 2 3
+auth/internal/interceptor/utils.go:112.18,114.5 1 1
+auth/internal/interceptor/utils.go:115.4,115.24 1 2
+auth/internal/interceptor/utils.go:118.2,118.16 1 4
+auth/internal/interceptor/utils.go:122.94,123.35 1 6
+auth/internal/interceptor/utils.go:123.35,125.3 1 0
+auth/internal/interceptor/utils.go:127.2,128.26 2 6
+auth/internal/interceptor/utils.go:128.26,131.3 2 1
+auth/internal/interceptor/utils.go:133.2,133.46 1 5
+auth/internal/interceptor/utils.go:140.132,141.43 1 3
+auth/internal/interceptor/utils.go:141.43,143.3 1 0
+auth/internal/interceptor/utils.go:145.2,146.52 2 3
+auth/internal/interceptor/utils.go:146.52,148.3 1 0
+auth/internal/interceptor/utils.go:150.2,151.17 2 3
+auth/internal/interceptor/utils.go:151.17,153.3 1 3
+auth/internal/interceptor/utils.go:155.2,159.3 1 3
+auth/internal/interceptor/utils.go:168.71,170.83 2 3
+auth/internal/interceptor/utils.go:170.83,171.58 1 2
+auth/internal/interceptor/utils.go:171.58,173.4 1 0
+auth/internal/interceptor/utils.go:174.3,174.32 1 2
+auth/internal/interceptor/utils.go:177.2,177.16 1 3
+auth/internal/interceptor/utils.go:177.16,179.3 1 2
+auth/internal/interceptor/utils.go:181.2,181.67 1 1
+auth/internal/interceptor/utils.go:181.67,183.3 1 1
+auth/internal/interceptor/utils.go:185.2,185.41 1 0
+auth/internal/interceptor/utils.go:189.58,197.13 3 2
+auth/internal/interceptor/utils.go:197.13,199.3 1 1
+auth/internal/interceptor/utils.go:200.2,200.21 1 1
+auth/internal/interceptor/utils.go:204.81,206.65 1 10
+auth/internal/interceptor/utils.go:206.65,208.10 2 2
+auth/internal/interceptor/utils.go:208.10,210.4 1 0
+auth/internal/interceptor/utils.go:211.3,211.20 1 2
+auth/internal/interceptor/utils.go:215.2,216.16 2 8
+auth/internal/interceptor/utils.go:216.16,218.3 1 0
+auth/internal/interceptor/utils.go:221.2,222.19 2 8
+auth/internal/interceptor/utils.go:226.63,228.2 1 1
+auth/internal/interceptor/utils.go:244.60,246.62 2 4
+auth/internal/interceptor/utils.go:246.62,248.3 1 2
+auth/internal/interceptor/utils.go:249.2,249.22 1 2
+auth/internal/interceptor/utils.go:266.58,268.9 2 4
+auth/internal/interceptor/utils.go:268.9,270.3 1 1
+auth/internal/interceptor/utils.go:272.2,273.41 2 3
+auth/internal/interceptor/utils.go:273.41,275.3 1 2
+auth/internal/interceptor/utils.go:277.2,277.24 1 1
+auth/internal/interceptor/utils.go:294.63,297.2 2 3
+auth/pkg/limiter.go:31.65,39.2 2 7
+auth/pkg/limiter.go:53.59,58.13 4 12
+auth/pkg/limiter.go:58.13,63.3 3 11
+auth/pkg/limiter.go:65.2,65.16 1 12
+auth/pkg/limiter.go:79.64,84.13 4 506
+auth/pkg/limiter.go:84.13,86.3 1 11
+auth/pkg/limiter.go:88.2,88.16 1 495
+auth/pkg/password_hash.go:22.50,23.15 1 8
+auth/pkg/password_hash.go:23.15,25.3 1 2
+auth/pkg/password_hash.go:26.2,26.36 1 8
+auth/pkg/password_hash.go:40.73,41.20 1 8
+auth/pkg/password_hash.go:41.20,43.3 1 1
+auth/pkg/password_hash.go:44.2,44.58 1 7
+auth/pkg/password_hash.go:44.58,46.3 1 1
+auth/pkg/password_hash.go:47.2,48.27 2 6
+auth/pkg/password_hash.go:63.89,64.26 1 3
+auth/pkg/password_hash.go:64.26,66.3 1 0
+auth/pkg/password_hash.go:67.2,67.20 1 3
+auth/pkg/password_hash.go:67.20,69.3 1 1
+auth/pkg/password_hash.go:70.2,71.16 2 2
+auth/pkg/password_hash.go:71.16,72.49 1 1
+auth/pkg/password_hash.go:72.49,74.4 1 1
+auth/pkg/password_hash.go:75.3,75.20 1 0
+auth/pkg/password_hash.go:77.2,77.18 1 1
+auth/pkg/token_generator.go:17.97,23.2 1 2
+auth/pkg/token_generator.go:26.78,27.19 1 4
+auth/pkg/token_generator.go:27.19,29.3 1 1
+auth/pkg/token_generator.go:30.2,35.40 6 4
+auth/ent/client.go:38.40,42.2 3 6
+auth/ent/client.go:44.25,49.2 4 6
+auth/ent/client.go:70.39,74.2 3 6
+auth/ent/client.go:77.42,78.27 1 6
+auth/ent/client.go:78.27,80.3 1 6
+auth/ent/client.go:81.2,81.13 1 6
+auth/ent/client.go:81.13,83.3 1 0
+auth/ent/client.go:87.21,88.25 1 0
+auth/ent/client.go:88.25,90.3 1 0
+auth/ent/client.go:94.34,95.25 1 0
+auth/ent/client.go:95.25,97.3 1 0
+auth/ent/client.go:101.43,102.25 1 6
+auth/ent/client.go:102.25,104.3 1 6
+auth/ent/client.go:110.82,111.20 1 6
+auth/ent/client.go:112.55,114.17 2 6
+auth/ent/client.go:114.17,116.4 1 0
+auth/ent/client.go:117.3,117.57 1 6
+auth/ent/client.go:118.10,119.63 1 0
+auth/ent/client.go:128.55,129.39 1 0
+auth/ent/client.go:129.39,131.3 1 0
+auth/ent/client.go:132.2,133.16 2 0
+auth/ent/client.go:133.16,135.3 1 0
+auth/ent/client.go:136.2,144.8 3 0
+auth/ent/client.go:148.81,149.39 1 0
+auth/ent/client.go:149.39,151.3 1 0
+auth/ent/client.go:152.2,155.16 2 0
+auth/ent/client.go:155.16,157.3 1 0
+auth/ent/client.go:158.2,166.8 3 0
+auth/ent/client.go:175.34,176.13 1 0
+auth/ent/client.go:176.13,178.3 1 0
+auth/ent/client.go:179.2,183.15 5 0
+auth/ent/client.go:187.32,189.2 1 6
+auth/ent/client.go:193.37,197.2 3 0
+auth/ent/client.go:201.57,205.2 3 0
+auth/ent/client.go:208.73,209.23 1 0
+auth/ent/client.go:210.21,211.31 1 0
+auth/ent/client.go:212.22,213.32 1 0
+auth/ent/client.go:214.21,215.31 1 0
+auth/ent/client.go:216.10,217.61 1 0
+auth/ent/client.go:227.42,229.2 1 7
+auth/ent/client.go:233.41,235.2 1 0
+auth/ent/client.go:239.61,241.2 1 0
+auth/ent/client.go:244.43,247.2 2 34
+auth/ent/client.go:250.74,252.2 1 0
+auth/ent/client.go:256.95,258.32 2 0
+auth/ent/client.go:258.32,260.3 1 0
+auth/ent/client.go:261.2,262.32 2 0
+auth/ent/client.go:262.32,265.3 2 0
+auth/ent/client.go:266.2,266.62 1 0
+auth/ent/client.go:270.43,273.2 2 0
+auth/ent/client.go:276.56,279.2 2 1
+auth/ent/client.go:282.60,285.2 2 3
+auth/ent/client.go:288.43,291.2 2 3
+auth/ent/client.go:294.56,296.2 1 0
+auth/ent/client.go:299.60,304.2 4 1
+auth/ent/client.go:307.41,313.2 1 18
+auth/ent/client.go:316.73,318.2 1 0
+auth/ent/client.go:321.65,323.16 2 0
+auth/ent/client.go:323.16,324.13 1 0
+auth/ent/client.go:326.2,326.12 1 0
+auth/ent/client.go:330.53,332.68 2 1
+auth/ent/client.go:332.68,341.3 4 1
+auth/ent/client.go:342.2,342.14 1 1
+auth/ent/client.go:346.37,348.2 1 41
+auth/ent/client.go:351.51,353.2 1 18
+auth/ent/client.go:355.82,356.16 1 0
+auth/ent/client.go:357.16,358.82 1 0
+auth/ent/client.go:359.16,360.82 1 0
+auth/ent/client.go:361.19,362.85 1 0
+auth/ent/client.go:363.29,364.82 1 0
+auth/ent/client.go:365.10,366.70 1 0
+auth/ent/client.go:376.44,378.2 1 8
+auth/ent/client.go:382.42,384.2 1 0
+auth/ent/client.go:388.62,390.2 1 0
+auth/ent/client.go:393.45,396.2 2 13
+auth/ent/client.go:399.77,401.2 1 0
+auth/ent/client.go:405.98,407.32 2 0
+auth/ent/client.go:407.32,409.3 1 0
+auth/ent/client.go:410.2,411.32 2 0
+auth/ent/client.go:411.32,414.3 2 0
+auth/ent/client.go:415.2,415.63 1 0
+auth/ent/client.go:419.45,422.2 2 4
+auth/ent/client.go:425.59,428.2 2 1
+auth/ent/client.go:431.62,434.2 2 0
+auth/ent/client.go:437.45,440.2 2 1
+auth/ent/client.go:443.59,445.2 1 0
+auth/ent/client.go:448.62,453.2 4 0
+auth/ent/client.go:456.43,462.2 1 10
+auth/ent/client.go:465.75,467.2 1 4
+auth/ent/client.go:470.67,472.16 2 0
+auth/ent/client.go:472.16,473.13 1 0
+auth/ent/client.go:475.2,475.12 1 0
+auth/ent/client.go:479.54,481.68 2 1
+auth/ent/client.go:481.68,490.3 4 1
+auth/ent/client.go:491.2,491.14 1 1
+auth/ent/client.go:495.38,497.2 1 19
+auth/ent/client.go:500.52,502.2 1 10
+auth/ent/client.go:504.84,505.16 1 0
+auth/ent/client.go:506.16,507.83 1 0
+auth/ent/client.go:508.16,509.83 1 0
+auth/ent/client.go:510.19,511.86 1 0
+auth/ent/client.go:512.29,513.83 1 0
+auth/ent/client.go:514.10,515.71 1 0
+auth/ent/client.go:525.42,527.2 1 8
+auth/ent/client.go:531.41,533.2 1 0
+auth/ent/client.go:537.61,539.2 1 0
+auth/ent/client.go:542.43,545.2 2 44
+auth/ent/client.go:548.74,550.2 1 0
+auth/ent/client.go:554.95,556.32 2 0
+auth/ent/client.go:556.32,558.3 1 0
+auth/ent/client.go:559.2,560.32 2 0
+auth/ent/client.go:560.32,563.3 2 0
+auth/ent/client.go:564.2,564.62 1 0
+auth/ent/client.go:568.43,571.2 2 0
+auth/ent/client.go:574.56,577.2 2 3
+auth/ent/client.go:580.60,583.2 2 10
+auth/ent/client.go:586.43,589.2 2 3
+auth/ent/client.go:592.56,594.2 1 0
+auth/ent/client.go:597.60,602.2 4 2
+auth/ent/client.go:605.41,611.2 1 30
+auth/ent/client.go:614.73,616.2 1 1
+auth/ent/client.go:619.65,621.16 2 0
+auth/ent/client.go:621.16,622.13 1 0
+auth/ent/client.go:624.2,624.12 1 0
+auth/ent/client.go:628.53,630.68 2 1
+auth/ent/client.go:630.68,639.3 4 1
+auth/ent/client.go:640.2,640.14 1 1
+auth/ent/client.go:644.55,646.68 2 1
+auth/ent/client.go:646.68,655.3 4 1
+auth/ent/client.go:656.2,656.14 1 1
+auth/ent/client.go:660.37,663.2 2 60
+auth/ent/client.go:666.51,668.2 1 30
+auth/ent/client.go:670.82,671.16 1 0
+auth/ent/client.go:672.16,673.82 1 0
+auth/ent/client.go:674.16,675.82 1 0
+auth/ent/client.go:676.19,677.85 1 0
+auth/ent/client.go:678.29,679.82 1 0
+auth/ent/client.go:680.10,681.70 1 0
+auth/ent/ent.go:42.47,45.2 2 0
+auth/ent/ent.go:48.68,50.2 1 0
+auth/ent/ent.go:55.45,58.2 2 0
+auth/ent/ent.go:61.67,63.2 1 0
+auth/ent/ent.go:75.46,76.22 1 0
+auth/ent/ent.go:76.22,82.3 1 0
+auth/ent/ent.go:83.2,83.35 1 0
+auth/ent/ent.go:87.48,88.31 1 0
+auth/ent/ent.go:88.31,89.28 1 0
+auth/ent/ent.go:89.28,90.56 1 0
+auth/ent/ent.go:90.56,92.5 1 0
+auth/ent/ent.go:93.4,93.30 1 0
+auth/ent/ent.go:99.49,100.31 1 0
+auth/ent/ent.go:100.31,101.28 1 0
+auth/ent/ent.go:101.28,102.56 1 0
+auth/ent/ent.go:102.56,104.5 1 0
+auth/ent/ent.go:105.4,105.31 1 0
+auth/ent/ent.go:118.53,119.38 1 0
+auth/ent/ent.go:119.38,121.3 1 0
+auth/ent/ent.go:125.28,126.38 1 0
+auth/ent/ent.go:126.38,128.3 1 0
+auth/ent/ent.go:132.38,133.38 1 0
+auth/ent/ent.go:133.38,134.59 1 0
+auth/ent/ent.go:134.59,137.4 2 0
+auth/ent/ent.go:138.3,138.29 1 0
+auth/ent/ent.go:143.39,144.38 1 0
+auth/ent/ent.go:144.38,145.59 1 0
+auth/ent/ent.go:145.59,148.4 2 0
+auth/ent/ent.go:149.3,149.29 1 0
+auth/ent/ent.go:154.38,155.38 1 0
+auth/ent/ent.go:155.38,156.59 1 0
+auth/ent/ent.go:156.59,159.4 2 0
+auth/ent/ent.go:160.3,160.29 1 0
+auth/ent/ent.go:165.38,166.38 1 0
+auth/ent/ent.go:166.38,167.59 1 0
+auth/ent/ent.go:167.59,170.4 2 0
+auth/ent/ent.go:171.3,171.29 1 0
+auth/ent/ent.go:182.42,184.2 1 0
+auth/ent/ent.go:187.42,189.2 1 0
+auth/ent/ent.go:192.40,193.16 1 0
+auth/ent/ent.go:193.16,195.3 1 0
+auth/ent/ent.go:196.2,197.27 2 0
+auth/ent/ent.go:206.40,208.2 1 0
+auth/ent/ent.go:211.33,212.16 1 1
+auth/ent/ent.go:212.16,214.3 1 0
+auth/ent/ent.go:215.2,216.27 2 1
+auth/ent/ent.go:220.36,221.21 1 0
+auth/ent/ent.go:221.21,223.3 1 0
+auth/ent/ent.go:224.2,224.12 1 0
+auth/ent/ent.go:233.43,235.2 1 0
+auth/ent/ent.go:238.36,239.16 1 0
+auth/ent/ent.go:239.16,241.3 1 0
+auth/ent/ent.go:242.2,243.27 2 0
+auth/ent/ent.go:252.41,254.2 1 0
+auth/ent/ent.go:257.34,258.16 1 0
+auth/ent/ent.go:258.16,260.3 1 0
+auth/ent/ent.go:261.2,262.27 2 0
+auth/ent/ent.go:274.41,276.2 1 4
+auth/ent/ent.go:279.42,281.2 1 0
+auth/ent/ent.go:284.40,285.16 1 0
+auth/ent/ent.go:285.16,287.3 1 0
+auth/ent/ent.go:288.2,289.27 2 0
+auth/ent/ent.go:301.54,302.39 1 0
+auth/ent/ent.go:302.39,303.13 1 0
+auth/ent/ent.go:308.67,309.22 1 0
+auth/ent/ent.go:309.22,311.3 1 0
+auth/ent/ent.go:312.2,313.40 2 0
+auth/ent/ent.go:313.40,315.3 1 0
+auth/ent/ent.go:316.2,316.15 1 0
+auth/ent/ent.go:320.59,322.16 2 0
+auth/ent/ent.go:322.16,323.13 1 0
+auth/ent/ent.go:325.2,325.10 1 0
+auth/ent/ent.go:329.70,331.41 2 0
+auth/ent/ent.go:331.41,333.3 1 0
+auth/ent/ent.go:334.2,334.16 1 0
+auth/ent/ent.go:335.9,336.19 1 0
+auth/ent/ent.go:337.9,338.32 1 0
+auth/ent/ent.go:339.10,340.85 1 0
+auth/ent/ent.go:342.2,342.8 1 0
+auth/ent/ent.go:346.56,348.16 2 0
+auth/ent/ent.go:348.16,349.13 1 0
+auth/ent/ent.go:351.2,351.10 1 0
+auth/ent/ent.go:355.61,356.22 1 0
+auth/ent/ent.go:356.22,358.3 1 0
+auth/ent/ent.go:359.2,360.40 2 0
+auth/ent/ent.go:360.40,362.3 1 0
+auth/ent/ent.go:363.2,363.15 1 0
+auth/ent/ent.go:367.53,369.16 2 0
+auth/ent/ent.go:369.16,370.13 1 0
+auth/ent/ent.go:372.2,372.10 1 0
+auth/ent/ent.go:376.64,378.38 2 0
+auth/ent/ent.go:378.38,380.3 1 0
+auth/ent/ent.go:381.2,381.16 1 0
+auth/ent/ent.go:382.9,383.19 1 0
+auth/ent/ent.go:384.9,385.32 1 0
+auth/ent/ent.go:386.10,387.82 1 0
+auth/ent/ent.go:389.2,389.8 1 0
+auth/ent/ent.go:393.50,395.16 2 0
+auth/ent/ent.go:395.16,396.13 1 0
+auth/ent/ent.go:398.2,398.10 1 0
+auth/ent/ent.go:402.69,403.22 1 0
+auth/ent/ent.go:403.22,405.3 1 0
+auth/ent/ent.go:406.2,407.40 2 0
+auth/ent/ent.go:407.40,409.3 1 0
+auth/ent/ent.go:410.2,410.15 1 0
+auth/ent/ent.go:414.61,416.16 2 0
+auth/ent/ent.go:416.16,417.13 1 0
+auth/ent/ent.go:419.2,419.10 1 0
+auth/ent/ent.go:423.72,425.42 2 0
+auth/ent/ent.go:425.42,427.3 1 0
+auth/ent/ent.go:428.2,428.16 1 0
+auth/ent/ent.go:429.9,430.19 1 0
+auth/ent/ent.go:431.9,432.32 1 0
+auth/ent/ent.go:433.10,434.86 1 0
+auth/ent/ent.go:436.2,436.8 1 0
+auth/ent/ent.go:440.58,442.16 2 0
+auth/ent/ent.go:442.16,443.13 1 0
+auth/ent/ent.go:445.2,445.10 1 0
+auth/ent/ent.go:449.63,450.22 1 0
+auth/ent/ent.go:450.22,452.3 1 0
+auth/ent/ent.go:453.2,454.40 2 0
+auth/ent/ent.go:454.40,456.3 1 0
+auth/ent/ent.go:457.2,457.15 1 0
+auth/ent/ent.go:461.55,463.16 2 0
+auth/ent/ent.go:463.16,464.13 1 0
+auth/ent/ent.go:466.2,466.10 1 0
+auth/ent/ent.go:470.66,472.39 2 0
+auth/ent/ent.go:472.39,474.3 1 0
+auth/ent/ent.go:475.2,475.16 1 0
+auth/ent/ent.go:476.9,477.19 1 0
+auth/ent/ent.go:478.9,479.32 1 0
+auth/ent/ent.go:480.10,481.83 1 0
+auth/ent/ent.go:483.2,483.8 1 0
+auth/ent/ent.go:487.52,489.16 2 0
+auth/ent/ent.go:489.16,490.13 1 0
+auth/ent/ent.go:492.2,492.10 1 0
+auth/ent/ent.go:499.112,500.21 1 120
+auth/ent/ent.go:500.21,502.3 1 60
+auth/ent/ent.go:503.2,503.84 1 60
+auth/ent/ent.go:503.84,505.10 2 60
+auth/ent/ent.go:505.10,507.4 1 0
+auth/ent/ent.go:509.3,510.19 2 60
+auth/ent/ent.go:512.2,512.39 1 60
+auth/ent/ent.go:512.39,513.22 1 60
+auth/ent/ent.go:513.22,515.4 1 0
+auth/ent/ent.go:516.3,516.22 1 60
+auth/ent/ent.go:518.2,519.16 2 60
+auth/ent/ent.go:519.16,521.3 1 2
+auth/ent/ent.go:522.2,523.9 2 58
+auth/ent/ent.go:523.9,525.3 1 0
+auth/ent/ent.go:526.2,526.16 1 58
+auth/ent/ent.go:530.85,531.38 1 90
+auth/ent/ent.go:531.38,534.3 2 54
+auth/ent/ent.go:535.2,535.12 1 90
+auth/ent/ent.go:540.14,541.71 1 50
+auth/ent/ent.go:541.71,543.10 2 50
+auth/ent/ent.go:543.10,545.4 1 0
+auth/ent/ent.go:546.3,546.27 1 50
+auth/ent/ent.go:552.14,553.71 1 4
+auth/ent/ent.go:553.71,555.10 2 4
+auth/ent/ent.go:555.10,557.4 1 0
+auth/ent/ent.go:558.3,558.29 1 4
+auth/ent/ent.go:562.113,563.40 1 58
+auth/ent/ent.go:563.40,565.3 1 0
+auth/ent/ent.go:566.2,567.16 2 58
+auth/ent/ent.go:567.16,569.3 1 0
+auth/ent/ent.go:570.2,571.9 2 58
+auth/ent/ent.go:571.9,573.3 1 0
+auth/ent/ent.go:574.2,574.16 1 58
+auth/ent/ent.go:579.92,581.81 2 0
+auth/ent/ent.go:581.81,583.10 2 0
+auth/ent/ent.go:583.10,585.4 1 0
+auth/ent/ent.go:586.3,586.62 1 0
+auth/ent/ent.go:586.62,588.4 1 0
+auth/ent/ent.go:589.3,589.71 1 0
+auth/ent/ent.go:589.71,591.4 1 0
+auth/ent/ent.go:592.3,592.16 1 0
+auth/ent/ent.go:594.2,594.40 1 0
+auth/ent/ent.go:594.40,596.3 1 0
+auth/ent/ent.go:597.2,598.16 2 0
+auth/ent/ent.go:598.16,600.3 1 0
+auth/ent/ent.go:601.2,601.37 1 0
+auth/ent/ent.go:602.61,602.61 0 0
+auth/ent/ent.go:603.31,604.28 1 0
+auth/ent/ent.go:605.38,606.21 1 0
+auth/ent/ent.go:608.2,608.12 1 0
+auth/ent/mutation.go:60.73,67.27 2 41
+auth/ent/mutation.go:67.27,69.3 1 4
+auth/ent/mutation.go:70.2,70.10 1 41
+auth/ent/mutation.go:74.39,75.31 1 3
+auth/ent/mutation.go:75.31,81.57 2 3
+auth/ent/mutation.go:81.57,82.19 1 0
+auth/ent/mutation.go:82.19,83.15 1 0
+auth/ent/mutation.go:83.15,85.6 1 0
+auth/ent/mutation.go:85.11,87.6 1 0
+auth/ent/mutation.go:89.4,89.21 1 0
+auth/ent/mutation.go:91.3,91.13 1 3
+auth/ent/mutation.go:96.38,97.31 1 1
+auth/ent/mutation.go:97.31,98.53 1 1
+auth/ent/mutation.go:98.53,100.4 1 0
+auth/ent/mutation.go:101.3,101.18 1 1
+auth/ent/mutation.go:107.40,111.2 3 0
+auth/ent/mutation.go:115.41,116.40 1 0
+auth/ent/mutation.go:116.40,118.3 1 0
+auth/ent/mutation.go:119.2,121.16 3 0
+auth/ent/mutation.go:126.41,128.2 1 34
+auth/ent/mutation.go:132.54,133.17 1 72
+auth/ent/mutation.go:133.17,135.3 1 34
+auth/ent/mutation.go:136.2,136.20 1 38
+auth/ent/mutation.go:143.67,144.9 1 0
+auth/ent/mutation.go:145.42,147.13 2 0
+auth/ent/mutation.go:147.13,149.4 1 0
+auth/ent/mutation.go:150.3,150.14 1 0
+auth/ent/mutation.go:151.36,152.65 1 0
+auth/ent/mutation.go:153.10,154.70 1 0
+auth/ent/mutation.go:159.42,161.2 1 35
+auth/ent/mutation.go:164.55,166.14 2 72
+auth/ent/mutation.go:166.14,168.3 1 3
+auth/ent/mutation.go:169.2,169.17 1 69
+auth/ent/mutation.go:175.75,176.27 1 0
+auth/ent/mutation.go:176.27,178.3 1 0
+auth/ent/mutation.go:179.2,179.38 1 0
+auth/ent/mutation.go:179.38,181.3 1 0
+auth/ent/mutation.go:182.2,183.16 2 0
+auth/ent/mutation.go:183.16,185.3 1 0
+auth/ent/mutation.go:186.2,186.27 1 0
+auth/ent/mutation.go:190.36,192.2 1 0
+auth/ent/mutation.go:195.51,198.2 2 36
+auth/ent/mutation.go:201.64,203.14 2 72
+auth/ent/mutation.go:203.14,205.3 1 2
+auth/ent/mutation.go:206.2,206.17 1 70
+auth/ent/mutation.go:212.84,213.27 1 0
+auth/ent/mutation.go:213.27,215.3 1 0
+auth/ent/mutation.go:216.2,216.38 1 0
+auth/ent/mutation.go:216.38,218.3 1 0
+auth/ent/mutation.go:219.2,220.16 2 0
+auth/ent/mutation.go:220.16,222.3 1 0
+auth/ent/mutation.go:223.2,223.34 1 0
+auth/ent/mutation.go:227.54,229.2 1 1
+auth/ent/mutation.go:232.63,233.35 1 4
+auth/ent/mutation.go:233.35,235.3 1 3
+auth/ent/mutation.go:236.2,236.34 1 1
+auth/ent/mutation.go:240.43,243.2 2 0
+auth/ent/mutation.go:246.50,248.2 1 34
+auth/ent/mutation.go:251.63,253.14 2 106
+auth/ent/mutation.go:253.14,255.3 1 38
+auth/ent/mutation.go:256.2,256.17 1 68
+auth/ent/mutation.go:262.83,263.27 1 0
+auth/ent/mutation.go:263.27,265.3 1 0
+auth/ent/mutation.go:266.2,266.38 1 0
+auth/ent/mutation.go:266.38,268.3 1 0
+auth/ent/mutation.go:269.2,270.16 2 0
+auth/ent/mutation.go:270.16,272.3 1 0
+auth/ent/mutation.go:273.2,273.32 1 0
+auth/ent/mutation.go:277.41,279.2 1 0
+auth/ent/mutation.go:282.50,284.2 1 38
+auth/ent/mutation.go:287.63,289.14 2 110
+auth/ent/mutation.go:289.14,291.3 1 37
+auth/ent/mutation.go:292.2,292.17 1 73
+auth/ent/mutation.go:298.83,299.27 1 0
+auth/ent/mutation.go:299.27,301.3 1 0
+auth/ent/mutation.go:302.2,302.38 1 0
+auth/ent/mutation.go:302.38,304.3 1 0
+auth/ent/mutation.go:305.2,306.16 2 0
+auth/ent/mutation.go:306.16,308.3 1 0
+auth/ent/mutation.go:309.2,309.32 1 0
+auth/ent/mutation.go:313.41,315.2 1 0
+auth/ent/mutation.go:318.50,319.20 1 2
+auth/ent/mutation.go:319.20,321.3 1 2
+auth/ent/mutation.go:322.2,322.21 1 2
+auth/ent/mutation.go:322.21,324.3 1 2
+auth/ent/mutation.go:328.37,330.2 1 0
+auth/ent/mutation.go:333.44,335.2 1 4
+auth/ent/mutation.go:338.53,339.27 1 0
+auth/ent/mutation.go:339.27,341.3 1 0
+auth/ent/mutation.go:342.2,342.21 1 0
+auth/ent/mutation.go:342.21,345.3 2 0
+auth/ent/mutation.go:349.57,350.33 1 4
+auth/ent/mutation.go:350.33,352.3 1 0
+auth/ent/mutation.go:353.2,353.8 1 4
+auth/ent/mutation.go:357.50,358.26 1 38
+auth/ent/mutation.go:358.26,360.3 1 2
+auth/ent/mutation.go:361.2,361.8 1 38
+auth/ent/mutation.go:365.37,369.2 3 0
+auth/ent/mutation.go:372.52,374.2 1 1
+auth/ent/mutation.go:378.58,380.20 2 0
+auth/ent/mutation.go:380.20,382.3 1 0
+auth/ent/mutation.go:383.2,383.15 1 0
+auth/ent/mutation.go:387.32,389.2 1 0
+auth/ent/mutation.go:392.37,394.2 1 0
+auth/ent/mutation.go:397.38,399.2 1 0
+auth/ent/mutation.go:404.42,406.19 2 0
+auth/ent/mutation.go:406.19,408.3 1 0
+auth/ent/mutation.go:409.2,409.26 1 0
+auth/ent/mutation.go:409.26,411.3 1 0
+auth/ent/mutation.go:412.2,412.25 1 0
+auth/ent/mutation.go:412.25,414.3 1 0
+auth/ent/mutation.go:415.2,415.25 1 0
+auth/ent/mutation.go:415.25,417.3 1 0
+auth/ent/mutation.go:418.2,418.15 1 0
+auth/ent/mutation.go:424.61,425.14 1 0
+auth/ent/mutation.go:426.22,427.18 1 0
+auth/ent/mutation.go:428.29,429.25 1 0
+auth/ent/mutation.go:430.27,431.23 1 0
+auth/ent/mutation.go:432.27,433.23 1 0
+auth/ent/mutation.go:435.2,435.19 1 0
+auth/ent/mutation.go:441.86,442.14 1 0
+auth/ent/mutation.go:443.22,444.24 1 0
+auth/ent/mutation.go:445.29,446.31 1 0
+auth/ent/mutation.go:447.27,448.29 1 0
+auth/ent/mutation.go:449.27,450.29 1 0
+auth/ent/mutation.go:452.2,452.55 1 0
+auth/ent/mutation.go:458.69,459.14 1 0
+auth/ent/mutation.go:460.22,462.10 2 0
+auth/ent/mutation.go:462.10,464.4 1 0
+auth/ent/mutation.go:465.3,466.13 2 0
+auth/ent/mutation.go:467.29,469.10 2 0
+auth/ent/mutation.go:469.10,471.4 1 0
+auth/ent/mutation.go:472.3,473.13 2 0
+auth/ent/mutation.go:474.27,476.10 2 0
+auth/ent/mutation.go:476.10,478.4 1 0
+auth/ent/mutation.go:479.3,480.13 2 0
+auth/ent/mutation.go:481.27,483.10 2 0
+auth/ent/mutation.go:483.10,485.4 1 0
+auth/ent/mutation.go:486.3,487.13 2 0
+auth/ent/mutation.go:489.2,489.50 1 0
+auth/ent/mutation.go:494.47,496.2 1 0
+auth/ent/mutation.go:501.66,503.2 1 0
+auth/ent/mutation.go:508.69,509.14 1 0
+auth/ent/mutation.go:511.2,511.58 1 0
+auth/ent/mutation.go:516.49,518.2 1 0
+auth/ent/mutation.go:522.55,525.2 2 0
+auth/ent/mutation.go:529.54,531.2 1 0
+auth/ent/mutation.go:535.54,536.14 1 0
+auth/ent/mutation.go:537.22,539.13 2 0
+auth/ent/mutation.go:540.29,542.13 2 0
+auth/ent/mutation.go:543.27,545.13 2 0
+auth/ent/mutation.go:546.27,548.13 2 0
+auth/ent/mutation.go:550.2,550.50 1 0
+auth/ent/mutation.go:554.46,556.20 2 0
+auth/ent/mutation.go:556.20,558.3 1 0
+auth/ent/mutation.go:559.2,559.14 1 0
+auth/ent/mutation.go:564.58,565.14 1 0
+auth/ent/mutation.go:566.22,568.27 2 0
+auth/ent/mutation.go:568.27,570.4 1 0
+auth/ent/mutation.go:571.3,571.13 1 0
+auth/ent/mutation.go:573.2,573.12 1 0
+auth/ent/mutation.go:577.48,579.27 2 0
+auth/ent/mutation.go:579.27,581.3 1 0
+auth/ent/mutation.go:582.2,582.14 1 0
+auth/ent/mutation.go:587.60,588.14 1 0
+auth/ent/mutation.go:589.22,591.34 2 0
+auth/ent/mutation.go:591.34,593.4 1 0
+auth/ent/mutation.go:594.3,594.13 1 0
+auth/ent/mutation.go:596.2,596.12 1 0
+auth/ent/mutation.go:600.48,602.20 2 0
+auth/ent/mutation.go:602.20,604.3 1 0
+auth/ent/mutation.go:605.2,605.14 1 0
+auth/ent/mutation.go:610.54,611.14 1 0
+auth/ent/mutation.go:612.22,613.24 1 0
+auth/ent/mutation.go:615.2,615.14 1 0
+auth/ent/mutation.go:620.53,621.14 1 0
+auth/ent/mutation.go:623.2,623.56 1 0
+auth/ent/mutation.go:628.53,629.14 1 0
+auth/ent/mutation.go:630.22,632.13 2 0
+auth/ent/mutation.go:634.2,634.49 1 0
+auth/ent/mutation.go:663.76,670.27 2 19
+auth/ent/mutation.go:670.27,672.3 1 1
+auth/ent/mutation.go:673.2,673.10 1 19
+auth/ent/mutation.go:677.41,678.32 1 0
+auth/ent/mutation.go:678.32,684.58 2 0
+auth/ent/mutation.go:684.58,685.19 1 0
+auth/ent/mutation.go:685.19,686.15 1 0
+auth/ent/mutation.go:686.15,688.6 1 0
+auth/ent/mutation.go:688.11,690.6 1 0
+auth/ent/mutation.go:692.4,692.21 1 0
+auth/ent/mutation.go:694.3,694.13 1 0
+auth/ent/mutation.go:699.41,700.32 1 1
+auth/ent/mutation.go:700.32,701.54 1 1
+auth/ent/mutation.go:701.54,703.4 1 0
+auth/ent/mutation.go:704.3,704.18 1 1
+auth/ent/mutation.go:710.41,714.2 3 0
+auth/ent/mutation.go:718.42,719.40 1 0
+auth/ent/mutation.go:719.40,721.3 1 0
+auth/ent/mutation.go:722.2,724.16 3 0
+auth/ent/mutation.go:729.42,731.2 1 13
+auth/ent/mutation.go:735.55,736.17 1 27
+auth/ent/mutation.go:736.17,738.3 1 13
+auth/ent/mutation.go:739.2,739.20 1 14
+auth/ent/mutation.go:746.68,747.9 1 0
+auth/ent/mutation.go:748.42,750.13 2 0
+auth/ent/mutation.go:750.13,752.4 1 0
+auth/ent/mutation.go:753.3,753.14 1 0
+auth/ent/mutation.go:754.36,755.66 1 0
+auth/ent/mutation.go:756.10,757.70 1 0
+auth/ent/mutation.go:762.44,764.2 1 13
+auth/ent/mutation.go:767.57,769.14 2 31
+auth/ent/mutation.go:769.14,771.3 1 5
+auth/ent/mutation.go:772.2,772.17 1 26
+auth/ent/mutation.go:778.77,779.27 1 0
+auth/ent/mutation.go:779.27,781.3 1 0
+auth/ent/mutation.go:782.2,782.38 1 0
+auth/ent/mutation.go:782.38,784.3 1 0
+auth/ent/mutation.go:785.2,786.16 2 0
+auth/ent/mutation.go:786.16,788.3 1 0
+auth/ent/mutation.go:789.2,789.28 1 0
+auth/ent/mutation.go:793.38,795.2 1 0
+auth/ent/mutation.go:798.47,800.2 1 13
+auth/ent/mutation.go:803.63,805.14 2 49
+auth/ent/mutation.go:805.14,807.3 1 10
+auth/ent/mutation.go:808.2,808.17 1 39
+auth/ent/mutation.go:814.80,815.27 1 0
+auth/ent/mutation.go:815.27,817.3 1 0
+auth/ent/mutation.go:818.2,818.38 1 0
+auth/ent/mutation.go:818.38,820.3 1 0
+auth/ent/mutation.go:821.2,822.16 2 0
+auth/ent/mutation.go:822.16,824.3 1 0
+auth/ent/mutation.go:825.2,825.27 1 0
+auth/ent/mutation.go:829.37,831.2 1 0
+auth/ent/mutation.go:834.51,836.2 1 13
+auth/ent/mutation.go:839.64,841.14 2 31
+auth/ent/mutation.go:841.14,843.3 1 5
+auth/ent/mutation.go:844.2,844.17 1 26
+auth/ent/mutation.go:850.84,851.27 1 0
+auth/ent/mutation.go:851.27,853.3 1 0
+auth/ent/mutation.go:854.2,854.38 1 0
+auth/ent/mutation.go:854.38,856.3 1 0
+auth/ent/mutation.go:857.2,858.16 2 0
+auth/ent/mutation.go:858.16,860.3 1 0
+auth/ent/mutation.go:861.2,861.32 1 0
+auth/ent/mutation.go:865.42,867.2 1 0
+auth/ent/mutation.go:870.44,872.2 1 18
+auth/ent/mutation.go:875.57,877.14 2 44
+auth/ent/mutation.go:877.14,879.3 1 13
+auth/ent/mutation.go:880.2,880.17 1 31
+auth/ent/mutation.go:886.77,887.27 1 0
+auth/ent/mutation.go:887.27,889.3 1 0
+auth/ent/mutation.go:890.2,890.38 1 0
+auth/ent/mutation.go:890.38,892.3 1 0
+auth/ent/mutation.go:893.2,894.16 2 0
+auth/ent/mutation.go:894.16,896.3 1 0
+auth/ent/mutation.go:897.2,897.30 1 0
+auth/ent/mutation.go:901.40,903.2 1 0
+auth/ent/mutation.go:906.51,908.2 1 13
+auth/ent/mutation.go:911.64,913.14 2 44
+auth/ent/mutation.go:913.14,915.3 1 18
+auth/ent/mutation.go:916.2,916.17 1 26
+auth/ent/mutation.go:922.84,923.27 1 0
+auth/ent/mutation.go:923.27,925.3 1 0
+auth/ent/mutation.go:926.2,926.38 1 0
+auth/ent/mutation.go:926.38,928.3 1 0
+auth/ent/mutation.go:929.2,930.16 2 0
+auth/ent/mutation.go:930.16,932.3 1 0
+auth/ent/mutation.go:933.2,933.32 1 0
+auth/ent/mutation.go:937.42,939.2 1 0
+auth/ent/mutation.go:942.51,944.2 1 18
+auth/ent/mutation.go:947.64,949.14 2 49
+auth/ent/mutation.go:949.14,951.3 1 18
+auth/ent/mutation.go:952.2,952.17 1 31
+auth/ent/mutation.go:958.84,959.27 1 0
+auth/ent/mutation.go:959.27,961.3 1 0
+auth/ent/mutation.go:962.2,962.38 1 0
+auth/ent/mutation.go:962.38,964.3 1 0
+auth/ent/mutation.go:965.2,966.16 2 0
+auth/ent/mutation.go:966.16,968.3 1 0
+auth/ent/mutation.go:969.2,969.32 1 0
+auth/ent/mutation.go:973.42,975.2 1 0
+auth/ent/mutation.go:978.46,980.2 1 13
+auth/ent/mutation.go:983.37,985.2 1 0
+auth/ent/mutation.go:988.44,990.2 1 10
+auth/ent/mutation.go:993.59,994.19 1 18
+auth/ent/mutation.go:994.19,996.3 1 13
+auth/ent/mutation.go:997.2,997.8 1 5
+auth/ent/mutation.go:1003.50,1004.29 1 18
+auth/ent/mutation.go:1004.29,1006.3 1 13
+auth/ent/mutation.go:1007.2,1007.8 1 18
+auth/ent/mutation.go:1011.37,1014.2 2 0
+auth/ent/mutation.go:1017.54,1019.2 1 5
+auth/ent/mutation.go:1023.59,1025.20 2 0
+auth/ent/mutation.go:1025.20,1027.3 1 0
+auth/ent/mutation.go:1028.2,1028.15 1 0
+auth/ent/mutation.go:1032.33,1034.2 1 0
+auth/ent/mutation.go:1037.38,1039.2 1 0
+auth/ent/mutation.go:1042.39,1044.2 1 0
+auth/ent/mutation.go:1049.43,1051.20 2 0
+auth/ent/mutation.go:1051.20,1053.3 1 0
+auth/ent/mutation.go:1054.2,1054.20 1 0
+auth/ent/mutation.go:1054.20,1056.3 1 0
+auth/ent/mutation.go:1057.2,1057.25 1 0
+auth/ent/mutation.go:1057.25,1059.3 1 0
+auth/ent/mutation.go:1060.2,1060.22 1 0
+auth/ent/mutation.go:1060.22,1062.3 1 0
+auth/ent/mutation.go:1063.2,1063.25 1 0
+auth/ent/mutation.go:1063.25,1065.3 1 0
+auth/ent/mutation.go:1066.2,1066.25 1 0
+auth/ent/mutation.go:1066.25,1068.3 1 0
+auth/ent/mutation.go:1069.2,1069.15 1 0
+auth/ent/mutation.go:1075.62,1076.14 1 0
+auth/ent/mutation.go:1077.24,1078.19 1 0
+auth/ent/mutation.go:1079.23,1080.21 1 0
+auth/ent/mutation.go:1081.28,1082.23 1 0
+auth/ent/mutation.go:1083.26,1084.21 1 0
+auth/ent/mutation.go:1085.28,1086.23 1 0
+auth/ent/mutation.go:1087.28,1088.23 1 0
+auth/ent/mutation.go:1090.2,1090.19 1 0
+auth/ent/mutation.go:1096.87,1097.14 1 0
+auth/ent/mutation.go:1098.24,1099.25 1 0
+auth/ent/mutation.go:1100.23,1101.24 1 0
+auth/ent/mutation.go:1102.28,1103.29 1 0
+auth/ent/mutation.go:1104.26,1105.27 1 0
+auth/ent/mutation.go:1106.28,1107.29 1 0
+auth/ent/mutation.go:1108.28,1109.29 1 0
+auth/ent/mutation.go:1111.2,1111.56 1 0
+auth/ent/mutation.go:1117.70,1118.14 1 0
+auth/ent/mutation.go:1119.24,1121.10 2 0
+auth/ent/mutation.go:1121.10,1123.4 1 0
+auth/ent/mutation.go:1124.3,1125.13 2 0
+auth/ent/mutation.go:1126.23,1128.10 2 0
+auth/ent/mutation.go:1128.10,1130.4 1 0
+auth/ent/mutation.go:1131.3,1132.13 2 0
+auth/ent/mutation.go:1133.28,1135.10 2 0
+auth/ent/mutation.go:1135.10,1137.4 1 0
+auth/ent/mutation.go:1138.3,1139.13 2 0
+auth/ent/mutation.go:1140.26,1142.10 2 0
+auth/ent/mutation.go:1142.10,1144.4 1 0
+auth/ent/mutation.go:1145.3,1146.13 2 0
+auth/ent/mutation.go:1147.28,1149.10 2 0
+auth/ent/mutation.go:1149.10,1151.4 1 0
+auth/ent/mutation.go:1152.3,1153.13 2 0
+auth/ent/mutation.go:1154.28,1156.10 2 0
+auth/ent/mutation.go:1156.10,1158.4 1 0
+auth/ent/mutation.go:1159.3,1160.13 2 0
+auth/ent/mutation.go:1162.2,1162.51 1 0
+auth/ent/mutation.go:1167.48,1169.2 1 0
+auth/ent/mutation.go:1174.67,1176.2 1 0
+auth/ent/mutation.go:1181.70,1182.14 1 0
+auth/ent/mutation.go:1184.2,1184.59 1 0
+auth/ent/mutation.go:1189.50,1191.2 1 0
+auth/ent/mutation.go:1195.56,1198.2 2 0
+auth/ent/mutation.go:1202.55,1204.2 1 0
+auth/ent/mutation.go:1208.55,1209.14 1 0
+auth/ent/mutation.go:1210.24,1212.13 2 0
+auth/ent/mutation.go:1213.23,1215.13 2 0
+auth/ent/mutation.go:1216.28,1218.13 2 0
+auth/ent/mutation.go:1219.26,1221.13 2 0
+auth/ent/mutation.go:1222.28,1224.13 2 0
+auth/ent/mutation.go:1225.28,1227.13 2 0
+auth/ent/mutation.go:1229.2,1229.51 1 0
+auth/ent/mutation.go:1233.47,1235.19 2 0
+auth/ent/mutation.go:1235.19,1237.3 1 0
+auth/ent/mutation.go:1238.2,1238.14 1 0
+auth/ent/mutation.go:1243.59,1244.14 1 0
+auth/ent/mutation.go:1245.22,1246.30 1 0
+auth/ent/mutation.go:1246.30,1248.4 1 0
+auth/ent/mutation.go:1250.2,1250.12 1 0
+auth/ent/mutation.go:1254.49,1257.2 2 0
+auth/ent/mutation.go:1261.61,1263.2 1 0
+auth/ent/mutation.go:1266.49,1268.19 2 0
+auth/ent/mutation.go:1268.19,1270.3 1 0
+auth/ent/mutation.go:1271.2,1271.14 1 0
+auth/ent/mutation.go:1276.55,1277.14 1 0
+auth/ent/mutation.go:1278.22,1279.23 1 0
+auth/ent/mutation.go:1281.2,1281.14 1 0
+auth/ent/mutation.go:1286.54,1287.14 1 0
+auth/ent/mutation.go:1288.22,1290.13 2 0
+auth/ent/mutation.go:1292.2,1292.57 1 0
+auth/ent/mutation.go:1297.54,1298.14 1 0
+auth/ent/mutation.go:1299.22,1301.13 2 0
+auth/ent/mutation.go:1303.2,1303.50 1 0
+auth/ent/mutation.go:1335.73,1342.27 2 60
+auth/ent/mutation.go:1342.27,1344.3 1 13
+auth/ent/mutation.go:1345.2,1345.10 1 60
+auth/ent/mutation.go:1349.39,1350.31 1 10
+auth/ent/mutation.go:1350.31,1356.57 2 10
+auth/ent/mutation.go:1356.57,1357.19 1 0
+auth/ent/mutation.go:1357.19,1358.15 1 0
+auth/ent/mutation.go:1358.15,1360.6 1 0
+auth/ent/mutation.go:1360.11,1362.6 1 0
+auth/ent/mutation.go:1364.4,1364.21 1 0
+auth/ent/mutation.go:1366.3,1366.13 1 10
+auth/ent/mutation.go:1371.38,1372.31 1 3
+auth/ent/mutation.go:1372.31,1373.53 1 3
+auth/ent/mutation.go:1373.53,1375.4 1 0
+auth/ent/mutation.go:1376.3,1376.18 1 3
+auth/ent/mutation.go:1382.40,1386.2 3 0
+auth/ent/mutation.go:1390.41,1391.40 1 0
+auth/ent/mutation.go:1391.40,1393.3 1 0
+auth/ent/mutation.go:1394.2,1396.16 3 0
+auth/ent/mutation.go:1401.41,1403.2 1 44
+auth/ent/mutation.go:1407.54,1408.17 1 101
+auth/ent/mutation.go:1408.17,1410.3 1 38
+auth/ent/mutation.go:1411.2,1411.20 1 63
+auth/ent/mutation.go:1418.67,1419.9 1 0
+auth/ent/mutation.go:1420.42,1422.13 2 0
+auth/ent/mutation.go:1422.13,1424.4 1 0
+auth/ent/mutation.go:1425.3,1425.14 1 0
+auth/ent/mutation.go:1426.36,1427.65 1 0
+auth/ent/mutation.go:1428.10,1429.70 1 0
+auth/ent/mutation.go:1434.46,1436.2 1 45
+auth/ent/mutation.go:1439.59,1441.14 2 101
+auth/ent/mutation.go:1441.14,1443.3 1 12
+auth/ent/mutation.go:1444.2,1444.17 1 89
+auth/ent/mutation.go:1450.79,1451.27 1 0
+auth/ent/mutation.go:1451.27,1453.3 1 0
+auth/ent/mutation.go:1454.2,1454.38 1 0
+auth/ent/mutation.go:1454.38,1456.3 1 0
+auth/ent/mutation.go:1457.2,1458.16 2 0
+auth/ent/mutation.go:1458.16,1460.3 1 0
+auth/ent/mutation.go:1461.2,1461.31 1 0
+auth/ent/mutation.go:1465.40,1467.2 1 0
+auth/ent/mutation.go:1470.43,1472.2 1 45
+auth/ent/mutation.go:1475.56,1477.14 2 101
+auth/ent/mutation.go:1477.14,1479.3 1 12
+auth/ent/mutation.go:1480.2,1480.17 1 89
+auth/ent/mutation.go:1486.76,1487.27 1 0
+auth/ent/mutation.go:1487.27,1489.3 1 0
+auth/ent/mutation.go:1490.2,1490.38 1 0
+auth/ent/mutation.go:1490.38,1492.3 1 0
+auth/ent/mutation.go:1493.2,1494.16 2 0
+auth/ent/mutation.go:1494.16,1496.3 1 0
+auth/ent/mutation.go:1497.2,1497.28 1 0
+auth/ent/mutation.go:1501.37,1503.2 1 0
+auth/ent/mutation.go:1506.46,1508.2 1 94
+auth/ent/mutation.go:1511.59,1513.14 2 161
+auth/ent/mutation.go:1513.14,1515.3 1 23
+auth/ent/mutation.go:1516.2,1516.17 1 138
+auth/ent/mutation.go:1522.79,1523.27 1 0
+auth/ent/mutation.go:1523.27,1525.3 1 0
+auth/ent/mutation.go:1526.2,1526.38 1 0
+auth/ent/mutation.go:1526.38,1528.3 1 0
+auth/ent/mutation.go:1529.2,1530.16 2 0
+auth/ent/mutation.go:1530.16,1532.3 1 0
+auth/ent/mutation.go:1533.2,1533.31 1 0
+auth/ent/mutation.go:1537.40,1539.2 1 0
+auth/ent/mutation.go:1542.50,1544.2 1 44
+auth/ent/mutation.go:1547.63,1549.14 2 145
+auth/ent/mutation.go:1549.14,1551.3 1 57
+auth/ent/mutation.go:1552.2,1552.17 1 88
+auth/ent/mutation.go:1558.83,1559.27 1 0
+auth/ent/mutation.go:1559.27,1561.3 1 0
+auth/ent/mutation.go:1562.2,1562.38 1 0
+auth/ent/mutation.go:1562.38,1564.3 1 0
+auth/ent/mutation.go:1565.2,1566.16 2 0
+auth/ent/mutation.go:1566.16,1568.3 1 0
+auth/ent/mutation.go:1569.2,1569.32 1 0
+auth/ent/mutation.go:1573.41,1575.2 1 0
+auth/ent/mutation.go:1578.50,1580.2 1 57
+auth/ent/mutation.go:1583.63,1585.14 2 158
+auth/ent/mutation.go:1585.14,1587.3 1 55
+auth/ent/mutation.go:1588.2,1588.17 1 103
+auth/ent/mutation.go:1594.83,1595.27 1 0
+auth/ent/mutation.go:1595.27,1597.3 1 0
+auth/ent/mutation.go:1598.2,1598.38 1 0
+auth/ent/mutation.go:1598.38,1600.3 1 0
+auth/ent/mutation.go:1601.2,1602.16 2 0
+auth/ent/mutation.go:1602.16,1604.3 1 0
+auth/ent/mutation.go:1605.2,1605.32 1 0
+auth/ent/mutation.go:1609.41,1611.2 1 0
+auth/ent/mutation.go:1614.50,1615.20 1 8
+auth/ent/mutation.go:1615.20,1617.3 1 8
+auth/ent/mutation.go:1618.2,1618.21 1 8
+auth/ent/mutation.go:1618.21,1620.3 1 8
+auth/ent/mutation.go:1624.37,1626.2 1 0
+auth/ent/mutation.go:1629.44,1631.2 1 15
+auth/ent/mutation.go:1634.53,1635.27 1 2
+auth/ent/mutation.go:1635.27,1637.3 1 2
+auth/ent/mutation.go:1638.2,1638.21 1 2
+auth/ent/mutation.go:1638.21,1641.3 2 2
+auth/ent/mutation.go:1645.57,1646.33 1 13
+auth/ent/mutation.go:1646.33,1648.3 1 2
+auth/ent/mutation.go:1649.2,1649.8 1 13
+auth/ent/mutation.go:1653.50,1654.26 1 57
+auth/ent/mutation.go:1654.26,1656.3 1 8
+auth/ent/mutation.go:1657.2,1657.8 1 57
+auth/ent/mutation.go:1661.37,1665.2 3 0
+auth/ent/mutation.go:1668.51,1669.21 1 0
+auth/ent/mutation.go:1669.21,1671.3 1 0
+auth/ent/mutation.go:1672.2,1672.21 1 0
+auth/ent/mutation.go:1672.21,1674.3 1 0
+auth/ent/mutation.go:1678.38,1680.2 1 0
+auth/ent/mutation.go:1683.45,1685.2 1 13
+auth/ent/mutation.go:1688.54,1689.28 1 0
+auth/ent/mutation.go:1689.28,1691.3 1 0
+auth/ent/mutation.go:1692.2,1692.21 1 0
+auth/ent/mutation.go:1692.21,1695.3 2 0
+auth/ent/mutation.go:1699.58,1700.34 1 13
+auth/ent/mutation.go:1700.34,1702.3 1 0
+auth/ent/mutation.go:1703.2,1703.8 1 13
+auth/ent/mutation.go:1707.51,1708.27 1 57
+auth/ent/mutation.go:1708.27,1710.3 1 0
+auth/ent/mutation.go:1711.2,1711.8 1 57
+auth/ent/mutation.go:1715.38,1719.2 3 0
+auth/ent/mutation.go:1722.52,1724.2 1 2
+auth/ent/mutation.go:1728.58,1730.20 2 0
+auth/ent/mutation.go:1730.20,1732.3 1 0
+auth/ent/mutation.go:1733.2,1733.15 1 0
+auth/ent/mutation.go:1737.32,1739.2 1 0
+auth/ent/mutation.go:1742.37,1744.2 1 0
+auth/ent/mutation.go:1747.38,1749.2 1 0
+auth/ent/mutation.go:1754.42,1756.23 2 0
+auth/ent/mutation.go:1756.23,1758.3 1 0
+auth/ent/mutation.go:1759.2,1759.20 1 0
+auth/ent/mutation.go:1759.20,1761.3 1 0
+auth/ent/mutation.go:1762.2,1762.23 1 0
+auth/ent/mutation.go:1762.23,1764.3 1 0
+auth/ent/mutation.go:1765.2,1765.25 1 0
+auth/ent/mutation.go:1765.25,1767.3 1 0
+auth/ent/mutation.go:1768.2,1768.25 1 0
+auth/ent/mutation.go:1768.25,1770.3 1 0
+auth/ent/mutation.go:1771.2,1771.15 1 0
+auth/ent/mutation.go:1777.61,1778.14 1 60
+auth/ent/mutation.go:1779.26,1780.22 1 0
+auth/ent/mutation.go:1781.23,1782.19 1 0
+auth/ent/mutation.go:1783.26,1784.22 1 60
+auth/ent/mutation.go:1785.27,1786.23 1 0
+auth/ent/mutation.go:1787.27,1788.23 1 0
+auth/ent/mutation.go:1790.2,1790.19 1 0
+auth/ent/mutation.go:1796.86,1797.14 1 0
+auth/ent/mutation.go:1798.26,1799.28 1 0
+auth/ent/mutation.go:1800.23,1801.25 1 0
+auth/ent/mutation.go:1802.26,1803.28 1 0
+auth/ent/mutation.go:1804.27,1805.29 1 0
+auth/ent/mutation.go:1806.27,1807.29 1 0
+auth/ent/mutation.go:1809.2,1809.55 1 0
+auth/ent/mutation.go:1815.69,1816.14 1 47
+auth/ent/mutation.go:1817.26,1819.10 2 0
+auth/ent/mutation.go:1819.10,1821.4 1 0
+auth/ent/mutation.go:1822.3,1823.13 2 0
+auth/ent/mutation.go:1824.23,1826.10 2 0
+auth/ent/mutation.go:1826.10,1828.4 1 0
+auth/ent/mutation.go:1829.3,1830.13 2 0
+auth/ent/mutation.go:1831.26,1833.10 2 47
+auth/ent/mutation.go:1833.10,1835.4 1 0
+auth/ent/mutation.go:1836.3,1837.13 2 47
+auth/ent/mutation.go:1838.27,1840.10 2 0
+auth/ent/mutation.go:1840.10,1842.4 1 0
+auth/ent/mutation.go:1843.3,1844.13 2 0
+auth/ent/mutation.go:1845.27,1847.10 2 0
+auth/ent/mutation.go:1847.10,1849.4 1 0
+auth/ent/mutation.go:1850.3,1851.13 2 0
+auth/ent/mutation.go:1853.2,1853.50 1 0
+auth/ent/mutation.go:1858.47,1860.2 1 0
+auth/ent/mutation.go:1865.66,1867.2 1 0
+auth/ent/mutation.go:1872.69,1873.14 1 0
+auth/ent/mutation.go:1875.2,1875.58 1 0
+auth/ent/mutation.go:1880.49,1882.2 1 0
+auth/ent/mutation.go:1886.55,1889.2 2 0
+auth/ent/mutation.go:1893.54,1895.2 1 0
+auth/ent/mutation.go:1899.54,1900.14 1 0
+auth/ent/mutation.go:1901.26,1903.13 2 0
+auth/ent/mutation.go:1904.23,1906.13 2 0
+auth/ent/mutation.go:1907.26,1909.13 2 0
+auth/ent/mutation.go:1910.27,1912.13 2 0
+auth/ent/mutation.go:1913.27,1915.13 2 0
+auth/ent/mutation.go:1917.2,1917.50 1 0
+auth/ent/mutation.go:1921.46,1923.20 2 0
+auth/ent/mutation.go:1923.20,1925.3 1 0
+auth/ent/mutation.go:1926.2,1926.21 1 0
+auth/ent/mutation.go:1926.21,1928.3 1 0
+auth/ent/mutation.go:1929.2,1929.14 1 0
+auth/ent/mutation.go:1934.58,1935.14 1 0
+auth/ent/mutation.go:1936.22,1938.27 2 0
+auth/ent/mutation.go:1938.27,1940.4 1 0
+auth/ent/mutation.go:1941.3,1941.13 1 0
+auth/ent/mutation.go:1942.23,1944.28 2 0
+auth/ent/mutation.go:1944.28,1946.4 1 0
+auth/ent/mutation.go:1947.3,1947.13 1 0
+auth/ent/mutation.go:1949.2,1949.12 1 0
+auth/ent/mutation.go:1953.48,1955.27 2 0
+auth/ent/mutation.go:1955.27,1957.3 1 0
+auth/ent/mutation.go:1958.2,1958.28 1 0
+auth/ent/mutation.go:1958.28,1960.3 1 0
+auth/ent/mutation.go:1961.2,1961.14 1 0
+auth/ent/mutation.go:1966.60,1967.14 1 0
+auth/ent/mutation.go:1968.22,1970.34 2 0
+auth/ent/mutation.go:1970.34,1972.4 1 0
+auth/ent/mutation.go:1973.3,1973.13 1 0
+auth/ent/mutation.go:1974.23,1976.35 2 0
+auth/ent/mutation.go:1976.35,1978.4 1 0
+auth/ent/mutation.go:1979.3,1979.13 1 0
+auth/ent/mutation.go:1981.2,1981.12 1 0
+auth/ent/mutation.go:1985.48,1987.20 2 0
+auth/ent/mutation.go:1987.20,1989.3 1 0
+auth/ent/mutation.go:1990.2,1990.21 1 0
+auth/ent/mutation.go:1990.21,1992.3 1 0
+auth/ent/mutation.go:1993.2,1993.14 1 0
+auth/ent/mutation.go:1998.54,1999.14 1 0
+auth/ent/mutation.go:2000.22,2001.24 1 0
+auth/ent/mutation.go:2002.23,2003.25 1 0
+auth/ent/mutation.go:2005.2,2005.14 1 0
+auth/ent/mutation.go:2010.53,2011.14 1 0
+auth/ent/mutation.go:2013.2,2013.56 1 0
+auth/ent/mutation.go:2018.53,2019.14 1 0
+auth/ent/mutation.go:2020.22,2022.13 2 0
+auth/ent/mutation.go:2023.23,2025.13 2 0
+auth/ent/mutation.go:2027.2,2027.49 1 0
+auth/ent/role.go:46.50,47.22 1 0
+auth/ent/role.go:47.22,49.3 1 0
+auth/ent/role.go:50.2,50.44 1 0
+auth/ent/role.go:54.58,56.25 2 21
+auth/ent/role.go:56.25,57.21 1 105
+auth/ent/role.go:58.30,59.27 1 21
+auth/ent/role.go:60.37,61.35 1 42
+auth/ent/role.go:62.49,63.33 1 42
+auth/ent/role.go:64.11,65.36 1 0
+auth/ent/role.go:68.2,68.20 1 21
+auth/ent/role.go:73.67,74.46 1 21
+auth/ent/role.go:74.46,76.3 1 0
+auth/ent/role.go:77.2,77.25 1 21
+auth/ent/role.go:77.25,78.21 1 105
+auth/ent/role.go:79.21,80.53 1 21
+auth/ent/role.go:80.53,82.5 1 0
+auth/ent/role.go:82.10,82.26 1 21
+auth/ent/role.go:82.26,84.5 1 21
+auth/ent/role.go:85.23,86.53 1 21
+auth/ent/role.go:86.53,88.5 1 0
+auth/ent/role.go:88.10,88.26 1 21
+auth/ent/role.go:88.26,90.5 1 21
+auth/ent/role.go:91.30,92.45 1 21
+auth/ent/role.go:92.45,94.5 1 0
+auth/ent/role.go:94.10,94.46 1 21
+auth/ent/role.go:94.46,95.66 1 21
+auth/ent/role.go:95.66,97.6 1 0
+auth/ent/role.go:99.28,100.51 1 21
+auth/ent/role.go:100.51,102.5 1 0
+auth/ent/role.go:102.10,102.26 1 21
+auth/ent/role.go:102.26,104.5 1 21
+auth/ent/role.go:105.28,106.51 1 21
+auth/ent/role.go:106.51,108.5 1 0
+auth/ent/role.go:108.10,108.26 1 21
+auth/ent/role.go:108.26,110.5 1 21
+auth/ent/role.go:111.11,112.45 1 0
+auth/ent/role.go:115.2,115.12 1 21
+auth/ent/role.go:120.54,122.2 1 0
+auth/ent/role.go:125.40,127.2 1 1
+auth/ent/role.go:132.40,134.2 1 0
+auth/ent/role.go:138.31,140.9 2 0
+auth/ent/role.go:140.9,141.51 1 0
+auth/ent/role.go:143.2,144.10 2 0
+auth/ent/role.go:148.32,165.2 16 0
+auth/ent/role_create.go:25.53,28.2 2 34
+auth/ent/role_create.go:31.62,34.2 2 34
+auth/ent/role_create.go:37.61,40.2 2 0
+auth/ent/role_create.go:43.70,44.14 1 0
+auth/ent/role_create.go:44.14,46.3 1 0
+auth/ent/role_create.go:47.2,47.11 1 0
+auth/ent/role_create.go:51.61,54.2 2 0
+auth/ent/role_create.go:57.70,58.14 1 0
+auth/ent/role_create.go:58.14,60.3 1 0
+auth/ent/role_create.go:61.2,61.11 1 0
+auth/ent/role_create.go:65.51,68.2 2 0
+auth/ent/role_create.go:71.60,72.14 1 0
+auth/ent/role_create.go:72.14,74.3 1 0
+auth/ent/role_create.go:75.2,75.11 1 0
+auth/ent/role_create.go:79.61,82.2 2 1
+auth/ent/role_create.go:85.56,87.19 2 1
+auth/ent/role_create.go:87.19,89.3 1 1
+auth/ent/role_create.go:90.2,90.30 1 1
+auth/ent/role_create.go:94.48,96.2 1 0
+auth/ent/role_create.go:99.64,102.2 2 34
+auth/ent/role_create.go:105.56,107.16 2 0
+auth/ent/role_create.go:107.16,108.13 1 0
+auth/ent/role_create.go:110.2,110.10 1 0
+auth/ent/role_create.go:114.55,117.2 2 0
+auth/ent/role_create.go:120.50,121.37 1 0
+auth/ent/role_create.go:121.37,122.13 1 0
+auth/ent/role_create.go:127.34,128.43 1 34
+auth/ent/role_create.go:128.43,131.3 2 34
+auth/ent/role_create.go:132.2,132.43 1 34
+auth/ent/role_create.go:132.43,135.3 2 34
+auth/ent/role_create.go:136.2,136.36 1 34
+auth/ent/role_create.go:136.36,139.3 2 34
+auth/ent/role_create.go:143.37,144.38 1 34
+auth/ent/role_create.go:144.38,146.3 1 0
+auth/ent/role_create.go:147.2,147.45 1 34
+auth/ent/role_create.go:147.45,149.3 1 0
+auth/ent/role_create.go:150.2,150.43 1 34
+auth/ent/role_create.go:150.43,152.3 1 0
+auth/ent/role_create.go:153.2,153.43 1 34
+auth/ent/role_create.go:153.43,155.3 1 0
+auth/ent/role_create.go:156.2,156.12 1 34
+auth/ent/role_create.go:159.67,160.35 1 34
+auth/ent/role_create.go:160.35,162.3 1 0
+auth/ent/role_create.go:163.2,164.67 2 34
+auth/ent/role_create.go:164.67,165.38 1 1
+auth/ent/role_create.go:165.38,167.4 1 1
+auth/ent/role_create.go:168.3,168.18 1 1
+auth/ent/role_create.go:170.2,170.27 1 33
+auth/ent/role_create.go:170.27,171.44 1 33
+auth/ent/role_create.go:171.44,173.4 1 33
+auth/ent/role_create.go:173.9,175.4 1 0
+auth/ent/role_create.go:177.2,179.19 3 33
+auth/ent/role_create.go:182.66,187.36 2 34
+auth/ent/role_create.go:187.36,190.3 2 34
+auth/ent/role_create.go:191.2,191.41 1 34
+auth/ent/role_create.go:191.41,194.3 2 34
+auth/ent/role_create.go:195.2,195.48 1 34
+auth/ent/role_create.go:195.48,198.3 2 34
+auth/ent/role_create.go:199.2,199.46 1 34
+auth/ent/role_create.go:199.46,202.3 2 34
+auth/ent/role_create.go:203.2,203.46 1 34
+auth/ent/role_create.go:203.46,206.3 2 34
+auth/ent/role_create.go:207.2,207.53 1 34
+auth/ent/role_create.go:207.53,218.27 2 1
+auth/ent/role_create.go:218.27,220.4 1 1
+auth/ent/role_create.go:221.3,221.42 1 1
+auth/ent/role_create.go:223.2,223.21 1 34
+auth/ent/role_create.go:234.71,235.20 1 0
+auth/ent/role_create.go:235.20,237.3 1 0
+auth/ent/role_create.go:238.2,241.30 4 0
+auth/ent/role_create.go:241.30,242.37 1 0
+auth/ent/role_create.go:242.37,245.86 3 0
+auth/ent/role_create.go:245.86,247.12 2 0
+auth/ent/role_create.go:247.12,249.6 1 0
+auth/ent/role_create.go:250.5,250.43 1 0
+auth/ent/role_create.go:250.43,252.6 1 0
+auth/ent/role_create.go:253.5,256.28 4 0
+auth/ent/role_create.go:256.28,258.6 1 0
+auth/ent/role_create.go:258.11,261.71 2 0
+auth/ent/role_create.go:261.71,262.42 1 0
+auth/ent/role_create.go:262.42,264.8 1 0
+auth/ent/role_create.go:267.5,267.19 1 0
+auth/ent/role_create.go:267.19,269.6 1 0
+auth/ent/role_create.go:270.5,272.25 3 0
+auth/ent/role_create.go:274.4,274.49 1 0
+auth/ent/role_create.go:274.49,276.5 1 0
+auth/ent/role_create.go:277.4,277.21 1 0
+auth/ent/role_create.go:280.2,280.23 1 0
+auth/ent/role_create.go:280.23,281.78 1 0
+auth/ent/role_create.go:281.78,283.4 1 0
+auth/ent/role_create.go:285.2,285.19 1 0
+auth/ent/role_create.go:289.63,291.16 2 0
+auth/ent/role_create.go:291.16,292.13 1 0
+auth/ent/role_create.go:294.2,294.10 1 0
+auth/ent/role_create.go:298.60,301.2 2 0
+auth/ent/role_create.go:304.55,305.38 1 0
+auth/ent/role_create.go:305.38,306.13 1 0
+auth/ent/role_delete.go:23.63,26.2 2 1
+auth/ent/role_delete.go:29.62,31.2 1 3
+auth/ent/role_delete.go:34.54,36.16 2 0
+auth/ent/role_delete.go:36.16,37.13 1 0
+auth/ent/role_delete.go:39.2,39.10 1 0
+auth/ent/role_delete.go:42.65,44.47 2 3
+auth/ent/role_delete.go:44.47,45.50 1 1
+auth/ent/role_delete.go:45.50,46.22 1 1
+auth/ent/role_delete.go:46.22,48.5 1 1
+auth/ent/role_delete.go:51.2,52.51 2 3
+auth/ent/role_delete.go:52.51,54.3 1 0
+auth/ent/role_delete.go:55.2,56.22 2 3
+auth/ent/role_delete.go:65.70,68.2 2 0
+auth/ent/role_delete.go:71.59,73.9 2 1
+auth/ent/role_delete.go:74.18,75.13 1 0
+auth/ent/role_delete.go:76.14,77.36 1 0
+auth/ent/role_delete.go:78.10,79.13 1 1
+auth/ent/role_delete.go:84.54,85.38 1 0
+auth/ent/role_delete.go:85.38,86.13 1 0
+auth/ent/role_query.go:33.61,36.2 2 14
+auth/ent/role_query.go:39.50,42.2 2 8
+auth/ent/role_query.go:45.52,48.2 2 1
+auth/ent/role_query.go:52.53,55.2 2 0
+auth/ent/role_query.go:58.62,61.2 2 0
+auth/ent/role_query.go:64.46,66.74 2 0
+auth/ent/role_query.go:66.74,67.46 1 0
+auth/ent/role_query.go:67.46,69.4 1 0
+auth/ent/role_query.go:70.3,71.40 2 0
+auth/ent/role_query.go:71.40,73.4 1 0
+auth/ent/role_query.go:74.3,80.20 3 0
+auth/ent/role_query.go:82.2,82.14 1 0
+auth/ent/role_query.go:87.64,89.16 2 0
+auth/ent/role_query.go:89.16,91.3 1 0
+auth/ent/role_query.go:92.2,92.21 1 0
+auth/ent/role_query.go:92.21,94.3 1 0
+auth/ent/role_query.go:95.2,95.22 1 0
+auth/ent/role_query.go:99.56,101.36 2 0
+auth/ent/role_query.go:101.36,102.13 1 0
+auth/ent/role_query.go:104.2,104.13 1 0
+auth/ent/role_query.go:109.74,111.82 2 0
+auth/ent/role_query.go:111.82,113.3 1 0
+auth/ent/role_query.go:114.2,114.19 1 0
+auth/ent/role_query.go:114.19,117.3 2 0
+auth/ent/role_query.go:118.2,118.20 1 0
+auth/ent/role_query.go:122.59,124.36 2 0
+auth/ent/role_query.go:124.36,125.13 1 0
+auth/ent/role_query.go:127.2,127.11 1 0
+auth/ent/role_query.go:133.63,135.16 2 7
+auth/ent/role_query.go:135.16,137.3 1 0
+auth/ent/role_query.go:138.2,138.20 1 7
+auth/ent/role_query.go:139.9,140.23 1 6
+auth/ent/role_query.go:141.9,142.41 1 1
+auth/ent/role_query.go:143.10,144.44 1 0
+auth/ent/role_query.go:149.55,151.16 2 0
+auth/ent/role_query.go:151.16,152.13 1 0
+auth/ent/role_query.go:154.2,154.13 1 0
+auth/ent/role_query.go:160.73,162.81 2 0
+auth/ent/role_query.go:162.81,164.3 1 0
+auth/ent/role_query.go:165.2,165.18 1 0
+auth/ent/role_query.go:166.9,167.14 1 0
+auth/ent/role_query.go:168.9,169.35 1 0
+auth/ent/role_query.go:170.10,171.38 1 0
+auth/ent/role_query.go:173.2,173.8 1 0
+auth/ent/role_query.go:177.58,179.16 2 0
+auth/ent/role_query.go:179.16,180.13 1 0
+auth/ent/role_query.go:182.2,182.11 1 0
+auth/ent/role_query.go:186.64,188.45 2 13
+auth/ent/role_query.go:188.45,190.3 1 0
+auth/ent/role_query.go:191.2,192.58 2 13
+auth/ent/role_query.go:196.56,198.16 2 0
+auth/ent/role_query.go:198.16,199.13 1 0
+auth/ent/role_query.go:201.2,201.14 1 0
+auth/ent/role_query.go:205.73,206.44 1 0
+auth/ent/role_query.go:206.44,208.3 1 0
+auth/ent/role_query.go:209.2,210.63 2 0
+auth/ent/role_query.go:210.63,212.3 1 0
+auth/ent/role_query.go:213.2,213.17 1 0
+auth/ent/role_query.go:217.57,219.16 2 0
+auth/ent/role_query.go:219.16,220.13 1 0
+auth/ent/role_query.go:222.2,222.12 1 0
+auth/ent/role_query.go:226.62,228.45 2 2
+auth/ent/role_query.go:228.45,230.3 1 0
+auth/ent/role_query.go:231.2,231.78 1 2
+auth/ent/role_query.go:235.54,237.16 2 0
+auth/ent/role_query.go:237.16,238.13 1 0
+auth/ent/role_query.go:240.2,240.14 1 0
+auth/ent/role_query.go:244.63,246.36 2 0
+auth/ent/role_query.go:247.23,248.20 1 0
+auth/ent/role_query.go:249.18,250.60 1 0
+auth/ent/role_query.go:251.10,252.19 1 0
+auth/ent/role_query.go:257.55,259.16 2 0
+auth/ent/role_query.go:259.16,260.13 1 0
+auth/ent/role_query.go:262.2,262.14 1 0
+auth/ent/role_query.go:267.41,268.15 1 0
+auth/ent/role_query.go:268.15,270.3 1 0
+auth/ent/role_query.go:271.2,281.3 1 0
+auth/ent/role_query.go:286.69,288.27 2 1
+auth/ent/role_query.go:288.27,290.3 1 0
+auth/ent/role_query.go:291.2,292.11 2 1
+auth/ent/role_query.go:309.75,316.2 6 0
+auth/ent/role_query.go:330.59,336.2 5 0
+auth/ent/role_query.go:339.66,341.2 1 0
+auth/ent/role_query.go:343.62,344.34 1 18
+auth/ent/role_query.go:344.34,345.19 1 0
+auth/ent/role_query.go:345.19,347.4 1 0
+auth/ent/role_query.go:348.3,348.39 1 0
+auth/ent/role_query.go:348.39,349.48 1 0
+auth/ent/role_query.go:349.48,351.5 1 0
+auth/ent/role_query.go:354.2,354.34 1 18
+auth/ent/role_query.go:354.34,355.27 1 0
+auth/ent/role_query.go:355.27,357.4 1 0
+auth/ent/role_query.go:359.2,359.20 1 18
+auth/ent/role_query.go:359.20,361.17 2 1
+auth/ent/role_query.go:361.17,363.4 1 0
+auth/ent/role_query.go:364.3,364.16 1 1
+auth/ent/role_query.go:366.2,366.12 1 18
+auth/ent/role_query.go:369.87,377.59 2 16
+auth/ent/role_query.go:377.59,379.3 1 17
+auth/ent/role_query.go:380.2,380.60 1 16
+auth/ent/role_query.go:380.60,385.3 4 17
+auth/ent/role_query.go:386.2,386.23 1 16
+auth/ent/role_query.go:386.23,388.3 1 3
+auth/ent/role_query.go:389.2,389.67 1 16
+auth/ent/role_query.go:389.67,391.3 1 0
+auth/ent/role_query.go:392.2,392.21 1 16
+auth/ent/role_query.go:392.21,394.3 1 3
+auth/ent/role_query.go:395.2,395.41 1 13
+auth/ent/role_query.go:395.41,397.18 1 1
+auth/ent/role_query.go:397.18,397.47 1 1
+auth/ent/role_query.go:398.27,398.71 1 1
+auth/ent/role_query.go:398.85,400.4 1 0
+auth/ent/role_query.go:402.2,402.19 1 13
+auth/ent/role_query.go:405.137,409.29 4 1
+auth/ent/role_query.go:409.29,412.18 3 1
+auth/ent/role_query.go:412.18,414.4 1 1
+auth/ent/role_query.go:416.2,416.36 1 1
+auth/ent/role_query.go:416.36,424.3 7 1
+auth/ent/role_query.go:425.2,425.48 1 1
+auth/ent/role_query.go:425.48,427.3 1 0
+auth/ent/role_query.go:428.2,428.70 1 1
+auth/ent/role_query.go:428.70,429.78 1 1
+auth/ent/role_query.go:429.78,432.60 3 1
+auth/ent/role_query.go:432.60,434.19 2 1
+auth/ent/role_query.go:434.19,436.6 1 0
+auth/ent/role_query.go:437.5,437.62 1 1
+auth/ent/role_query.go:439.4,439.61 1 1
+auth/ent/role_query.go:439.61,442.29 3 1
+auth/ent/role_query.go:442.29,445.6 2 1
+auth/ent/role_query.go:446.5,447.15 2 0
+auth/ent/role_query.go:451.2,452.16 2 1
+auth/ent/role_query.go:452.16,454.3 1 0
+auth/ent/role_query.go:455.2,455.30 1 1
+auth/ent/role_query.go:455.30,457.10 2 1
+auth/ent/role_query.go:457.10,459.4 1 0
+auth/ent/role_query.go:460.3,460.25 1 1
+auth/ent/role_query.go:460.25,462.4 1 1
+auth/ent/role_query.go:464.2,464.12 1 1
+auth/ent/role_query.go:467.65,470.28 3 2
+auth/ent/role_query.go:470.28,472.3 1 0
+auth/ent/role_query.go:473.2,473.51 1 2
+auth/ent/role_query.go:476.54,479.44 3 18
+auth/ent/role_query.go:479.44,481.3 1 0
+auth/ent/role_query.go:481.8,481.27 1 18
+auth/ent/role_query.go:481.27,483.3 1 1
+auth/ent/role_query.go:484.2,484.46 1 18
+auth/ent/role_query.go:484.46,487.25 3 0
+auth/ent/role_query.go:487.25,488.33 1 0
+auth/ent/role_query.go:488.33,490.5 1 0
+auth/ent/role_query.go:493.2,493.38 1 18
+auth/ent/role_query.go:493.38,494.50 1 14
+auth/ent/role_query.go:494.50,495.22 1 14
+auth/ent/role_query.go:495.22,497.5 1 14
+auth/ent/role_query.go:500.2,500.41 1 18
+auth/ent/role_query.go:500.41,502.3 1 8
+auth/ent/role_query.go:503.2,503.44 1 18
+auth/ent/role_query.go:503.44,505.3 1 1
+auth/ent/role_query.go:506.2,506.33 1 18
+auth/ent/role_query.go:506.33,507.46 1 0
+auth/ent/role_query.go:507.46,508.22 1 0
+auth/ent/role_query.go:508.22,510.5 1 0
+auth/ent/role_query.go:513.2,513.14 1 18
+auth/ent/role_query.go:516.66,520.23 4 0
+auth/ent/role_query.go:520.23,522.3 1 0
+auth/ent/role_query.go:523.2,524.19 2 0
+auth/ent/role_query.go:524.19,527.3 2 0
+auth/ent/role_query.go:528.2,528.44 1 0
+auth/ent/role_query.go:528.44,530.3 1 0
+auth/ent/role_query.go:531.2,531.34 1 0
+auth/ent/role_query.go:531.34,533.3 1 0
+auth/ent/role_query.go:534.2,534.29 1 0
+auth/ent/role_query.go:534.29,536.3 1 0
+auth/ent/role_query.go:537.2,537.44 1 0
+auth/ent/role_query.go:537.44,541.3 1 0
+auth/ent/role_query.go:542.2,542.41 1 0
+auth/ent/role_query.go:542.41,544.3 1 0
+auth/ent/role_query.go:545.2,545.17 1 0
+auth/ent/role_query.go:555.70,558.2 2 0
+auth/ent/role_query.go:561.64,563.52 2 0
+auth/ent/role_query.go:563.52,565.3 1 0
+auth/ent/role_query.go:566.2,566.97 1 0
+auth/ent/role_query.go:569.84,572.29 3 0
+auth/ent/role_query.go:572.29,574.3 1 0
+auth/ent/role_query.go:575.2,575.42 1 0
+auth/ent/role_query.go:575.42,577.31 2 0
+auth/ent/role_query.go:577.31,579.4 1 0
+auth/ent/role_query.go:580.3,581.30 2 0
+auth/ent/role_query.go:583.2,584.39 2 0
+auth/ent/role_query.go:584.39,586.3 1 0
+auth/ent/role_query.go:587.2,589.71 3 0
+auth/ent/role_query.go:589.71,591.3 1 0
+auth/ent/role_query.go:592.2,593.31 2 0
+auth/ent/role_query.go:603.67,606.2 2 0
+auth/ent/role_query.go:609.62,611.45 2 0
+auth/ent/role_query.go:611.45,613.3 1 0
+auth/ent/role_query.go:614.2,614.91 1 0
+auth/ent/role_query.go:617.82,620.28 3 0
+auth/ent/role_query.go:620.28,622.3 1 0
+auth/ent/role_query.go:623.2,623.38 1 0
+auth/ent/role_query.go:624.38,625.34 1 0
+auth/ent/role_query.go:626.38,627.40 1 0
+auth/ent/role_query.go:629.2,631.64 3 0
+auth/ent/role_query.go:631.64,633.3 1 0
+auth/ent/role_query.go:634.2,635.31 2 0
+auth/ent/role_update.go:28.63,31.2 2 0
+auth/ent/role_update.go:34.53,37.2 2 0
+auth/ent/role_update.go:40.62,41.14 1 0
+auth/ent/role_update.go:41.14,43.3 1 0
+auth/ent/role_update.go:44.2,44.11 1 0
+auth/ent/role_update.go:48.62,51.2 2 0
+auth/ent/role_update.go:54.65,57.2 2 0
+auth/ent/role_update.go:60.61,63.2 2 0
+auth/ent/role_update.go:66.70,67.14 1 0
+auth/ent/role_update.go:67.14,69.3 1 0
+auth/ent/role_update.go:70.2,70.11 1 0
+auth/ent/role_update.go:74.61,77.2 2 0
+auth/ent/role_update.go:80.61,83.2 2 0
+auth/ent/role_update.go:86.56,88.19 2 0
+auth/ent/role_update.go:88.19,90.3 1 0
+auth/ent/role_update.go:91.2,91.30 1 0
+auth/ent/role_update.go:95.48,97.2 1 0
+auth/ent/role_update.go:100.48,103.2 2 0
+auth/ent/role_update.go:106.64,109.2 2 0
+auth/ent/role_update.go:112.59,114.19 2 0
+auth/ent/role_update.go:114.19,116.3 1 0
+auth/ent/role_update.go:117.2,117.33 1 0
+auth/ent/role_update.go:121.62,124.2 2 0
+auth/ent/role_update.go:127.54,129.16 2 0
+auth/ent/role_update.go:129.16,130.13 1 0
+auth/ent/role_update.go:132.2,132.17 1 0
+auth/ent/role_update.go:136.55,139.2 2 0
+auth/ent/role_update.go:142.50,143.37 1 0
+auth/ent/role_update.go:143.37,144.13 1 0
+auth/ent/role_update.go:149.34,150.43 1 0
+auth/ent/role_update.go:150.43,153.3 2 0
+auth/ent/role_update.go:156.71,158.47 2 0
+auth/ent/role_update.go:158.47,159.50 1 0
+auth/ent/role_update.go:159.50,160.22 1 0
+auth/ent/role_update.go:160.22,162.5 1 0
+auth/ent/role_update.go:165.2,165.41 1 0
+auth/ent/role_update.go:165.41,167.3 1 0
+auth/ent/role_update.go:168.2,168.48 1 0
+auth/ent/role_update.go:168.48,170.3 1 0
+auth/ent/role_update.go:171.2,171.56 1 0
+auth/ent/role_update.go:171.56,172.48 1 0
+auth/ent/role_update.go:172.48,174.4 1 0
+auth/ent/role_update.go:176.2,176.46 1 0
+auth/ent/role_update.go:176.46,178.3 1 0
+auth/ent/role_update.go:179.2,179.46 1 0
+auth/ent/role_update.go:179.46,181.3 1 0
+auth/ent/role_update.go:182.2,182.32 1 0
+auth/ent/role_update.go:182.32,194.3 2 0
+auth/ent/role_update.go:195.2,195.91 1 0
+auth/ent/role_update.go:195.91,206.27 2 0
+auth/ent/role_update.go:206.27,208.4 1 0
+auth/ent/role_update.go:209.3,209.54 1 0
+auth/ent/role_update.go:211.2,211.53 1 0
+auth/ent/role_update.go:211.53,222.27 2 0
+auth/ent/role_update.go:222.27,224.4 1 0
+auth/ent/role_update.go:225.3,225.50 1 0
+auth/ent/role_update.go:227.2,227.70 1 0
+auth/ent/role_update.go:227.70,228.49 1 0
+auth/ent/role_update.go:228.49,230.4 1 0
+auth/ent/role_update.go:230.9,230.45 1 0
+auth/ent/role_update.go:230.45,232.4 1 0
+auth/ent/role_update.go:233.3,233.16 1 0
+auth/ent/role_update.go:235.2,236.15 2 0
+auth/ent/role_update.go:248.60,251.2 2 1
+auth/ent/role_update.go:254.69,255.14 1 0
+auth/ent/role_update.go:255.14,257.3 1 0
+auth/ent/role_update.go:258.2,258.12 1 0
+auth/ent/role_update.go:262.69,265.2 2 2
+auth/ent/role_update.go:268.72,271.2 2 1
+auth/ent/role_update.go:274.68,277.2 2 0
+auth/ent/role_update.go:280.77,281.14 1 0
+auth/ent/role_update.go:281.14,283.3 1 0
+auth/ent/role_update.go:284.2,284.12 1 0
+auth/ent/role_update.go:288.68,291.2 2 1
+auth/ent/role_update.go:294.68,297.2 2 1
+auth/ent/role_update.go:300.63,302.19 2 0
+auth/ent/role_update.go:302.19,304.3 1 0
+auth/ent/role_update.go:305.2,305.31 1 0
+auth/ent/role_update.go:309.52,311.2 1 0
+auth/ent/role_update.go:314.55,317.2 2 0
+auth/ent/role_update.go:320.71,323.2 2 0
+auth/ent/role_update.go:326.66,328.19 2 0
+auth/ent/role_update.go:328.19,330.3 1 0
+auth/ent/role_update.go:331.2,331.34 1 0
+auth/ent/role_update.go:335.70,338.2 2 0
+auth/ent/role_update.go:342.81,345.2 2 0
+auth/ent/role_update.go:348.68,351.2 2 4
+auth/ent/role_update.go:354.60,356.16 2 0
+auth/ent/role_update.go:356.16,357.13 1 0
+auth/ent/role_update.go:359.2,359.13 1 0
+auth/ent/role_update.go:363.59,366.2 2 3
+auth/ent/role_update.go:369.54,370.38 1 0
+auth/ent/role_update.go:370.38,371.13 1 0
+auth/ent/role_update.go:376.38,377.44 1 4
+auth/ent/role_update.go:377.44,380.3 2 3
+auth/ent/role_update.go:383.81,386.9 3 4
+auth/ent/role_update.go:386.9,388.3 1 0
+auth/ent/role_update.go:389.2,390.43 2 4
+auth/ent/role_update.go:390.43,393.28 3 0
+auth/ent/role_update.go:393.28,394.28 1 0
+auth/ent/role_update.go:394.28,396.5 1 0
+auth/ent/role_update.go:397.4,397.25 1 0
+auth/ent/role_update.go:397.25,399.5 1 0
+auth/ent/role_update.go:402.2,402.48 1 4
+auth/ent/role_update.go:402.48,403.50 1 0
+auth/ent/role_update.go:403.50,404.22 1 0
+auth/ent/role_update.go:404.22,406.5 1 0
+auth/ent/role_update.go:409.2,409.42 1 4
+auth/ent/role_update.go:409.42,411.3 1 1
+auth/ent/role_update.go:412.2,412.49 1 4
+auth/ent/role_update.go:412.49,414.3 1 2
+auth/ent/role_update.go:415.2,415.57 1 4
+auth/ent/role_update.go:415.57,416.48 1 1
+auth/ent/role_update.go:416.48,418.4 1 1
+auth/ent/role_update.go:420.2,420.47 1 4
+auth/ent/role_update.go:420.47,422.3 1 0
+auth/ent/role_update.go:423.2,423.47 1 4
+auth/ent/role_update.go:423.47,425.3 1 4
+auth/ent/role_update.go:426.2,426.33 1 4
+auth/ent/role_update.go:426.33,438.3 2 0
+auth/ent/role_update.go:439.2,439.93 1 4
+auth/ent/role_update.go:439.93,450.27 2 0
+auth/ent/role_update.go:450.27,452.4 1 0
+auth/ent/role_update.go:453.3,453.54 1 0
+auth/ent/role_update.go:455.2,455.54 1 4
+auth/ent/role_update.go:455.54,466.27 2 1
+auth/ent/role_update.go:466.27,468.4 1 1
+auth/ent/role_update.go:469.3,469.50 1 1
+auth/ent/role_update.go:471.2,474.67 4 4
+auth/ent/role_update.go:474.67,475.49 1 0
+auth/ent/role_update.go:475.49,477.4 1 0
+auth/ent/role_update.go:477.9,477.45 1 0
+auth/ent/role_update.go:477.45,479.4 1 0
+auth/ent/role_update.go:480.3,480.18 1 0
+auth/ent/role_update.go:482.2,483.19 2 4
+auth/ent/token.go:51.48,52.19 1 0
+auth/ent/token.go:52.19,54.3 1 0
+auth/ent/token.go:54.8,54.29 1 0
+auth/ent/token.go:54.29,56.3 1 0
+auth/ent/token.go:57.2,57.43 1 0
+auth/ent/token.go:61.59,63.25 2 8
+auth/ent/token.go:63.25,64.21 1 56
+auth/ent/token.go:65.27,66.33 1 8
+auth/ent/token.go:67.57,68.35 1 24
+auth/ent/token.go:69.73,70.33 1 24
+auth/ent/token.go:71.29,72.35 1 0
+auth/ent/token.go:73.11,74.36 1 0
+auth/ent/token.go:77.2,77.20 1 8
+auth/ent/token.go:82.68,83.46 1 8
+auth/ent/token.go:83.46,85.3 1 0
+auth/ent/token.go:86.2,86.25 1 8
+auth/ent/token.go:86.25,87.21 1 56
+auth/ent/token.go:88.22,89.53 1 8
+auth/ent/token.go:89.53,91.5 1 0
+auth/ent/token.go:91.10,91.26 1 8
+auth/ent/token.go:91.26,93.5 1 8
+auth/ent/token.go:94.25,95.53 1 8
+auth/ent/token.go:95.53,97.5 1 0
+auth/ent/token.go:97.10,97.26 1 8
+auth/ent/token.go:97.26,99.5 1 8
+auth/ent/token.go:100.24,101.53 1 8
+auth/ent/token.go:101.53,103.5 1 0
+auth/ent/token.go:103.10,103.26 1 8
+auth/ent/token.go:103.26,105.5 1 8
+auth/ent/token.go:106.29,107.51 1 8
+auth/ent/token.go:107.51,109.5 1 0
+auth/ent/token.go:109.10,109.26 1 8
+auth/ent/token.go:109.26,111.5 1 8
+auth/ent/token.go:112.27,113.51 1 8
+auth/ent/token.go:113.51,115.5 1 0
+auth/ent/token.go:115.10,115.26 1 8
+auth/ent/token.go:115.26,117.5 1 8
+auth/ent/token.go:118.29,119.51 1 8
+auth/ent/token.go:119.51,121.5 1 0
+auth/ent/token.go:121.10,121.26 1 8
+auth/ent/token.go:121.26,123.5 1 8
+auth/ent/token.go:124.29,125.51 1 8
+auth/ent/token.go:125.51,127.5 1 0
+auth/ent/token.go:127.10,127.26 1 8
+auth/ent/token.go:127.26,129.5 1 8
+auth/ent/token.go:130.29,131.53 1 0
+auth/ent/token.go:131.53,133.5 1 0
+auth/ent/token.go:133.10,133.26 1 0
+auth/ent/token.go:133.26,136.5 2 0
+auth/ent/token.go:137.11,138.45 1 0
+auth/ent/token.go:141.2,141.12 1 8
+auth/ent/token.go:146.55,148.2 1 0
+auth/ent/token.go:151.40,153.2 1 1
+auth/ent/token.go:158.42,160.2 1 1
+auth/ent/token.go:164.33,166.9 2 0
+auth/ent/token.go:166.9,167.52 1 0
+auth/ent/token.go:169.2,170.10 2 0
+auth/ent/token.go:174.33,197.2 22 0
+auth/ent/token_create.go:25.56,28.2 2 13
+auth/ent/token_create.go:31.59,34.2 2 13
+auth/ent/token_create.go:37.63,40.2 2 13
+auth/ent/token_create.go:43.56,46.2 2 0
+auth/ent/token_create.go:49.65,50.14 1 0
+auth/ent/token_create.go:50.14,52.3 1 0
+auth/ent/token_create.go:53.2,53.11 1 0
+auth/ent/token_create.go:57.63,60.2 2 0
+auth/ent/token_create.go:63.72,64.14 1 0
+auth/ent/token_create.go:64.14,66.3 1 0
+auth/ent/token_create.go:67.2,67.11 1 0
+auth/ent/token_create.go:71.63,74.2 2 0
+auth/ent/token_create.go:77.72,78.14 1 0
+auth/ent/token_create.go:78.14,80.3 1 0
+auth/ent/token_create.go:81.2,81.11 1 0
+auth/ent/token_create.go:85.53,88.2 2 0
+auth/ent/token_create.go:91.62,92.14 1 0
+auth/ent/token_create.go:92.14,94.3 1 0
+auth/ent/token_create.go:95.2,95.11 1 0
+auth/ent/token_create.go:99.58,102.2 2 13
+auth/ent/token_create.go:105.54,107.2 1 4
+auth/ent/token_create.go:110.50,112.2 1 0
+auth/ent/token_create.go:115.66,118.2 2 13
+auth/ent/token_create.go:121.58,123.16 2 0
+auth/ent/token_create.go:123.16,124.13 1 0
+auth/ent/token_create.go:126.2,126.10 1 0
+auth/ent/token_create.go:130.56,133.2 2 0
+auth/ent/token_create.go:136.51,137.37 1 0
+auth/ent/token_create.go:137.37,138.13 1 0
+auth/ent/token_create.go:143.35,144.41 1 13
+auth/ent/token_create.go:144.41,147.3 2 13
+auth/ent/token_create.go:148.2,148.43 1 13
+auth/ent/token_create.go:148.43,151.3 2 13
+auth/ent/token_create.go:152.2,152.43 1 13
+auth/ent/token_create.go:152.43,155.3 2 13
+auth/ent/token_create.go:156.2,156.36 1 13
+auth/ent/token_create.go:156.36,159.3 2 13
+auth/ent/token_create.go:163.38,164.39 1 13
+auth/ent/token_create.go:164.39,166.3 1 0
+auth/ent/token_create.go:167.2,167.41 1 13
+auth/ent/token_create.go:167.41,169.3 1 0
+auth/ent/token_create.go:170.2,170.40 1 13
+auth/ent/token_create.go:170.40,171.48 1 13
+auth/ent/token_create.go:171.48,173.4 1 0
+auth/ent/token_create.go:175.2,175.43 1 13
+auth/ent/token_create.go:175.43,177.3 1 0
+auth/ent/token_create.go:178.2,178.41 1 13
+auth/ent/token_create.go:178.41,180.3 1 0
+auth/ent/token_create.go:181.2,181.43 1 13
+auth/ent/token_create.go:181.43,183.3 1 0
+auth/ent/token_create.go:184.2,184.43 1 13
+auth/ent/token_create.go:184.43,186.3 1 0
+auth/ent/token_create.go:187.2,187.40 1 13
+auth/ent/token_create.go:187.40,189.3 1 0
+auth/ent/token_create.go:190.2,190.12 1 13
+auth/ent/token_create.go:193.69,194.35 1 13
+auth/ent/token_create.go:194.35,196.3 1 0
+auth/ent/token_create.go:197.2,198.67 2 13
+auth/ent/token_create.go:198.67,199.38 1 1
+auth/ent/token_create.go:199.38,201.4 1 1
+auth/ent/token_create.go:202.3,202.18 1 1
+auth/ent/token_create.go:204.2,204.27 1 12
+auth/ent/token_create.go:204.27,205.44 1 12
+auth/ent/token_create.go:205.44,207.4 1 12
+auth/ent/token_create.go:207.9,209.4 1 0
+auth/ent/token_create.go:211.2,213.19 3 12
+auth/ent/token_create.go:216.68,221.36 2 13
+auth/ent/token_create.go:221.36,224.3 2 13
+auth/ent/token_create.go:225.2,225.42 1 13
+auth/ent/token_create.go:225.42,228.3 2 13
+auth/ent/token_create.go:229.2,229.44 1 13
+auth/ent/token_create.go:229.44,232.3 2 13
+auth/ent/token_create.go:233.2,233.46 1 13
+auth/ent/token_create.go:233.46,236.3 2 13
+auth/ent/token_create.go:237.2,237.44 1 13
+auth/ent/token_create.go:237.44,240.3 2 13
+auth/ent/token_create.go:241.2,241.46 1 13
+auth/ent/token_create.go:241.46,244.3 2 13
+auth/ent/token_create.go:245.2,245.46 1 13
+auth/ent/token_create.go:245.46,248.3 2 13
+auth/ent/token_create.go:249.2,249.52 1 13
+auth/ent/token_create.go:249.52,260.27 2 13
+auth/ent/token_create.go:260.27,262.4 1 13
+auth/ent/token_create.go:263.3,264.42 2 13
+auth/ent/token_create.go:266.2,266.21 1 13
+auth/ent/token_create.go:277.73,278.20 1 0
+auth/ent/token_create.go:278.20,280.3 1 0
+auth/ent/token_create.go:281.2,284.30 4 0
+auth/ent/token_create.go:284.30,285.37 1 0
+auth/ent/token_create.go:285.37,288.86 3 0
+auth/ent/token_create.go:288.86,290.12 2 0
+auth/ent/token_create.go:290.12,292.6 1 0
+auth/ent/token_create.go:293.5,293.43 1 0
+auth/ent/token_create.go:293.43,295.6 1 0
+auth/ent/token_create.go:296.5,299.28 4 0
+auth/ent/token_create.go:299.28,301.6 1 0
+auth/ent/token_create.go:301.11,304.71 2 0
+auth/ent/token_create.go:304.71,305.42 1 0
+auth/ent/token_create.go:305.42,307.8 1 0
+auth/ent/token_create.go:310.5,310.19 1 0
+auth/ent/token_create.go:310.19,312.6 1 0
+auth/ent/token_create.go:313.5,315.25 3 0
+auth/ent/token_create.go:317.4,317.49 1 0
+auth/ent/token_create.go:317.49,319.5 1 0
+auth/ent/token_create.go:320.4,320.21 1 0
+auth/ent/token_create.go:323.2,323.23 1 0
+auth/ent/token_create.go:323.23,324.78 1 0
+auth/ent/token_create.go:324.78,326.4 1 0
+auth/ent/token_create.go:328.2,328.19 1 0
+auth/ent/token_create.go:332.65,334.16 2 0
+auth/ent/token_create.go:334.16,335.13 1 0
+auth/ent/token_create.go:337.2,337.10 1 0
+auth/ent/token_create.go:341.61,344.2 2 0
+auth/ent/token_create.go:347.56,348.38 1 0
+auth/ent/token_create.go:348.38,349.13 1 0
+auth/ent/token_delete.go:23.66,26.2 2 1
+auth/ent/token_delete.go:29.63,31.2 1 1
+auth/ent/token_delete.go:34.55,36.16 2 0
+auth/ent/token_delete.go:36.16,37.13 1 0
+auth/ent/token_delete.go:39.2,39.10 1 0
+auth/ent/token_delete.go:42.66,44.47 2 1
+auth/ent/token_delete.go:44.47,45.50 1 1
+auth/ent/token_delete.go:45.50,46.22 1 1
+auth/ent/token_delete.go:46.22,48.5 1 1
+auth/ent/token_delete.go:51.2,52.51 2 1
+auth/ent/token_delete.go:52.51,54.3 1 0
+auth/ent/token_delete.go:55.2,56.22 2 1
+auth/ent/token_delete.go:65.73,68.2 2 0
+auth/ent/token_delete.go:71.60,73.9 2 0
+auth/ent/token_delete.go:74.18,75.13 1 0
+auth/ent/token_delete.go:76.14,77.37 1 0
+auth/ent/token_delete.go:78.10,79.13 1 0
+auth/ent/token_delete.go:84.55,85.38 1 0
+auth/ent/token_delete.go:85.38,86.13 1 0
+auth/ent/token_query.go:33.64,36.2 2 9
+auth/ent/token_query.go:39.52,42.2 2 7
+auth/ent/token_query.go:45.54,48.2 2 0
+auth/ent/token_query.go:52.55,55.2 2 0
+auth/ent/token_query.go:58.65,61.2 2 0
+auth/ent/token_query.go:64.46,66.74 2 0
+auth/ent/token_query.go:66.74,67.46 1 0
+auth/ent/token_query.go:67.46,69.4 1 0
+auth/ent/token_query.go:70.3,71.40 2 0
+auth/ent/token_query.go:71.40,73.4 1 0
+auth/ent/token_query.go:74.3,80.20 3 0
+auth/ent/token_query.go:82.2,82.14 1 0
+auth/ent/token_query.go:87.66,89.16 2 0
+auth/ent/token_query.go:89.16,91.3 1 0
+auth/ent/token_query.go:92.2,92.21 1 0
+auth/ent/token_query.go:92.21,94.3 1 0
+auth/ent/token_query.go:95.2,95.22 1 0
+auth/ent/token_query.go:99.58,101.36 2 0
+auth/ent/token_query.go:101.36,102.13 1 0
+auth/ent/token_query.go:104.2,104.13 1 0
+auth/ent/token_query.go:109.75,111.82 2 0
+auth/ent/token_query.go:111.82,113.3 1 0
+auth/ent/token_query.go:114.2,114.19 1 0
+auth/ent/token_query.go:114.19,117.3 2 0
+auth/ent/token_query.go:118.2,118.20 1 0
+auth/ent/token_query.go:122.60,124.36 2 0
+auth/ent/token_query.go:124.36,125.13 1 0
+auth/ent/token_query.go:127.2,127.11 1 0
+auth/ent/token_query.go:133.65,135.16 2 7
+auth/ent/token_query.go:135.16,137.3 1 0
+auth/ent/token_query.go:138.2,138.20 1 7
+auth/ent/token_query.go:139.9,140.23 1 5
+auth/ent/token_query.go:141.9,142.42 1 2
+auth/ent/token_query.go:143.10,144.45 1 0
+auth/ent/token_query.go:149.57,151.16 2 0
+auth/ent/token_query.go:151.16,152.13 1 0
+auth/ent/token_query.go:154.2,154.13 1 0
+auth/ent/token_query.go:160.74,162.81 2 0
+auth/ent/token_query.go:162.81,164.3 1 0
+auth/ent/token_query.go:165.2,165.18 1 0
+auth/ent/token_query.go:166.9,167.14 1 0
+auth/ent/token_query.go:168.9,169.36 1 0
+auth/ent/token_query.go:170.10,171.39 1 0
+auth/ent/token_query.go:173.2,173.8 1 0
+auth/ent/token_query.go:177.59,179.16 2 0
+auth/ent/token_query.go:179.16,180.13 1 0
+auth/ent/token_query.go:182.2,182.11 1 0
+auth/ent/token_query.go:186.66,188.45 2 10
+auth/ent/token_query.go:188.45,190.3 1 0
+auth/ent/token_query.go:191.2,192.59 2 10
+auth/ent/token_query.go:196.58,198.16 2 0
+auth/ent/token_query.go:198.16,199.13 1 0
+auth/ent/token_query.go:201.2,201.14 1 0
+auth/ent/token_query.go:205.74,206.44 1 0
+auth/ent/token_query.go:206.44,208.3 1 0
+auth/ent/token_query.go:209.2,210.64 2 0
+auth/ent/token_query.go:210.64,212.3 1 0
+auth/ent/token_query.go:213.2,213.17 1 0
+auth/ent/token_query.go:217.58,219.16 2 0
+auth/ent/token_query.go:219.16,220.13 1 0
+auth/ent/token_query.go:222.2,222.12 1 0
+auth/ent/token_query.go:226.63,228.45 2 0
+auth/ent/token_query.go:228.45,230.3 1 0
+auth/ent/token_query.go:231.2,231.79 1 0
+auth/ent/token_query.go:235.55,237.16 2 0
+auth/ent/token_query.go:237.16,238.13 1 0
+auth/ent/token_query.go:240.2,240.14 1 0
+auth/ent/token_query.go:244.64,246.36 2 0
+auth/ent/token_query.go:247.23,248.20 1 0
+auth/ent/token_query.go:249.18,250.60 1 0
+auth/ent/token_query.go:251.10,252.19 1 0
+auth/ent/token_query.go:257.56,259.16 2 0
+auth/ent/token_query.go:259.16,260.13 1 0
+auth/ent/token_query.go:262.2,262.14 1 0
+auth/ent/token_query.go:267.43,268.15 1 0
+auth/ent/token_query.go:268.15,270.3 1 0
+auth/ent/token_query.go:271.2,281.3 1 0
+auth/ent/token_query.go:286.70,288.27 2 0
+auth/ent/token_query.go:288.27,290.3 1 0
+auth/ent/token_query.go:291.2,292.11 2 0
+auth/ent/token_query.go:309.77,316.2 6 0
+auth/ent/token_query.go:330.61,336.2 5 0
+auth/ent/token_query.go:339.68,341.2 1 0
+auth/ent/token_query.go:343.63,344.34 1 10
+auth/ent/token_query.go:344.34,345.19 1 0
+auth/ent/token_query.go:345.19,347.4 1 0
+auth/ent/token_query.go:348.3,348.39 1 0
+auth/ent/token_query.go:348.39,349.48 1 0
+auth/ent/token_query.go:349.48,351.5 1 0
+auth/ent/token_query.go:354.2,354.34 1 10
+auth/ent/token_query.go:354.34,355.28 1 0
+auth/ent/token_query.go:355.28,357.4 1 0
+auth/ent/token_query.go:359.2,359.20 1 10
+auth/ent/token_query.go:359.20,361.17 2 1
+auth/ent/token_query.go:361.17,363.4 1 0
+auth/ent/token_query.go:364.3,364.16 1 1
+auth/ent/token_query.go:366.2,366.12 1 10
+auth/ent/token_query.go:369.89,378.24 2 10
+auth/ent/token_query.go:378.24,380.3 1 0
+auth/ent/token_query.go:381.2,381.13 1 10
+auth/ent/token_query.go:381.13,383.3 1 0
+auth/ent/token_query.go:384.2,384.59 1 10
+auth/ent/token_query.go:384.59,386.3 1 7
+auth/ent/token_query.go:387.2,387.60 1 10
+auth/ent/token_query.go:387.60,392.3 4 7
+auth/ent/token_query.go:393.2,393.23 1 10
+auth/ent/token_query.go:393.23,395.3 1 0
+auth/ent/token_query.go:396.2,396.67 1 10
+auth/ent/token_query.go:396.67,398.3 1 0
+auth/ent/token_query.go:399.2,399.21 1 10
+auth/ent/token_query.go:399.21,401.3 1 3
+auth/ent/token_query.go:402.2,402.40 1 7
+auth/ent/token_query.go:402.40,404.28 1 0
+auth/ent/token_query.go:404.28,404.48 1 0
+auth/ent/token_query.go:404.62,406.4 1 0
+auth/ent/token_query.go:408.2,408.19 1 7
+auth/ent/token_query.go:411.140,414.23 3 0
+auth/ent/token_query.go:414.23,415.34 1 0
+auth/ent/token_query.go:415.34,416.12 1 0
+auth/ent/token_query.go:418.3,419.32 2 0
+auth/ent/token_query.go:419.32,421.4 1 0
+auth/ent/token_query.go:422.3,422.46 1 0
+auth/ent/token_query.go:424.2,424.19 1 0
+auth/ent/token_query.go:424.19,426.3 1 0
+auth/ent/token_query.go:427.2,429.16 3 0
+auth/ent/token_query.go:429.16,431.3 1 0
+auth/ent/token_query.go:432.2,432.30 1 0
+auth/ent/token_query.go:432.30,434.10 2 0
+auth/ent/token_query.go:434.10,436.4 1 0
+auth/ent/token_query.go:437.3,437.24 1 0
+auth/ent/token_query.go:437.24,439.4 1 0
+auth/ent/token_query.go:441.2,441.12 1 0
+auth/ent/token_query.go:444.66,447.28 3 0
+auth/ent/token_query.go:447.28,449.3 1 0
+auth/ent/token_query.go:450.2,450.51 1 0
+auth/ent/token_query.go:453.55,456.44 3 10
+auth/ent/token_query.go:456.44,458.3 1 0
+auth/ent/token_query.go:458.8,458.27 1 10
+auth/ent/token_query.go:458.27,460.3 1 1
+auth/ent/token_query.go:461.2,461.46 1 10
+auth/ent/token_query.go:461.46,464.25 3 0
+auth/ent/token_query.go:464.25,465.34 1 0
+auth/ent/token_query.go:465.34,467.5 1 0
+auth/ent/token_query.go:470.2,470.38 1 10
+auth/ent/token_query.go:470.38,471.50 1 9
+auth/ent/token_query.go:471.50,472.22 1 9
+auth/ent/token_query.go:472.22,474.5 1 13
+auth/ent/token_query.go:477.2,477.41 1 10
+auth/ent/token_query.go:477.41,479.3 1 7
+auth/ent/token_query.go:480.2,480.44 1 10
+auth/ent/token_query.go:480.44,482.3 1 0
+auth/ent/token_query.go:483.2,483.33 1 10
+auth/ent/token_query.go:483.33,484.46 1 0
+auth/ent/token_query.go:484.46,485.22 1 0
+auth/ent/token_query.go:485.22,487.5 1 0
+auth/ent/token_query.go:490.2,490.14 1 10
+auth/ent/token_query.go:493.67,497.23 4 0
+auth/ent/token_query.go:497.23,499.3 1 0
+auth/ent/token_query.go:500.2,501.19 2 0
+auth/ent/token_query.go:501.19,504.3 2 0
+auth/ent/token_query.go:505.2,505.44 1 0
+auth/ent/token_query.go:505.44,507.3 1 0
+auth/ent/token_query.go:508.2,508.34 1 0
+auth/ent/token_query.go:508.34,510.3 1 0
+auth/ent/token_query.go:511.2,511.29 1 0
+auth/ent/token_query.go:511.29,513.3 1 0
+auth/ent/token_query.go:514.2,514.44 1 0
+auth/ent/token_query.go:514.44,518.3 1 0
+auth/ent/token_query.go:519.2,519.41 1 0
+auth/ent/token_query.go:519.41,521.3 1 0
+auth/ent/token_query.go:522.2,522.17 1 0
+auth/ent/token_query.go:532.72,535.2 2 0
+auth/ent/token_query.go:538.65,540.52 2 0
+auth/ent/token_query.go:540.52,542.3 1 0
+auth/ent/token_query.go:543.2,543.99 1 0
+auth/ent/token_query.go:546.86,549.29 3 0
+auth/ent/token_query.go:549.29,551.3 1 0
+auth/ent/token_query.go:552.2,552.42 1 0
+auth/ent/token_query.go:552.42,554.31 2 0
+auth/ent/token_query.go:554.31,556.4 1 0
+auth/ent/token_query.go:557.3,558.30 2 0
+auth/ent/token_query.go:560.2,561.39 2 0
+auth/ent/token_query.go:561.39,563.3 1 0
+auth/ent/token_query.go:564.2,566.71 3 0
+auth/ent/token_query.go:566.71,568.3 1 0
+auth/ent/token_query.go:569.2,570.31 2 0
+auth/ent/token_query.go:580.69,583.2 2 0
+auth/ent/token_query.go:586.63,588.45 2 0
+auth/ent/token_query.go:588.45,590.3 1 0
+auth/ent/token_query.go:591.2,591.94 1 0
+auth/ent/token_query.go:594.84,597.28 3 0
+auth/ent/token_query.go:597.28,599.3 1 0
+auth/ent/token_query.go:600.2,600.38 1 0
+auth/ent/token_query.go:601.38,602.34 1 0
+auth/ent/token_query.go:603.38,604.40 1 0
+auth/ent/token_query.go:606.2,608.64 3 0
+auth/ent/token_query.go:608.64,610.3 1 0
+auth/ent/token_query.go:611.2,612.31 2 0
+auth/ent/token_update.go:27.66,30.2 2 4
+auth/ent/token_update.go:33.56,36.2 2 0
+auth/ent/token_update.go:39.65,40.14 1 0
+auth/ent/token_update.go:40.14,42.3 1 0
+auth/ent/token_update.go:43.2,43.11 1 0
+auth/ent/token_update.go:47.59,50.2 2 0
+auth/ent/token_update.go:53.68,54.14 1 0
+auth/ent/token_update.go:54.14,56.3 1 0
+auth/ent/token_update.go:57.2,57.11 1 0
+auth/ent/token_update.go:61.63,64.2 2 0
+auth/ent/token_update.go:67.72,68.14 1 0
+auth/ent/token_update.go:68.14,70.3 1 0
+auth/ent/token_update.go:71.2,71.11 1 0
+auth/ent/token_update.go:75.56,78.2 2 4
+auth/ent/token_update.go:81.65,82.14 1 0
+auth/ent/token_update.go:82.14,84.3 1 0
+auth/ent/token_update.go:85.2,85.11 1 0
+auth/ent/token_update.go:89.63,92.2 2 0
+auth/ent/token_update.go:95.72,96.14 1 0
+auth/ent/token_update.go:96.14,98.3 1 0
+auth/ent/token_update.go:99.2,99.11 1 0
+auth/ent/token_update.go:103.63,106.2 2 0
+auth/ent/token_update.go:109.58,112.2 2 0
+auth/ent/token_update.go:115.54,117.2 1 0
+auth/ent/token_update.go:120.50,122.2 1 0
+auth/ent/token_update.go:125.49,128.2 2 0
+auth/ent/token_update.go:131.63,134.2 2 4
+auth/ent/token_update.go:137.55,139.16 2 0
+auth/ent/token_update.go:139.16,140.13 1 0
+auth/ent/token_update.go:142.2,142.17 1 0
+auth/ent/token_update.go:146.56,149.2 2 0
+auth/ent/token_update.go:152.51,153.37 1 0
+auth/ent/token_update.go:153.37,154.13 1 0
+auth/ent/token_update.go:159.35,160.43 1 4
+auth/ent/token_update.go:160.43,163.3 2 4
+auth/ent/token_update.go:167.38,168.40 1 4
+auth/ent/token_update.go:168.40,169.48 1 0
+auth/ent/token_update.go:169.48,171.4 1 0
+auth/ent/token_update.go:173.2,173.69 1 4
+auth/ent/token_update.go:173.69,175.3 1 0
+auth/ent/token_update.go:176.2,176.12 1 4
+auth/ent/token_update.go:179.72,180.35 1 4
+auth/ent/token_update.go:180.35,182.3 1 0
+auth/ent/token_update.go:183.2,184.47 2 4
+auth/ent/token_update.go:184.47,185.50 1 4
+auth/ent/token_update.go:185.50,186.22 1 4
+auth/ent/token_update.go:186.22,188.5 1 8
+auth/ent/token_update.go:191.2,191.42 1 4
+auth/ent/token_update.go:191.42,193.3 1 0
+auth/ent/token_update.go:194.2,194.44 1 4
+auth/ent/token_update.go:194.44,196.3 1 0
+auth/ent/token_update.go:197.2,197.46 1 4
+auth/ent/token_update.go:197.46,199.3 1 0
+auth/ent/token_update.go:200.2,200.44 1 4
+auth/ent/token_update.go:200.44,202.3 1 4
+auth/ent/token_update.go:203.2,203.46 1 4
+auth/ent/token_update.go:203.46,205.3 1 0
+auth/ent/token_update.go:206.2,206.46 1 4
+auth/ent/token_update.go:206.46,208.3 1 4
+auth/ent/token_update.go:209.2,209.31 1 4
+auth/ent/token_update.go:209.31,221.3 2 0
+auth/ent/token_update.go:222.2,222.52 1 4
+auth/ent/token_update.go:222.52,233.27 2 0
+auth/ent/token_update.go:233.27,235.4 1 0
+auth/ent/token_update.go:236.3,236.50 1 0
+auth/ent/token_update.go:238.2,238.70 1 4
+auth/ent/token_update.go:238.70,239.49 1 0
+auth/ent/token_update.go:239.49,241.4 1 0
+auth/ent/token_update.go:241.9,241.45 1 0
+auth/ent/token_update.go:241.45,243.4 1 0
+auth/ent/token_update.go:244.3,244.16 1 0
+auth/ent/token_update.go:246.2,247.15 2 4
+auth/ent/token_update.go:259.63,262.2 2 0
+auth/ent/token_update.go:265.72,266.14 1 0
+auth/ent/token_update.go:266.14,268.3 1 0
+auth/ent/token_update.go:269.2,269.12 1 0
+auth/ent/token_update.go:273.66,276.2 2 0
+auth/ent/token_update.go:279.75,280.14 1 0
+auth/ent/token_update.go:280.14,282.3 1 0
+auth/ent/token_update.go:283.2,283.12 1 0
+auth/ent/token_update.go:287.70,290.2 2 0
+auth/ent/token_update.go:293.79,294.14 1 0
+auth/ent/token_update.go:294.14,296.3 1 0
+auth/ent/token_update.go:297.2,297.12 1 0
+auth/ent/token_update.go:301.63,304.2 2 1
+auth/ent/token_update.go:307.72,308.14 1 0
+auth/ent/token_update.go:308.14,310.3 1 0
+auth/ent/token_update.go:311.2,311.12 1 0
+auth/ent/token_update.go:315.70,318.2 2 0
+auth/ent/token_update.go:321.79,322.14 1 0
+auth/ent/token_update.go:322.14,324.3 1 0
+auth/ent/token_update.go:325.2,325.12 1 0
+auth/ent/token_update.go:329.70,332.2 2 0
+auth/ent/token_update.go:335.65,338.2 2 0
+auth/ent/token_update.go:341.61,343.2 1 0
+auth/ent/token_update.go:346.54,348.2 1 0
+auth/ent/token_update.go:351.56,354.2 2 0
+auth/ent/token_update.go:357.73,360.2 2 0
+auth/ent/token_update.go:364.83,367.2 2 0
+auth/ent/token_update.go:370.70,373.2 2 1
+auth/ent/token_update.go:376.62,378.16 2 0
+auth/ent/token_update.go:378.16,379.13 1 0
+auth/ent/token_update.go:381.2,381.13 1 0
+auth/ent/token_update.go:385.60,388.2 2 0
+auth/ent/token_update.go:391.55,392.38 1 0
+auth/ent/token_update.go:392.38,393.13 1 0
+auth/ent/token_update.go:398.39,399.44 1 1
+auth/ent/token_update.go:399.44,402.3 2 1
+auth/ent/token_update.go:406.42,407.41 1 1
+auth/ent/token_update.go:407.41,408.48 1 0
+auth/ent/token_update.go:408.48,410.4 1 0
+auth/ent/token_update.go:412.2,412.71 1 1
+auth/ent/token_update.go:412.71,414.3 1 0
+auth/ent/token_update.go:415.2,415.12 1 1
+auth/ent/token_update.go:418.83,419.36 1 1
+auth/ent/token_update.go:419.36,421.3 1 0
+auth/ent/token_update.go:422.2,424.9 3 1
+auth/ent/token_update.go:424.9,426.3 1 0
+auth/ent/token_update.go:427.2,428.43 2 1
+auth/ent/token_update.go:428.43,431.28 3 0
+auth/ent/token_update.go:431.28,432.29 1 0
+auth/ent/token_update.go:432.29,434.5 1 0
+auth/ent/token_update.go:435.4,435.26 1 0
+auth/ent/token_update.go:435.26,437.5 1 0
+auth/ent/token_update.go:440.2,440.48 1 1
+auth/ent/token_update.go:440.48,441.50 1 0
+auth/ent/token_update.go:441.50,442.22 1 0
+auth/ent/token_update.go:442.22,444.5 1 0
+auth/ent/token_update.go:447.2,447.43 1 1
+auth/ent/token_update.go:447.43,449.3 1 0
+auth/ent/token_update.go:450.2,450.45 1 1
+auth/ent/token_update.go:450.45,452.3 1 0
+auth/ent/token_update.go:453.2,453.47 1 1
+auth/ent/token_update.go:453.47,455.3 1 0
+auth/ent/token_update.go:456.2,456.45 1 1
+auth/ent/token_update.go:456.45,458.3 1 1
+auth/ent/token_update.go:459.2,459.47 1 1
+auth/ent/token_update.go:459.47,461.3 1 0
+auth/ent/token_update.go:462.2,462.47 1 1
+auth/ent/token_update.go:462.47,464.3 1 1
+auth/ent/token_update.go:465.2,465.32 1 1
+auth/ent/token_update.go:465.32,477.3 2 0
+auth/ent/token_update.go:478.2,478.53 1 1
+auth/ent/token_update.go:478.53,489.27 2 0
+auth/ent/token_update.go:489.27,491.4 1 0
+auth/ent/token_update.go:492.3,492.50 1 0
+auth/ent/token_update.go:494.2,497.67 4 1
+auth/ent/token_update.go:497.67,498.49 1 0
+auth/ent/token_update.go:498.49,500.4 1 0
+auth/ent/token_update.go:500.9,500.45 1 0
+auth/ent/token_update.go:500.45,502.4 1 0
+auth/ent/token_update.go:503.3,503.18 1 0
+auth/ent/token_update.go:505.2,506.19 2 1
+auth/ent/tx.go:59.63,61.2 1 0
+auth/ent/tx.go:64.30,66.65 2 0
+auth/ent/tx.go:66.65,68.3 1 0
+auth/ent/tx.go:69.2,72.39 4 0
+auth/ent/tx.go:72.39,74.3 1 0
+auth/ent/tx.go:75.2,75.30 1 0
+auth/ent/tx.go:79.38,84.2 4 0
+auth/ent/tx.go:115.67,117.2 1 0
+auth/ent/tx.go:120.32,122.68 2 0
+auth/ent/tx.go:122.68,124.3 1 0
+auth/ent/tx.go:125.2,128.39 4 0
+auth/ent/tx.go:128.39,130.3 1 0
+auth/ent/tx.go:131.2,131.32 1 0
+auth/ent/tx.go:135.42,140.2 4 0
+auth/ent/tx.go:143.32,144.26 1 0
+auth/ent/tx.go:144.26,147.3 2 0
+auth/ent/tx.go:148.2,148.18 1 0
+auth/ent/tx.go:151.22,155.2 3 0
+auth/ent/tx.go:180.72,182.16 2 0
+auth/ent/tx.go:182.16,184.3 1 0
+auth/ent/tx.go:185.2,185.41 1 0
+auth/ent/tx.go:190.61,190.79 1 0
+auth/ent/tx.go:193.38,193.65 1 0
+auth/ent/tx.go:196.32,196.46 1 0
+auth/ent/tx.go:200.33,200.47 1 0
+auth/ent/tx.go:204.35,204.49 1 0
+auth/ent/tx.go:207.80,209.2 1 0
+auth/ent/tx.go:212.81,214.2 1 0
+auth/ent/user.go:49.50,50.22 1 0
+auth/ent/user.go:50.22,52.3 1 0
+auth/ent/user.go:53.2,53.44 1 0
+auth/ent/user.go:58.52,59.22 1 0
+auth/ent/user.go:59.22,61.3 1 0
+auth/ent/user.go:62.2,62.45 1 0
+auth/ent/user.go:66.58,68.25 2 40
+auth/ent/user.go:68.25,69.21 1 240
+auth/ent/user.go:70.78,71.35 1 160
+auth/ent/user.go:72.49,73.33 1 80
+auth/ent/user.go:74.11,75.36 1 0
+auth/ent/user.go:78.2,78.20 1 40
+auth/ent/user.go:83.67,84.46 1 40
+auth/ent/user.go:84.46,86.3 1 0
+auth/ent/user.go:87.2,87.25 1 40
+auth/ent/user.go:87.25,88.21 1 240
+auth/ent/user.go:89.21,90.53 1 40
+auth/ent/user.go:90.53,92.5 1 0
+auth/ent/user.go:92.10,92.26 1 40
+auth/ent/user.go:92.26,94.5 1 40
+auth/ent/user.go:95.27,96.53 1 40
+auth/ent/user.go:96.53,98.5 1 0
+auth/ent/user.go:98.10,98.26 1 40
+auth/ent/user.go:98.26,100.5 1 40
+auth/ent/user.go:101.24,102.53 1 40
+auth/ent/user.go:102.53,104.5 1 0
+auth/ent/user.go:104.10,104.26 1 40
+auth/ent/user.go:104.26,106.5 1 40
+auth/ent/user.go:107.27,108.53 1 40
+auth/ent/user.go:108.53,110.5 1 0
+auth/ent/user.go:110.10,110.26 1 40
+auth/ent/user.go:110.26,112.5 1 40
+auth/ent/user.go:113.28,114.51 1 40
+auth/ent/user.go:114.51,116.5 1 0
+auth/ent/user.go:116.10,116.26 1 40
+auth/ent/user.go:116.26,118.5 1 40
+auth/ent/user.go:119.28,120.51 1 40
+auth/ent/user.go:120.51,122.5 1 0
+auth/ent/user.go:122.10,122.26 1 40
+auth/ent/user.go:122.26,124.5 1 40
+auth/ent/user.go:125.11,126.45 1 0
+auth/ent/user.go:129.2,129.12 1 40
+auth/ent/user.go:134.54,136.2 1 0
+auth/ent/user.go:139.40,141.2 1 1
+auth/ent/user.go:144.42,146.2 1 1
+auth/ent/user.go:151.40,153.2 1 0
+auth/ent/user.go:157.31,159.9 2 0
+auth/ent/user.go:159.9,160.51 1 0
+auth/ent/user.go:162.2,163.10 2 0
+auth/ent/user.go:167.32,187.2 19 1
+auth/ent/user_create.go:26.57,29.2 2 44
+auth/ent/user_create.go:32.54,35.2 2 44
+auth/ent/user_create.go:38.57,41.2 2 44
+auth/ent/user_create.go:44.61,47.2 2 0
+auth/ent/user_create.go:50.70,51.14 1 0
+auth/ent/user_create.go:51.14,53.3 1 0
+auth/ent/user_create.go:54.2,54.11 1 0
+auth/ent/user_create.go:58.61,61.2 2 0
+auth/ent/user_create.go:64.70,65.14 1 0
+auth/ent/user_create.go:65.14,67.3 1 0
+auth/ent/user_create.go:68.2,68.11 1 0
+auth/ent/user_create.go:72.51,75.2 2 6
+auth/ent/user_create.go:78.60,79.14 1 0
+auth/ent/user_create.go:79.14,81.3 1 0
+auth/ent/user_create.go:82.2,82.11 1 0
+auth/ent/user_create.go:86.61,89.2 2 0
+auth/ent/user_create.go:92.56,94.19 2 0
+auth/ent/user_create.go:94.19,96.3 1 0
+auth/ent/user_create.go:97.2,97.30 1 0
+auth/ent/user_create.go:101.62,104.2 2 0
+auth/ent/user_create.go:107.58,109.19 2 0
+auth/ent/user_create.go:109.19,111.3 1 0
+auth/ent/user_create.go:112.2,112.31 1 0
+auth/ent/user_create.go:116.48,118.2 1 0
+auth/ent/user_create.go:121.64,122.38 1 44
+auth/ent/user_create.go:122.38,124.3 1 0
+auth/ent/user_create.go:125.2,125.58 1 44
+auth/ent/user_create.go:129.56,131.16 2 1
+auth/ent/user_create.go:131.16,132.13 1 0
+auth/ent/user_create.go:134.2,134.10 1 1
+auth/ent/user_create.go:138.55,141.2 2 0
+auth/ent/user_create.go:144.50,145.37 1 0
+auth/ent/user_create.go:145.37,146.13 1 0
+auth/ent/user_create.go:151.40,152.43 1 44
+auth/ent/user_create.go:152.43,153.35 1 44
+auth/ent/user_create.go:153.35,155.4 1 0
+auth/ent/user_create.go:156.3,157.30 2 44
+auth/ent/user_create.go:159.2,159.43 1 44
+auth/ent/user_create.go:159.43,160.35 1 44
+auth/ent/user_create.go:160.35,162.4 1 0
+auth/ent/user_create.go:163.3,164.30 2 44
+auth/ent/user_create.go:166.2,166.36 1 44
+auth/ent/user_create.go:166.36,167.28 1 38
+auth/ent/user_create.go:167.28,169.4 1 0
+auth/ent/user_create.go:170.3,171.23 2 38
+auth/ent/user_create.go:173.2,173.12 1 44
+auth/ent/user_create.go:177.37,178.42 1 44
+auth/ent/user_create.go:178.42,180.3 1 0
+auth/ent/user_create.go:181.2,181.39 1 44
+auth/ent/user_create.go:181.39,183.3 1 0
+auth/ent/user_create.go:184.2,184.42 1 44
+auth/ent/user_create.go:184.42,186.3 1 0
+auth/ent/user_create.go:187.2,187.43 1 44
+auth/ent/user_create.go:187.43,189.3 1 0
+auth/ent/user_create.go:190.2,190.43 1 44
+auth/ent/user_create.go:190.43,192.3 1 0
+auth/ent/user_create.go:193.2,193.12 1 44
+auth/ent/user_create.go:196.67,197.35 1 44
+auth/ent/user_create.go:197.35,199.3 1 0
+auth/ent/user_create.go:200.2,201.67 2 44
+auth/ent/user_create.go:201.67,202.38 1 2
+auth/ent/user_create.go:202.38,204.4 1 2
+auth/ent/user_create.go:205.3,205.18 1 2
+auth/ent/user_create.go:207.2,207.27 1 42
+auth/ent/user_create.go:207.27,208.44 1 42
+auth/ent/user_create.go:208.44,210.4 1 42
+auth/ent/user_create.go:210.9,212.4 1 0
+auth/ent/user_create.go:214.2,216.19 3 42
+auth/ent/user_create.go:219.66,224.36 2 44
+auth/ent/user_create.go:224.36,227.3 2 44
+auth/ent/user_create.go:228.2,228.45 1 44
+auth/ent/user_create.go:228.45,231.3 2 44
+auth/ent/user_create.go:232.2,232.42 1 44
+auth/ent/user_create.go:232.42,235.3 2 44
+auth/ent/user_create.go:236.2,236.45 1 44
+auth/ent/user_create.go:236.45,239.3 2 44
+auth/ent/user_create.go:240.2,240.46 1 44
+auth/ent/user_create.go:240.46,243.3 2 44
+auth/ent/user_create.go:244.2,244.46 1 44
+auth/ent/user_create.go:244.46,247.3 2 44
+auth/ent/user_create.go:248.2,248.53 1 44
+auth/ent/user_create.go:248.53,259.27 2 0
+auth/ent/user_create.go:259.27,261.4 1 0
+auth/ent/user_create.go:262.3,262.42 1 0
+auth/ent/user_create.go:264.2,264.54 1 44
+auth/ent/user_create.go:264.54,275.27 2 0
+auth/ent/user_create.go:275.27,277.4 1 0
+auth/ent/user_create.go:278.3,278.42 1 0
+auth/ent/user_create.go:280.2,280.21 1 44
+auth/ent/user_create.go:291.71,292.20 1 0
+auth/ent/user_create.go:292.20,294.3 1 0
+auth/ent/user_create.go:295.2,298.30 4 0
+auth/ent/user_create.go:298.30,299.37 1 0
+auth/ent/user_create.go:299.37,302.86 3 0
+auth/ent/user_create.go:302.86,304.12 2 0
+auth/ent/user_create.go:304.12,306.6 1 0
+auth/ent/user_create.go:307.5,307.43 1 0
+auth/ent/user_create.go:307.43,309.6 1 0
+auth/ent/user_create.go:310.5,313.28 4 0
+auth/ent/user_create.go:313.28,315.6 1 0
+auth/ent/user_create.go:315.11,318.71 2 0
+auth/ent/user_create.go:318.71,319.42 1 0
+auth/ent/user_create.go:319.42,321.8 1 0
+auth/ent/user_create.go:324.5,324.19 1 0
+auth/ent/user_create.go:324.19,326.6 1 0
+auth/ent/user_create.go:327.5,329.25 3 0
+auth/ent/user_create.go:331.4,331.49 1 0
+auth/ent/user_create.go:331.49,333.5 1 0
+auth/ent/user_create.go:334.4,334.21 1 0
+auth/ent/user_create.go:337.2,337.23 1 0
+auth/ent/user_create.go:337.23,338.78 1 0
+auth/ent/user_create.go:338.78,340.4 1 0
+auth/ent/user_create.go:342.2,342.19 1 0
+auth/ent/user_create.go:346.63,348.16 2 0
+auth/ent/user_create.go:348.16,349.13 1 0
+auth/ent/user_create.go:351.2,351.10 1 0
+auth/ent/user_create.go:355.60,358.2 2 0
+auth/ent/user_create.go:361.55,362.38 1 0
+auth/ent/user_create.go:362.38,363.13 1 0
+auth/ent/user_delete.go:23.63,26.2 2 2
+auth/ent/user_delete.go:29.62,31.2 1 3
+auth/ent/user_delete.go:34.54,36.16 2 0
+auth/ent/user_delete.go:36.16,37.13 1 0
+auth/ent/user_delete.go:39.2,39.10 1 0
+auth/ent/user_delete.go:42.65,44.47 2 3
+auth/ent/user_delete.go:44.47,45.50 1 2
+auth/ent/user_delete.go:45.50,46.22 1 2
+auth/ent/user_delete.go:46.22,48.5 1 2
+auth/ent/user_delete.go:51.2,52.51 2 3
+auth/ent/user_delete.go:52.51,54.3 1 0
+auth/ent/user_delete.go:55.2,56.22 2 3
+auth/ent/user_delete.go:65.70,68.2 2 0
+auth/ent/user_delete.go:71.59,73.9 2 2
+auth/ent/user_delete.go:74.18,75.13 1 0
+auth/ent/user_delete.go:76.14,77.36 1 1
+auth/ent/user_delete.go:78.10,79.13 1 1
+auth/ent/user_delete.go:84.54,85.38 1 0
+auth/ent/user_delete.go:85.38,86.13 1 0
+auth/ent/user_query.go:35.61,38.2 2 24
+auth/ent/user_query.go:41.50,44.2 2 24
+auth/ent/user_query.go:47.52,50.2 2 2
+auth/ent/user_query.go:54.53,57.2 2 0
+auth/ent/user_query.go:60.62,63.2 2 0
+auth/ent/user_query.go:66.46,68.74 2 0
+auth/ent/user_query.go:68.74,69.46 1 0
+auth/ent/user_query.go:69.46,71.4 1 0
+auth/ent/user_query.go:72.3,73.40 2 0
+auth/ent/user_query.go:73.40,75.4 1 0
+auth/ent/user_query.go:76.3,82.20 3 0
+auth/ent/user_query.go:84.2,84.14 1 0
+auth/ent/user_query.go:88.48,90.74 2 0
+auth/ent/user_query.go:90.74,91.46 1 0
+auth/ent/user_query.go:91.46,93.4 1 0
+auth/ent/user_query.go:94.3,95.40 2 0
+auth/ent/user_query.go:95.40,97.4 1 0
+auth/ent/user_query.go:98.3,104.20 3 0
+auth/ent/user_query.go:106.2,106.14 1 0
+auth/ent/user_query.go:111.64,113.16 2 0
+auth/ent/user_query.go:113.16,115.3 1 0
+auth/ent/user_query.go:116.2,116.21 1 0
+auth/ent/user_query.go:116.21,118.3 1 0
+auth/ent/user_query.go:119.2,119.22 1 0
+auth/ent/user_query.go:123.56,125.36 2 0
+auth/ent/user_query.go:125.36,126.13 1 0
+auth/ent/user_query.go:128.2,128.13 1 0
+auth/ent/user_query.go:133.74,135.82 2 0
+auth/ent/user_query.go:135.82,137.3 1 0
+auth/ent/user_query.go:138.2,138.19 1 0
+auth/ent/user_query.go:138.19,141.3 2 0
+auth/ent/user_query.go:142.2,142.20 1 0
+auth/ent/user_query.go:146.59,148.36 2 0
+auth/ent/user_query.go:148.36,149.13 1 0
+auth/ent/user_query.go:151.2,151.11 1 0
+auth/ent/user_query.go:157.63,159.16 2 22
+auth/ent/user_query.go:159.16,161.3 1 0
+auth/ent/user_query.go:162.2,162.20 1 22
+auth/ent/user_query.go:163.9,164.23 1 17
+auth/ent/user_query.go:165.9,166.41 1 5
+auth/ent/user_query.go:167.10,168.44 1 0
+auth/ent/user_query.go:173.55,175.16 2 0
+auth/ent/user_query.go:175.16,176.13 1 0
+auth/ent/user_query.go:178.2,178.13 1 0
+auth/ent/user_query.go:184.73,186.81 2 0
+auth/ent/user_query.go:186.81,188.3 1 0
+auth/ent/user_query.go:189.2,189.18 1 0
+auth/ent/user_query.go:190.9,191.14 1 0
+auth/ent/user_query.go:192.9,193.35 1 0
+auth/ent/user_query.go:194.10,195.38 1 0
+auth/ent/user_query.go:197.2,197.8 1 0
+auth/ent/user_query.go:201.58,203.16 2 0
+auth/ent/user_query.go:203.16,204.13 1 0
+auth/ent/user_query.go:206.2,206.11 1 0
+auth/ent/user_query.go:210.64,212.45 2 27
+auth/ent/user_query.go:212.45,214.3 1 0
+auth/ent/user_query.go:215.2,216.58 2 27
+auth/ent/user_query.go:220.56,222.16 2 0
+auth/ent/user_query.go:222.16,223.13 1 0
+auth/ent/user_query.go:225.2,225.14 1 0
+auth/ent/user_query.go:229.73,230.44 1 0
+auth/ent/user_query.go:230.44,232.3 1 0
+auth/ent/user_query.go:233.2,234.63 2 0
+auth/ent/user_query.go:234.63,236.3 1 0
+auth/ent/user_query.go:237.2,237.17 1 0
+auth/ent/user_query.go:241.57,243.16 2 0
+auth/ent/user_query.go:243.16,244.13 1 0
+auth/ent/user_query.go:246.2,246.12 1 0
+auth/ent/user_query.go:250.62,252.45 2 2
+auth/ent/user_query.go:252.45,254.3 1 0
+auth/ent/user_query.go:255.2,255.78 1 2
+auth/ent/user_query.go:259.54,261.16 2 0
+auth/ent/user_query.go:261.16,262.13 1 0
+auth/ent/user_query.go:264.2,264.14 1 0
+auth/ent/user_query.go:268.63,270.36 2 0
+auth/ent/user_query.go:271.23,272.20 1 0
+auth/ent/user_query.go:273.18,274.60 1 0
+auth/ent/user_query.go:275.10,276.19 1 0
+auth/ent/user_query.go:281.55,283.16 2 0
+auth/ent/user_query.go:283.16,284.13 1 0
+auth/ent/user_query.go:286.2,286.14 1 0
+auth/ent/user_query.go:291.41,292.15 1 0
+auth/ent/user_query.go:292.15,294.3 1 0
+auth/ent/user_query.go:295.2,306.3 1 0
+auth/ent/user_query.go:311.69,313.27 2 3
+auth/ent/user_query.go:313.27,315.3 1 0
+auth/ent/user_query.go:316.2,317.11 2 3
+auth/ent/user_query.go:322.71,324.27 2 0
+auth/ent/user_query.go:324.27,326.3 1 0
+auth/ent/user_query.go:327.2,328.11 2 0
+auth/ent/user_query.go:345.75,352.2 6 0
+auth/ent/user_query.go:366.59,372.2 5 0
+auth/ent/user_query.go:375.66,377.2 1 0
+auth/ent/user_query.go:379.62,380.34 1 30
+auth/ent/user_query.go:380.34,381.19 1 0
+auth/ent/user_query.go:381.19,383.4 1 0
+auth/ent/user_query.go:384.3,384.39 1 0
+auth/ent/user_query.go:384.39,385.48 1 0
+auth/ent/user_query.go:385.48,387.5 1 0
+auth/ent/user_query.go:390.2,390.34 1 30
+auth/ent/user_query.go:390.34,391.27 1 0
+auth/ent/user_query.go:391.27,393.4 1 0
+auth/ent/user_query.go:395.2,395.20 1 30
+auth/ent/user_query.go:395.20,397.17 2 2
+auth/ent/user_query.go:397.17,399.4 1 0
+auth/ent/user_query.go:400.3,400.16 1 2
+auth/ent/user_query.go:402.2,402.12 1 30
+auth/ent/user_query.go:405.87,414.59 2 28
+auth/ent/user_query.go:414.59,416.3 1 27
+auth/ent/user_query.go:417.2,417.60 1 28
+auth/ent/user_query.go:417.60,422.3 4 27
+auth/ent/user_query.go:423.2,423.23 1 28
+auth/ent/user_query.go:423.23,425.3 1 1
+auth/ent/user_query.go:426.2,426.67 1 28
+auth/ent/user_query.go:426.67,428.3 1 0
+auth/ent/user_query.go:429.2,429.21 1 28
+auth/ent/user_query.go:429.21,431.3 1 5
+auth/ent/user_query.go:432.2,432.41 1 23
+auth/ent/user_query.go:432.41,434.18 1 3
+auth/ent/user_query.go:434.18,434.47 1 3
+auth/ent/user_query.go:435.27,435.71 1 2
+auth/ent/user_query.go:435.85,437.4 1 0
+auth/ent/user_query.go:439.2,439.42 1 23
+auth/ent/user_query.go:439.42,441.18 1 0
+auth/ent/user_query.go:441.18,441.49 1 0
+auth/ent/user_query.go:442.28,442.74 1 0
+auth/ent/user_query.go:442.88,444.4 1 0
+auth/ent/user_query.go:446.2,446.19 1 23
+auth/ent/user_query.go:449.137,453.29 4 3
+auth/ent/user_query.go:453.29,456.18 3 3
+auth/ent/user_query.go:456.18,458.4 1 3
+auth/ent/user_query.go:460.2,460.36 1 3
+auth/ent/user_query.go:460.36,468.3 7 3
+auth/ent/user_query.go:469.2,469.48 1 3
+auth/ent/user_query.go:469.48,471.3 1 0
+auth/ent/user_query.go:472.2,472.70 1 3
+auth/ent/user_query.go:472.70,473.78 1 3
+auth/ent/user_query.go:473.78,476.60 3 3
+auth/ent/user_query.go:476.60,478.19 2 2
+auth/ent/user_query.go:478.19,480.6 1 0
+auth/ent/user_query.go:481.5,481.62 1 2
+auth/ent/user_query.go:483.4,483.61 1 3
+auth/ent/user_query.go:483.61,486.29 3 2
+auth/ent/user_query.go:486.29,489.6 2 2
+auth/ent/user_query.go:490.5,491.15 2 0
+auth/ent/user_query.go:495.2,496.16 2 3
+auth/ent/user_query.go:496.16,498.3 1 0
+auth/ent/user_query.go:499.2,499.30 1 3
+auth/ent/user_query.go:499.30,501.10 2 2
+auth/ent/user_query.go:501.10,503.4 1 0
+auth/ent/user_query.go:504.3,504.25 1 2
+auth/ent/user_query.go:504.25,506.4 1 2
+auth/ent/user_query.go:508.2,508.12 1 3
+auth/ent/user_query.go:510.140,513.23 3 0
+auth/ent/user_query.go:513.23,516.18 3 0
+auth/ent/user_query.go:516.18,518.4 1 0
+auth/ent/user_query.go:520.2,521.52 2 0
+auth/ent/user_query.go:521.52,523.3 1 0
+auth/ent/user_query.go:524.2,525.16 2 0
+auth/ent/user_query.go:525.16,527.3 1 0
+auth/ent/user_query.go:528.2,528.30 1 0
+auth/ent/user_query.go:528.30,530.16 2 0
+auth/ent/user_query.go:530.16,532.4 1 0
+auth/ent/user_query.go:533.3,534.10 2 0
+auth/ent/user_query.go:534.10,536.4 1 0
+auth/ent/user_query.go:537.3,537.18 1 0
+auth/ent/user_query.go:539.2,539.12 1 0
+auth/ent/user_query.go:542.65,545.28 3 2
+auth/ent/user_query.go:545.28,547.3 1 0
+auth/ent/user_query.go:548.2,548.51 1 2
+auth/ent/user_query.go:551.54,554.44 3 30
+auth/ent/user_query.go:554.44,556.3 1 0
+auth/ent/user_query.go:556.8,556.27 1 30
+auth/ent/user_query.go:556.27,558.3 1 2
+auth/ent/user_query.go:559.2,559.46 1 30
+auth/ent/user_query.go:559.46,562.25 3 0
+auth/ent/user_query.go:562.25,563.33 1 0
+auth/ent/user_query.go:563.33,565.5 1 0
+auth/ent/user_query.go:568.2,568.38 1 30
+auth/ent/user_query.go:568.38,569.50 1 24
+auth/ent/user_query.go:569.50,570.22 1 24
+auth/ent/user_query.go:570.22,572.5 1 24
+auth/ent/user_query.go:575.2,575.41 1 30
+auth/ent/user_query.go:575.41,577.3 1 24
+auth/ent/user_query.go:578.2,578.44 1 30
+auth/ent/user_query.go:578.44,580.3 1 2
+auth/ent/user_query.go:581.2,581.33 1 30
+auth/ent/user_query.go:581.33,582.46 1 0
+auth/ent/user_query.go:582.46,583.22 1 0
+auth/ent/user_query.go:583.22,585.5 1 0
+auth/ent/user_query.go:588.2,588.14 1 30
+auth/ent/user_query.go:591.66,595.23 4 0
+auth/ent/user_query.go:595.23,597.3 1 0
+auth/ent/user_query.go:598.2,599.19 2 0
+auth/ent/user_query.go:599.19,602.3 2 0
+auth/ent/user_query.go:603.2,603.44 1 0
+auth/ent/user_query.go:603.44,605.3 1 0
+auth/ent/user_query.go:606.2,606.34 1 0
+auth/ent/user_query.go:606.34,608.3 1 0
+auth/ent/user_query.go:609.2,609.29 1 0
+auth/ent/user_query.go:609.29,611.3 1 0
+auth/ent/user_query.go:612.2,612.44 1 0
+auth/ent/user_query.go:612.44,616.3 1 0
+auth/ent/user_query.go:617.2,617.41 1 0
+auth/ent/user_query.go:617.41,619.3 1 0
+auth/ent/user_query.go:620.2,620.17 1 0
+auth/ent/user_query.go:630.70,633.2 2 0
+auth/ent/user_query.go:636.64,638.52 2 0
+auth/ent/user_query.go:638.52,640.3 1 0
+auth/ent/user_query.go:641.2,641.97 1 0
+auth/ent/user_query.go:644.84,647.29 3 0
+auth/ent/user_query.go:647.29,649.3 1 0
+auth/ent/user_query.go:650.2,650.42 1 0
+auth/ent/user_query.go:650.42,652.31 2 0
+auth/ent/user_query.go:652.31,654.4 1 0
+auth/ent/user_query.go:655.3,656.30 2 0
+auth/ent/user_query.go:658.2,659.39 2 0
+auth/ent/user_query.go:659.39,661.3 1 0
+auth/ent/user_query.go:662.2,664.71 3 0
+auth/ent/user_query.go:664.71,666.3 1 0
+auth/ent/user_query.go:667.2,668.31 2 0
+auth/ent/user_query.go:678.67,681.2 2 0
+auth/ent/user_query.go:684.62,686.45 2 0
+auth/ent/user_query.go:686.45,688.3 1 0
+auth/ent/user_query.go:689.2,689.91 1 0
+auth/ent/user_query.go:692.82,695.28 3 0
+auth/ent/user_query.go:695.28,697.3 1 0
+auth/ent/user_query.go:698.2,698.38 1 0
+auth/ent/user_query.go:699.38,700.34 1 0
+auth/ent/user_query.go:701.38,702.40 1 0
+auth/ent/user_query.go:704.2,706.64 3 0
+auth/ent/user_query.go:706.64,708.3 1 0
+auth/ent/user_query.go:709.2,710.31 2 0
+auth/ent/user_update.go:28.63,31.2 2 0
+auth/ent/user_update.go:34.57,37.2 2 0
+auth/ent/user_update.go:40.66,41.14 1 0
+auth/ent/user_update.go:41.14,43.3 1 0
+auth/ent/user_update.go:44.2,44.11 1 0
+auth/ent/user_update.go:48.54,51.2 2 0
+auth/ent/user_update.go:54.63,55.14 1 0
+auth/ent/user_update.go:55.14,57.3 1 0
+auth/ent/user_update.go:58.2,58.11 1 0
+auth/ent/user_update.go:62.57,65.2 2 0
+auth/ent/user_update.go:68.66,69.14 1 0
+auth/ent/user_update.go:69.14,71.3 1 0
+auth/ent/user_update.go:72.2,72.11 1 0
+auth/ent/user_update.go:76.61,79.2 2 0
+auth/ent/user_update.go:82.70,83.14 1 0
+auth/ent/user_update.go:83.14,85.3 1 0
+auth/ent/user_update.go:86.2,86.11 1 0
+auth/ent/user_update.go:90.61,93.2 2 0
+auth/ent/user_update.go:96.61,99.2 2 0
+auth/ent/user_update.go:102.56,104.19 2 0
+auth/ent/user_update.go:104.19,106.3 1 0
+auth/ent/user_update.go:107.2,107.30 1 0
+auth/ent/user_update.go:111.62,114.2 2 0
+auth/ent/user_update.go:117.58,119.19 2 0
+auth/ent/user_update.go:119.19,121.3 1 0
+auth/ent/user_update.go:122.2,122.31 1 0
+auth/ent/user_update.go:126.48,128.2 1 0
+auth/ent/user_update.go:131.48,134.2 2 0
+auth/ent/user_update.go:137.64,140.2 2 0
+auth/ent/user_update.go:143.59,145.19 2 0
+auth/ent/user_update.go:145.19,147.3 1 0
+auth/ent/user_update.go:148.2,148.33 1 0
+auth/ent/user_update.go:152.49,155.2 2 0
+auth/ent/user_update.go:158.65,161.2 2 0
+auth/ent/user_update.go:164.61,166.19 2 0
+auth/ent/user_update.go:166.19,168.3 1 0
+auth/ent/user_update.go:169.2,169.34 1 0
+auth/ent/user_update.go:173.62,174.38 1 0
+auth/ent/user_update.go:174.38,176.3 1 0
+auth/ent/user_update.go:177.2,177.58 1 0
+auth/ent/user_update.go:181.54,183.16 2 0
+auth/ent/user_update.go:183.16,184.13 1 0
+auth/ent/user_update.go:186.2,186.17 1 0
+auth/ent/user_update.go:190.55,193.2 2 0
+auth/ent/user_update.go:196.50,197.37 1 0
+auth/ent/user_update.go:197.37,198.13 1 0
+auth/ent/user_update.go:203.40,204.43 1 0
+auth/ent/user_update.go:204.43,205.41 1 0
+auth/ent/user_update.go:205.41,207.4 1 0
+auth/ent/user_update.go:208.3,209.30 2 0
+auth/ent/user_update.go:211.2,211.12 1 0
+auth/ent/user_update.go:214.71,216.47 2 0
+auth/ent/user_update.go:216.47,217.50 1 0
+auth/ent/user_update.go:217.50,218.22 1 0
+auth/ent/user_update.go:218.22,220.5 1 0
+auth/ent/user_update.go:223.2,223.45 1 0
+auth/ent/user_update.go:223.45,225.3 1 0
+auth/ent/user_update.go:226.2,226.42 1 0
+auth/ent/user_update.go:226.42,228.3 1 0
+auth/ent/user_update.go:229.2,229.45 1 0
+auth/ent/user_update.go:229.45,231.3 1 0
+auth/ent/user_update.go:232.2,232.46 1 0
+auth/ent/user_update.go:232.46,234.3 1 0
+auth/ent/user_update.go:235.2,235.46 1 0
+auth/ent/user_update.go:235.46,237.3 1 0
+auth/ent/user_update.go:238.2,238.32 1 0
+auth/ent/user_update.go:238.32,250.3 2 0
+auth/ent/user_update.go:251.2,251.91 1 0
+auth/ent/user_update.go:251.91,262.27 2 0
+auth/ent/user_update.go:262.27,264.4 1 0
+auth/ent/user_update.go:265.3,265.54 1 0
+auth/ent/user_update.go:267.2,267.53 1 0
+auth/ent/user_update.go:267.53,278.27 2 0
+auth/ent/user_update.go:278.27,280.4 1 0
+auth/ent/user_update.go:281.3,281.50 1 0
+auth/ent/user_update.go:283.2,283.33 1 0
+auth/ent/user_update.go:283.33,295.3 2 0
+auth/ent/user_update.go:296.2,296.93 1 0
+auth/ent/user_update.go:296.93,307.27 2 0
+auth/ent/user_update.go:307.27,309.4 1 0
+auth/ent/user_update.go:310.3,310.54 1 0
+auth/ent/user_update.go:312.2,312.54 1 0
+auth/ent/user_update.go:312.54,323.27 2 0
+auth/ent/user_update.go:323.27,325.4 1 0
+auth/ent/user_update.go:326.3,326.50 1 0
+auth/ent/user_update.go:328.2,328.70 1 0
+auth/ent/user_update.go:328.70,329.49 1 0
+auth/ent/user_update.go:329.49,331.4 1 0
+auth/ent/user_update.go:331.9,331.45 1 0
+auth/ent/user_update.go:331.45,333.4 1 0
+auth/ent/user_update.go:334.3,334.16 1 0
+auth/ent/user_update.go:336.2,337.15 2 0
+auth/ent/user_update.go:349.64,352.2 2 1
+auth/ent/user_update.go:355.73,356.14 1 0
+auth/ent/user_update.go:356.14,358.3 1 0
+auth/ent/user_update.go:359.2,359.12 1 0
+auth/ent/user_update.go:363.61,366.2 2 1
+auth/ent/user_update.go:369.70,370.14 1 0
+auth/ent/user_update.go:370.14,372.3 1 0
+auth/ent/user_update.go:373.2,373.12 1 0
+auth/ent/user_update.go:377.64,380.2 2 3
+auth/ent/user_update.go:383.73,384.14 1 0
+auth/ent/user_update.go:384.14,386.3 1 0
+auth/ent/user_update.go:387.2,387.12 1 0
+auth/ent/user_update.go:391.68,394.2 2 0
+auth/ent/user_update.go:397.77,398.14 1 0
+auth/ent/user_update.go:398.14,400.3 1 0
+auth/ent/user_update.go:401.2,401.12 1 0
+auth/ent/user_update.go:405.68,408.2 2 2
+auth/ent/user_update.go:411.68,414.2 2 8
+auth/ent/user_update.go:417.63,419.19 2 0
+auth/ent/user_update.go:419.19,421.3 1 0
+auth/ent/user_update.go:422.2,422.31 1 0
+auth/ent/user_update.go:426.69,429.2 2 0
+auth/ent/user_update.go:432.65,434.19 2 0
+auth/ent/user_update.go:434.19,436.3 1 0
+auth/ent/user_update.go:437.2,437.32 1 0
+auth/ent/user_update.go:441.52,443.2 1 0
+auth/ent/user_update.go:446.55,449.2 2 0
+auth/ent/user_update.go:452.71,455.2 2 2
+auth/ent/user_update.go:458.66,460.19 2 0
+auth/ent/user_update.go:460.19,462.3 1 0
+auth/ent/user_update.go:463.2,463.34 1 0
+auth/ent/user_update.go:467.56,470.2 2 0
+auth/ent/user_update.go:473.72,476.2 2 0
+auth/ent/user_update.go:479.68,481.19 2 0
+auth/ent/user_update.go:481.19,483.3 1 0
+auth/ent/user_update.go:484.2,484.35 1 0
+auth/ent/user_update.go:488.70,491.2 2 0
+auth/ent/user_update.go:495.81,498.2 2 0
+auth/ent/user_update.go:501.68,502.39 1 13
+auth/ent/user_update.go:502.39,504.3 1 0
+auth/ent/user_update.go:505.2,505.61 1 13
+auth/ent/user_update.go:509.60,511.16 2 0
+auth/ent/user_update.go:511.16,512.13 1 0
+auth/ent/user_update.go:514.2,514.13 1 0
+auth/ent/user_update.go:518.59,521.2 2 12
+auth/ent/user_update.go:524.54,525.38 1 0
+auth/ent/user_update.go:525.38,526.13 1 0
+auth/ent/user_update.go:531.44,532.44 1 13
+auth/ent/user_update.go:532.44,533.41 1 11
+auth/ent/user_update.go:533.41,535.4 1 0
+auth/ent/user_update.go:536.3,537.31 2 11
+auth/ent/user_update.go:539.2,539.12 1 13
+auth/ent/user_update.go:542.81,545.9 3 13
+auth/ent/user_update.go:545.9,547.3 1 0
+auth/ent/user_update.go:548.2,549.43 2 13
+auth/ent/user_update.go:549.43,552.28 3 0
+auth/ent/user_update.go:552.28,553.28 1 0
+auth/ent/user_update.go:553.28,555.5 1 0
+auth/ent/user_update.go:556.4,556.25 1 0
+auth/ent/user_update.go:556.25,558.5 1 0
+auth/ent/user_update.go:561.2,561.48 1 13
+auth/ent/user_update.go:561.48,562.50 1 0
+auth/ent/user_update.go:562.50,563.22 1 0
+auth/ent/user_update.go:563.22,565.5 1 0
+auth/ent/user_update.go:568.2,568.46 1 13
+auth/ent/user_update.go:568.46,570.3 1 1
+auth/ent/user_update.go:571.2,571.43 1 13
+auth/ent/user_update.go:571.43,573.3 1 1
+auth/ent/user_update.go:574.2,574.46 1 13
+auth/ent/user_update.go:574.46,576.3 1 3
+auth/ent/user_update.go:577.2,577.47 1 13
+auth/ent/user_update.go:577.47,579.3 1 0
+auth/ent/user_update.go:580.2,580.47 1 13
+auth/ent/user_update.go:580.47,582.3 1 13
+auth/ent/user_update.go:583.2,583.33 1 13
+auth/ent/user_update.go:583.33,595.3 2 0
+auth/ent/user_update.go:596.2,596.93 1 13
+auth/ent/user_update.go:596.93,607.27 2 2
+auth/ent/user_update.go:607.27,609.4 1 2
+auth/ent/user_update.go:610.3,610.54 1 2
+auth/ent/user_update.go:612.2,612.54 1 13
+auth/ent/user_update.go:612.54,623.27 2 8
+auth/ent/user_update.go:623.27,625.4 1 8
+auth/ent/user_update.go:626.3,626.50 1 8
+auth/ent/user_update.go:628.2,628.34 1 13
+auth/ent/user_update.go:628.34,640.3 2 0
+auth/ent/user_update.go:641.2,641.95 1 13
+auth/ent/user_update.go:641.95,652.27 2 0
+auth/ent/user_update.go:652.27,654.4 1 0
+auth/ent/user_update.go:655.3,655.54 1 0
+auth/ent/user_update.go:657.2,657.55 1 13
+auth/ent/user_update.go:657.55,668.27 2 0
+auth/ent/user_update.go:668.27,670.4 1 0
+auth/ent/user_update.go:671.3,671.50 1 0
+auth/ent/user_update.go:673.2,676.67 4 13
+auth/ent/user_update.go:676.67,677.49 1 0
+auth/ent/user_update.go:677.49,679.4 1 0
+auth/ent/user_update.go:679.9,679.45 1 0
+auth/ent/user_update.go:679.45,681.4 1 0
+auth/ent/user_update.go:682.3,682.18 1 0
+auth/ent/user_update.go:684.2,685.19 2 13
+auth/ent/enttest/enttest.go:35.45,36.26 1 0
+auth/ent/enttest/enttest.go:36.26,38.3 1 0
+auth/ent/enttest/enttest.go:42.62,43.26 1 0
+auth/ent/enttest/enttest.go:43.26,45.3 1 0
+auth/ent/enttest/enttest.go:48.41,50.27 2 6
+auth/ent/enttest/enttest.go:50.27,52.3 1 0
+auth/ent/enttest/enttest.go:53.2,53.10 1 6
+auth/ent/enttest/enttest.go:57.86,60.16 3 6
+auth/ent/enttest/enttest.go:60.16,63.3 2 0
+auth/ent/enttest/enttest.go:64.2,65.10 2 6
+auth/ent/enttest/enttest.go:69.56,74.2 4 0
+auth/ent/enttest/enttest.go:75.59,77.16 2 6
+auth/ent/enttest/enttest.go:77.16,80.3 2 0
+auth/ent/enttest/enttest.go:81.2,81.97 1 6
+auth/ent/enttest/enttest.go:81.97,84.3 2 0
+auth/ent/migrate/migrate.go:41.44,41.72 1 6
+auth/ent/migrate/migrate.go:44.82,46.2 1 0
+auth/ent/migrate/migrate.go:49.105,51.16 2 6
+auth/ent/migrate/migrate.go:51.16,53.3 1 0
+auth/ent/migrate/migrate.go:54.2,54.39 1 6
+auth/ent/migrate/migrate.go:62.96,64.2 1 0
+auth/ent/migrate/schema.go:99.13,103.2 3 1
+auth/ent/role/role.go:52.38,53.25 1 0
+auth/ent/role/role.go:53.25,54.27 1 0
+auth/ent/role/role.go:54.27,56.4 1 0
+auth/ent/role/role.go:58.2,58.14 1 0
+auth/ent/role/role.go:76.52,78.2 1 0
+auth/ent/role/role.go:81.54,83.2 1 0
+auth/ent/role/role.go:86.59,88.2 1 0
+auth/ent/role/role.go:91.59,93.2 1 0
+auth/ent/role/role.go:96.60,97.31 1 0
+auth/ent/role/role.go:97.31,99.3 1 0
+auth/ent/role/role.go:103.70,104.31 1 0
+auth/ent/role/role.go:104.31,106.3 1 0
+auth/ent/role/role.go:108.36,114.2 1 3
+auth/ent/role/where.go:14.35,16.2 1 8
+auth/ent/role/where.go:19.37,21.2 1 0
+auth/ent/role/where.go:24.38,26.2 1 0
+auth/ent/role/where.go:29.41,31.2 1 0
+auth/ent/role/where.go:34.44,36.2 1 0
+auth/ent/role/where.go:39.37,41.2 1 0
+auth/ent/role/where.go:44.38,46.2 1 0
+auth/ent/role/where.go:49.37,51.2 1 0
+auth/ent/role/where.go:54.38,56.2 1 0
+auth/ent/role/where.go:59.44,61.2 1 0
+auth/ent/role/where.go:64.47,66.2 1 0
+auth/ent/role/where.go:69.36,71.2 1 1
+auth/ent/role/where.go:74.44,76.2 1 0
+auth/ent/role/where.go:79.44,81.2 1 0
+auth/ent/role/where.go:84.38,86.2 1 0
+auth/ent/role/where.go:89.39,91.2 1 0
+auth/ent/role/where.go:94.42,96.2 1 0
+auth/ent/role/where.go:99.45,101.2 1 0
+auth/ent/role/where.go:104.38,106.2 1 0
+auth/ent/role/where.go:109.39,111.2 1 0
+auth/ent/role/where.go:114.38,116.2 1 0
+auth/ent/role/where.go:119.39,121.2 1 0
+auth/ent/role/where.go:124.44,126.2 1 0
+auth/ent/role/where.go:129.45,131.2 1 1
+auth/ent/role/where.go:134.45,136.2 1 0
+auth/ent/role/where.go:139.45,141.2 1 0
+auth/ent/role/where.go:144.48,146.2 1 0
+auth/ent/role/where.go:149.46,151.2 1 0
+auth/ent/role/where.go:154.47,156.2 1 0
+auth/ent/role/where.go:159.50,161.2 1 0
+auth/ent/role/where.go:164.53,166.2 1 0
+auth/ent/role/where.go:169.46,171.2 1 0
+auth/ent/role/where.go:174.47,176.2 1 0
+auth/ent/role/where.go:179.46,181.2 1 0
+auth/ent/role/where.go:184.47,186.2 1 0
+auth/ent/role/where.go:189.46,191.2 1 0
+auth/ent/role/where.go:194.47,196.2 1 0
+auth/ent/role/where.go:199.50,201.2 1 0
+auth/ent/role/where.go:204.53,206.2 1 0
+auth/ent/role/where.go:209.46,211.2 1 0
+auth/ent/role/where.go:214.47,216.2 1 0
+auth/ent/role/where.go:219.46,221.2 1 0
+auth/ent/role/where.go:224.47,226.2 1 0
+auth/ent/role/where.go:229.32,230.46 1 0
+auth/ent/role/where.go:230.46,236.3 2 0
+auth/ent/role/where.go:240.59,241.46 1 3
+auth/ent/role/where.go:241.46,243.60 2 3
+auth/ent/role/where.go:243.60,244.28 1 3
+auth/ent/role/where.go:244.28,246.5 1 3
+auth/ent/role/where.go:252.55,254.2 1 0
+auth/ent/role/where.go:257.54,259.2 1 0
+auth/ent/role/where.go:262.43,264.2 1 0
+auth/ent/runtime/runtime.go:16.13,71.2 31 1
+auth/ent/schema/role.go:18.34,21.30 1 1
+auth/ent/schema/role.go:21.30,23.5 1 34
+auth/ent/schema/role.go:35.32,40.2 1 0
+auth/ent/schema/token.go:18.35,21.30 1 1
+auth/ent/schema/token.go:21.30,23.5 1 13
+auth/ent/schema/token.go:39.33,46.2 1 0
+auth/ent/schema/user.go:20.34,23.30 1 1
+auth/ent/schema/user.go:23.30,25.5 1 38
+auth/ent/schema/user.go:38.32,43.2 1 0
+auth/ent/schema/user.go:46.32,50.2 1 1
+auth/ent/schema/user.go:53.30,54.44 1 1
+auth/ent/schema/user.go:54.44,55.86 1 60
+auth/ent/schema/user.go:55.86,56.47 1 60
+auth/ent/schema/user.go:56.47,58.19 2 47
+auth/ent/schema/user.go:58.19,60.6 1 0
+auth/ent/schema/user.go:61.5,61.41 1 47
+auth/ent/schema/user.go:63.4,63.30 1 60
+auth/ent/token/token.go:61.38,62.25 1 0
+auth/ent/token/token.go:62.25,63.27 1 0
+auth/ent/token/token.go:63.27,65.4 1 0
+auth/ent/token/token.go:67.2,67.29 1 0
+auth/ent/token/token.go:67.29,68.31 1 0
+auth/ent/token/token.go:68.31,70.4 1 0
+auth/ent/token/token.go:72.2,72.14 1 0
+auth/ent/token/token.go:97.35,99.2 1 2
+auth/ent/token/token.go:102.38,103.15 1 13
+auth/ent/token/token.go:104.31,105.13 1 13
+auth/ent/token/token.go:106.10,107.75 1 0
+auth/ent/token/token.go:115.52,117.2 1 0
+auth/ent/token/token.go:120.55,122.2 1 0
+auth/ent/token/token.go:125.54,127.2 1 0
+auth/ent/token/token.go:130.59,132.2 1 0
+auth/ent/token/token.go:135.57,137.2 1 0
+auth/ent/token/token.go:140.59,142.2 1 0
+auth/ent/token/token.go:145.59,147.2 1 0
+auth/ent/token/token.go:150.73,151.31 1 0
+auth/ent/token/token.go:151.31,153.3 1 0
+auth/ent/token/token.go:155.35,161.2 1 3
+auth/ent/token/where.go:14.36,16.2 1 4
+auth/ent/token/where.go:19.38,21.2 1 0
+auth/ent/token/where.go:24.39,26.2 1 0
+auth/ent/token/where.go:29.42,31.2 1 0
+auth/ent/token/where.go:34.45,36.2 1 0
+auth/ent/token/where.go:39.38,41.2 1 0
+auth/ent/token/where.go:44.39,46.2 1 0
+auth/ent/token/where.go:49.38,51.2 1 0
+auth/ent/token/where.go:54.39,56.2 1 0
+auth/ent/token/where.go:59.45,61.2 1 0
+auth/ent/token/where.go:64.48,66.2 1 0
+auth/ent/token/where.go:69.38,71.2 1 6
+auth/ent/token/where.go:74.45,76.2 1 0
+auth/ent/token/where.go:79.38,81.2 1 4
+auth/ent/token/where.go:84.45,86.2 1 0
+auth/ent/token/where.go:89.45,91.2 1 0
+auth/ent/token/where.go:94.40,96.2 1 0
+auth/ent/token/where.go:99.41,101.2 1 0
+auth/ent/token/where.go:104.44,106.2 1 0
+auth/ent/token/where.go:109.47,111.2 1 0
+auth/ent/token/where.go:114.40,116.2 1 0
+auth/ent/token/where.go:119.41,121.2 1 0
+auth/ent/token/where.go:124.40,126.2 1 0
+auth/ent/token/where.go:129.41,131.2 1 0
+auth/ent/token/where.go:134.46,136.2 1 0
+auth/ent/token/where.go:139.47,141.2 1 0
+auth/ent/token/where.go:144.47,146.2 1 0
+auth/ent/token/where.go:149.47,151.2 1 0
+auth/ent/token/where.go:154.50,156.2 1 0
+auth/ent/token/where.go:159.37,161.2 1 0
+auth/ent/token/where.go:164.38,166.2 1 0
+auth/ent/token/where.go:169.41,171.2 1 0
+auth/ent/token/where.go:174.44,176.2 1 0
+auth/ent/token/where.go:179.47,181.2 1 0
+auth/ent/token/where.go:184.48,186.2 1 0
+auth/ent/token/where.go:189.51,191.2 1 0
+auth/ent/token/where.go:194.54,196.2 1 0
+auth/ent/token/where.go:199.47,201.2 1 2
+auth/ent/token/where.go:204.48,206.2 1 0
+auth/ent/token/where.go:209.47,211.2 1 1
+auth/ent/token/where.go:214.48,216.2 1 0
+auth/ent/token/where.go:219.40,221.2 1 3
+auth/ent/token/where.go:224.41,226.2 1 0
+auth/ent/token/where.go:229.47,231.2 1 0
+auth/ent/token/where.go:234.48,236.2 1 0
+auth/ent/token/where.go:239.51,241.2 1 0
+auth/ent/token/where.go:244.54,246.2 1 0
+auth/ent/token/where.go:249.47,251.2 1 0
+auth/ent/token/where.go:254.48,256.2 1 0
+auth/ent/token/where.go:259.47,261.2 1 0
+auth/ent/token/where.go:264.48,266.2 1 0
+auth/ent/token/where.go:269.47,271.2 1 0
+auth/ent/token/where.go:274.48,276.2 1 0
+auth/ent/token/where.go:279.51,281.2 1 0
+auth/ent/token/where.go:284.54,286.2 1 0
+auth/ent/token/where.go:289.47,291.2 1 0
+auth/ent/token/where.go:294.48,296.2 1 0
+auth/ent/token/where.go:299.47,301.2 1 0
+auth/ent/token/where.go:304.48,306.2 1 0
+auth/ent/token/where.go:309.32,310.47 1 0
+auth/ent/token/where.go:310.47,316.3 2 0
+auth/ent/token/where.go:320.59,321.47 1 3
+auth/ent/token/where.go:321.47,323.60 2 3
+auth/ent/token/where.go:323.60,324.28 1 3
+auth/ent/token/where.go:324.28,326.5 1 3
+auth/ent/token/where.go:332.57,334.2 1 0
+auth/ent/token/where.go:337.56,339.2 1 1
+auth/ent/token/where.go:342.45,344.2 1 0
+auth/ent/user/user.go:65.38,66.25 1 0
+auth/ent/user/user.go:66.25,67.27 1 0
+auth/ent/user/user.go:67.27,69.4 1 0
+auth/ent/user/user.go:71.2,71.14 1 0
+auth/ent/user/user.go:95.52,97.2 1 0
+auth/ent/user/user.go:100.58,102.2 1 0
+auth/ent/user/user.go:105.55,107.2 1 0
+auth/ent/user/user.go:110.58,112.2 1 0
+auth/ent/user/user.go:115.59,117.2 1 0
+auth/ent/user/user.go:120.59,122.2 1 0
+auth/ent/user/user.go:125.60,126.31 1 0
+auth/ent/user/user.go:126.31,128.3 1 0
+auth/ent/user/user.go:132.70,133.31 1 0
+auth/ent/user/user.go:133.31,135.3 1 0
+auth/ent/user/user.go:139.61,140.31 1 0
+auth/ent/user/user.go:140.31,142.3 1 0
+auth/ent/user/user.go:146.71,147.31 1 0
+auth/ent/user/user.go:147.31,149.3 1 0
+auth/ent/user/user.go:151.36,157.2 1 1
+auth/ent/user/user.go:158.37,164.2 1 0
+auth/ent/user/where.go:14.35,16.2 1 18
+auth/ent/user/where.go:19.37,21.2 1 0
+auth/ent/user/where.go:24.38,26.2 1 0
+auth/ent/user/where.go:29.41,31.2 1 0
+auth/ent/user/where.go:34.44,36.2 1 0
+auth/ent/user/where.go:39.37,41.2 1 0
+auth/ent/user/where.go:44.38,46.2 1 0
+auth/ent/user/where.go:49.37,51.2 1 0
+auth/ent/user/where.go:54.38,56.2 1 0
+auth/ent/user/where.go:59.44,61.2 1 0
+auth/ent/user/where.go:64.47,66.2 1 0
+auth/ent/user/where.go:69.40,71.2 1 9
+auth/ent/user/where.go:74.37,76.2 1 2
+auth/ent/user/where.go:79.40,81.2 1 0
+auth/ent/user/where.go:84.44,86.2 1 0
+auth/ent/user/where.go:89.44,91.2 1 0
+auth/ent/user/where.go:94.42,96.2 1 0
+auth/ent/user/where.go:99.43,101.2 1 0
+auth/ent/user/where.go:104.46,106.2 1 0
+auth/ent/user/where.go:109.49,111.2 1 0
+auth/ent/user/where.go:114.42,116.2 1 0
+auth/ent/user/where.go:119.43,121.2 1 0
+auth/ent/user/where.go:124.42,126.2 1 0
+auth/ent/user/where.go:129.43,131.2 1 0
+auth/ent/user/where.go:134.48,136.2 1 1
+auth/ent/user/where.go:139.49,141.2 1 0
+auth/ent/user/where.go:144.49,146.2 1 0
+auth/ent/user/where.go:149.49,151.2 1 0
+auth/ent/user/where.go:154.52,156.2 1 0
+auth/ent/user/where.go:159.39,161.2 1 0
+auth/ent/user/where.go:164.40,166.2 1 0
+auth/ent/user/where.go:169.43,171.2 1 0
+auth/ent/user/where.go:174.46,176.2 1 0
+auth/ent/user/where.go:179.39,181.2 1 0
+auth/ent/user/where.go:184.40,186.2 1 0
+auth/ent/user/where.go:189.39,191.2 1 0
+auth/ent/user/where.go:194.40,196.2 1 0
+auth/ent/user/where.go:199.45,201.2 1 1
+auth/ent/user/where.go:204.46,206.2 1 0
+auth/ent/user/where.go:209.46,211.2 1 0
+auth/ent/user/where.go:214.46,216.2 1 0
+auth/ent/user/where.go:219.49,221.2 1 0
+auth/ent/user/where.go:224.42,226.2 1 0
+auth/ent/user/where.go:229.43,231.2 1 0
+auth/ent/user/where.go:234.46,236.2 1 0
+auth/ent/user/where.go:239.49,241.2 1 0
+auth/ent/user/where.go:244.42,246.2 1 0
+auth/ent/user/where.go:249.43,251.2 1 0
+auth/ent/user/where.go:254.42,256.2 1 0
+auth/ent/user/where.go:259.43,261.2 1 0
+auth/ent/user/where.go:264.48,266.2 1 0
+auth/ent/user/where.go:269.49,271.2 1 0
+auth/ent/user/where.go:274.49,276.2 1 0
+auth/ent/user/where.go:279.49,281.2 1 0
+auth/ent/user/where.go:284.52,286.2 1 0
+auth/ent/user/where.go:289.46,291.2 1 0
+auth/ent/user/where.go:294.47,296.2 1 0
+auth/ent/user/where.go:299.50,301.2 1 0
+auth/ent/user/where.go:304.53,306.2 1 0
+auth/ent/user/where.go:309.46,311.2 1 0
+auth/ent/user/where.go:314.47,316.2 1 0
+auth/ent/user/where.go:319.46,321.2 1 0
+auth/ent/user/where.go:324.47,326.2 1 0
+auth/ent/user/where.go:329.46,331.2 1 0
+auth/ent/user/where.go:334.47,336.2 1 0
+auth/ent/user/where.go:339.50,341.2 1 0
+auth/ent/user/where.go:344.53,346.2 1 0
+auth/ent/user/where.go:349.46,351.2 1 0
+auth/ent/user/where.go:354.47,356.2 1 0
+auth/ent/user/where.go:359.46,361.2 1 0
+auth/ent/user/where.go:364.47,366.2 1 0
+auth/ent/user/where.go:369.32,370.46 1 0
+auth/ent/user/where.go:370.46,376.3 2 0
+auth/ent/user/where.go:380.59,381.46 1 1
+auth/ent/user/where.go:381.46,383.60 2 1
+auth/ent/user/where.go:383.60,384.28 1 1
+auth/ent/user/where.go:384.28,386.5 1 1
+auth/ent/user/where.go:392.33,393.46 1 0
+auth/ent/user/where.go:393.46,399.3 2 0
+auth/ent/user/where.go:403.61,404.46 1 0
+auth/ent/user/where.go:404.46,406.60 2 0
+auth/ent/user/where.go:406.60,407.28 1 0
+auth/ent/user/where.go:407.28,409.5 1 0
+auth/ent/user/where.go:415.55,417.2 1 0
+auth/ent/user/where.go:420.54,422.2 1 1
+auth/ent/user/where.go:425.43,427.2 1 0
+auth/internal/repository/role.go:375.60,377.2 1 1
+auth/internal/repository/role.go:379.89,385.2 1 27
+auth/internal/repository/role.go:387.85,389.2 1 5
+auth/internal/repository/role.go:391.89,393.2 1 1
+auth/internal/repository/role.go:395.89,401.2 1 1
+auth/internal/repository/role.go:403.71,405.2 1 1
+auth/internal/repository/role.go:407.92,412.2 1 1
+auth/internal/repository/role.go:414.66,416.2 1 2
+auth/internal/repository/role.go:418.94,422.2 1 1
+auth/internal/repository/role.go:424.97,426.16 2 1
+auth/internal/repository/role.go:426.16,428.3 1 0
+auth/internal/repository/role.go:430.2,431.41 2 1
+auth/internal/repository/role.go:431.41,432.22 1 2
+auth/internal/repository/role.go:432.22,434.4 1 1
+auth/internal/repository/role.go:437.2,443.12 3 1
+auth/internal/repository/role.go:446.95,448.16 2 0
+auth/internal/repository/role.go:448.16,450.3 1 0
+auth/internal/repository/role.go:451.2,451.34 1 0
+auth/internal/repository/role.go:454.90,458.2 1 1
+auth/internal/repository/role.go:460.95,464.2 1 0
+auth/internal/repository/role.go:466.98,471.16 2 1
+auth/internal/repository/role.go:471.16,473.3 1 0
+auth/internal/repository/role.go:474.2,474.34 1 1
+auth/internal/repository/role.go:477.89,481.2 1 1
+auth/internal/repository/role.go:483.100,487.2 1 3
+auth/internal/repository/role.go:489.93,493.2 1 3
+auth/internal/repository/role.go:495.95,499.2 1 1
+auth/internal/repository/token.go:93.62,95.2 1 1
+auth/internal/repository/token.go:98.142,106.2 1 9
+auth/internal/repository/token.go:109.99,114.2 1 3
+auth/internal/repository/token.go:117.86,127.16 2 3
+auth/internal/repository/token.go:127.16,129.3 1 0
+auth/internal/repository/token.go:131.2,131.19 1 3
+auth/internal/repository/token.go:131.19,133.3 1 2
+auth/internal/repository/token.go:135.2,135.12 1 1
+auth/internal/repository/token.go:139.74,150.2 2 1
+auth/internal/repository/token.go:153.108,162.2 1 2
+auth/internal/repository/token.go:165.89,175.2 2 1
+auth/internal/repository/user.go:354.60,356.2 1 1
+auth/internal/repository/user.go:359.86,366.2 1 24
+auth/internal/repository/user.go:369.85,371.2 1 5
+auth/internal/repository/user.go:374.97,376.2 1 2
+auth/internal/repository/user.go:379.91,381.2 1 2
+auth/internal/repository/user.go:384.86,391.2 1 1
+auth/internal/repository/user.go:394.71,396.2 1 2
+auth/internal/repository/user.go:398.92,403.2 1 2
+auth/internal/repository/user.go:406.66,408.2 1 2
+auth/internal/repository/user.go:411.84,415.2 1 5
+auth/internal/repository/user.go:418.87,422.2 1 1
+auth/internal/repository/user.go:425.92,430.16 2 3
+auth/internal/repository/user.go:430.16,432.3 1 0
+auth/internal/repository/user.go:433.2,433.27 1 3
+auth/internal/repository/user.go:437.89,446.2 1 1
+auth/internal/repository/user.go:449.96,451.16 2 1
+auth/internal/repository/user.go:451.16,453.3 1 0
+auth/internal/repository/user.go:455.2,458.12 1 1
+auth/internal/repository/user.go:463.98,467.2 1 1
+auth/internal/repository/user.go:470.93,472.16 2 5
+auth/internal/repository/user.go:472.16,474.3 1 0
+auth/internal/repository/user.go:475.2,477.28 2 5
+auth/internal/repository/user.go:481.92,483.16 2 2
+auth/internal/repository/user.go:483.16,484.26 1 1
+auth/internal/repository/user.go:484.26,486.4 1 1
+auth/internal/repository/user.go:487.3,487.13 1 0
+auth/internal/repository/user.go:490.2,490.70 1 1
diff --git a/pkg/go.mod b/pkg/go.mod
index 563f14c..ee20eb3 100644
--- a/pkg/go.mod
+++ b/pkg/go.mod
@@ -2,14 +2,20 @@ module pkg
go 1.21
-require github.com/spf13/viper v1.19.0
+require (
+ github.com/spf13/viper v1.19.0
+ github.com/stretchr/testify v1.9.0
+)
require (
+ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
+ github.com/google/go-cmp v0.6.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
+ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
@@ -20,8 +26,9 @@ require (
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
- golang.org/x/sys v0.18.0 // indirect
- golang.org/x/text v0.14.0 // indirect
+ golang.org/x/sys v0.20.0 // indirect
+ golang.org/x/text v0.15.0 // indirect
+ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/pkg/go.sum b/pkg/go.sum
index 2b668ad..0c89791 100644
--- a/pkg/go.sum
+++ b/pkg/go.sum
@@ -1,9 +1,14 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
+github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
@@ -11,6 +16,8 @@ github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
+github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
@@ -33,6 +40,7 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
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.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
@@ -42,11 +50,10 @@ go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
-golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
-golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
-golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
+golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
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/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/qodana.yaml b/qodana.yaml
new file mode 100644
index 0000000..215d808
--- /dev/null
+++ b/qodana.yaml
@@ -0,0 +1,29 @@
+#-------------------------------------------------------------------------------#
+# Qodana analysis is configured by qodana.yaml file #
+# https://www.jetbrains.com/help/qodana/qodana-yaml.html #
+#-------------------------------------------------------------------------------#
+version: "1.0"
+
+#Specify inspection profile for code analysis
+profile:
+ name: qodana.starter
+
+#Enable inspections
+#include:
+# - name:
+
+#Disable inspections
+#exclude:
+# - name:
+# paths:
+# -
+
+#Execute shell command before Qodana execution (Applied in CI/CD pipeline)
+#bootstrap: sh ./prepare-qodana.sh
+
+#Install IDE plugins before Qodana execution (Applied in CI/CD pipeline)
+#plugins:
+# - id: #(plugin id can be found at https://plugins.jetbrains.com)
+
+#Specify Qodana linter for analysis (Applied in CI/CD pipeline)
+linter: jetbrains/qodana-go:latest
diff --git a/scripts/generate_certs.sh b/scripts/generate_certs.sh
index 4463be8..d37211a 100644
--- a/scripts/generate_certs.sh
+++ b/scripts/generate_certs.sh
@@ -30,4 +30,4 @@ openssl x509 -req -in $CERT_DIR/client-req.pem -days 360 -CA $CERT_DIR/ca-cert.p
echo "Client's signed certificate generated"
-echo "All certificates have been generated in $CERT_DIR"
\ No newline at end of file
+echo "All certificates have been generated in $CERT_DIR"
diff --git a/web/.eslintrc.js b/web/.eslintrc.js
new file mode 100644
index 0000000..0cff6df
--- /dev/null
+++ b/web/.eslintrc.js
@@ -0,0 +1,16 @@
+module.exports = {
+ root: true,
+ parser: "@typescript-eslint/parser",
+ plugins: ["@typescript-eslint"],
+ extends: [
+ "eslint:recommended",
+ "plugin:@typescript-eslint/recommended",
+ "next/core-web-vitals",
+ ],
+ env: {
+ browser: true,
+ node: true,
+ es6: true,
+ },
+ rules: {},
+};
diff --git a/web/.eslintrc.json b/web/.eslintrc.json
deleted file mode 100644
index bffb357..0000000
--- a/web/.eslintrc.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "extends": "next/core-web-vitals"
-}
diff --git a/web/components.json b/web/components.json
index b0af43f..e5972ab 100644
--- a/web/components.json
+++ b/web/components.json
@@ -13,4 +13,4 @@
"utils": "@/lib/utils",
"components": "@/components"
}
-}
\ No newline at end of file
+}
diff --git a/web/components/ui/avatar.tsx b/web/components/ui/avatar.tsx
index 51e507b..09cd14d 100644
--- a/web/components/ui/avatar.tsx
+++ b/web/components/ui/avatar.tsx
@@ -1,9 +1,9 @@
-"use client"
+"use client";
-import * as React from "react"
-import * as AvatarPrimitive from "@radix-ui/react-avatar"
+import * as React from "react";
+import * as AvatarPrimitive from "@radix-ui/react-avatar";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
const Avatar = React.forwardRef<
React.ElementRef,
@@ -13,12 +13,12 @@ const Avatar = React.forwardRef<
ref={ref}
className={cn(
"relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",
- className
+ className,
)}
{...props}
/>
-))
-Avatar.displayName = AvatarPrimitive.Root.displayName
+));
+Avatar.displayName = AvatarPrimitive.Root.displayName;
const AvatarImage = React.forwardRef<
React.ElementRef,
@@ -29,8 +29,8 @@ const AvatarImage = React.forwardRef<
className={cn("aspect-square h-full w-full", className)}
{...props}
/>
-))
-AvatarImage.displayName = AvatarPrimitive.Image.displayName
+));
+AvatarImage.displayName = AvatarPrimitive.Image.displayName;
const AvatarFallback = React.forwardRef<
React.ElementRef,
@@ -40,11 +40,11 @@ const AvatarFallback = React.forwardRef<
ref={ref}
className={cn(
"flex h-full w-full items-center justify-center rounded-full bg-muted",
- className
+ className,
)}
{...props}
/>
-))
-AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName
+));
+AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;
-export { Avatar, AvatarImage, AvatarFallback }
+export { Avatar, AvatarImage, AvatarFallback };
diff --git a/web/components/ui/badge.tsx b/web/components/ui/badge.tsx
index f000e3e..d3d5d60 100644
--- a/web/components/ui/badge.tsx
+++ b/web/components/ui/badge.tsx
@@ -1,7 +1,7 @@
-import * as React from "react"
-import { cva, type VariantProps } from "class-variance-authority"
+import * as React from "react";
+import { cva, type VariantProps } from "class-variance-authority";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
const badgeVariants = cva(
"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
@@ -20,8 +20,8 @@ const badgeVariants = cva(
defaultVariants: {
variant: "default",
},
- }
-)
+ },
+);
export interface BadgeProps
extends React.HTMLAttributes,
@@ -30,7 +30,7 @@ export interface BadgeProps
function Badge({ className, variant, ...props }: BadgeProps) {
return (
- )
+ );
}
-export { Badge, badgeVariants }
+export { Badge, badgeVariants };
diff --git a/web/components/ui/breadcrumb.tsx b/web/components/ui/breadcrumb.tsx
index 71a5c32..6934f83 100644
--- a/web/components/ui/breadcrumb.tsx
+++ b/web/components/ui/breadcrumb.tsx
@@ -1,16 +1,16 @@
-import * as React from "react"
-import { Slot } from "@radix-ui/react-slot"
-import { ChevronRight, MoreHorizontal } from "lucide-react"
+import * as React from "react";
+import { Slot } from "@radix-ui/react-slot";
+import { ChevronRight, MoreHorizontal } from "lucide-react";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
const Breadcrumb = React.forwardRef<
HTMLElement,
React.ComponentPropsWithoutRef<"nav"> & {
- separator?: React.ReactNode
+ separator?: React.ReactNode;
}
->(({ ...props }, ref) => )
-Breadcrumb.displayName = "Breadcrumb"
+>(({ ...props }, ref) => );
+Breadcrumb.displayName = "Breadcrumb";
const BreadcrumbList = React.forwardRef<
HTMLOListElement,
@@ -20,12 +20,12 @@ const BreadcrumbList = React.forwardRef<
ref={ref}
className={cn(
"flex flex-wrap items-center gap-1.5 break-words text-sm text-muted-foreground sm:gap-2.5",
- className
+ className,
)}
{...props}
/>
-))
-BreadcrumbList.displayName = "BreadcrumbList"
+));
+BreadcrumbList.displayName = "BreadcrumbList";
const BreadcrumbItem = React.forwardRef<
HTMLLIElement,
@@ -36,16 +36,16 @@ const BreadcrumbItem = React.forwardRef<
className={cn("inline-flex items-center gap-1.5", className)}
{...props}
/>
-))
-BreadcrumbItem.displayName = "BreadcrumbItem"
+));
+BreadcrumbItem.displayName = "BreadcrumbItem";
const BreadcrumbLink = React.forwardRef<
HTMLAnchorElement,
React.ComponentPropsWithoutRef<"a"> & {
- asChild?: boolean
+ asChild?: boolean;
}
>(({ asChild, className, ...props }, ref) => {
- const Comp = asChild ? Slot : "a"
+ const Comp = asChild ? Slot : "a";
return (
- )
-})
-BreadcrumbLink.displayName = "BreadcrumbLink"
+ );
+});
+BreadcrumbLink.displayName = "BreadcrumbLink";
const BreadcrumbPage = React.forwardRef<
HTMLSpanElement,
@@ -69,8 +69,8 @@ const BreadcrumbPage = React.forwardRef<
className={cn("font-normal text-foreground", className)}
{...props}
/>
-))
-BreadcrumbPage.displayName = "BreadcrumbPage"
+));
+BreadcrumbPage.displayName = "BreadcrumbPage";
const BreadcrumbSeparator = ({
children,
@@ -85,8 +85,8 @@ const BreadcrumbSeparator = ({
>
{children ?? }
-)
-BreadcrumbSeparator.displayName = "BreadcrumbSeparator"
+);
+BreadcrumbSeparator.displayName = "BreadcrumbSeparator";
const BreadcrumbEllipsis = ({
className,
@@ -101,8 +101,8 @@ const BreadcrumbEllipsis = ({
More
-)
-BreadcrumbEllipsis.displayName = "BreadcrumbElipssis"
+);
+BreadcrumbEllipsis.displayName = "BreadcrumbElipssis";
export {
Breadcrumb,
@@ -112,4 +112,4 @@ export {
BreadcrumbPage,
BreadcrumbSeparator,
BreadcrumbEllipsis,
-}
+};
diff --git a/web/components/ui/button.tsx b/web/components/ui/button.tsx
index 0ba4277..57c9fe4 100644
--- a/web/components/ui/button.tsx
+++ b/web/components/ui/button.tsx
@@ -1,8 +1,8 @@
-import * as React from "react"
-import { Slot } from "@radix-ui/react-slot"
-import { cva, type VariantProps } from "class-variance-authority"
+import * as React from "react";
+import { Slot } from "@radix-ui/react-slot";
+import { cva, type VariantProps } from "class-variance-authority";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
const buttonVariants = cva(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
@@ -30,27 +30,27 @@ const buttonVariants = cva(
variant: "default",
size: "default",
},
- }
-)
+ },
+);
export interface ButtonProps
extends React.ButtonHTMLAttributes,
VariantProps {
- asChild?: boolean
+ asChild?: boolean;
}
const Button = React.forwardRef(
({ className, variant, size, asChild = false, ...props }, ref) => {
- const Comp = asChild ? Slot : "button"
+ const Comp = asChild ? Slot : "button";
return (
- )
- }
-)
-Button.displayName = "Button"
+ );
+ },
+);
+Button.displayName = "Button";
-export { Button, buttonVariants }
+export { Button, buttonVariants };
diff --git a/web/components/ui/card.tsx b/web/components/ui/card.tsx
index afa13ec..dc3b01d 100644
--- a/web/components/ui/card.tsx
+++ b/web/components/ui/card.tsx
@@ -1,6 +1,6 @@
-import * as React from "react"
+import * as React from "react";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
const Card = React.forwardRef<
HTMLDivElement,
@@ -10,12 +10,12 @@ const Card = React.forwardRef<
ref={ref}
className={cn(
"rounded-lg border bg-card text-card-foreground shadow-sm",
- className
+ className,
)}
{...props}
/>
-))
-Card.displayName = "Card"
+));
+Card.displayName = "Card";
const CardHeader = React.forwardRef<
HTMLDivElement,
@@ -26,8 +26,8 @@ const CardHeader = React.forwardRef<
className={cn("flex flex-col space-y-1.5 p-6", className)}
{...props}
/>
-))
-CardHeader.displayName = "CardHeader"
+));
+CardHeader.displayName = "CardHeader";
const CardTitle = React.forwardRef<
HTMLParagraphElement,
@@ -37,12 +37,12 @@ const CardTitle = React.forwardRef<
ref={ref}
className={cn(
"text-2xl font-semibold leading-none tracking-tight",
- className
+ className,
)}
{...props}
/>
-))
-CardTitle.displayName = "CardTitle"
+));
+CardTitle.displayName = "CardTitle";
const CardDescription = React.forwardRef<
HTMLParagraphElement,
@@ -53,16 +53,16 @@ const CardDescription = React.forwardRef<
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
-))
-CardDescription.displayName = "CardDescription"
+));
+CardDescription.displayName = "CardDescription";
const CardContent = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes
>(({ className, ...props }, ref) => (
-))
-CardContent.displayName = "CardContent"
+));
+CardContent.displayName = "CardContent";
const CardFooter = React.forwardRef<
HTMLDivElement,
@@ -73,7 +73,14 @@ const CardFooter = React.forwardRef<
className={cn("flex items-center p-6 pt-0", className)}
{...props}
/>
-))
-CardFooter.displayName = "CardFooter"
+));
+CardFooter.displayName = "CardFooter";
-export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
+export {
+ Card,
+ CardHeader,
+ CardFooter,
+ CardTitle,
+ CardDescription,
+ CardContent,
+};
diff --git a/web/components/ui/checkbox.tsx b/web/components/ui/checkbox.tsx
index df61a13..5985e3c 100644
--- a/web/components/ui/checkbox.tsx
+++ b/web/components/ui/checkbox.tsx
@@ -1,10 +1,10 @@
-"use client"
+"use client";
-import * as React from "react"
-import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
-import { Check } from "lucide-react"
+import * as React from "react";
+import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
+import { Check } from "lucide-react";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
const Checkbox = React.forwardRef<
React.ElementRef,
@@ -14,7 +14,7 @@ const Checkbox = React.forwardRef<
ref={ref}
className={cn(
"peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
- className
+ className,
)}
{...props}
>
@@ -24,7 +24,7 @@ const Checkbox = React.forwardRef<
-))
-Checkbox.displayName = CheckboxPrimitive.Root.displayName
+));
+Checkbox.displayName = CheckboxPrimitive.Root.displayName;
-export { Checkbox }
+export { Checkbox };
diff --git a/web/components/ui/dropdown-menu.tsx b/web/components/ui/dropdown-menu.tsx
index f69a0d6..3a0c7fe 100644
--- a/web/components/ui/dropdown-menu.tsx
+++ b/web/components/ui/dropdown-menu.tsx
@@ -1,27 +1,27 @@
-"use client"
+"use client";
-import * as React from "react"
-import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
-import { Check, ChevronRight, Circle } from "lucide-react"
+import * as React from "react";
+import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
+import { Check, ChevronRight, Circle } from "lucide-react";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
-const DropdownMenu = DropdownMenuPrimitive.Root
+const DropdownMenu = DropdownMenuPrimitive.Root;
-const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger
+const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
-const DropdownMenuGroup = DropdownMenuPrimitive.Group
+const DropdownMenuGroup = DropdownMenuPrimitive.Group;
-const DropdownMenuPortal = DropdownMenuPrimitive.Portal
+const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
-const DropdownMenuSub = DropdownMenuPrimitive.Sub
+const DropdownMenuSub = DropdownMenuPrimitive.Sub;
-const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup
+const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
const DropdownMenuSubTrigger = React.forwardRef<
React.ElementRef,
React.ComponentPropsWithoutRef & {
- inset?: boolean
+ inset?: boolean;
}
>(({ className, inset, children, ...props }, ref) => (
{children}
-))
+));
DropdownMenuSubTrigger.displayName =
- DropdownMenuPrimitive.SubTrigger.displayName
+ DropdownMenuPrimitive.SubTrigger.displayName;
const DropdownMenuSubContent = React.forwardRef<
React.ElementRef,
@@ -48,13 +48,13 @@ const DropdownMenuSubContent = React.forwardRef<
ref={ref}
className={cn(
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
- className
+ className,
)}
{...props}
/>
-))
+));
DropdownMenuSubContent.displayName =
- DropdownMenuPrimitive.SubContent.displayName
+ DropdownMenuPrimitive.SubContent.displayName;
const DropdownMenuContent = React.forwardRef<
React.ElementRef,
@@ -66,18 +66,18 @@ const DropdownMenuContent = React.forwardRef<
sideOffset={sideOffset}
className={cn(
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
- className
+ className,
)}
{...props}
/>
-))
-DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName
+));
+DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
const DropdownMenuItem = React.forwardRef<
React.ElementRef,
React.ComponentPropsWithoutRef & {
- inset?: boolean
+ inset?: boolean;
}
>(({ className, inset, ...props }, ref) => (
-))
-DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName
+));
+DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
const DropdownMenuCheckboxItem = React.forwardRef<
React.ElementRef,
@@ -100,7 +100,7 @@ const DropdownMenuCheckboxItem = React.forwardRef<
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
- className
+ className,
)}
checked={checked}
{...props}
@@ -112,9 +112,9 @@ const DropdownMenuCheckboxItem = React.forwardRef<
{children}
-))
+));
DropdownMenuCheckboxItem.displayName =
- DropdownMenuPrimitive.CheckboxItem.displayName
+ DropdownMenuPrimitive.CheckboxItem.displayName;
const DropdownMenuRadioItem = React.forwardRef<
React.ElementRef,
@@ -124,7 +124,7 @@ const DropdownMenuRadioItem = React.forwardRef<
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
- className
+ className,
)}
{...props}
>
@@ -135,13 +135,13 @@ const DropdownMenuRadioItem = React.forwardRef<
{children}
-))
-DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName
+));
+DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
const DropdownMenuLabel = React.forwardRef<
React.ElementRef,
React.ComponentPropsWithoutRef & {
- inset?: boolean
+ inset?: boolean;
}
>(({ className, inset, ...props }, ref) => (
-))
-DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName
+));
+DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
const DropdownMenuSeparator = React.forwardRef<
React.ElementRef,
@@ -165,8 +165,8 @@ const DropdownMenuSeparator = React.forwardRef<
className={cn("-mx-1 my-1 h-px bg-muted", className)}
{...props}
/>
-))
-DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName
+));
+DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
const DropdownMenuShortcut = ({
className,
@@ -177,9 +177,9 @@ const DropdownMenuShortcut = ({
className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
{...props}
/>
- )
-}
-DropdownMenuShortcut.displayName = "DropdownMenuShortcut"
+ );
+};
+DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
export {
DropdownMenu,
@@ -197,4 +197,4 @@ export {
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuRadioGroup,
-}
+};
diff --git a/web/components/ui/input.tsx b/web/components/ui/input.tsx
index 677d05f..9d631e7 100644
--- a/web/components/ui/input.tsx
+++ b/web/components/ui/input.tsx
@@ -1,6 +1,6 @@
-import * as React from "react"
+import * as React from "react";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
export interface InputProps
extends React.InputHTMLAttributes {}
@@ -12,14 +12,14 @@ const Input = React.forwardRef(
type={type}
className={cn(
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
- className
+ className,
)}
ref={ref}
{...props}
/>
- )
- }
-)
-Input.displayName = "Input"
+ );
+ },
+);
+Input.displayName = "Input";
-export { Input }
+export { Input };
diff --git a/web/components/ui/label.tsx b/web/components/ui/label.tsx
index 5341821..84f8b0c 100644
--- a/web/components/ui/label.tsx
+++ b/web/components/ui/label.tsx
@@ -1,14 +1,14 @@
-"use client"
+"use client";
-import * as React from "react"
-import * as LabelPrimitive from "@radix-ui/react-label"
-import { cva, type VariantProps } from "class-variance-authority"
+import * as React from "react";
+import * as LabelPrimitive from "@radix-ui/react-label";
+import { cva, type VariantProps } from "class-variance-authority";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
const labelVariants = cva(
- "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
-)
+ "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
+);
const Label = React.forwardRef<
React.ElementRef,
@@ -20,7 +20,7 @@ const Label = React.forwardRef<
className={cn(labelVariants(), className)}
{...props}
/>
-))
-Label.displayName = LabelPrimitive.Root.displayName
+));
+Label.displayName = LabelPrimitive.Root.displayName;
-export { Label }
+export { Label };
diff --git a/web/components/ui/sheet.tsx b/web/components/ui/sheet.tsx
index a37f17b..575f05d 100644
--- a/web/components/ui/sheet.tsx
+++ b/web/components/ui/sheet.tsx
@@ -1,19 +1,19 @@
-"use client"
+"use client";
-import * as React from "react"
-import * as SheetPrimitive from "@radix-ui/react-dialog"
-import { cva, type VariantProps } from "class-variance-authority"
-import { X } from "lucide-react"
+import * as React from "react";
+import * as SheetPrimitive from "@radix-ui/react-dialog";
+import { cva, type VariantProps } from "class-variance-authority";
+import { X } from "lucide-react";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
-const Sheet = SheetPrimitive.Root
+const Sheet = SheetPrimitive.Root;
-const SheetTrigger = SheetPrimitive.Trigger
+const SheetTrigger = SheetPrimitive.Trigger;
-const SheetClose = SheetPrimitive.Close
+const SheetClose = SheetPrimitive.Close;
-const SheetPortal = SheetPrimitive.Portal
+const SheetPortal = SheetPrimitive.Portal;
const SheetOverlay = React.forwardRef<
React.ElementRef,
@@ -22,13 +22,13 @@ const SheetOverlay = React.forwardRef<
-))
-SheetOverlay.displayName = SheetPrimitive.Overlay.displayName
+));
+SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
const sheetVariants = cva(
"fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500",
@@ -46,8 +46,8 @@ const sheetVariants = cva(
defaultVariants: {
side: "right",
},
- }
-)
+ },
+);
interface SheetContentProps
extends React.ComponentPropsWithoutRef,
@@ -71,8 +71,8 @@ const SheetContent = React.forwardRef<
-))
-SheetContent.displayName = SheetPrimitive.Content.displayName
+));
+SheetContent.displayName = SheetPrimitive.Content.displayName;
const SheetHeader = ({
className,
@@ -81,12 +81,12 @@ const SheetHeader = ({
-)
-SheetHeader.displayName = "SheetHeader"
+);
+SheetHeader.displayName = "SheetHeader";
const SheetFooter = ({
className,
@@ -95,12 +95,12 @@ const SheetFooter = ({
-)
-SheetFooter.displayName = "SheetFooter"
+);
+SheetFooter.displayName = "SheetFooter";
const SheetTitle = React.forwardRef<
React.ElementRef,
@@ -111,8 +111,8 @@ const SheetTitle = React.forwardRef<
className={cn("text-lg font-semibold text-foreground", className)}
{...props}
/>
-))
-SheetTitle.displayName = SheetPrimitive.Title.displayName
+));
+SheetTitle.displayName = SheetPrimitive.Title.displayName;
const SheetDescription = React.forwardRef<
React.ElementRef,
@@ -123,8 +123,8 @@ const SheetDescription = React.forwardRef<
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
-))
-SheetDescription.displayName = SheetPrimitive.Description.displayName
+));
+SheetDescription.displayName = SheetPrimitive.Description.displayName;
export {
Sheet,
@@ -137,4 +137,4 @@ export {
SheetFooter,
SheetTitle,
SheetDescription,
-}
+};
diff --git a/web/components/ui/tooltip.tsx b/web/components/ui/tooltip.tsx
index 30fc44d..2c42a2c 100644
--- a/web/components/ui/tooltip.tsx
+++ b/web/components/ui/tooltip.tsx
@@ -1,15 +1,15 @@
-"use client"
+"use client";
-import * as React from "react"
-import * as TooltipPrimitive from "@radix-ui/react-tooltip"
+import * as React from "react";
+import * as TooltipPrimitive from "@radix-ui/react-tooltip";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
-const TooltipProvider = TooltipPrimitive.Provider
+const TooltipProvider = TooltipPrimitive.Provider;
-const Tooltip = TooltipPrimitive.Root
+const Tooltip = TooltipPrimitive.Root;
-const TooltipTrigger = TooltipPrimitive.Trigger
+const TooltipTrigger = TooltipPrimitive.Trigger;
const TooltipContent = React.forwardRef<
React.ElementRef,
@@ -20,11 +20,11 @@ const TooltipContent = React.forwardRef<
sideOffset={sideOffset}
className={cn(
"z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
- className
+ className,
)}
{...props}
/>
-))
-TooltipContent.displayName = TooltipPrimitive.Content.displayName
+));
+TooltipContent.displayName = TooltipPrimitive.Content.displayName;
-export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
+export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
diff --git a/web/eslint.config.js b/web/eslint.config.js
new file mode 100644
index 0000000..d6f8fd1
--- /dev/null
+++ b/web/eslint.config.js
@@ -0,0 +1,11 @@
+import js from "@eslint/js";
+import tseslint from "typescript-eslint";
+
+export default [
+ js.configs.recommended,
+ ...tseslint.configs.recommended,
+ {
+ files: ["**/*.{js,mjs,cjs,ts,tsx}"],
+ rules: {},
+ },
+];
diff --git a/web/lib/utils.ts b/web/lib/utils.ts
index d084cca..365058c 100644
--- a/web/lib/utils.ts
+++ b/web/lib/utils.ts
@@ -1,6 +1,6 @@
-import { type ClassValue, clsx } from "clsx"
-import { twMerge } from "tailwind-merge"
+import { type ClassValue, clsx } from "clsx";
+import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
- return twMerge(clsx(inputs))
+ return twMerge(clsx(inputs));
}
diff --git a/web/public/next.svg b/web/public/next.svg
index 5174b28..5bb00d4 100644
--- a/web/public/next.svg
+++ b/web/public/next.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
diff --git a/web/public/placeholder.svg b/web/public/placeholder.svg
index e763910..9b13eb6 100644
--- a/web/public/placeholder.svg
+++ b/web/public/placeholder.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
diff --git a/web/public/vercel.svg b/web/public/vercel.svg
index d2f8422..1aeda7d 100644
--- a/web/public/vercel.svg
+++ b/web/public/vercel.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
diff --git a/yarn.lock b/yarn.lock
new file mode 100644
index 0000000..682c4b5
--- /dev/null
+++ b/yarn.lock
@@ -0,0 +1,803 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0":
+ version "4.4.0"
+ resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59"
+ integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==
+ dependencies:
+ eslint-visitor-keys "^3.3.0"
+
+"@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1":
+ version "4.11.0"
+ resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.0.tgz#b0ffd0312b4a3fd2d6f77237e7248a5ad3a680ae"
+ integrity sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==
+
+"@eslint/config-array@^0.17.0":
+ version "0.17.0"
+ resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.17.0.tgz#ff305e1ee618a00e6e5d0485454c8d92d94a860d"
+ integrity sha512-A68TBu6/1mHHuc5YJL0U0VVeGNiklLAL6rRmhTCP2B5XjWLMnrX+HkO+IAXyHvks5cyyY1jjK5ITPQ1HGS2EVA==
+ dependencies:
+ "@eslint/object-schema" "^2.1.4"
+ debug "^4.3.1"
+ minimatch "^3.1.2"
+
+"@eslint/eslintrc@^3.1.0":
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.1.0.tgz#dbd3482bfd91efa663cbe7aa1f506839868207b6"
+ integrity sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==
+ dependencies:
+ ajv "^6.12.4"
+ debug "^4.3.2"
+ espree "^10.0.1"
+ globals "^14.0.0"
+ ignore "^5.2.0"
+ import-fresh "^3.2.1"
+ js-yaml "^4.1.0"
+ minimatch "^3.1.2"
+ strip-json-comments "^3.1.1"
+
+"@eslint/js@9.6.0":
+ version "9.6.0"
+ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.6.0.tgz#5b0cb058cc13d9c92d4e561d3538807fa5127c95"
+ integrity sha512-D9B0/3vNg44ZeWbYMpBoXqNP4j6eQD5vNwIlGAuFRRzK/WtT/jvDQW3Bi9kkf3PMDMlM7Yi+73VLUsn5bJcl8A==
+
+"@eslint/object-schema@^2.1.4":
+ version "2.1.4"
+ resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.4.tgz#9e69f8bb4031e11df79e03db09f9dbbae1740843"
+ integrity sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==
+
+"@humanwhocodes/module-importer@^1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c"
+ integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==
+
+"@humanwhocodes/retry@^0.3.0":
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.0.tgz#6d86b8cb322660f03d3f0aa94b99bdd8e172d570"
+ integrity sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==
+
+"@nodelib/fs.scandir@2.1.5":
+ version "2.1.5"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
+ integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==
+ dependencies:
+ "@nodelib/fs.stat" "2.0.5"
+ run-parallel "^1.1.9"
+
+"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b"
+ integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
+
+"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8":
+ version "1.2.8"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a"
+ integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
+ dependencies:
+ "@nodelib/fs.scandir" "2.1.5"
+ fastq "^1.6.0"
+
+"@types/json-schema@^7.0.12":
+ version "7.0.15"
+ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
+ integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
+
+"@types/semver@^7.5.0":
+ version "7.5.8"
+ resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e"
+ integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==
+
+"@typescript-eslint/eslint-plugin@6.7.0":
+ version "6.7.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.0.tgz#ed2a38867190f8a688af85ad7c8a74670b8b3675"
+ integrity sha512-gUqtknHm0TDs1LhY12K2NA3Rmlmp88jK9Tx8vGZMfHeNMLE3GH2e9TRub+y+SOjuYgtOmok+wt1AyDPZqxbNag==
+ dependencies:
+ "@eslint-community/regexpp" "^4.5.1"
+ "@typescript-eslint/scope-manager" "6.7.0"
+ "@typescript-eslint/type-utils" "6.7.0"
+ "@typescript-eslint/utils" "6.7.0"
+ "@typescript-eslint/visitor-keys" "6.7.0"
+ debug "^4.3.4"
+ graphemer "^1.4.0"
+ ignore "^5.2.4"
+ natural-compare "^1.4.0"
+ semver "^7.5.4"
+ ts-api-utils "^1.0.1"
+
+"@typescript-eslint/parser@6.7.0":
+ version "6.7.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.7.0.tgz#332fe9c7ecf6783d3250b4c8a960bd4af0995807"
+ integrity sha512-jZKYwqNpNm5kzPVP5z1JXAuxjtl2uG+5NpaMocFPTNC2EdYIgbXIPImObOkhbONxtFTTdoZstLZefbaK+wXZng==
+ dependencies:
+ "@typescript-eslint/scope-manager" "6.7.0"
+ "@typescript-eslint/types" "6.7.0"
+ "@typescript-eslint/typescript-estree" "6.7.0"
+ "@typescript-eslint/visitor-keys" "6.7.0"
+ debug "^4.3.4"
+
+"@typescript-eslint/scope-manager@6.7.0":
+ version "6.7.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.7.0.tgz#6b3c22187976e2bf5ed0dc0d9095f1f2cbd1d106"
+ integrity sha512-lAT1Uau20lQyjoLUQ5FUMSX/dS07qux9rYd5FGzKz/Kf8W8ccuvMyldb8hadHdK/qOI7aikvQWqulnEq2nCEYA==
+ dependencies:
+ "@typescript-eslint/types" "6.7.0"
+ "@typescript-eslint/visitor-keys" "6.7.0"
+
+"@typescript-eslint/type-utils@6.7.0":
+ version "6.7.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.7.0.tgz#21a013d4c7f96255f5e64ac59fb41301d1e052ba"
+ integrity sha512-f/QabJgDAlpSz3qduCyQT0Fw7hHpmhOzY/Rv6zO3yO+HVIdPfIWhrQoAyG+uZVtWAIS85zAyzgAFfyEr+MgBpg==
+ dependencies:
+ "@typescript-eslint/typescript-estree" "6.7.0"
+ "@typescript-eslint/utils" "6.7.0"
+ debug "^4.3.4"
+ ts-api-utils "^1.0.1"
+
+"@typescript-eslint/types@6.7.0":
+ version "6.7.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.7.0.tgz#8de8ba9cafadc38e89003fe303e219c9250089ae"
+ integrity sha512-ihPfvOp7pOcN/ysoj0RpBPOx3HQTJTrIN8UZK+WFd3/iDeFHHqeyYxa4hQk4rMhsz9H9mXpR61IzwlBVGXtl9Q==
+
+"@typescript-eslint/typescript-estree@6.7.0":
+ version "6.7.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.0.tgz#20ce2801733bd46f02cc0f141f5b63fbbf2afb63"
+ integrity sha512-dPvkXj3n6e9yd/0LfojNU8VMUGHWiLuBZvbM6V6QYD+2qxqInE7J+J/ieY2iGwR9ivf/R/haWGkIj04WVUeiSQ==
+ dependencies:
+ "@typescript-eslint/types" "6.7.0"
+ "@typescript-eslint/visitor-keys" "6.7.0"
+ debug "^4.3.4"
+ globby "^11.1.0"
+ is-glob "^4.0.3"
+ semver "^7.5.4"
+ ts-api-utils "^1.0.1"
+
+"@typescript-eslint/utils@6.7.0":
+ version "6.7.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.7.0.tgz#61b6f1f1b82ad529abfcee074d21764e880886fb"
+ integrity sha512-MfCq3cM0vh2slSikQYqK2Gq52gvOhe57vD2RM3V4gQRZYX4rDPnKLu5p6cm89+LJiGlwEXU8hkYxhqqEC/V3qA==
+ dependencies:
+ "@eslint-community/eslint-utils" "^4.4.0"
+ "@types/json-schema" "^7.0.12"
+ "@types/semver" "^7.5.0"
+ "@typescript-eslint/scope-manager" "6.7.0"
+ "@typescript-eslint/types" "6.7.0"
+ "@typescript-eslint/typescript-estree" "6.7.0"
+ semver "^7.5.4"
+
+"@typescript-eslint/visitor-keys@6.7.0":
+ version "6.7.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.0.tgz#34140ac76dfb6316d17012e4469acf3366ad3f44"
+ integrity sha512-/C1RVgKFDmGMcVGeD8HjKv2bd72oI1KxQDeY8uc66gw9R0OK0eMq48cA+jv9/2Ag6cdrsUGySm1yzYmfz0hxwQ==
+ dependencies:
+ "@typescript-eslint/types" "6.7.0"
+ eslint-visitor-keys "^3.4.1"
+
+acorn-jsx@^5.3.2:
+ version "5.3.2"
+ resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
+ integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
+
+acorn@^8.12.0:
+ version "8.12.1"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248"
+ integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==
+
+ajv@^6.12.4:
+ version "6.12.6"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
+ integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
+ dependencies:
+ fast-deep-equal "^3.1.1"
+ fast-json-stable-stringify "^2.0.0"
+ json-schema-traverse "^0.4.1"
+ uri-js "^4.2.2"
+
+ansi-regex@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
+ integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
+
+ansi-styles@^4.1.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
+ integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
+ dependencies:
+ color-convert "^2.0.1"
+
+argparse@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
+ integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
+
+array-union@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
+ integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
+
+balanced-match@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
+ integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
+
+brace-expansion@^1.1.7:
+ version "1.1.11"
+ resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
+ integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
+ dependencies:
+ balanced-match "^1.0.0"
+ concat-map "0.0.1"
+
+braces@^3.0.3:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789"
+ integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==
+ dependencies:
+ fill-range "^7.1.1"
+
+callsites@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
+ integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
+
+chalk@^4.0.0:
+ version "4.1.2"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
+ integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
+ dependencies:
+ ansi-styles "^4.1.0"
+ supports-color "^7.1.0"
+
+color-convert@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
+ integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
+ dependencies:
+ color-name "~1.1.4"
+
+color-name@~1.1.4:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
+ integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
+
+concat-map@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+ integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
+
+cross-spawn@^7.0.2:
+ version "7.0.3"
+ resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
+ integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
+ dependencies:
+ path-key "^3.1.0"
+ shebang-command "^2.0.0"
+ which "^2.0.1"
+
+debug@^4.3.1, debug@^4.3.2, debug@^4.3.4:
+ version "4.3.5"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.5.tgz#e83444eceb9fedd4a1da56d671ae2446a01a6e1e"
+ integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==
+ dependencies:
+ ms "2.1.2"
+
+deep-is@^0.1.3:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
+ integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
+
+dir-glob@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
+ integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==
+ dependencies:
+ path-type "^4.0.0"
+
+escape-string-regexp@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
+ integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
+
+eslint-scope@^8.0.1:
+ version "8.0.1"
+ resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.0.1.tgz#a9601e4b81a0b9171657c343fb13111688963cfc"
+ integrity sha512-pL8XjgP4ZOmmwfFE8mEhSxA7ZY4C+LWyqjQ3o4yWkkmD0qcMT9kkW3zWHOczhWcjTSgqycYAgwSlXvZltv65og==
+ dependencies:
+ esrecurse "^4.3.0"
+ estraverse "^5.2.0"
+
+eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1:
+ version "3.4.3"
+ resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800"
+ integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
+
+eslint-visitor-keys@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz#e3adc021aa038a2a8e0b2f8b0ce8f66b9483b1fb"
+ integrity sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==
+
+eslint@9.6.0:
+ version "9.6.0"
+ resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.6.0.tgz#9f54373afa15e1ba356656a8d96233182027fb49"
+ integrity sha512-ElQkdLMEEqQNM9Njff+2Y4q2afHk7JpkPvrd7Xh7xefwgQynqPxwf55J7di9+MEibWUGdNjFF9ITG9Pck5M84w==
+ dependencies:
+ "@eslint-community/eslint-utils" "^4.2.0"
+ "@eslint-community/regexpp" "^4.6.1"
+ "@eslint/config-array" "^0.17.0"
+ "@eslint/eslintrc" "^3.1.0"
+ "@eslint/js" "9.6.0"
+ "@humanwhocodes/module-importer" "^1.0.1"
+ "@humanwhocodes/retry" "^0.3.0"
+ "@nodelib/fs.walk" "^1.2.8"
+ ajv "^6.12.4"
+ chalk "^4.0.0"
+ cross-spawn "^7.0.2"
+ debug "^4.3.2"
+ escape-string-regexp "^4.0.0"
+ eslint-scope "^8.0.1"
+ eslint-visitor-keys "^4.0.0"
+ espree "^10.1.0"
+ esquery "^1.5.0"
+ esutils "^2.0.2"
+ fast-deep-equal "^3.1.3"
+ file-entry-cache "^8.0.0"
+ find-up "^5.0.0"
+ glob-parent "^6.0.2"
+ ignore "^5.2.0"
+ imurmurhash "^0.1.4"
+ is-glob "^4.0.0"
+ is-path-inside "^3.0.3"
+ json-stable-stringify-without-jsonify "^1.0.1"
+ levn "^0.4.1"
+ lodash.merge "^4.6.2"
+ minimatch "^3.1.2"
+ natural-compare "^1.4.0"
+ optionator "^0.9.3"
+ strip-ansi "^6.0.1"
+ text-table "^0.2.0"
+
+espree@^10.0.1, espree@^10.1.0:
+ version "10.1.0"
+ resolved "https://registry.yarnpkg.com/espree/-/espree-10.1.0.tgz#8788dae611574c0f070691f522e4116c5a11fc56"
+ integrity sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==
+ dependencies:
+ acorn "^8.12.0"
+ acorn-jsx "^5.3.2"
+ eslint-visitor-keys "^4.0.0"
+
+esquery@^1.5.0:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b"
+ integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==
+ dependencies:
+ estraverse "^5.1.0"
+
+esrecurse@^4.3.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921"
+ integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==
+ dependencies:
+ estraverse "^5.2.0"
+
+estraverse@^5.1.0, estraverse@^5.2.0:
+ version "5.3.0"
+ resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123"
+ integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
+
+esutils@^2.0.2:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
+ integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
+
+fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
+ integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
+
+fast-glob@^3.2.9:
+ version "3.3.2"
+ resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129"
+ integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==
+ dependencies:
+ "@nodelib/fs.stat" "^2.0.2"
+ "@nodelib/fs.walk" "^1.2.3"
+ glob-parent "^5.1.2"
+ merge2 "^1.3.0"
+ micromatch "^4.0.4"
+
+fast-json-stable-stringify@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
+ integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
+
+fast-levenshtein@^2.0.6:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
+ integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==
+
+fastq@^1.6.0:
+ version "1.17.1"
+ resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47"
+ integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==
+ dependencies:
+ reusify "^1.0.4"
+
+file-entry-cache@^8.0.0:
+ version "8.0.0"
+ resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f"
+ integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==
+ dependencies:
+ flat-cache "^4.0.0"
+
+fill-range@^7.1.1:
+ version "7.1.1"
+ resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292"
+ integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==
+ dependencies:
+ to-regex-range "^5.0.1"
+
+find-up@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc"
+ integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==
+ dependencies:
+ locate-path "^6.0.0"
+ path-exists "^4.0.0"
+
+flat-cache@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.1.tgz#0ece39fcb14ee012f4b0410bd33dd9c1f011127c"
+ integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==
+ dependencies:
+ flatted "^3.2.9"
+ keyv "^4.5.4"
+
+flatted@^3.2.9:
+ version "3.3.1"
+ resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a"
+ integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==
+
+glob-parent@^5.1.2:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
+ integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
+ dependencies:
+ is-glob "^4.0.1"
+
+glob-parent@^6.0.2:
+ version "6.0.2"
+ resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3"
+ integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==
+ dependencies:
+ is-glob "^4.0.3"
+
+globals@^14.0.0:
+ version "14.0.0"
+ resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e"
+ integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==
+
+globby@^11.1.0:
+ version "11.1.0"
+ resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b"
+ integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==
+ dependencies:
+ array-union "^2.1.0"
+ dir-glob "^3.0.1"
+ fast-glob "^3.2.9"
+ ignore "^5.2.0"
+ merge2 "^1.4.1"
+ slash "^3.0.0"
+
+graphemer@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6"
+ integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==
+
+has-flag@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
+ integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
+
+ignore@^5.2.0, ignore@^5.2.4:
+ version "5.3.1"
+ resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef"
+ integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==
+
+import-fresh@^3.2.1:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
+ integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==
+ dependencies:
+ parent-module "^1.0.0"
+ resolve-from "^4.0.0"
+
+imurmurhash@^0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
+ integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==
+
+is-extglob@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
+ integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
+
+is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3:
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
+ integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
+ dependencies:
+ is-extglob "^2.1.1"
+
+is-number@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
+ integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
+
+is-path-inside@^3.0.3:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283"
+ integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
+
+isexe@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
+ integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
+
+js-yaml@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
+ integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
+ dependencies:
+ argparse "^2.0.1"
+
+json-buffer@3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13"
+ integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==
+
+json-schema-traverse@^0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
+ integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
+
+json-stable-stringify-without-jsonify@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
+ integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==
+
+keyv@^4.5.4:
+ version "4.5.4"
+ resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93"
+ integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==
+ dependencies:
+ json-buffer "3.0.1"
+
+levn@^0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade"
+ integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==
+ dependencies:
+ prelude-ls "^1.2.1"
+ type-check "~0.4.0"
+
+locate-path@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286"
+ integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==
+ dependencies:
+ p-locate "^5.0.0"
+
+lodash.merge@^4.6.2:
+ version "4.6.2"
+ resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
+ integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
+
+merge2@^1.3.0, merge2@^1.4.1:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
+ integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
+
+micromatch@^4.0.4:
+ version "4.0.7"
+ resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.7.tgz#33e8190d9fe474a9895525f5618eee136d46c2e5"
+ integrity sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==
+ dependencies:
+ braces "^3.0.3"
+ picomatch "^2.3.1"
+
+minimatch@^3.1.2:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
+ integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
+ dependencies:
+ brace-expansion "^1.1.7"
+
+ms@2.1.2:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
+ integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
+
+natural-compare@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
+ integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
+
+optionator@^0.9.3:
+ version "0.9.4"
+ resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734"
+ integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==
+ dependencies:
+ deep-is "^0.1.3"
+ fast-levenshtein "^2.0.6"
+ levn "^0.4.1"
+ prelude-ls "^1.2.1"
+ type-check "^0.4.0"
+ word-wrap "^1.2.5"
+
+p-limit@^3.0.2:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b"
+ integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==
+ dependencies:
+ yocto-queue "^0.1.0"
+
+p-locate@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834"
+ integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==
+ dependencies:
+ p-limit "^3.0.2"
+
+parent-module@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
+ integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
+ dependencies:
+ callsites "^3.0.0"
+
+path-exists@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
+ integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
+
+path-key@^3.1.0:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
+ integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
+
+path-type@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
+ integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
+
+picomatch@^2.3.1:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
+ integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
+
+prelude-ls@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
+ integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
+
+punycode@^2.1.0:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5"
+ integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==
+
+queue-microtask@^1.2.2:
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
+ integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
+
+resolve-from@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
+ integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
+
+reusify@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
+ integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
+
+run-parallel@^1.1.9:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
+ integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==
+ dependencies:
+ queue-microtask "^1.2.2"
+
+semver@^7.5.4:
+ version "7.6.2"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13"
+ integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==
+
+shebang-command@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
+ integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
+ dependencies:
+ shebang-regex "^3.0.0"
+
+shebang-regex@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
+ integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
+
+slash@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
+ integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
+
+strip-ansi@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
+ integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
+ dependencies:
+ ansi-regex "^5.0.1"
+
+strip-json-comments@^3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
+ integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
+
+supports-color@^7.1.0:
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
+ integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
+ dependencies:
+ has-flag "^4.0.0"
+
+text-table@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
+ integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==
+
+to-regex-range@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
+ integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
+ dependencies:
+ is-number "^7.0.0"
+
+ts-api-utils@^1.0.1:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1"
+ integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==
+
+type-check@^0.4.0, type-check@~0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
+ integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==
+ dependencies:
+ prelude-ls "^1.2.1"
+
+typescript@5.2.2:
+ version "5.2.2"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78"
+ integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==
+
+uri-js@^4.2.2:
+ version "4.4.1"
+ resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
+ integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
+ dependencies:
+ punycode "^2.1.0"
+
+which@^2.0.1:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
+ integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
+ dependencies:
+ isexe "^2.0.0"
+
+word-wrap@^1.2.5:
+ version "1.2.5"
+ resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34"
+ integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==
+
+yocto-queue@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
+ integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==