mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2025-12-29 17:17:55 -05:00
Compare commits
152 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
94b79a0587 | ||
|
|
9a2dd317b2 | ||
|
|
7ea75839bc | ||
|
|
69e25b8401 | ||
|
|
cfb8926183 | ||
|
|
f8bbc0e0d0 | ||
|
|
5aa62bff7a | ||
|
|
61664c4fd0 | ||
|
|
092c801533 | ||
|
|
7338856202 | ||
|
|
d9f6f92912 | ||
|
|
fad25421ff | ||
|
|
f3823c3089 | ||
|
|
07798c9189 | ||
|
|
62870549a4 | ||
|
|
67d258bfb1 | ||
|
|
9a135406b7 | ||
|
|
3d6442be2e | ||
|
|
b11cd0def3 | ||
|
|
d827766133 | ||
|
|
6744d85c5a | ||
|
|
8908f5e8ff | ||
|
|
c9a704d446 | ||
|
|
ac8b58233e | ||
|
|
e9201d65a0 | ||
|
|
888d0c8d99 | ||
|
|
6bd9b47799 | ||
|
|
beb7920b50 | ||
|
|
02b37cc17c | ||
|
|
33b7fa79f9 | ||
|
|
f9d4a038b3 | ||
|
|
1dce3f8700 | ||
|
|
4108cc6877 | ||
|
|
54f934cbb0 | ||
|
|
b9b4643085 | ||
|
|
479c8a0e0e | ||
|
|
448755d149 | ||
|
|
9bcdbc358e | ||
|
|
129fb1e62d | ||
|
|
1e95c9d39a | ||
|
|
47ebe9a20b | ||
|
|
14a623e669 | ||
|
|
23c942fff0 | ||
|
|
c4080e9523 | ||
|
|
e305d915ed | ||
|
|
448c6b9f5a | ||
|
|
9193df0385 | ||
|
|
533eb39909 | ||
|
|
1bb07292dd | ||
|
|
e6ea1b15f4 | ||
|
|
6864970e3f | ||
|
|
daafbc9119 | ||
|
|
fdab4dd174 | ||
|
|
1c1e1a2d4e | ||
|
|
167b448bf3 | ||
|
|
5a5124067b | ||
|
|
7a00f49510 | ||
|
|
729c94afcf | ||
|
|
bbb0e6048f | ||
|
|
a40d5240aa | ||
|
|
3569a36c1b | ||
|
|
41f630d698 | ||
|
|
7644bfc5cc | ||
|
|
d703d5030a | ||
|
|
c3ed685391 | ||
|
|
d396a8b852 | ||
|
|
89feb86062 | ||
|
|
ac4bb4a73c | ||
|
|
6770322a73 | ||
|
|
1197ab5212 | ||
|
|
7a73066f47 | ||
|
|
51805e710d | ||
|
|
abb454da37 | ||
|
|
57572a1fcb | ||
|
|
a73b125505 | ||
|
|
524e13ae89 | ||
|
|
328b15be1e | ||
|
|
83c9559fe0 | ||
|
|
79aa0c5340 | ||
|
|
f1fb44946c | ||
|
|
bfb99927ad | ||
|
|
981e8fe5a3 | ||
|
|
7e1a21994b | ||
|
|
f6e5348648 | ||
|
|
f140eabf9e | ||
|
|
db36794920 | ||
|
|
78ae9b2907 | ||
|
|
86f7be40f9 | ||
|
|
5b3ebbd695 | ||
|
|
23a528789d | ||
|
|
f5f82fe031 | ||
|
|
ce63949988 | ||
|
|
3ed30f58bd | ||
|
|
24655b6577 | ||
|
|
51c2497e6d | ||
|
|
f4d8e632fd | ||
|
|
b37a45f26f | ||
|
|
9bc192a042 | ||
|
|
9f2694f683 | ||
|
|
c29b777638 | ||
|
|
329108f0f8 | ||
|
|
7098772ac0 | ||
|
|
c59601df52 | ||
|
|
45be2ef0d8 | ||
|
|
2e4f611d5b | ||
|
|
db7d0535f6 | ||
|
|
d849f4fc4e | ||
|
|
7e97dec71b | ||
|
|
f601f6853f | ||
|
|
1ba4513328 | ||
|
|
a4678fe007 | ||
|
|
fcd1ddde8f | ||
|
|
06425411d2 | ||
|
|
6a62068c2a | ||
|
|
93471b56dd | ||
|
|
e44e3f2806 | ||
|
|
0016085933 | ||
|
|
887257fa38 | ||
|
|
11ad5a64fa | ||
|
|
64abdad3d0 | ||
|
|
5927f1da00 | ||
|
|
73bee868d6 | ||
|
|
6b7c004d0b | ||
|
|
8cd62fcf24 | ||
|
|
c1e8b51ad8 | ||
|
|
103f6795b1 | ||
|
|
baf5143626 | ||
|
|
00ff858f19 | ||
|
|
27fa5e3236 | ||
|
|
97f97a4a4a | ||
|
|
9079629947 | ||
|
|
765a5bccd7 | ||
|
|
250400639a | ||
|
|
9499d84e78 | ||
|
|
eccc900918 | ||
|
|
6e4cbf2230 | ||
|
|
9e7f4487ad | ||
|
|
0f5855cef4 | ||
|
|
df93ea4649 | ||
|
|
19c870425e | ||
|
|
a24ead6d20 | ||
|
|
e23b8f412b | ||
|
|
b954681c3b | ||
|
|
73e535580f | ||
|
|
30f1f80be6 | ||
|
|
8a3dd88959 | ||
|
|
f46900597f | ||
|
|
8f63b29b56 | ||
|
|
aa57b3155a | ||
|
|
96684df32d | ||
|
|
2e281aae62 | ||
|
|
70fc6eb40b |
@@ -65,12 +65,6 @@ $(GOVULNCHECK): $(BINGO_DIR)/govulncheck.mod
|
||||
@echo "(re)installing $(GOBIN)/govulncheck-v1.1.4"
|
||||
@cd $(BINGO_DIR) && GOWORK=off $(GO) build -mod=mod -modfile=govulncheck.mod -o=$(GOBIN)/govulncheck-v1.1.4 "golang.org/x/vuln/cmd/govulncheck"
|
||||
|
||||
HUGO := $(GOBIN)/hugo-v0.123.7
|
||||
$(HUGO): $(BINGO_DIR)/hugo.mod
|
||||
@# Install binary/ries using Go 1.14+ build command. This is using bwplotka/bingo-controlled, separate go module with pinned dependencies.
|
||||
@echo "(re)installing $(GOBIN)/hugo-v0.123.7"
|
||||
@cd $(BINGO_DIR) && GOWORK=off $(GO) build -mod=mod -modfile=hugo.mod -o=$(GOBIN)/hugo-v0.123.7 "github.com/gohugoio/hugo"
|
||||
|
||||
MOCKERY := $(GOBIN)/mockery-v2.53.2
|
||||
$(MOCKERY): $(BINGO_DIR)/mockery.mod
|
||||
@# Install binary/ries using Go 1.14+ build command. This is using bwplotka/bingo-controlled, separate go module with pinned dependencies.
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT
|
||||
|
||||
go 1.17
|
||||
|
||||
replace github.com/markbates/inflect => github.com/markbates/inflect v0.0.0-20171215194931-a12c3aec81a6
|
||||
|
||||
require github.com/gohugoio/hugo v0.123.7
|
||||
1751
.bingo/hugo.sum
1751
.bingo/hugo.sum
File diff suppressed because it is too large
Load Diff
@@ -24,8 +24,6 @@ GOLANGCI_LINT="${GOBIN}/golangci-lint-v1.64.6"
|
||||
|
||||
GOVULNCHECK="${GOBIN}/govulncheck-v1.1.4"
|
||||
|
||||
HUGO="${GOBIN}/hugo-v0.123.7"
|
||||
|
||||
MOCKERY="${GOBIN}/mockery-v2.53.2"
|
||||
|
||||
MUTAGEN="${GOBIN}/mutagen-v0.18.1"
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# The test runner source for UI tests
|
||||
WEB_COMMITID=8c10b33af6ec3a949f95a57f197ee915d666f343
|
||||
WEB_COMMITID=9d5615635b05b177946649962d61df78c8d9fc07
|
||||
WEB_BRANCH=main
|
||||
|
||||
85
CHANGELOG.md
85
CHANGELOG.md
@@ -1,5 +1,90 @@
|
||||
# Changelog
|
||||
|
||||
## [3.0.0](https://github.com/opencloud-eu/opencloud/releases/tag/v3.0.0) - 2025-06-10
|
||||
|
||||
### ❤️ Thanks to all contributors! ❤️
|
||||
|
||||
@AlexAndBear, @ScharfViktor, @VuiMuich, @aduffeck, @butonic, @fschade, @kulmann, @micbar, @prashant-gurung899, @rhafer
|
||||
|
||||
### 💥 Breaking changes
|
||||
|
||||
- do not automatically expand drive root permissions [[#495](https://github.com/opencloud-eu/opencloud/pull/495)]
|
||||
|
||||
### ✨ Features
|
||||
|
||||
- Enhancement: Introduced support for PrivateLink in WebDAV search responses [[#983](https://github.com/opencloud-eu/opencloud/pull/983)]
|
||||
- Add profile photo [[#864](https://github.com/opencloud-eu/opencloud/pull/864)]
|
||||
- feat: hide close button in collabora [[#828](https://github.com/opencloud-eu/opencloud/pull/828)]
|
||||
|
||||
### 📈 Enhancement
|
||||
|
||||
- graph: Add $filter to only list (and/or count) member permissions [[#996](https://github.com/opencloud-eu/opencloud/pull/996)]
|
||||
- [full-ci] chore: bump web to v3.0.0 [[#1026](https://github.com/opencloud-eu/opencloud/pull/1026)]
|
||||
- [full-ci] chore: bump web to v3.0.0-alpha.1 [[#972](https://github.com/opencloud-eu/opencloud/pull/972)]
|
||||
- feat: add shareType to sharees field on activities api [[#954](https://github.com/opencloud-eu/opencloud/pull/954)]
|
||||
- graph: Add more $select options to ListPermissions endpoint [[#916](https://github.com/opencloud-eu/opencloud/pull/916)]
|
||||
- feat: add webp format [[#869](https://github.com/opencloud-eu/opencloud/pull/869)]
|
||||
|
||||
### ✅ Tests
|
||||
|
||||
- apiTest. count permission in the list permissions endpoint [[#1010](https://github.com/opencloud-eu/opencloud/pull/1010)]
|
||||
- apiTest. select option for root/permissions endpoint [[#942](https://github.com/opencloud-eu/opencloud/pull/942)]
|
||||
- [full-ci] ApiTest. checking private link in report response [[#993](https://github.com/opencloud-eu/opencloud/pull/993)]
|
||||
- [full-ci] Change `eicar_com.zip` virus file and update tests [[#992](https://github.com/opencloud-eu/opencloud/pull/992)]
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- Fix broken urls in README.md of deployment example [[#1023](https://github.com/opencloud-eu/opencloud/pull/1023)]
|
||||
- Make activitylog service scalable [[#941](https://github.com/opencloud-eu/opencloud/pull/941)]
|
||||
- Fix purging revisions from decomposeds3 blobstores [[#958](https://github.com/opencloud-eu/opencloud/pull/958)]
|
||||
- fix(graph-metadata): lazy cs3 metadata storage initialization [[#946](https://github.com/opencloud-eu/opencloud/pull/946)]
|
||||
- always get the user email for admin user [[#898](https://github.com/opencloud-eu/opencloud/pull/898)]
|
||||
|
||||
### 📚 Documentation
|
||||
|
||||
- Updated boxes in readme [[#970](https://github.com/opencloud-eu/opencloud/pull/970)]
|
||||
|
||||
### 📦️ Dependencies
|
||||
|
||||
- [decomposed] bump-version-v3.0.0 [[#1030](https://github.com/opencloud-eu/opencloud/pull/1030)]
|
||||
- [full-ci] chore:reva bump v.2.33.1 [[#1027](https://github.com/opencloud-eu/opencloud/pull/1027)]
|
||||
- build(deps): bump i18next from 25.1.2 to 25.2.1 in /services/idp [[#1024](https://github.com/opencloud-eu/opencloud/pull/1024)]
|
||||
- build(deps): bump golang.org/x/image from 0.27.0 to 0.28.0 [[#1012](https://github.com/opencloud-eu/opencloud/pull/1012)]
|
||||
- build(deps): bump @types/node from 22.15.29 to 22.15.30 in /services/idp [[#1008](https://github.com/opencloud-eu/opencloud/pull/1008)]
|
||||
- build(deps): bump github.com/open-policy-agent/opa from 1.5.0 to 1.5.1 [[#1000](https://github.com/opencloud-eu/opencloud/pull/1000)]
|
||||
- build(deps): bump golang.org/x/sync from 0.14.0 to 0.15.0 [[#1006](https://github.com/opencloud-eu/opencloud/pull/1006)]
|
||||
- build(deps-dev): bump eslint-plugin-react from 7.37.2 to 7.37.5 in /services/idp [[#1004](https://github.com/opencloud-eu/opencloud/pull/1004)]
|
||||
- build(deps-dev): bump postcss-normalize from 13.0.0 to 13.0.1 in /services/idp [[#1003](https://github.com/opencloud-eu/opencloud/pull/1003)]
|
||||
- build(deps): bump @testing-library/react from 11.2.7 to 12.1.5 in /services/idp [[#994](https://github.com/opencloud-eu/opencloud/pull/994)]
|
||||
- build(deps): bump github.com/blevesearch/bleve/v2 from 2.5.1 to 2.5.2 [[#999](https://github.com/opencloud-eu/opencloud/pull/999)]
|
||||
- build(deps): bump @fontsource/roboto from 5.1.0 to 5.2.5 in /services/idp [[#995](https://github.com/opencloud-eu/opencloud/pull/995)]
|
||||
- build(deps): bump google.golang.org/grpc from 1.72.1 to 1.72.2 [[#991](https://github.com/opencloud-eu/opencloud/pull/991)]
|
||||
- build(deps): bump github.com/nats-io/nats.go from 1.42.0 to 1.43.0 [[#990](https://github.com/opencloud-eu/opencloud/pull/990)]
|
||||
- build(deps): bump @types/jest from 29.5.12 to 29.5.14 in /services/idp [[#987](https://github.com/opencloud-eu/opencloud/pull/987)]
|
||||
- build(deps): bump github.com/leonelquinteros/gotext from 1.7.1 to 1.7.2 [[#981](https://github.com/opencloud-eu/opencloud/pull/981)]
|
||||
- build(deps): bump @types/node from 22.15.19 to 22.15.29 in /services/idp [[#980](https://github.com/opencloud-eu/opencloud/pull/980)]
|
||||
- build(deps): bump github.com/opencloud-eu/libre-graph-api-go from 1.0.6 to 1.0.7 [[#982](https://github.com/opencloud-eu/opencloud/pull/982)]
|
||||
- build(deps-dev): bump sass-loader from 16.0.4 to 16.0.5 in /services/idp [[#979](https://github.com/opencloud-eu/opencloud/pull/979)]
|
||||
- build(deps): bump web-vitals from 4.2.4 to 5.0.2 in /services/idp [[#978](https://github.com/opencloud-eu/opencloud/pull/978)]
|
||||
- build(deps): bump github.com/open-policy-agent/opa from 1.4.2 to 1.5.0 [[#977](https://github.com/opencloud-eu/opencloud/pull/977)]
|
||||
- build(deps-dev): bump cldr from 7.5.0 to 7.9.0 in /services/idp [[#975](https://github.com/opencloud-eu/opencloud/pull/975)]
|
||||
- build(deps): bump github.com/olekukonko/tablewriter from 1.0.6 to 1.0.7 [[#974](https://github.com/opencloud-eu/opencloud/pull/974)]
|
||||
- build(deps): bump go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc from 0.60.0 to 0.61.0 [[#915](https://github.com/opencloud-eu/opencloud/pull/915)]
|
||||
- build(deps): bump go.opentelemetry.io/contrib/zpages from 0.60.0 to 0.61.0 [[#938](https://github.com/opencloud-eu/opencloud/pull/938)]
|
||||
- build(deps): bump @testing-library/user-event from 14.5.2 to 14.6.1 in /services/idp [[#939](https://github.com/opencloud-eu/opencloud/pull/939)]
|
||||
- build(deps): bump i18next-browser-languagedetector from 7.2.1 to 8.1.0 in /services/idp [[#937](https://github.com/opencloud-eu/opencloud/pull/937)]
|
||||
- build(deps): bump go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp from 0.60.0 to 0.61.0 [[#923](https://github.com/opencloud-eu/opencloud/pull/923)]
|
||||
- build(deps): bump github.com/nats-io/nats-server/v2 from 2.11.3 to 2.11.4 [[#914](https://github.com/opencloud-eu/opencloud/pull/914)]
|
||||
- build(deps): bump go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc from 1.35.0 to 1.36.0 [[#907](https://github.com/opencloud-eu/opencloud/pull/907)]
|
||||
- build(deps): bump go.opentelemetry.io/otel/trace from 1.35.0 to 1.36.0 [[#906](https://github.com/opencloud-eu/opencloud/pull/906)]
|
||||
- build(deps): bump github.com/blevesearch/bleve/v2 from 2.5.0 to 2.5.1 [[#900](https://github.com/opencloud-eu/opencloud/pull/900)]
|
||||
- build(deps): bump axios from 1.7.7 to 1.8.2 in /services/idp [[#902](https://github.com/opencloud-eu/opencloud/pull/902)]
|
||||
- build(deps): bump github.com/opencloud-eu/libre-graph-api-go from 1.0.5 to 1.0.6 [[#899](https://github.com/opencloud-eu/opencloud/pull/899)]
|
||||
- build(deps): bump @types/node from 20.14.11 to 22.15.19 in /services/idp [[#886](https://github.com/opencloud-eu/opencloud/pull/886)]
|
||||
- build(deps-dev): bump i18next-conv from 14.1.0 to 15.1.1 in /services/idp [[#887](https://github.com/opencloud-eu/opencloud/pull/887)]
|
||||
- build(deps): bump golang.org/x/net from 0.39.0 to 0.40.0 [[#889](https://github.com/opencloud-eu/opencloud/pull/889)]
|
||||
- build(deps): bump github.com/olekukonko/tablewriter from 0.0.5 to 1.0.6 [[#888](https://github.com/opencloud-eu/opencloud/pull/888)]
|
||||
|
||||
## [2.3.0](https://github.com/opencloud-eu/opencloud/releases/tag/v2.3.0) - 2025-05-19
|
||||
|
||||
### ❤️ Thanks to all contributors! ❤️
|
||||
|
||||
@@ -8,7 +8,7 @@ This deployment example is documented in two locations for different audiences:
|
||||
|
||||
* In the [Admin Documentation](https://docs.opencloud.eu/docs/admin/intro)\
|
||||
Providing two variants using detailed configuration step by step guides:\
|
||||
[Docker Compose Setup](https://docs.opencloud.eu/docs/admin/getting-started/docker/docker-compose) and [Docker Compose Local](https://docs.opencloud.eu/docs/admin/getting-started/docker/docker-compose-local).\
|
||||
[Docker Compose Setup](https://docs.opencloud.eu/docs/admin/getting-started/container/docker-compose) and [Docker Compose Local](https://docs.opencloud.eu/docs/admin/getting-started/container/docker-compose-local).\
|
||||
Note that these examples use LetsEncrypt certificates and are intended for production use.
|
||||
|
||||
* In the [Developer Documentation](https://docs.opencloud.eu/docs/dev/intro)\
|
||||
|
||||
@@ -53,7 +53,7 @@ services:
|
||||
restart: always
|
||||
|
||||
collabora:
|
||||
image: collabora/code:25.04.1.1.1
|
||||
image: collabora/code:25.04.2.1.1
|
||||
# release notes: https://www.collaboraonline.com/release-notes/
|
||||
networks:
|
||||
opencloud-net:
|
||||
|
||||
107
go.mod
107
go.mod
@@ -11,7 +11,7 @@ require (
|
||||
github.com/Nerzal/gocloak/v13 v13.9.0
|
||||
github.com/bbalet/stopwords v1.0.0
|
||||
github.com/beevik/etree v1.5.1
|
||||
github.com/blevesearch/bleve/v2 v2.5.0
|
||||
github.com/blevesearch/bleve/v2 v2.5.2
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible
|
||||
github.com/coreos/go-oidc/v3 v3.14.1
|
||||
github.com/cs3org/go-cs3apis v0.0.0-20241105092511-3ad35d174fc1
|
||||
@@ -49,25 +49,25 @@ require (
|
||||
github.com/jinzhu/now v1.1.5
|
||||
github.com/justinas/alice v1.2.0
|
||||
github.com/kovidgoyal/imaging v1.6.4
|
||||
github.com/leonelquinteros/gotext v1.7.1
|
||||
github.com/leonelquinteros/gotext v1.7.2
|
||||
github.com/libregraph/idm v0.5.0
|
||||
github.com/libregraph/lico v0.66.0
|
||||
github.com/mitchellh/mapstructure v1.5.0
|
||||
github.com/mna/pigeon v1.3.0
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
|
||||
github.com/nats-io/nats-server/v2 v2.11.3
|
||||
github.com/nats-io/nats.go v1.42.0
|
||||
github.com/nats-io/nats-server/v2 v2.11.4
|
||||
github.com/nats-io/nats.go v1.43.0
|
||||
github.com/oklog/run v1.1.0
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
github.com/olekukonko/tablewriter v1.0.7
|
||||
github.com/onsi/ginkgo v1.16.5
|
||||
github.com/onsi/ginkgo/v2 v2.23.4
|
||||
github.com/onsi/gomega v1.37.0
|
||||
github.com/open-policy-agent/opa v1.4.2
|
||||
github.com/opencloud-eu/libre-graph-api-go v1.0.5
|
||||
github.com/opencloud-eu/reva/v2 v2.33.0
|
||||
github.com/open-policy-agent/opa v1.5.1
|
||||
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20250603072916-fa601fb14450
|
||||
github.com/opencloud-eu/reva/v2 v2.33.1
|
||||
github.com/orcaman/concurrent-map v1.0.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/pkg/xattr v0.4.10
|
||||
github.com/pkg/xattr v0.4.11
|
||||
github.com/prometheus/client_golang v1.22.0
|
||||
github.com/r3labs/sse/v2 v2.10.0
|
||||
github.com/riandyrn/otelchi v0.12.1
|
||||
@@ -88,24 +88,24 @@ require (
|
||||
github.com/xhit/go-simple-mail/v2 v2.16.0
|
||||
go-micro.dev/v4 v4.11.0
|
||||
go.etcd.io/bbolt v1.4.0
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0
|
||||
go.opentelemetry.io/contrib/zpages v0.60.0
|
||||
go.opentelemetry.io/otel v1.35.0
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0
|
||||
go.opentelemetry.io/contrib/zpages v0.61.0
|
||||
go.opentelemetry.io/otel v1.36.0
|
||||
go.opentelemetry.io/otel/exporters/jaeger v1.17.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0
|
||||
go.opentelemetry.io/otel/sdk v1.35.0
|
||||
go.opentelemetry.io/otel/trace v1.35.0
|
||||
golang.org/x/crypto v0.38.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.36.0
|
||||
go.opentelemetry.io/otel/sdk v1.36.0
|
||||
go.opentelemetry.io/otel/trace v1.36.0
|
||||
golang.org/x/crypto v0.39.0
|
||||
golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac
|
||||
golang.org/x/image v0.27.0
|
||||
golang.org/x/net v0.39.0
|
||||
golang.org/x/image v0.28.0
|
||||
golang.org/x/net v0.40.0
|
||||
golang.org/x/oauth2 v0.30.0
|
||||
golang.org/x/sync v0.14.0
|
||||
golang.org/x/sync v0.15.0
|
||||
golang.org/x/term v0.32.0
|
||||
golang.org/x/text v0.25.0
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb
|
||||
google.golang.org/grpc v1.72.1
|
||||
golang.org/x/text v0.26.0
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237
|
||||
google.golang.org/grpc v1.72.2
|
||||
google.golang.org/protobuf v1.36.6
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
gotest.tools/v3 v3.5.2
|
||||
@@ -128,35 +128,35 @@ require (
|
||||
github.com/amoghe/go-crypt v0.0.0-20220222110647-20eada5f5964 // indirect
|
||||
github.com/armon/go-radix v1.0.0 // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||
github.com/aws/aws-sdk-go v1.55.6 // indirect
|
||||
github.com/aws/aws-sdk-go v1.55.7 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bitly/go-simplejson v0.5.0 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.22.0 // indirect
|
||||
github.com/blevesearch/bleve_index_api v1.2.7 // indirect
|
||||
github.com/blevesearch/geo v0.1.20 // indirect
|
||||
github.com/blevesearch/bleve_index_api v1.2.8 // indirect
|
||||
github.com/blevesearch/geo v0.2.3 // indirect
|
||||
github.com/blevesearch/go-faiss v1.0.25 // indirect
|
||||
github.com/blevesearch/go-porterstemmer v1.0.3 // indirect
|
||||
github.com/blevesearch/gtreap v0.1.1 // indirect
|
||||
github.com/blevesearch/mmap-go v1.0.4 // indirect
|
||||
github.com/blevesearch/scorch_segment_api/v2 v2.3.9 // indirect
|
||||
github.com/blevesearch/scorch_segment_api/v2 v2.3.10 // indirect
|
||||
github.com/blevesearch/segment v0.9.1 // indirect
|
||||
github.com/blevesearch/snowballstem v0.9.0 // indirect
|
||||
github.com/blevesearch/upsidedown_store_api v1.0.2 // indirect
|
||||
github.com/blevesearch/vellum v1.1.0 // indirect
|
||||
github.com/blevesearch/zapx/v11 v11.4.1 // indirect
|
||||
github.com/blevesearch/zapx/v12 v12.4.1 // indirect
|
||||
github.com/blevesearch/zapx/v13 v13.4.1 // indirect
|
||||
github.com/blevesearch/zapx/v14 v14.4.1 // indirect
|
||||
github.com/blevesearch/zapx/v15 v15.4.1 // indirect
|
||||
github.com/blevesearch/zapx/v16 v16.2.2 // indirect
|
||||
github.com/blevesearch/zapx/v11 v11.4.2 // indirect
|
||||
github.com/blevesearch/zapx/v12 v12.4.2 // indirect
|
||||
github.com/blevesearch/zapx/v13 v13.4.2 // indirect
|
||||
github.com/blevesearch/zapx/v14 v14.4.2 // indirect
|
||||
github.com/blevesearch/zapx/v15 v15.4.2 // indirect
|
||||
github.com/blevesearch/zapx/v16 v16.2.4 // indirect
|
||||
github.com/bluele/gcache v0.0.2 // indirect
|
||||
github.com/bombsimon/logrusr/v3 v3.1.0 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/cenkalti/backoff/v5 v5.0.2 // indirect
|
||||
github.com/ceph/go-ceph v0.33.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/cevaris/ordered_map v0.0.0-20190319150403-3adeae072e73 // indirect
|
||||
github.com/cloudflare/circl v1.3.7 // indirect
|
||||
github.com/coreos/go-semver v0.3.0 // indirect
|
||||
github.com/coreos/go-semver v0.3.1 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
||||
github.com/cornelk/hashmap v1.0.8 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect
|
||||
@@ -177,7 +177,7 @@ require (
|
||||
github.com/evanphx/json-patch/v5 v5.5.0 // indirect
|
||||
github.com/fatih/color v1.18.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.8.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||
github.com/gdexlab/go-render v1.0.1 // indirect
|
||||
github.com/go-acme/lego/v4 v4.4.0 // indirect
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect
|
||||
@@ -211,12 +211,11 @@ require (
|
||||
github.com/gofrs/flock v0.12.1 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
|
||||
github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/gomodule/redigo v1.9.2 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/google/go-tpm v0.9.3 // indirect
|
||||
github.com/google/go-tpm v0.9.5 // indirect
|
||||
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect
|
||||
github.com/google/renameio/v2 v2.0.0 // indirect
|
||||
github.com/gookit/color v1.5.4 // indirect
|
||||
@@ -247,7 +246,7 @@ require (
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.27 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.28 // indirect
|
||||
github.com/maxymania/go-system v0.0.0-20170110133659-647cc364bf0b // indirect
|
||||
github.com/mendsley/gojwk v0.0.0-20141217222730-4d5ec6e58103 // indirect
|
||||
github.com/miekg/dns v1.1.57 // indirect
|
||||
@@ -255,7 +254,7 @@ require (
|
||||
github.com/minio/crc64nvme v1.0.1 // indirect
|
||||
github.com/minio/highwayhash v1.0.3 // indirect
|
||||
github.com/minio/md5-simd v1.1.2 // indirect
|
||||
github.com/minio/minio-go/v7 v7.0.89 // indirect
|
||||
github.com/minio/minio-go/v7 v7.0.92 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
@@ -266,17 +265,20 @@ require (
|
||||
github.com/nats-io/nkeys v0.4.11 // indirect
|
||||
github.com/nats-io/nuid v1.0.1 // indirect
|
||||
github.com/nxadm/tail v1.4.8 // indirect
|
||||
github.com/olekukonko/errors v0.0.0-20250405072817-4e6d85265da6 // indirect
|
||||
github.com/olekukonko/ll v0.0.8 // indirect
|
||||
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect
|
||||
github.com/pablodz/inotifywaitgo v0.0.9 // indirect
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
|
||||
github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.15 // indirect
|
||||
github.com/pjbgf/sha1cd v0.3.2 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/pquerna/cachecontrol v0.2.0 // indirect
|
||||
github.com/prometheus/alertmanager v0.28.1 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/client_model v0.6.2 // indirect
|
||||
github.com/prometheus/common v0.62.0 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
github.com/prometheus/statsd_exporter v0.22.8 // indirect
|
||||
@@ -302,8 +304,10 @@ require (
|
||||
github.com/tchap/go-patricia/v2 v2.3.2 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.1 // indirect
|
||||
github.com/tinylib/msgp v1.3.0 // indirect
|
||||
github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208 // indirect
|
||||
github.com/trustelem/zxcvbn v1.0.1 // indirect
|
||||
github.com/vektah/gqlparser/v2 v2.5.26 // indirect
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
|
||||
github.com/wk8/go-ordered-map v1.0.0 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||
@@ -312,25 +316,24 @@ require (
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
|
||||
github.com/yashtewari/glob-intersection v0.2.0 // indirect
|
||||
go.etcd.io/etcd/api/v3 v3.5.20 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.20 // indirect
|
||||
go.etcd.io/etcd/client/v3 v3.5.20 // indirect
|
||||
go.etcd.io/etcd/api/v3 v3.6.0 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.6.0 // indirect
|
||||
go.etcd.io/etcd/client/v3 v3.6.0 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.35.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
|
||||
go.uber.org/atomic v1.11.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.36.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.36.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.6.0 // indirect
|
||||
go.uber.org/automaxprocs v1.6.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.23.0 // indirect
|
||||
golang.org/x/mod v0.24.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
golang.org/x/mod v0.25.0 // indirect
|
||||
golang.org/x/sys v0.33.0 // indirect
|
||||
golang.org/x/time v0.11.0 // indirect
|
||||
golang.org/x/tools v0.31.0 // indirect
|
||||
golang.org/x/tools v0.33.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||
google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237 // indirect
|
||||
gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
|
||||
217
go.sum
217
go.sum
@@ -109,6 +109,8 @@ github.com/alexedwards/argon2id v1.0.0/go.mod h1:tYKkqIjzXvZdzPvADMWOEZ+l6+BD6Ct
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.61.976/go.mod h1:pUKYbK5JQ+1Dfxk80P0qxGqe5dkxDoabbZS7zOcouyA=
|
||||
github.com/amoghe/go-crypt v0.0.0-20220222110647-20eada5f5964 h1:I9YN9WMo3SUh7p/4wKeNvD/IQla3U3SUa61U7ul+xM4=
|
||||
github.com/amoghe/go-crypt v0.0.0-20220222110647-20eada5f5964/go.mod h1:eFiR01PwTcpbzXtdMces7zxg6utvFM5puiWHpWB8D/k=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
|
||||
github.com/antithesishq/antithesis-sdk-go v0.4.3-default-no-op h1:+OSa/t11TFhqfrX0EOSqQBDJ0YlpmK0rDSiB19dg9M0=
|
||||
@@ -126,13 +128,12 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
||||
github.com/aws/aws-sdk-go v1.37.27/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
||||
github.com/aws/aws-sdk-go v1.55.6 h1:cSg4pvZ3m8dgYcgqB97MrcdjUmZ1BeMYKUxMMB89IPk=
|
||||
github.com/aws/aws-sdk-go v1.55.6/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
|
||||
github.com/aws/aws-sdk-go v1.55.7 h1:UJrkFq7es5CShfBwlWAC8DA077vp8PyVbQd3lqLiztE=
|
||||
github.com/aws/aws-sdk-go v1.55.7/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
|
||||
github.com/bbalet/stopwords v1.0.0 h1:0TnGycCtY0zZi4ltKoOGRFIlZHv0WqpoIGUsObjztfo=
|
||||
github.com/bbalet/stopwords v1.0.0/go.mod h1:sAWrQoDMfqARGIn4s6dp7OW7ISrshUD8IP2q3KoqPjc=
|
||||
github.com/beevik/etree v1.5.1 h1:TC3zyxYp+81wAmbsi8SWUpZCurbxa6S8RITYRSkNRwo=
|
||||
github.com/beevik/etree v1.5.1/go.mod h1:gPNJNaBGVZ9AwsidazFZyygnd+0pAU38N4D+WemwKNs=
|
||||
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
@@ -146,12 +147,12 @@ github.com/bits-and-blooms/bitset v1.12.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6
|
||||
github.com/bits-and-blooms/bitset v1.22.0 h1:Tquv9S8+SGaS3EhyA+up3FXzmkhxPGjQQCkcs2uw7w4=
|
||||
github.com/bits-and-blooms/bitset v1.22.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
|
||||
github.com/blevesearch/bleve/v2 v2.5.0 h1:HzYqBy/5/M9Ul9ESEmXzN/3Jl7YpmWBdHM/+zzv/3k4=
|
||||
github.com/blevesearch/bleve/v2 v2.5.0/go.mod h1:PcJzTPnEynO15dCf9isxOga7YFRa/cMSsbnRwnszXUk=
|
||||
github.com/blevesearch/bleve_index_api v1.2.7 h1:c8r9vmbaYQroAMSGag7zq5gEVPiuXrUQDqfnj7uYZSY=
|
||||
github.com/blevesearch/bleve_index_api v1.2.7/go.mod h1:rKQDl4u51uwafZxFrPD1R7xFOwKnzZW7s/LSeK4lgo0=
|
||||
github.com/blevesearch/geo v0.1.20 h1:paaSpu2Ewh/tn5DKn/FB5SzvH0EWupxHEIwbCk/QPqM=
|
||||
github.com/blevesearch/geo v0.1.20/go.mod h1:DVG2QjwHNMFmjo+ZgzrIq2sfCh6rIHzy9d9d0B59I6w=
|
||||
github.com/blevesearch/bleve/v2 v2.5.2 h1:Ab0r0MODV2C5A6BEL87GqLBySqp/s9xFgceCju6BQk8=
|
||||
github.com/blevesearch/bleve/v2 v2.5.2/go.mod h1:5Dj6dUQxZM6aqYT3eutTD/GpWKGFSsV8f7LDidFbwXo=
|
||||
github.com/blevesearch/bleve_index_api v1.2.8 h1:Y98Pu5/MdlkRyLM0qDHostYo7i+Vv1cDNhqTeR4Sy6Y=
|
||||
github.com/blevesearch/bleve_index_api v1.2.8/go.mod h1:rKQDl4u51uwafZxFrPD1R7xFOwKnzZW7s/LSeK4lgo0=
|
||||
github.com/blevesearch/geo v0.2.3 h1:K9/vbGI9ehlXdxjxDRJtoAMt7zGAsMIzc6n8zWcwnhg=
|
||||
github.com/blevesearch/geo v0.2.3/go.mod h1:K56Q33AzXt2YExVHGObtmRSFYZKYGv0JEN5mdacJJR8=
|
||||
github.com/blevesearch/go-faiss v1.0.25 h1:lel1rkOUGbT1CJ0YgzKwC7k+XH0XVBHnCVWahdCXk4U=
|
||||
github.com/blevesearch/go-faiss v1.0.25/go.mod h1:OMGQwOaRRYxrmeNdMrXJPvVx8gBnvE5RYrr0BahNnkk=
|
||||
github.com/blevesearch/go-porterstemmer v1.0.3 h1:GtmsqID0aZdCSNiY8SkuPJ12pD4jI+DdXTAn4YRcHCo=
|
||||
@@ -160,8 +161,8 @@ github.com/blevesearch/gtreap v0.1.1 h1:2JWigFrzDMR+42WGIN/V2p0cUvn4UP3C4Q5nmaZG
|
||||
github.com/blevesearch/gtreap v0.1.1/go.mod h1:QaQyDRAT51sotthUWAH4Sj08awFSSWzgYICSZ3w0tYk=
|
||||
github.com/blevesearch/mmap-go v1.0.4 h1:OVhDhT5B/M1HNPpYPBKIEJaD0F3Si+CrEKULGCDPWmc=
|
||||
github.com/blevesearch/mmap-go v1.0.4/go.mod h1:EWmEAOmdAS9z/pi/+Toxu99DnsbhG1TIxUoRmJw/pSs=
|
||||
github.com/blevesearch/scorch_segment_api/v2 v2.3.9 h1:X6nJXnNHl7nasXW+U6y2Ns2Aw8F9STszkYkyBfQ+p0o=
|
||||
github.com/blevesearch/scorch_segment_api/v2 v2.3.9/go.mod h1:IrzspZlVjhf4X29oJiEhBxEteTqOY9RlYlk1lCmYHr4=
|
||||
github.com/blevesearch/scorch_segment_api/v2 v2.3.10 h1:Yqk0XD1mE0fDZAJXTjawJ8If/85JxnLd8v5vG/jWE/s=
|
||||
github.com/blevesearch/scorch_segment_api/v2 v2.3.10/go.mod h1:Z3e6ChN3qyN35yaQpl00MfI5s8AxUJbpTR/DL8QOQ+8=
|
||||
github.com/blevesearch/segment v0.9.1 h1:+dThDy+Lvgj5JMxhmOVlgFfkUtZV2kw49xax4+jTfSU=
|
||||
github.com/blevesearch/segment v0.9.1/go.mod h1:zN21iLm7+GnBHWTao9I+Au/7MBiL8pPFtJBJTsk6kQw=
|
||||
github.com/blevesearch/snowballstem v0.9.0 h1:lMQ189YspGP6sXvZQ4WZ+MLawfV8wOmPoD/iWeNXm8s=
|
||||
@@ -170,18 +171,18 @@ github.com/blevesearch/upsidedown_store_api v1.0.2 h1:U53Q6YoWEARVLd1OYNc9kvhBMG
|
||||
github.com/blevesearch/upsidedown_store_api v1.0.2/go.mod h1:M01mh3Gpfy56Ps/UXHjEO/knbqyQ1Oamg8If49gRwrQ=
|
||||
github.com/blevesearch/vellum v1.1.0 h1:CinkGyIsgVlYf8Y2LUQHvdelgXr6PYuvoDIajq6yR9w=
|
||||
github.com/blevesearch/vellum v1.1.0/go.mod h1:QgwWryE8ThtNPxtgWJof5ndPfx0/YMBh+W2weHKPw8Y=
|
||||
github.com/blevesearch/zapx/v11 v11.4.1 h1:qFCPlFbsEdwbbckJkysptSQOsHn4s6ZOHL5GMAIAVHA=
|
||||
github.com/blevesearch/zapx/v11 v11.4.1/go.mod h1:qNOGxIqdPC1MXauJCD9HBG487PxviTUUbmChFOAosGs=
|
||||
github.com/blevesearch/zapx/v12 v12.4.1 h1:K77bhypII60a4v8mwvav7r4IxWA8qxhNjgF9xGdb9eQ=
|
||||
github.com/blevesearch/zapx/v12 v12.4.1/go.mod h1:QRPrlPOzAxBNMI0MkgdD+xsTqx65zbuPr3Ko4Re49II=
|
||||
github.com/blevesearch/zapx/v13 v13.4.1 h1:EnkEMZFUK0lsW/jOJJF2xOcp+W8TjEsyeN5BeAZEYYE=
|
||||
github.com/blevesearch/zapx/v13 v13.4.1/go.mod h1:e6duBMlCvgbH9rkzNMnUa9hRI9F7ri2BRcHfphcmGn8=
|
||||
github.com/blevesearch/zapx/v14 v14.4.1 h1:G47kGCshknBZzZAtjcnIAMn3oNx8XBLxp8DMq18ogyE=
|
||||
github.com/blevesearch/zapx/v14 v14.4.1/go.mod h1:O7sDxiaL2r2PnCXbhh1Bvm7b4sP+jp4unE9DDPWGoms=
|
||||
github.com/blevesearch/zapx/v15 v15.4.1 h1:B5IoTMUCEzFdc9FSQbhVOxAY+BO17c05866fNruiI7g=
|
||||
github.com/blevesearch/zapx/v15 v15.4.1/go.mod h1:b/MreHjYeQoLjyY2+UaM0hGZZUajEbE0xhnr1A2/Q6Y=
|
||||
github.com/blevesearch/zapx/v16 v16.2.2 h1:MifKJVRTEhMTgSlle2bDRTb39BGc9jXFRLPZc6r0Rzk=
|
||||
github.com/blevesearch/zapx/v16 v16.2.2/go.mod h1:B9Pk4G1CqtErgQV9DyCSA9Lb7WZe4olYfGw7fVDZ4sk=
|
||||
github.com/blevesearch/zapx/v11 v11.4.2 h1:l46SV+b0gFN+Rw3wUI1YdMWdSAVhskYuvxlcgpQFljs=
|
||||
github.com/blevesearch/zapx/v11 v11.4.2/go.mod h1:4gdeyy9oGa/lLa6D34R9daXNUvfMPZqUYjPwiLmekwc=
|
||||
github.com/blevesearch/zapx/v12 v12.4.2 h1:fzRbhllQmEMUuAQ7zBuMvKRlcPA5ESTgWlDEoB9uQNE=
|
||||
github.com/blevesearch/zapx/v12 v12.4.2/go.mod h1:TdFmr7afSz1hFh/SIBCCZvcLfzYvievIH6aEISCte58=
|
||||
github.com/blevesearch/zapx/v13 v13.4.2 h1:46PIZCO/ZuKZYgxI8Y7lOJqX3Irkc3N8W82QTK3MVks=
|
||||
github.com/blevesearch/zapx/v13 v13.4.2/go.mod h1:knK8z2NdQHlb5ot/uj8wuvOq5PhDGjNYQQy0QDnopZk=
|
||||
github.com/blevesearch/zapx/v14 v14.4.2 h1:2SGHakVKd+TrtEqpfeq8X+So5PShQ5nW6GNxT7fWYz0=
|
||||
github.com/blevesearch/zapx/v14 v14.4.2/go.mod h1:rz0XNb/OZSMjNorufDGSpFpjoFKhXmppH9Hi7a877D8=
|
||||
github.com/blevesearch/zapx/v15 v15.4.2 h1:sWxpDE0QQOTjyxYbAVjt3+0ieu8NCE0fDRaFxEsp31k=
|
||||
github.com/blevesearch/zapx/v15 v15.4.2/go.mod h1:1pssev/59FsuWcgSnTa0OeEpOzmhtmr/0/11H0Z8+Nw=
|
||||
github.com/blevesearch/zapx/v16 v16.2.4 h1:tGgfvleXTAkwsD5mEzgM3zCS/7pgocTCnO1oyAUjlww=
|
||||
github.com/blevesearch/zapx/v16 v16.2.4/go.mod h1:Rti/REtuuMmzwsI8/C/qIzRaEoSK/wiFYw5e5ctUKKs=
|
||||
github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw=
|
||||
github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0=
|
||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
|
||||
@@ -201,6 +202,8 @@ github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QH
|
||||
github.com/cenkalti/backoff/v4 v4.1.0/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/cenkalti/backoff/v5 v5.0.2 h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8=
|
||||
github.com/cenkalti/backoff/v5 v5.0.2/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/ceph/go-ceph v0.33.0 h1:xT9v/MAa+DIBmflyITyFkGRgWngATghGegKJguEOInQ=
|
||||
@@ -224,8 +227,9 @@ github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkE
|
||||
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-oidc/v3 v3.14.1 h1:9ePWwfdwC4QKRlCXsJGou56adA/owXczOzwKdOumLqk=
|
||||
github.com/coreos/go-oidc/v3 v3.14.1/go.mod h1:HaZ3szPaZ0e4r6ebqvsLWlk2Tn+aejfmrfah6hnSYEU=
|
||||
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-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
|
||||
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
@@ -316,8 +320,8 @@ github.com/fschade/icap-client v0.0.0-20240802074440-aade4a234387 h1:Y3wZgTr29sL
|
||||
github.com/fschade/icap-client v0.0.0-20240802074440-aade4a234387/go.mod h1:HpntrRsQA6RKNXy2Nbr4kVj+NO3OYWpAQUVxeya+3sU=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
|
||||
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY=
|
||||
github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok=
|
||||
github.com/gdexlab/go-render v1.0.1 h1:rxqB3vo5s4n1kF0ySmoNeSPRYkEsyHgln4jFIQY7v0U=
|
||||
@@ -458,8 +462,6 @@ github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXe
|
||||
github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 h1:gtexQ/VGyN+VVFRXSFiguSNcXmS6rkKT+X7FdIrTtfo=
|
||||
github.com/golang/geo v0.0.0-20210211234256-740aa86cb551/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
@@ -527,8 +529,8 @@ github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD
|
||||
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||
github.com/google/go-tika v0.3.1 h1:l+jr10hDhZjcgxFRfcQChRLo1bPXQeLFluMyvDhXTTA=
|
||||
github.com/google/go-tika v0.3.1/go.mod h1:DJh5N8qxXIl85QkqmXknd+PeeRkUOTbvwyYf7ieDz6c=
|
||||
github.com/google/go-tpm v0.9.3 h1:+yx0/anQuGzi+ssRqeD6WpXjW2L/V0dItUayO0i9sRc=
|
||||
github.com/google/go-tpm v0.9.3/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY=
|
||||
github.com/google/go-tpm v0.9.5 h1:ocUmnDebX54dnW+MQWGQRbdaAcJELsa6PqZhJ48KwVU=
|
||||
github.com/google/go-tpm v0.9.5/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
@@ -714,8 +716,8 @@ github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvf
|
||||
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
|
||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||
github.com/leonelquinteros/gotext v1.7.1 h1:/JNPeE3lY5JeVYv2+KBpz39994W3W9fmZCGq3eO9Ri8=
|
||||
github.com/leonelquinteros/gotext v1.7.1/go.mod h1:I0WoFDn9u2D3VbPnnDPT8mzZu0iSXG8iih+AH2fHHqg=
|
||||
github.com/leonelquinteros/gotext v1.7.2 h1:bDPndU8nt+/kRo1m4l/1OXiiy2v7Z7dfPQ9+YP7G1Mc=
|
||||
github.com/leonelquinteros/gotext v1.7.2/go.mod h1:9/haCkm5P7Jay1sxKDGJ5WIg4zkz8oZKw4ekNpALob8=
|
||||
github.com/libregraph/idm v0.5.0 h1:tDMwKbAOZzdeDYMxVlY5PbSqRKO7dbAW9KT42A51WSk=
|
||||
github.com/libregraph/idm v0.5.0/go.mod h1:BGMwIQ/6orJSPVzJ1x6kgG2JyG9GY05YFmbsnaD80k0=
|
||||
github.com/libregraph/lico v0.66.0 h1:7T6fD1YF0Ep9n0g4KN6dvWHTlDC3awrQpgsP5GdYCF4=
|
||||
@@ -761,8 +763,8 @@ github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-sqlite3 v1.14.27 h1:drZCnuvf37yPfs95E5jd9s3XhdVWLal+6BOK6qrv6IU=
|
||||
github.com/mattn/go-sqlite3 v1.14.27/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/mattn/go-sqlite3 v1.14.28 h1:ThEiQrnbtumT+QMknw63Befp/ce/nUPgBPMlRFEum7A=
|
||||
github.com/mattn/go-sqlite3 v1.14.28/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/mattn/go-tty v0.0.0-20180219170247-931426f7535a/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=
|
||||
github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvrWyR0=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
@@ -782,8 +784,8 @@ github.com/minio/highwayhash v1.0.3 h1:kbnuUMoHYyVl7szWjSxJnxw11k2U709jqFPPmIUyD
|
||||
github.com/minio/highwayhash v1.0.3/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ=
|
||||
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
|
||||
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
|
||||
github.com/minio/minio-go/v7 v7.0.89 h1:hx4xV5wwTUfyv8LarhJAwNecnXpoTsj9v3f3q/ZkiJU=
|
||||
github.com/minio/minio-go/v7 v7.0.89/go.mod h1:2rFnGAp02p7Dddo1Fq4S2wYOfpF0MUTSeLTRC90I204=
|
||||
github.com/minio/minio-go/v7 v7.0.92 h1:jpBFWyRS3p8P/9tsRc+NuvqoFi7qAmTCFPoRFmobbVw=
|
||||
github.com/minio/minio-go/v7 v7.0.92/go.mod h1:vTIc8DNcnAZIhyFsk8EB90AbPjj3j68aWIEQCiPj7d0=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
|
||||
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
|
||||
@@ -820,10 +822,10 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW
|
||||
github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04/go.mod h1:5sN+Lt1CaY4wsPvgQH/jsuJi4XO2ssZbdsIizr4CVC8=
|
||||
github.com/nats-io/jwt/v2 v2.7.4 h1:jXFuDDxs/GQjGDZGhNgH4tXzSUK6WQi2rsj4xmsNOtI=
|
||||
github.com/nats-io/jwt/v2 v2.7.4/go.mod h1:me11pOkwObtcBNR8AiMrUbtVOUGkqYjMQZ6jnSdVUIA=
|
||||
github.com/nats-io/nats-server/v2 v2.11.3 h1:AbGtXxuwjo0gBroLGGr/dE0vf24kTKdRnBq/3z/Fdoc=
|
||||
github.com/nats-io/nats-server/v2 v2.11.3/go.mod h1:6Z6Fd+JgckqzKig7DYwhgrE7bJ6fypPHnGPND+DqgMY=
|
||||
github.com/nats-io/nats.go v1.42.0 h1:ynIMupIOvf/ZWH/b2qda6WGKGNSjwOUutTpWRvAmhaM=
|
||||
github.com/nats-io/nats.go v1.42.0/go.mod h1:iRWIPokVIFbVijxuMQq4y9ttaBTMe0SFdlZfMDd+33g=
|
||||
github.com/nats-io/nats-server/v2 v2.11.4 h1:oQhvy6He6ER926sGqIKBKuYHH4BGnUQCNb0Y5Qa+M54=
|
||||
github.com/nats-io/nats-server/v2 v2.11.4/go.mod h1:jFnKKwbNeq6IfLHq+OMnl7vrFRihQ/MkhRbiWfjLdjU=
|
||||
github.com/nats-io/nats.go v1.43.0 h1:uRFZ2FEoRvP64+UUhaTokyS18XBCR/xM2vQZKO4i8ug=
|
||||
github.com/nats-io/nats.go v1.43.0/go.mod h1:iRWIPokVIFbVijxuMQq4y9ttaBTMe0SFdlZfMDd+33g=
|
||||
github.com/nats-io/nkeys v0.4.11 h1:q44qGV008kYd9W1b1nEBkNzvnWxtRSQ7A8BoqRrcfa0=
|
||||
github.com/nats-io/nkeys v0.4.11/go.mod h1:szDimtgmfOi9n25JpfIdGw12tZFYXqhGxjhVxsatHVE=
|
||||
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
|
||||
@@ -842,8 +844,13 @@ github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+
|
||||
github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA=
|
||||
github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
github.com/olekukonko/errors v0.0.0-20250405072817-4e6d85265da6 h1:r3FaAI0NZK3hSmtTDrBVREhKULp8oUeqLT5Eyl2mSPo=
|
||||
github.com/olekukonko/errors v0.0.0-20250405072817-4e6d85265da6/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=
|
||||
github.com/olekukonko/ll v0.0.8 h1:sbGZ1Fx4QxJXEqL/6IG8GEFnYojUSQ45dJVwN2FH2fc=
|
||||
github.com/olekukonko/ll v0.0.8/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=
|
||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
github.com/olekukonko/tablewriter v1.0.7 h1:HCC2e3MM+2g72M81ZcJU11uciw6z/p82aEnm4/ySDGw=
|
||||
github.com/olekukonko/tablewriter v1.0.7/go.mod h1:H428M+HzoUXC6JU2Abj9IT9ooRmdq9CxuDmKMtrOCMs=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
@@ -856,14 +863,14 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y=
|
||||
github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
|
||||
github.com/open-policy-agent/opa v1.4.2 h1:ag4upP7zMsa4WE2p1pwAFeG4Pn3mNwfAx9DLhhJfbjU=
|
||||
github.com/open-policy-agent/opa v1.4.2/go.mod h1:DNzZPKqKh4U0n0ANxcCVlw8lCSv2c+h5G/3QvSYdWZ8=
|
||||
github.com/open-policy-agent/opa v1.5.1 h1:LTxxBJusMVjfs67W4FoRcnMfXADIGFMzpqnfk6D08Cg=
|
||||
github.com/open-policy-agent/opa v1.5.1/go.mod h1:bYbS7u+uhTI+cxHQIpzvr5hxX0hV7urWtY+38ZtjMgk=
|
||||
github.com/opencloud-eu/go-micro-plugins/v4/store/nats-js-kv v0.0.0-20250512152754-23325793059a h1:Sakl76blJAaM6NxylVkgSzktjo2dS504iDotEFJsh3M=
|
||||
github.com/opencloud-eu/go-micro-plugins/v4/store/nats-js-kv v0.0.0-20250512152754-23325793059a/go.mod h1:pjcozWijkNPbEtX5SIQaxEW/h8VAVZYTLx+70bmB3LY=
|
||||
github.com/opencloud-eu/libre-graph-api-go v1.0.5 h1:Wv09oIjCF8zRN8roPzjXXo6ORp2h87/YhmdXE9N4p/A=
|
||||
github.com/opencloud-eu/libre-graph-api-go v1.0.5/go.mod h1:pzatilMEHZFT3qV7C/X3MqOa3NlRQuYhlRhZTL+hN6Q=
|
||||
github.com/opencloud-eu/reva/v2 v2.33.0 h1:uFbt4BC21gU0bbrp4CHABhWR4Xk5H+e2kA7KrEUXGEQ=
|
||||
github.com/opencloud-eu/reva/v2 v2.33.0/go.mod h1:wRZ/7eJTOfkhjtDlYcNt83Loz2drfXssh+5JMDcq/5o=
|
||||
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20250603072916-fa601fb14450 h1:QWn9G2f1R/EbyZSbkjtd9jqNq9X0NIphmmD4KYLNZtA=
|
||||
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20250603072916-fa601fb14450/go.mod h1:pzatilMEHZFT3qV7C/X3MqOa3NlRQuYhlRhZTL+hN6Q=
|
||||
github.com/opencloud-eu/reva/v2 v2.33.1 h1:dm3AxLx7MCHPI9h23iYr/Uw/AQHmQN+G4XlbZQnm35Y=
|
||||
github.com/opencloud-eu/reva/v2 v2.33.1/go.mod h1:0Eu27TSdmj1+0PGn8MjFNh84nW16kGzt2Cxdz9oUncM=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
|
||||
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
|
||||
@@ -885,6 +892,8 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9
|
||||
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
|
||||
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
|
||||
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
|
||||
github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c h1:dAMKvw0MlJT1GshSTtih8C2gDs04w8dReiOGXrGLNoY=
|
||||
github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pierrec/lz4/v4 v4.1.15 h1:MO0/ucJhngq7299dKLwIMtgTfbkoSPF6AoMYDd8Q4q0=
|
||||
github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
@@ -896,8 +905,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
|
||||
github.com/pkg/term v1.1.0/go.mod h1:E25nymQcrSllhX42Ok8MRm1+hyBdHY0dCeiKZ9jpNGw=
|
||||
github.com/pkg/xattr v0.4.10 h1:Qe0mtiNFHQZ296vRgUjRCoPHPqH7VdTOrZx3g0T+pGA=
|
||||
github.com/pkg/xattr v0.4.10/go.mod h1:di8WF84zAKk8jzR1UBTEWh9AUlIZZ7M/JNt8e9B6ktU=
|
||||
github.com/pkg/xattr v0.4.11 h1:DA7usy0rTMNMGvm06b5LhZUwiPj708D89S8DkXpMB1E=
|
||||
github.com/pkg/xattr v0.4.11/go.mod h1:di8WF84zAKk8jzR1UBTEWh9AUlIZZ7M/JNt8e9B6ktU=
|
||||
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/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
@@ -928,8 +937,8 @@ github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
||||
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||
github.com/prometheus/common v0.0.0-20170706130215-fb369f752a7f/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
@@ -1082,6 +1091,8 @@ github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JT
|
||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
|
||||
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tinylib/msgp v1.3.0 h1:ULuf7GPooDaIlbyvgAxBV/FI7ynli6LZ1/nVUNu+0ww=
|
||||
github.com/tinylib/msgp v1.3.0/go.mod h1:ykjzy2wzgrlvpDCRc4LA8UXy6D8bzMSuAF3WD57Gok0=
|
||||
github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU=
|
||||
github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY=
|
||||
github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYgY=
|
||||
@@ -1102,6 +1113,8 @@ github.com/urfave/cli/v2 v2.27.6/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
||||
github.com/valyala/fasttemplate v1.1.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
||||
github.com/vektah/gqlparser/v2 v2.5.26 h1:REqqFkO8+SOEgZHR/eHScjjVjGS8Nk3RMO/juiTobN4=
|
||||
github.com/vektah/gqlparser/v2 v2.5.26/go.mod h1:D1/VCZtV3LPnQrcPBeR/q5jkSQIPti0uYCP/RI0gIeo=
|
||||
github.com/vinyldns/go-vinyldns v0.0.0-20200917153823-148a5f6b8f14/go.mod h1:RWc47jtnVuQv6+lY3c768WtXCas/Xi+U5UFc5xULmYg=
|
||||
github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
|
||||
github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
|
||||
@@ -1143,12 +1156,12 @@ github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQ
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/bbolt v1.4.0 h1:TU77id3TnN/zKr7CO/uk+fBCwF2jGcMuw2B/FMAzYIk=
|
||||
go.etcd.io/bbolt v1.4.0/go.mod h1:AsD+OCi/qPN1giOX1aiLAha3o1U8rAz65bvN4j0sRuk=
|
||||
go.etcd.io/etcd/api/v3 v3.5.20 h1:aKfz3nPZECWoZJXMSH9y6h2adXjtOHaHTGEVCuCmaz0=
|
||||
go.etcd.io/etcd/api/v3 v3.5.20/go.mod h1:QqKGViq4KTgOG43dr/uH0vmGWIaoJY3ggFi6ZH0TH/U=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.20 h1:sZIAtra+xCo56gdf6BR62to/hiie5Bwl7hQIqMzVTEM=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.20/go.mod h1:qaOi1k4ZA9lVLejXNvyPABrVEe7VymMF2433yyRQ7O0=
|
||||
go.etcd.io/etcd/client/v3 v3.5.20 h1:jMT2MwQEhyvhQg49Cec+1ZHJzfUf6ZgcmV0GjPv0tIQ=
|
||||
go.etcd.io/etcd/client/v3 v3.5.20/go.mod h1:J5lbzYRMUR20YolS5UjlqqMcu3/wdEvG5VNBhzyo3m0=
|
||||
go.etcd.io/etcd/api/v3 v3.6.0 h1:vdbkcUBGLf1vfopoGE/uS3Nv0KPyIpUV/HM6w9yx2kM=
|
||||
go.etcd.io/etcd/api/v3 v3.6.0/go.mod h1:Wt5yZqEmxgTNJGHob7mTVBJDZNXiHPtXTcPab37iFOw=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.6.0 h1:nchnPqpuxvv3UuGGHaz0DQKYi5EIW5wOYsgUNRc365k=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.6.0/go.mod h1:Jv5SFWMnGvIBn8o3OaBq/PnT0jjsX8iNokAUessNjoA=
|
||||
go.etcd.io/etcd/client/v3 v3.6.0 h1:/yjKzD+HW5v/3DVj9tpwFxzNbu8hjcKID183ug9duWk=
|
||||
go.etcd.io/etcd/client/v3 v3.6.0/go.mod h1:Jzk/Knqe06pkOZPHXsQ0+vNDvMQrgIqJ0W8DwPdMJMg=
|
||||
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
@@ -1161,37 +1174,35 @@ go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 h1:x7wzEgXfnzJcHDwStJT+mxOz4etr2EcexjqhBvmoakw=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0/go.mod h1:rg+RlpR5dKwaS95IyyZqj5Wd4E13lk/msnTS0Xl9lJM=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ=
|
||||
go.opentelemetry.io/contrib/zpages v0.60.0 h1:wOM9ie1Hz4H88L9KE6GrGbKJhfm+8F1NfW/Y3q9Xt+8=
|
||||
go.opentelemetry.io/contrib/zpages v0.60.0/go.mod h1:xqfToSRGh2MYUsfyErNz8jnNDPlnpZqWM/y6Z2Cx7xw=
|
||||
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
|
||||
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 h1:q4XOmH/0opmeuJtPsbFNivyl7bCt7yRBbeEm2sC/XtQ=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
|
||||
go.opentelemetry.io/contrib/zpages v0.61.0 h1:tYvUj377Dn3k1wf1le/f8YWSNQ8k0byS3jK8PiIXu9Y=
|
||||
go.opentelemetry.io/contrib/zpages v0.61.0/go.mod h1:MFNPHMJOGA1P6m5501ANjOJDp4A9BUQja1Y53CDL8LQ=
|
||||
go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
|
||||
go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
|
||||
go.opentelemetry.io/otel/exporters/jaeger v1.17.0 h1:D7UpUy2Xc2wsi1Ras6V40q806WM07rqoCWzXu7Sqy+4=
|
||||
go.opentelemetry.io/otel/exporters/jaeger v1.17.0/go.mod h1:nPCqOnEH9rNLKqH/+rrUjiMzHJdV1BlpKcTwRTyKkKI=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 h1:1fTNlAIJZGWLP5FVu0fikVry1IsiUnXjf7QFvoNN3Xw=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0/go.mod h1:zjPK58DtkqQFn+YUMbx0M2XV3QgKU0gS9LeGohREyK4=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 h1:m639+BofXTvcY1q8CGs4ItwQarYtJPOWmVobfM1HpVI=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0/go.mod h1:LjReUci/F4BUyv+y4dwnq3h/26iNOeC3wAIqgvTIZVo=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.36.0 h1:dNzwXjZKpMpE2JhmO+9HsPl42NIXFIFSUSSs0fiqra0=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.36.0/go.mod h1:90PoxvaEB5n6AOdZvi+yWJQoE95U8Dhhw2bSyRqnTD0=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.36.0 h1:JgtbA0xkWHnTmYk7YusopJFX6uleBmAuZ8n05NEh8nQ=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.36.0/go.mod h1:179AK5aar5R3eS9FucPy6rggvU0g52cvKId8pv4+v0c=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 h1:xJ2qHD0C1BeYVTLLR9sX12+Qb95kfeD/byKj6Ky1pXg=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0/go.mod h1:u5BF1xyjstDowA1R5QAO9JHzqK+ublenEW/dyqTjBVk=
|
||||
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
|
||||
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
|
||||
go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
|
||||
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w=
|
||||
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
|
||||
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
|
||||
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
|
||||
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
|
||||
go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
|
||||
go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
|
||||
go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
|
||||
go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
|
||||
go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
|
||||
go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
|
||||
go.opentelemetry.io/proto/otlp v1.6.0 h1:jQjP+AQyTf+Fe7OKj/MfkDrmK4MNVtw2NpXsf9fefDI=
|
||||
go.opentelemetry.io/proto/otlp v1.6.0/go.mod h1:cicgGehlFuNdgZkcALOCh3VE6K/u2tAjzlRhDwmVpZc=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
||||
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
|
||||
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
|
||||
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
||||
@@ -1204,8 +1215,8 @@ go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN8
|
||||
go.uber.org/ratelimit v0.0.0-20180316092928-c15da0234277/go.mod h1:2X8KaoNd1J0lZV+PxJk/5+DGbO/tpwLR1m++a7FnB/Y=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
|
||||
go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY=
|
||||
go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY=
|
||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||
golang.org/x/crypto v0.0.0-20180621125126-a49355c7e3f8/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
@@ -1227,8 +1238,8 @@ golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
|
||||
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
|
||||
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
|
||||
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -1244,8 +1255,8 @@ golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac/go.mod h1:hH+7mtFmImwwcMvScy
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E=
|
||||
golang.org/x/image v0.27.0 h1:C8gA4oWU/tKkdCfYT6T2u4faJu3MeNS5O8UPWlPF61w=
|
||||
golang.org/x/image v0.27.0/go.mod h1:xbdrClrAUway1MUTEZDq9mz/UpRwYAkFFNUslZtcB+g=
|
||||
golang.org/x/image v0.28.0 h1:gdem5JW1OLS4FbkWgLO+7ZeFzYtL3xClb97GaUzYMFE=
|
||||
golang.org/x/image v0.28.0/go.mod h1:GUJYXtnGKEUgggyzh+Vxt+AviiCcyiwpsl8iQ8MvwGY=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
@@ -1270,8 +1281,8 @@ 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/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
|
||||
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||
golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
|
||||
golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -1326,8 +1337,8 @@ golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
|
||||
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
|
||||
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
|
||||
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -1354,8 +1365,8 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
|
||||
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
|
||||
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20180622082034-63fc586f45fe/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -1466,8 +1477,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
|
||||
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
|
||||
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
|
||||
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -1530,8 +1541,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
||||
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.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU=
|
||||
golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ=
|
||||
golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
|
||||
golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -1593,10 +1604,10 @@ google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6D
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb h1:ITgPrl429bc6+2ZraNSzMDk3I95nmQln2fuPstKwFDE=
|
||||
google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:sAo5UzpjUwgFBCzupwhcLcxHVDK7vG5IqI30YnwX2eE=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb h1:p31xT4yrYrSM/G4Sn2+TNUkVhFCbG9y8itM2S6Th950=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb h1:TLPQVbx1GJ8VKZxz52VAxl1EBgKXXbTiU9Fc5fZeLn4=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237 h1:Kog3KlB4xevJlAcbbbzPfRG0+X9fdoGM+UBRKVz6Wr0=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237/go.mod h1:ezi0AVyMKDWy5xAncvjLWH7UcLBB5n7y2fQ8MzjJcto=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237 h1:cJfm9zPbe1e873mHJzmQ1nwVEeRDU/T1wXDK2kUSU34=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
@@ -1612,8 +1623,8 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA=
|
||||
google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
|
||||
google.golang.org/grpc v1.72.2 h1:TdbGzwb82ty4OusHWepvFWGLgIbNo1/SUynEN0ssqv8=
|
||||
google.golang.org/grpc v1.72.2/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
|
||||
google.golang.org/grpc/examples v0.0.0-20211102180624-670c133e568e h1:m7aQHHqd0q89mRwhwS9Bx2rjyl/hsFAeta+uGrHsQaU=
|
||||
google.golang.org/grpc/examples v0.0.0-20211102180624-670c133e568e/go.mod h1:gID3PKrg7pWKntu9Ss6zTLJ0ttC0X9IHgREOCZwbCVU=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
|
||||
@@ -14,7 +14,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
tw "github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter/tw"
|
||||
"github.com/opencloud-eu/opencloud/opencloud/pkg/register"
|
||||
"github.com/opencloud-eu/opencloud/pkg/config"
|
||||
"github.com/opencloud-eu/opencloud/pkg/version"
|
||||
@@ -403,11 +404,24 @@ func benchmark(iterations int, path string) error {
|
||||
fmt.Printf("Iterations: %d\n", iterations)
|
||||
fmt.Println("")
|
||||
|
||||
table := tw.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"Test", "Iterations", "dur/it", "total"})
|
||||
table.SetAutoFormatHeaders(false)
|
||||
table.SetColumnAlignment([]int{tw.ALIGN_LEFT, tw.ALIGN_RIGHT, tw.ALIGN_RIGHT, tw.ALIGN_RIGHT})
|
||||
table.SetAutoMergeCellsByColumnIndex([]int{2, 3})
|
||||
cfg := tablewriter.Config{
|
||||
Header: tw.CellConfig{
|
||||
Formatting: tw.CellFormatting{
|
||||
AutoFormat: tw.Off,
|
||||
},
|
||||
},
|
||||
Row: tw.CellConfig{
|
||||
ColumnAligns: []tw.Align{
|
||||
tw.AlignLeft,
|
||||
tw.AlignRight,
|
||||
tw.AlignRight,
|
||||
tw.AlignRight,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
table := tablewriter.NewTable(os.Stdout, tablewriter.WithConfig(cfg))
|
||||
table.Header([]string{"Test", "Iterations", "dur/it", "total"})
|
||||
for _, t := range []string{"lockedfile open(wo,c,t) close", "stat", "fopen(wo,t) write close", "fopen(ro) close", "fopen(ro) read close", "xattr-set", "xattr-get"} {
|
||||
start := time.Now()
|
||||
err := tests[t]()
|
||||
|
||||
@@ -4,7 +4,8 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
tw "github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter/tw"
|
||||
"github.com/urfave/cli/v2"
|
||||
mreg "go-micro.dev/v4/registry"
|
||||
|
||||
@@ -62,9 +63,8 @@ func VersionCommand(cfg *config.Config) *cli.Command {
|
||||
return nil
|
||||
}
|
||||
|
||||
table := tw.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"Version", "Address", "Id"})
|
||||
table.SetAutoFormatHeaders(false)
|
||||
table := tablewriter.NewTable(os.Stdout, tablewriter.WithHeaderAutoFormat(tw.Off))
|
||||
table.Header([]string{"Version", "Address", "Id"})
|
||||
for _, s := range services {
|
||||
for _, n := range s.Nodes {
|
||||
table.Append([]string{s.Version, n.Address, n.Id})
|
||||
|
||||
@@ -19,6 +19,7 @@ var (
|
||||
// 9113a718-8285-4b32-9042-f930f1a58ac2.REV.2024-05-22T07:32:53.89969726Z.mpk
|
||||
// 9113a718-8285-4b32-9042-f930f1a58ac2.REV.2024-05-22T07:32:53.89969726Z.mlock
|
||||
_versionRegex = regexp.MustCompile(`\.REV\.[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]+Z*`)
|
||||
_spaceIDRegex = regexp.MustCompile(`/spaces/(.+)/nodes/`)
|
||||
)
|
||||
|
||||
// DelBlobstore is the interface for a blobstore that can delete blobs.
|
||||
@@ -145,7 +146,10 @@ func PurgeRevisions(nodes <-chan string, bs DelBlobstore, dryRun, verbose bool)
|
||||
continue
|
||||
}
|
||||
|
||||
var blobID string
|
||||
var (
|
||||
spaceID, blobID string
|
||||
)
|
||||
|
||||
e := filepath.Ext(d)
|
||||
switch e {
|
||||
case ".mpk":
|
||||
@@ -154,6 +158,12 @@ func PurgeRevisions(nodes <-chan string, bs DelBlobstore, dryRun, verbose bool)
|
||||
fmt.Printf("error getting blobID from %s: %v\n", d, err)
|
||||
continue
|
||||
}
|
||||
matches := _spaceIDRegex.FindStringSubmatch(d)
|
||||
if len(matches) != 2 {
|
||||
fmt.Printf("error extracting spaceID from %s\n", d)
|
||||
continue
|
||||
}
|
||||
spaceID = strings.ReplaceAll(matches[1], "/", "")
|
||||
|
||||
countBlobs++
|
||||
case ".mlock":
|
||||
@@ -165,7 +175,7 @@ func PurgeRevisions(nodes <-chan string, bs DelBlobstore, dryRun, verbose bool)
|
||||
if !dryRun {
|
||||
if blobID != "" {
|
||||
// TODO: needs spaceID for decomposeds3
|
||||
if err := bs.Delete(&node.Node{BlobID: blobID}); err != nil {
|
||||
if err := bs.Delete(&node.Node{BaseNode: node.BaseNode{SpaceID: spaceID}, BlobID: blobID}); err != nil {
|
||||
fmt.Printf("error deleting blob %s: %v\n", blobID, err)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -480,8 +480,8 @@ func (s *Service) generateRunSet(cfg *occfg.Config) {
|
||||
// List running processes for the Service Controller.
|
||||
func (s *Service) List(_ struct{}, reply *string) error {
|
||||
tableString := &strings.Builder{}
|
||||
table := tablewriter.NewWriter(tableString)
|
||||
table.SetHeader([]string{"Service"})
|
||||
table := tablewriter.NewTable(tableString)
|
||||
table.Header([]string{"Service"})
|
||||
|
||||
names := []string{}
|
||||
for t := range s.serviceToken {
|
||||
|
||||
166
pkg/storage/metadata/lazy.go
Normal file
166
pkg/storage/metadata/lazy.go
Normal file
@@ -0,0 +1,166 @@
|
||||
package metadata
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"sync"
|
||||
|
||||
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/utils/metadata"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/storage"
|
||||
)
|
||||
|
||||
// Lazy is a lazy storage implementation that initializes the underlying storage only when needed.
|
||||
type Lazy struct {
|
||||
next func() (metadata.Storage, error)
|
||||
|
||||
initName string `validate:"required"`
|
||||
initCTX context.Context `validate:"required"`
|
||||
}
|
||||
|
||||
func NewLazyStorage(next metadata.Storage) (*Lazy, error) {
|
||||
s := &Lazy{}
|
||||
s.next = sync.OnceValues[metadata.Storage, error](func() (metadata.Storage, error) {
|
||||
if err := validator.New(validator.WithPrivateFieldValidation()).Struct(s); err != nil {
|
||||
return nil, errors.Join(storage.ErrStorageInitialization, storage.ErrStorageValidation, err)
|
||||
}
|
||||
|
||||
if err := next.Init(s.initCTX, s.initName); err != nil {
|
||||
return nil, errors.Join(storage.ErrStorageInitialization, err)
|
||||
}
|
||||
|
||||
return next, nil
|
||||
})
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// Backend wraps the backend of the next storage
|
||||
func (s *Lazy) Backend() string {
|
||||
next, err := s.next()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return next.Backend()
|
||||
}
|
||||
|
||||
// Init prepares the required data for the underlying lazy storage initialization
|
||||
func (s *Lazy) Init(ctx context.Context, name string) (err error) {
|
||||
s.initCTX = ctx
|
||||
s.initName = name
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Upload wraps the upload method of the next storage
|
||||
func (s *Lazy) Upload(ctx context.Context, req metadata.UploadRequest) (*metadata.UploadResponse, error) {
|
||||
next, err := s.next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return next.Upload(ctx, req)
|
||||
}
|
||||
|
||||
// Download wraps the download method of the next storage
|
||||
func (s *Lazy) Download(ctx context.Context, req metadata.DownloadRequest) (*metadata.DownloadResponse, error) {
|
||||
next, err := s.next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return next.Download(ctx, req)
|
||||
}
|
||||
|
||||
// SimpleUpload wraps the simple upload method of the next storage
|
||||
func (s *Lazy) SimpleUpload(ctx context.Context, uploadpath string, content []byte) error {
|
||||
next, err := s.next()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return next.SimpleUpload(ctx, uploadpath, content)
|
||||
}
|
||||
|
||||
// SimpleDownload wraps the simple download method of the next storage
|
||||
func (s *Lazy) SimpleDownload(ctx context.Context, path string) ([]byte, error) {
|
||||
next, err := s.next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return next.SimpleDownload(ctx, path)
|
||||
}
|
||||
|
||||
// Delete wraps the delete method of the next storage
|
||||
func (s *Lazy) Delete(ctx context.Context, path string) error {
|
||||
next, err := s.next()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return next.Delete(ctx, path)
|
||||
}
|
||||
|
||||
// Stat wraps the stat method of the next storage
|
||||
func (s *Lazy) Stat(ctx context.Context, path string) (*provider.ResourceInfo, error) {
|
||||
next, err := s.next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return next.Stat(ctx, path)
|
||||
}
|
||||
|
||||
// ReadDir wraps the read directory method of the next storage
|
||||
func (s *Lazy) ReadDir(ctx context.Context, path string) ([]string, error) {
|
||||
next, err := s.next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return next.ReadDir(ctx, path)
|
||||
}
|
||||
|
||||
// ListDir wraps the list directory method of the next storage
|
||||
func (s *Lazy) ListDir(ctx context.Context, path string) ([]*provider.ResourceInfo, error) {
|
||||
next, err := s.next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return next.ListDir(ctx, path)
|
||||
}
|
||||
|
||||
// CreateSymlink wraps the create symlink method of the next storage
|
||||
func (s *Lazy) CreateSymlink(ctx context.Context, oldname, newname string) error {
|
||||
next, err := s.next()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return next.CreateSymlink(ctx, oldname, newname)
|
||||
}
|
||||
|
||||
// ResolveSymlink wraps the resolve symlink method of the next storage
|
||||
func (s *Lazy) ResolveSymlink(ctx context.Context, name string) (string, error) {
|
||||
next, err := s.next()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return next.ResolveSymlink(ctx, name)
|
||||
}
|
||||
|
||||
// MakeDirIfNotExist wraps the make directory if not exist method of the next storage
|
||||
func (s *Lazy) MakeDirIfNotExist(ctx context.Context, name string) error {
|
||||
next, err := s.next()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return next.MakeDirIfNotExist(ctx, name)
|
||||
}
|
||||
13
pkg/storage/storage.go
Normal file
13
pkg/storage/storage.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrStorageInitialization is returned when the storage initialization fails
|
||||
ErrStorageInitialization = errors.New("failed to initialize storage")
|
||||
|
||||
// ErrStorageValidation is returned when the storage configuration is invalid
|
||||
ErrStorageValidation = errors.New("failed to validate storage configuration")
|
||||
)
|
||||
@@ -16,7 +16,7 @@ var (
|
||||
// LatestTag is the latest released version plus the dev meta version.
|
||||
// Will be overwritten by the release pipeline
|
||||
// Needs a manual change for every tagged release
|
||||
LatestTag = "2.3.0+dev"
|
||||
LatestTag = "3.0.0+dev"
|
||||
|
||||
// Date indicates the build date.
|
||||
// This has been removed, it looks like you can only replace static strings with recent go versions
|
||||
|
||||
@@ -34,6 +34,7 @@ type Config struct {
|
||||
Context context.Context `yaml:"-"`
|
||||
|
||||
WriteBufferDuration time.Duration `yaml:"write_buffer_duration" env:"ACTIVITYLOG_WRITE_BUFFER_DURATION" desc:"The duration to wait before flushing the write buffer. This is used to reduce the number of writes to the store." introductionVersion:"%%NEXT%%"`
|
||||
MaxActivities int `yaml:"max_activities" env:"ACTIVITYLOG_MAX_ACTIVITIES" desc:"The maximum number of activities to keep in the store per resource. If the number of activities exceeds this value, the oldest activities will be removed." introductionVersion:"%%NEXT%%"`
|
||||
}
|
||||
|
||||
// Events combines the configuration options for the event bus.
|
||||
|
||||
@@ -53,6 +53,7 @@ func DefaultConfig() *config.Config {
|
||||
},
|
||||
},
|
||||
WriteBufferDuration: 10 * time.Second,
|
||||
MaxActivities: 6000,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +88,6 @@ func Server(opts ...Option) (http.Service, error) {
|
||||
svc.HistoryClient(options.HistoryClient),
|
||||
svc.ValueClient(options.ValueClient),
|
||||
svc.RegisteredEvents(options.RegisteredEvents),
|
||||
svc.WriteBufferDuration(options.Config.WriteBufferDuration),
|
||||
)
|
||||
if err != nil {
|
||||
return http.Service{}, err
|
||||
|
||||
129
services/activitylog/pkg/service/migrations.go
Normal file
129
services/activitylog/pkg/service/migrations.go
Normal file
@@ -0,0 +1,129 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/nats-io/nats.go"
|
||||
"github.com/vmihailenco/msgpack/v5"
|
||||
)
|
||||
|
||||
const activitylogVersionKey = "activitylog.version"
|
||||
const currentMigrationVersion = "1"
|
||||
|
||||
// RunMigrations checks the activitylog data version and runs migrations if necessary.
|
||||
// It should be called during service startup, after the NATS KeyValue store is initialized.
|
||||
func (a *ActivitylogService) runMigrations(ctx context.Context, kv nats.KeyValue) error {
|
||||
entry, err := kv.Get(activitylogVersionKey)
|
||||
if err == nats.ErrKeyNotFound {
|
||||
a.log.Info().Msg("activitylog version key not found. Running migration to V1...")
|
||||
return a.migrateToV1(ctx, kv)
|
||||
} else if err != nil {
|
||||
return fmt.Errorf("failed to get activitylog version from NATS KV store: %w", err)
|
||||
}
|
||||
|
||||
version := string(entry.Value())
|
||||
if version == currentMigrationVersion {
|
||||
a.log.Debug().Str("currentVersion", version).Msg("No migration needed")
|
||||
return nil
|
||||
}
|
||||
|
||||
// If version is something else, it might indicate a future version or an unexpected state.
|
||||
// Add logic here if more complex version handling is needed.
|
||||
return fmt.Errorf("unexpected activitylog version: %s, expected %s or older", version, currentMigrationVersion)
|
||||
}
|
||||
|
||||
// migrateToV1 performs the data migration to version 1.
|
||||
// It iterates over all keys, expecting their values to be JSON arrays of strings.
|
||||
// For each such key, it creates a new key in the format "originalKey.count.timestamp"
|
||||
// and stores the original list of strings (re-marshalled to messagepack) as its value.
|
||||
// Finally, it sets the activitylog.version key to "1".
|
||||
func (a *ActivitylogService) migrateToV1(_ context.Context, kv nats.KeyValue) error {
|
||||
lister, err := kv.ListKeys()
|
||||
if err != nil {
|
||||
return fmt.Errorf("migrateToV1: failed to list keys from NATS KV store: %w", err)
|
||||
}
|
||||
|
||||
migratedCount := 0
|
||||
skippedCount := 0
|
||||
|
||||
keyChan := lister.Keys()
|
||||
defer lister.Stop()
|
||||
|
||||
// keyValueEnvelope is the data structure used by the go micro plugin which was used previously.
|
||||
type keyValueEnvelope struct {
|
||||
Key string `json:"key"`
|
||||
Data []byte `json:"data"`
|
||||
Metadata map[string]interface{} `json:"metadata"`
|
||||
}
|
||||
|
||||
for key := range keyChan {
|
||||
if key == activitylogVersionKey {
|
||||
skippedCount++
|
||||
continue // Skip the version key itself
|
||||
}
|
||||
|
||||
// Get the original value
|
||||
entry, err := kv.Get(key)
|
||||
if err != nil {
|
||||
a.log.Error().Err(err).Str("key", key).Msg("migrateToV1: Failed to get value for key. Skipping.")
|
||||
skippedCount++
|
||||
continue
|
||||
}
|
||||
valBytes := entry.Value()
|
||||
|
||||
val := keyValueEnvelope{}
|
||||
// Unmarshal the value into the keyValueEnvelope structure
|
||||
if err := json.Unmarshal(valBytes, &val); err != nil {
|
||||
a.log.Error().Err(err).Str("key", key).Msg("migrateToV1: Value for key ss not a keyValueEnvelope. Skipping.")
|
||||
skippedCount++
|
||||
continue
|
||||
}
|
||||
|
||||
// Unmarshal value into a list of strings
|
||||
var activities []RawActivity
|
||||
if err := msgpack.Unmarshal(val.Data, &activities); err != nil {
|
||||
if err := json.Unmarshal(val.Data, &activities); err != nil {
|
||||
// This key's value is not a JSON array of strings. Skip it.
|
||||
a.log.Error().Err(err).Str("key", key).Msg("migrateToV1: Value for key is not a msgback or JSON array of strings. Skipping.")
|
||||
skippedCount++
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Construct the new key
|
||||
newKey := natsKey(val.Key, len(activities))
|
||||
newValue, err := msgpack.Marshal(activities)
|
||||
if err != nil {
|
||||
a.log.Error().Err(err).Str("key", key).Msg("migrateToV1: Failed to marshal activities. Skipping.")
|
||||
skippedCount++
|
||||
continue
|
||||
}
|
||||
|
||||
// Write the value (the list of strings, marshalled as messagepack) under the new key
|
||||
if _, err := kv.Put(newKey, newValue); err != nil {
|
||||
a.log.Error().Err(err).Str("newKey", newKey).Str("key", key).Msg("migrateToV1: Failed to put new key. Skipping.")
|
||||
skippedCount++
|
||||
continue
|
||||
}
|
||||
|
||||
// delete old key, it's no longer needed
|
||||
if err := kv.Delete(key); err != nil {
|
||||
log.Printf("migrateToV1: Failed to delete old key '%s' after migration: %v. Skipping deletion.", key, err)
|
||||
skippedCount++
|
||||
continue
|
||||
}
|
||||
|
||||
migratedCount++
|
||||
}
|
||||
|
||||
// Set the activitylog version to "1" after migration
|
||||
if _, err := kv.PutString(activitylogVersionKey, currentMigrationVersion); err != nil {
|
||||
return fmt.Errorf("migrateToV1: failed to set activitylog version key to '%s' in NATS KV store: %w", currentMigrationVersion, err)
|
||||
}
|
||||
|
||||
a.log.Info().Int("migrated", migratedCount).Int("skipped", skippedCount).Msg("Migration to V1 complete")
|
||||
return nil
|
||||
}
|
||||
@@ -31,6 +31,7 @@ type Options struct {
|
||||
HistoryClient ehsvc.EventHistoryService
|
||||
ValueClient settingssvc.ValueService
|
||||
WriteBufferDuration time.Duration
|
||||
MaxActivities int
|
||||
}
|
||||
|
||||
// Logger configures a logger for the activitylog service
|
||||
@@ -102,10 +103,3 @@ func ValueClient(vs settingssvc.ValueService) Option {
|
||||
o.ValueClient = vs
|
||||
}
|
||||
}
|
||||
|
||||
// WriteBufferDuration sets the write buffer duration
|
||||
func WriteBufferDuration(d time.Duration) Option {
|
||||
return func(o *Options) {
|
||||
o.WriteBufferDuration = d
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,9 +12,9 @@ import (
|
||||
user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
|
||||
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
|
||||
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storagespace"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/utils"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/l10n"
|
||||
)
|
||||
@@ -61,6 +61,13 @@ type Actor struct {
|
||||
DisplayName string `json:"displayName"`
|
||||
}
|
||||
|
||||
// Sharee represents a share reciever (group or user)
|
||||
type Sharee struct {
|
||||
ID string `json:"id"`
|
||||
DisplayName string `json:"displayName"`
|
||||
ShareType string `json:"shareType"`
|
||||
}
|
||||
|
||||
// ActivityOption allows setting variables for an activity
|
||||
type ActivityOption func(context.Context, gateway.GatewayAPIClient, map[string]interface{}) error
|
||||
|
||||
@@ -204,20 +211,23 @@ func WithSharee(uid *user.UserId, gid *group.GroupId) ActivityOption {
|
||||
case uid != nil:
|
||||
u, err := utils.GetUser(uid, gwc)
|
||||
if err != nil {
|
||||
vars["sharee"] = Actor{
|
||||
vars["sharee"] = Sharee{
|
||||
DisplayName: "DeletedUser",
|
||||
ShareType: "user",
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
vars["sharee"] = Actor{
|
||||
vars["sharee"] = Sharee{
|
||||
ID: uid.GetOpaqueId(),
|
||||
DisplayName: u.GetUsername(),
|
||||
ShareType: "user",
|
||||
}
|
||||
case gid != nil:
|
||||
vars["sharee"] = Actor{
|
||||
vars["sharee"] = Sharee{
|
||||
ID: gid.GetOpaqueId(),
|
||||
DisplayName: "DeletedGroup",
|
||||
ShareType: "group",
|
||||
}
|
||||
r, err := gwc.GetGroup(ctx, &group.GetGroupRequest{GroupId: gid})
|
||||
if err != nil {
|
||||
@@ -228,9 +238,10 @@ func WithSharee(uid *user.UserId, gid *group.GroupId) ActivityOption {
|
||||
return fmt.Errorf("error getting group: %s", r.GetStatus().GetMessage())
|
||||
}
|
||||
|
||||
vars["sharee"] = Actor{
|
||||
vars["sharee"] = Sharee{
|
||||
ID: gid.GetOpaqueId(),
|
||||
DisplayName: r.GetGroup().GetDisplayName(),
|
||||
ShareType: "group",
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,11 +2,14 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base32"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -14,12 +17,13 @@ import (
|
||||
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/jellydator/ttlcache/v2"
|
||||
"github.com/nats-io/nats.go"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/events"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storagespace"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/utils"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/vmihailenco/msgpack/v5"
|
||||
microstore "go-micro.dev/v4/store"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
@@ -29,7 +33,7 @@ import (
|
||||
)
|
||||
|
||||
// Nats runs into max payload exceeded errors at around 7k activities. Let's keep a buffer.
|
||||
var _maxActivities = 6000
|
||||
var _maxActivitiesDefault = 6000
|
||||
|
||||
// RawActivity represents an activity as it is stored in the activitylog store
|
||||
type RawActivity struct {
|
||||
@@ -43,7 +47,6 @@ type ActivitylogService struct {
|
||||
cfg *config.Config
|
||||
log log.Logger
|
||||
events <-chan events.Event
|
||||
store microstore.Store
|
||||
gws pool.Selectable[gateway.GatewayAPIClient]
|
||||
mux *chi.Mux
|
||||
evHistory ehsvc.EventHistoryService
|
||||
@@ -53,6 +56,9 @@ type ActivitylogService struct {
|
||||
tracer trace.Tracer
|
||||
debouncer *Debouncer
|
||||
parentIdCache *ttlcache.Cache
|
||||
natskv nats.KeyValue
|
||||
|
||||
maxActivities int
|
||||
|
||||
registeredEvents map[string]events.Unmarshaller
|
||||
}
|
||||
@@ -71,6 +77,12 @@ type queueItem struct {
|
||||
timer *time.Timer
|
||||
}
|
||||
|
||||
type batchInfo struct {
|
||||
key string
|
||||
count int
|
||||
timestamp time.Time
|
||||
}
|
||||
|
||||
// NewDebouncer returns a new Debouncer instance
|
||||
func NewDebouncer(d time.Duration, f func(id string, ra []RawActivity) error) *Debouncer {
|
||||
return &Debouncer{
|
||||
@@ -128,7 +140,9 @@ func (d *Debouncer) Debounce(id string, ra RawActivity) {
|
||||
|
||||
// New creates a new ActivitylogService
|
||||
func New(opts ...Option) (*ActivitylogService, error) {
|
||||
o := &Options{}
|
||||
o := &Options{
|
||||
MaxActivities: _maxActivitiesDefault,
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(o)
|
||||
}
|
||||
@@ -137,10 +151,6 @@ func New(opts ...Option) (*ActivitylogService, error) {
|
||||
return nil, errors.New("stream is required")
|
||||
}
|
||||
|
||||
if o.Store == nil {
|
||||
return nil, errors.New("store is required")
|
||||
}
|
||||
|
||||
ch, err := events.Consume(o.Stream, o.Config.Service.Name, o.RegisteredEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -152,11 +162,41 @@ func New(opts ...Option) (*ActivitylogService, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Connect to NATS servers
|
||||
natsOptions := nats.Options{
|
||||
Servers: o.Config.Store.Nodes,
|
||||
}
|
||||
conn, err := natsOptions.Connect()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
js, err := conn.JetStream()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
kv, err := js.KeyValue(o.Config.Store.Database)
|
||||
if err != nil {
|
||||
if !errors.Is(err, nats.ErrBucketNotFound) {
|
||||
return nil, errors.Wrapf(err, "Failed to get bucket (%s)", o.Config.Store.Database)
|
||||
}
|
||||
|
||||
kv, err = js.CreateKeyValue(&nats.KeyValueConfig{
|
||||
Bucket: o.Config.Store.Database,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Failed to create bucket (%s)", o.Config.Store.Database)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s := &ActivitylogService{
|
||||
log: o.Logger,
|
||||
cfg: o.Config,
|
||||
events: ch,
|
||||
store: o.Store,
|
||||
gws: o.GatewaySelector,
|
||||
mux: o.Mux,
|
||||
evHistory: o.HistoryClient,
|
||||
@@ -166,8 +206,16 @@ func New(opts ...Option) (*ActivitylogService, error) {
|
||||
tp: o.TraceProvider,
|
||||
tracer: o.TraceProvider.Tracer("github.com/opencloud-eu/opencloud/services/activitylog/pkg/service"),
|
||||
parentIdCache: cache,
|
||||
maxActivities: o.Config.MaxActivities,
|
||||
natskv: kv,
|
||||
}
|
||||
s.debouncer = NewDebouncer(o.Config.WriteBufferDuration, s.storeActivity)
|
||||
|
||||
// run migrations
|
||||
err = s.runMigrations(context.Background(), kv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.debouncer = NewDebouncer(o.WriteBufferDuration, s.storeActivity)
|
||||
|
||||
s.mux.Get("/graph/v1beta1/extensions/org.libregraph/activities", s.HandleGetItemActivities)
|
||||
|
||||
@@ -250,7 +298,7 @@ func (a *ActivitylogService) AddActivity(initRef *provider.Reference, parentId *
|
||||
ctx, span = a.tracer.Start(ctx, "AddActivity")
|
||||
defer span.End()
|
||||
|
||||
return a.addActivity(ctx, initRef, parentId, eventID, timestamp, func(ref *provider.Reference) (*provider.ResourceInfo, error) {
|
||||
return a.addActivity(ctx, initRef, parentId, eventID, timestamp, func(ctx context.Context, ref *provider.Reference) (*provider.ResourceInfo, error) {
|
||||
return utils.GetResource(ctx, ref, gwc)
|
||||
})
|
||||
}
|
||||
@@ -285,10 +333,10 @@ func (a *ActivitylogService) AddActivityTrashed(resourceID *provider.ResourceId,
|
||||
}
|
||||
|
||||
var span trace.Span
|
||||
ctx, span = a.tracer.Start(ctx, "AddActivity")
|
||||
ctx, span = a.tracer.Start(ctx, "AddActivityTrashed")
|
||||
defer span.End()
|
||||
|
||||
return a.addActivity(ctx, ref, parentId, eventID, timestamp, func(ref *provider.Reference) (*provider.ResourceInfo, error) {
|
||||
return a.addActivity(ctx, ref, parentId, eventID, timestamp, func(ctx context.Context, ref *provider.Reference) (*provider.ResourceInfo, error) {
|
||||
return utils.GetResource(ctx, ref, gwc)
|
||||
})
|
||||
}
|
||||
@@ -343,10 +391,8 @@ func (a *ActivitylogService) RemoveActivities(rid *provider.ResourceId, toDelete
|
||||
return err
|
||||
}
|
||||
|
||||
return a.store.Write(µstore.Record{
|
||||
Key: storagespace.FormatResourceID(rid),
|
||||
Value: b,
|
||||
})
|
||||
_, err = a.natskv.Put(storagespace.FormatResourceID(rid), b)
|
||||
return err
|
||||
}
|
||||
|
||||
// RemoveResource removes the resource from the store
|
||||
@@ -358,45 +404,53 @@ func (a *ActivitylogService) RemoveResource(rid *provider.ResourceId) error {
|
||||
a.lock.Lock()
|
||||
defer a.lock.Unlock()
|
||||
|
||||
return a.store.Delete(storagespace.FormatResourceID(rid))
|
||||
return a.natskv.Delete(storagespace.FormatResourceID(rid))
|
||||
}
|
||||
|
||||
func (a *ActivitylogService) activities(rid *provider.ResourceId) ([]RawActivity, error) {
|
||||
resourceID := storagespace.FormatResourceID(rid)
|
||||
|
||||
records, err := a.store.Read(resourceID)
|
||||
if err != nil && err != microstore.ErrNotFound {
|
||||
return nil, fmt.Errorf("could not read activities: %w", err)
|
||||
}
|
||||
glob := fmt.Sprintf("%s.>", base32.StdEncoding.EncodeToString([]byte(resourceID)))
|
||||
|
||||
if len(records) == 0 {
|
||||
return []RawActivity{}, nil
|
||||
watcher, err := a.natskv.Watch(glob, nats.IgnoreDeletes())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer watcher.Stop()
|
||||
|
||||
var activities []RawActivity
|
||||
if err := msgpack.Unmarshal(records[0].Value, &activities); err != nil {
|
||||
a.log.Debug().Err(err).Str("resourceID", resourceID).Msg("could not unmarshal messagepack, trying json")
|
||||
if err := json.Unmarshal(records[0].Value, &activities); err != nil {
|
||||
return nil, fmt.Errorf("could not unmarshal activities: %w", err)
|
||||
for update := range watcher.Updates() {
|
||||
if update == nil {
|
||||
break
|
||||
}
|
||||
|
||||
var batchActivities []RawActivity
|
||||
if err := msgpack.Unmarshal(update.Value(), &batchActivities); err != nil {
|
||||
a.log.Debug().Err(err).Str("resourceID", resourceID).Msg("could not unmarshal messagepack, trying json")
|
||||
}
|
||||
activities = append(activities, batchActivities...)
|
||||
}
|
||||
|
||||
return activities, nil
|
||||
}
|
||||
|
||||
// note: getResource is abstracted to allow unit testing, in general this will just be utils.GetResource
|
||||
func (a *ActivitylogService) addActivity(ctx context.Context, initRef *provider.Reference, parentId *provider.ResourceId, eventID string, timestamp time.Time, getResource func(*provider.Reference) (*provider.ResourceInfo, error)) error {
|
||||
func (a *ActivitylogService) addActivity(ctx context.Context, initRef *provider.Reference, parentId *provider.ResourceId, eventID string, timestamp time.Time, getResource func(context.Context, *provider.Reference) (*provider.ResourceInfo, error)) error {
|
||||
var (
|
||||
err error
|
||||
depth int
|
||||
ref = initRef
|
||||
)
|
||||
ctx, span := a.tracer.Start(ctx, "addActivity")
|
||||
defer span.End()
|
||||
for {
|
||||
var info *provider.ResourceInfo
|
||||
id := ref.GetResourceId()
|
||||
if ref.Path != "" {
|
||||
// Path based reference, we need to resolve the resource id
|
||||
info, err = getResource(ref)
|
||||
ctx, span = a.tracer.Start(ctx, "addActivity.getResource")
|
||||
info, err = getResource(ctx, ref)
|
||||
span.End()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not get resource info: %w", err)
|
||||
}
|
||||
@@ -407,17 +461,15 @@ func (a *ActivitylogService) addActivity(ctx context.Context, initRef *provider.
|
||||
}
|
||||
|
||||
key := storagespace.FormatResourceID(id)
|
||||
_, span := a.tracer.Start(ctx, "queueStoreActivity")
|
||||
a.debouncer.Debounce(key, RawActivity{
|
||||
EventID: eventID,
|
||||
Depth: depth,
|
||||
Timestamp: timestamp,
|
||||
})
|
||||
span.End()
|
||||
|
||||
if id.OpaqueId == id.SpaceId {
|
||||
// we are at the root of the space, no need to go further
|
||||
return nil
|
||||
break
|
||||
}
|
||||
|
||||
// check if parent id is cached
|
||||
@@ -426,8 +478,8 @@ func (a *ActivitylogService) addActivity(ctx context.Context, initRef *provider.
|
||||
if parentId == nil {
|
||||
if v, err := a.parentIdCache.Get(key); err != nil {
|
||||
if info == nil {
|
||||
_, span = a.tracer.Start(ctx, "getResource")
|
||||
info, err = getResource(ref)
|
||||
ctx, span := a.tracer.Start(ctx, "addActivity.getResource parent")
|
||||
info, err = getResource(ctx, ref)
|
||||
span.End()
|
||||
if err != nil || info.GetParentId() == nil || info.GetParentId().GetOpaqueId() == "" {
|
||||
return fmt.Errorf("could not get parent id: %w", err)
|
||||
@@ -446,6 +498,8 @@ func (a *ActivitylogService) addActivity(ctx context.Context, initRef *provider.
|
||||
ref = &provider.Reference{ResourceId: parentId}
|
||||
parentId = nil // reset parent id so it's not reused in the next iteration
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *ActivitylogService) storeActivity(resourceID string, activities []RawActivity) error {
|
||||
@@ -454,43 +508,110 @@ func (a *ActivitylogService) storeActivity(resourceID string, activities []RawAc
|
||||
|
||||
ctx, span := a.tracer.Start(context.Background(), "storeActivity")
|
||||
defer span.End()
|
||||
_, subspan := a.tracer.Start(ctx, "store.Read")
|
||||
records, err := a.store.Read(resourceID)
|
||||
if err != nil && err != microstore.ErrNotFound {
|
||||
return err
|
||||
}
|
||||
subspan.End()
|
||||
|
||||
_, subspan = a.tracer.Start(ctx, "Unmarshal")
|
||||
var existingActivities []RawActivity
|
||||
if len(records) > 0 {
|
||||
if err := msgpack.Unmarshal(records[0].Value, &existingActivities); err != nil {
|
||||
a.log.Debug().Err(err).Str("resourceID", resourceID).Msg("could not unmarshal messagepack, trying json")
|
||||
if err := json.Unmarshal(records[0].Value, &existingActivities); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
subspan.End()
|
||||
|
||||
if l := len(existingActivities) + len(activities); l >= _maxActivities {
|
||||
start := min(len(existingActivities), l-_maxActivities+1)
|
||||
existingActivities = existingActivities[start:]
|
||||
}
|
||||
|
||||
activities = append(existingActivities, activities...)
|
||||
|
||||
_, subspan = a.tracer.Start(ctx, "Unmarshal")
|
||||
_, subspan := a.tracer.Start(ctx, "storeActivity.Marshal")
|
||||
b, err := msgpack.Marshal(activities)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
subspan.End()
|
||||
|
||||
return a.store.Write(µstore.Record{
|
||||
Key: resourceID,
|
||||
Value: b,
|
||||
_, subspan = a.tracer.Start(ctx, "storeActivity.natskv.Put")
|
||||
key := natsKey(resourceID, len(activities))
|
||||
_, err = a.natskv.Put(key, b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
subspan.End()
|
||||
|
||||
ctx, subspan = a.tracer.Start(ctx, "storeActivity.enforceMaxActivities")
|
||||
a.enforceMaxActivities(ctx, resourceID)
|
||||
subspan.End()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *ActivitylogService) enforceMaxActivities(ctx context.Context, resourceID string) {
|
||||
if a.maxActivities <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
key := fmt.Sprintf("%s.>", base32.StdEncoding.EncodeToString([]byte(resourceID)))
|
||||
|
||||
_, subspan := a.tracer.Start(ctx, "enforceMaxActivities.watch")
|
||||
watcher, err := a.natskv.Watch(key, nats.IgnoreDeletes())
|
||||
if err != nil {
|
||||
a.log.Error().Err(err).Str("resourceID", resourceID).Msg("could not watch")
|
||||
return
|
||||
}
|
||||
defer watcher.Stop()
|
||||
|
||||
var keys []string
|
||||
for update := range watcher.Updates() {
|
||||
if update == nil {
|
||||
break
|
||||
}
|
||||
|
||||
var batchActivities []RawActivity
|
||||
if err := msgpack.Unmarshal(update.Value(), &batchActivities); err != nil {
|
||||
a.log.Debug().Err(err).Str("resourceID", resourceID).Msg("could not unmarshal messagepack, trying json")
|
||||
}
|
||||
keys = append(keys, update.Key())
|
||||
}
|
||||
subspan.End()
|
||||
|
||||
_, subspan = a.tracer.Start(ctx, "enforceMaxActivities.compile")
|
||||
// Parse keys into batches
|
||||
batches := make([]batchInfo, 0)
|
||||
var activitiesCount int
|
||||
for _, k := range keys {
|
||||
parts := strings.SplitN(k, ".", 3)
|
||||
if len(parts) < 3 {
|
||||
a.log.Warn().Str("key", k).Msg("skipping key, not enough parts")
|
||||
continue
|
||||
}
|
||||
|
||||
c, err := strconv.Atoi(parts[1])
|
||||
if err != nil {
|
||||
a.log.Warn().Str("key", k).Msg("skipping key, can not parse count")
|
||||
continue
|
||||
}
|
||||
|
||||
// parse timestamp
|
||||
nano, err := strconv.ParseInt(parts[2], 10, 64)
|
||||
if err != nil {
|
||||
a.log.Warn().Str("key", k).Msg("skipping key, can not parse timestamp")
|
||||
continue
|
||||
}
|
||||
|
||||
batches = append(batches, batchInfo{
|
||||
key: k,
|
||||
count: c,
|
||||
timestamp: time.Unix(0, nano),
|
||||
})
|
||||
activitiesCount += c
|
||||
}
|
||||
|
||||
// sort batches by timestamp
|
||||
sort.Slice(batches, func(i, j int) bool {
|
||||
return batches[i].timestamp.Before(batches[j].timestamp)
|
||||
})
|
||||
subspan.End()
|
||||
|
||||
_, subspan = a.tracer.Start(ctx, "enforceMaxActivities.delete")
|
||||
// remove oldest keys until we are at max activities
|
||||
for _, b := range batches {
|
||||
if activitiesCount-b.count < a.maxActivities {
|
||||
break
|
||||
}
|
||||
|
||||
activitiesCount -= b.count
|
||||
err = a.natskv.Delete(b.key)
|
||||
if err != nil {
|
||||
a.log.Error().Err(err).Str("key", b.key).Msg("could not delete key")
|
||||
break
|
||||
}
|
||||
}
|
||||
subspan.End()
|
||||
}
|
||||
|
||||
func toRef(r *provider.ResourceId) *provider.Reference {
|
||||
@@ -531,3 +652,10 @@ func (a *ActivitylogService) removeCachedParentID(ref *provider.Reference) {
|
||||
a.log.Error().Interface("event", ref).Err(err).Msg("could not delete parent id cache")
|
||||
}
|
||||
}
|
||||
|
||||
func natsKey(resourceID string, activitiesCount int) string {
|
||||
return fmt.Sprintf("%s.%d.%d",
|
||||
base32.StdEncoding.EncodeToString([]byte(resourceID)),
|
||||
activitiesCount,
|
||||
time.Now().UnixNano())
|
||||
}
|
||||
|
||||
@@ -2,30 +2,101 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
"github.com/jellydator/ttlcache/v2"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/google/uuid"
|
||||
nserver "github.com/nats-io/nats-server/v2/server"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/store"
|
||||
"github.com/opencloud-eu/opencloud/services/activitylog/pkg/config"
|
||||
eventsmocks "github.com/opencloud-eu/reva/v2/pkg/events/mocks"
|
||||
"github.com/test-go/testify/mock"
|
||||
"go.opentelemetry.io/otel/trace/noop"
|
||||
)
|
||||
|
||||
var (
|
||||
server *nserver.Server
|
||||
tmpdir string
|
||||
)
|
||||
|
||||
func getFreeLocalhostPort() (int, error) {
|
||||
l, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
port := l.Addr().(*net.TCPAddr).Port
|
||||
_ = l.Close() // Close the listener immediately to free the port
|
||||
return port, nil
|
||||
}
|
||||
|
||||
// Spawn a nats server and a JetStream instance for the duration of the test suite.
|
||||
// The different tests need to make sure to use different databases to avoid conflicts.
|
||||
var _ = SynchronizedBeforeSuite(func() {
|
||||
port, err := getFreeLocalhostPort()
|
||||
server, err = nserver.NewServer(&nserver.Options{
|
||||
Port: port,
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
tmpdir, err = os.MkdirTemp("", "activitylog-test")
|
||||
natsdir := filepath.Join(tmpdir, "nats-js")
|
||||
jsConf := &nserver.JetStreamConfig{
|
||||
StoreDir: natsdir,
|
||||
}
|
||||
// first start NATS
|
||||
go server.Start()
|
||||
time.Sleep(time.Second)
|
||||
|
||||
// second start JetStream
|
||||
err = server.EnableJetStream(jsConf)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}, func() {})
|
||||
|
||||
var _ = SynchronizedAfterSuite(func() {
|
||||
server.Shutdown()
|
||||
_ = os.RemoveAll(tmpdir)
|
||||
}, func() {})
|
||||
|
||||
var _ = Describe("ActivitylogService", func() {
|
||||
var (
|
||||
alog *ActivitylogService
|
||||
getResource func(ref *provider.Reference) (*provider.ResourceInfo, error)
|
||||
alog *ActivitylogService
|
||||
getResource func(_ context.Context, ref *provider.Reference) (*provider.ResourceInfo, error)
|
||||
writebufferduration = 100 * time.Millisecond
|
||||
)
|
||||
|
||||
JustBeforeEach(func() {
|
||||
var err error
|
||||
stream := &eventsmocks.Stream{}
|
||||
stream.EXPECT().Consume(mock.Anything, mock.Anything).Return(nil, nil)
|
||||
alog, err = New(
|
||||
Config(&config.Config{
|
||||
Service: config.Service{
|
||||
Name: "activitylog-test",
|
||||
},
|
||||
Store: config.Store{
|
||||
Store: "nats-js-kv",
|
||||
Nodes: []string{server.Addr().String()},
|
||||
Database: "activitylog-test-" + uuid.New().String(),
|
||||
},
|
||||
MaxActivities: 4,
|
||||
WriteBufferDuration: writebufferduration,
|
||||
}),
|
||||
Stream(stream),
|
||||
TraceProvider(noop.NewTracerProvider()),
|
||||
Mux(chi.NewMux()),
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
Context("with a noop debouncer", func() {
|
||||
BeforeEach(func() {
|
||||
alog = &ActivitylogService{
|
||||
store: store.Create(),
|
||||
tracer: noop.NewTracerProvider().Tracer("test"),
|
||||
parentIdCache: ttlcache.NewCache(),
|
||||
}
|
||||
alog.debouncer = NewDebouncer(0, alog.storeActivity)
|
||||
writebufferduration = 0
|
||||
})
|
||||
|
||||
Describe("AddActivity", func() {
|
||||
@@ -76,8 +147,8 @@ var _ = Describe("ActivitylogService", func() {
|
||||
for _, tc := range testCases {
|
||||
tc := tc // capture range variable
|
||||
Context(tc.Name, func() {
|
||||
BeforeEach(func() {
|
||||
getResource = func(ref *provider.Reference) (*provider.ResourceInfo, error) {
|
||||
JustBeforeEach(func() {
|
||||
getResource = func(_ context.Context, ref *provider.Reference) (*provider.ResourceInfo, error) {
|
||||
return tc.Tree[ref.GetResourceId().GetOpaqueId()], nil
|
||||
}
|
||||
|
||||
@@ -107,30 +178,92 @@ var _ = Describe("ActivitylogService", func() {
|
||||
"spaceid": resourceInfo("spaceid", "spaceid"),
|
||||
}
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
alog = &ActivitylogService{
|
||||
store: store.Create(),
|
||||
tracer: noop.NewTracerProvider().Tracer("test"),
|
||||
parentIdCache: ttlcache.NewCache(),
|
||||
}
|
||||
alog.debouncer = NewDebouncer(100*time.Millisecond, alog.storeActivity)
|
||||
writebufferduration = 100 * time.Millisecond
|
||||
})
|
||||
|
||||
It("should debounce activities", func() {
|
||||
getResource = func(ref *provider.Reference) (*provider.ResourceInfo, error) {
|
||||
return tree[ref.GetResourceId().GetOpaqueId()], nil
|
||||
}
|
||||
Describe("addActivity", func() {
|
||||
var (
|
||||
getResource = func(_ context.Context, ref *provider.Reference) (*provider.ResourceInfo, error) {
|
||||
return tree[ref.GetResourceId().GetOpaqueId()], nil
|
||||
}
|
||||
)
|
||||
|
||||
err := alog.addActivity(context.Background(), reference("base"), nil, "activity1", time.Time{}, getResource)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
err = alog.addActivity(context.Background(), reference("base"), nil, "activity2", time.Time{}, getResource)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
It("debounces activities", func() {
|
||||
|
||||
Eventually(func(g Gomega) {
|
||||
activities, err := alog.Activities(resourceID("base"))
|
||||
g.Expect(err).NotTo(HaveOccurred())
|
||||
g.Expect(activities).To(ConsistOf(activitites("activity1", 0, "activity2", 0)))
|
||||
}).Should(Succeed())
|
||||
err := alog.addActivity(context.Background(), reference("base"), nil, "activity1", time.Time{}, getResource)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
err = alog.addActivity(context.Background(), reference("base"), nil, "activity2", time.Time{}, getResource)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
Eventually(func(g Gomega) {
|
||||
activities, err := alog.Activities(resourceID("base"))
|
||||
g.Expect(err).NotTo(HaveOccurred())
|
||||
g.Expect(activities).To(ConsistOf(activitites("activity1", 0, "activity2", 0)))
|
||||
}).Should(Succeed())
|
||||
})
|
||||
|
||||
It("adheres to the MaxActivities setting", func() {
|
||||
err := alog.addActivity(context.Background(), reference("base"), nil, "activity1", time.Time{}, getResource)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Eventually(func(g Gomega) {
|
||||
activities, err := alog.Activities(resourceID("base"))
|
||||
g.Expect(err).NotTo(HaveOccurred())
|
||||
g.Expect(len(activities)).To(Equal(1))
|
||||
}).Should(Succeed())
|
||||
|
||||
err = alog.addActivity(context.Background(), reference("base"), nil, "activity2", time.Time{}, getResource)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Eventually(func(g Gomega) {
|
||||
activities, err := alog.Activities(resourceID("base"))
|
||||
g.Expect(err).NotTo(HaveOccurred())
|
||||
g.Expect(len(activities)).To(Equal(2))
|
||||
}).Should(Succeed())
|
||||
|
||||
err = alog.addActivity(context.Background(), reference("base"), nil, "activity3", time.Time{}, getResource)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
err = alog.addActivity(context.Background(), reference("base"), nil, "activity4", time.Time{}, getResource)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
err = alog.addActivity(context.Background(), reference("base"), nil, "activity5", time.Time{}, getResource)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
Eventually(func(g Gomega) {
|
||||
activities, err := alog.Activities(resourceID("base"))
|
||||
g.Expect(err).NotTo(HaveOccurred())
|
||||
g.Expect(activities).To(ConsistOf(activitites("activity2", 0, "activity3", 0, "activity4", 0, "activity5", 0)))
|
||||
}).Should(Succeed())
|
||||
})
|
||||
})
|
||||
|
||||
Describe("Activities", func() {
|
||||
It("combines multiple batches", func() {
|
||||
getResource = func(_ context.Context, ref *provider.Reference) (*provider.ResourceInfo, error) {
|
||||
return tree[ref.GetResourceId().GetOpaqueId()], nil
|
||||
}
|
||||
|
||||
err := alog.addActivity(context.Background(), reference("base"), nil, "activity1", time.Time{}, getResource)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
err = alog.addActivity(context.Background(), reference("base"), nil, "activity2", time.Time{}, getResource)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
Eventually(func(g Gomega) {
|
||||
activities, err := alog.Activities(resourceID("base"))
|
||||
g.Expect(err).NotTo(HaveOccurred())
|
||||
g.Expect(activities).To(ConsistOf(activitites("activity1", 0, "activity2", 0)))
|
||||
}).Should(Succeed())
|
||||
|
||||
err = alog.addActivity(context.Background(), reference("base"), nil, "activity3", time.Time{}, getResource)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
err = alog.addActivity(context.Background(), reference("base"), nil, "activity4", time.Time{}, getResource)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
Eventually(func(g Gomega) {
|
||||
activities, err := alog.Activities(resourceID("base"))
|
||||
g.Expect(err).NotTo(HaveOccurred())
|
||||
g.Expect(activities).To(ConsistOf(activitites("activity1", 0, "activity2", 0, "activity3", 0, "activity4", 0)))
|
||||
}).Should(Succeed())
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -7,7 +7,8 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/pkg/registry"
|
||||
"github.com/opencloud-eu/opencloud/pkg/version"
|
||||
|
||||
tw "github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter/tw"
|
||||
"github.com/opencloud-eu/opencloud/services/app-provider/pkg/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
@@ -35,9 +36,8 @@ func Version(cfg *config.Config) *cli.Command {
|
||||
return nil
|
||||
}
|
||||
|
||||
table := tw.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"Version", "Address", "Id"})
|
||||
table.SetAutoFormatHeaders(false)
|
||||
table := tablewriter.NewTable(os.Stdout, tablewriter.WithHeaderAutoFormat(tw.Off))
|
||||
table.Header([]string{"Version", "Address", "Id"})
|
||||
for _, s := range services {
|
||||
for _, n := range s.Nodes {
|
||||
table.Append([]string{s.Version, n.Address, n.Id})
|
||||
|
||||
@@ -7,7 +7,8 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/pkg/registry"
|
||||
"github.com/opencloud-eu/opencloud/pkg/version"
|
||||
|
||||
tw "github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter/tw"
|
||||
"github.com/opencloud-eu/opencloud/services/app-registry/pkg/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
@@ -35,9 +36,8 @@ func Version(cfg *config.Config) *cli.Command {
|
||||
return nil
|
||||
}
|
||||
|
||||
table := tw.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"Version", "Address", "Id"})
|
||||
table.SetAutoFormatHeaders(false)
|
||||
table := tablewriter.NewTable(os.Stdout, tablewriter.WithHeaderAutoFormat(tw.Off))
|
||||
table.Header([]string{"Version", "Address", "Id"})
|
||||
for _, s := range services {
|
||||
for _, n := range s.Nodes {
|
||||
table.Append([]string{s.Version, n.Address, n.Id})
|
||||
|
||||
@@ -7,7 +7,8 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/pkg/registry"
|
||||
"github.com/opencloud-eu/opencloud/pkg/version"
|
||||
|
||||
tw "github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter/tw"
|
||||
"github.com/opencloud-eu/opencloud/services/auth-app/pkg/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
@@ -35,9 +36,8 @@ func Version(cfg *config.Config) *cli.Command {
|
||||
return nil
|
||||
}
|
||||
|
||||
table := tw.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"Version", "Address", "Id"})
|
||||
table.SetAutoFormatHeaders(false)
|
||||
table := tablewriter.NewTable(os.Stdout, tablewriter.WithHeaderAutoFormat(tw.Off))
|
||||
table.Header([]string{"Version", "Address", "Id"})
|
||||
for _, s := range services {
|
||||
for _, n := range s.Nodes {
|
||||
table.Append([]string{s.Version, n.Address, n.Id})
|
||||
|
||||
@@ -7,7 +7,8 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/pkg/registry"
|
||||
"github.com/opencloud-eu/opencloud/pkg/version"
|
||||
|
||||
tw "github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter/tw"
|
||||
"github.com/opencloud-eu/opencloud/services/auth-basic/pkg/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
@@ -35,9 +36,8 @@ func Version(cfg *config.Config) *cli.Command {
|
||||
return nil
|
||||
}
|
||||
|
||||
table := tw.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"Version", "Address", "Id"})
|
||||
table.SetAutoFormatHeaders(false)
|
||||
table := tablewriter.NewTable(os.Stdout, tablewriter.WithHeaderAutoFormat(tw.Off))
|
||||
table.Header([]string{"Version", "Address", "Id"})
|
||||
for _, s := range services {
|
||||
for _, n := range s.Nodes {
|
||||
table.Append([]string{s.Version, n.Address, n.Id})
|
||||
|
||||
@@ -7,7 +7,8 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/pkg/registry"
|
||||
"github.com/opencloud-eu/opencloud/pkg/version"
|
||||
|
||||
tw "github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter/tw"
|
||||
"github.com/opencloud-eu/opencloud/services/auth-bearer/pkg/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
@@ -35,9 +36,8 @@ func Version(cfg *config.Config) *cli.Command {
|
||||
return nil
|
||||
}
|
||||
|
||||
table := tw.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"Version", "Address", "Id"})
|
||||
table.SetAutoFormatHeaders(false)
|
||||
table := tablewriter.NewTable(os.Stdout, tablewriter.WithHeaderAutoFormat(tw.Off))
|
||||
table.Header([]string{"Version", "Address", "Id"})
|
||||
for _, s := range services {
|
||||
for _, n := range s.Nodes {
|
||||
table.Append([]string{s.Version, n.Address, n.Id})
|
||||
|
||||
@@ -7,7 +7,8 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/pkg/registry"
|
||||
"github.com/opencloud-eu/opencloud/pkg/version"
|
||||
|
||||
tw "github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter/tw"
|
||||
"github.com/opencloud-eu/opencloud/services/auth-machine/pkg/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
@@ -35,9 +36,8 @@ func Version(cfg *config.Config) *cli.Command {
|
||||
return nil
|
||||
}
|
||||
|
||||
table := tw.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"Version", "Address", "Id"})
|
||||
table.SetAutoFormatHeaders(false)
|
||||
table := tablewriter.NewTable(os.Stdout, tablewriter.WithHeaderAutoFormat(tw.Off))
|
||||
table.Header([]string{"Version", "Address", "Id"})
|
||||
for _, s := range services {
|
||||
for _, n := range s.Nodes {
|
||||
table.Append([]string{s.Version, n.Address, n.Id})
|
||||
|
||||
@@ -7,7 +7,8 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/pkg/registry"
|
||||
"github.com/opencloud-eu/opencloud/pkg/version"
|
||||
|
||||
tw "github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter/tw"
|
||||
"github.com/opencloud-eu/opencloud/services/auth-service/pkg/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
@@ -35,9 +36,8 @@ func Version(cfg *config.Config) *cli.Command {
|
||||
return nil
|
||||
}
|
||||
|
||||
table := tw.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"Version", "Address", "Id"})
|
||||
table.SetAutoFormatHeaders(false)
|
||||
table := tablewriter.NewTable(os.Stdout, tablewriter.WithHeaderAutoFormat(tw.Off))
|
||||
table.Header([]string{"Version", "Address", "Id"})
|
||||
for _, s := range services {
|
||||
for _, n := range s.Nodes {
|
||||
table.Append([]string{s.Version, n.Address, n.Id})
|
||||
|
||||
@@ -7,7 +7,8 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/pkg/registry"
|
||||
"github.com/opencloud-eu/opencloud/pkg/version"
|
||||
|
||||
tw "github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter/tw"
|
||||
"github.com/opencloud-eu/opencloud/services/collaboration/pkg/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
@@ -35,9 +36,8 @@ func Version(cfg *config.Config) *cli.Command {
|
||||
return nil
|
||||
}
|
||||
|
||||
table := tw.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"Version", "Address", "Id"})
|
||||
table.SetAutoFormatHeaders(false)
|
||||
table := tablewriter.NewTable(os.Stdout, tablewriter.WithHeaderAutoFormat(tw.Off))
|
||||
table.Header([]string{"Version", "Address", "Id"})
|
||||
for _, s := range services {
|
||||
for _, n := range s.Nodes {
|
||||
table.Append([]string{s.Version, n.Address, n.Id})
|
||||
|
||||
@@ -292,6 +292,10 @@ func (s *Service) addQueryToURL(baseURL string, req *appproviderv1beta1.OpenInAp
|
||||
}
|
||||
}
|
||||
|
||||
if strings.ToLower(s.config.App.Product) == "collabora" {
|
||||
q.Add("closebutton", "false")
|
||||
}
|
||||
|
||||
qs := q.Encode()
|
||||
u.RawQuery = qs
|
||||
|
||||
|
||||
@@ -190,16 +190,16 @@ var _ = Describe("Discovery", func() {
|
||||
Expect(resp.GetAppUrl().GetFormParameters()["access_token_ttl"]).To(Equal(strconv.FormatInt(nowTime.Add(5*time.Hour).Unix()*1000, 10)))
|
||||
},
|
||||
Entry("Microsoft chat no lang", "Microsoft", "", false, "https://cloud.opencloud.test/hosting/wopi/word/edit?WOPISrc=https%3A%2F%2Fwopi.opencloud.test%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e"),
|
||||
Entry("Collabora chat no lang", "Collabora", "", false, "https://cloud.opencloud.test/hosting/wopi/word/view?WOPISrc=https%3A%2F%2Fwopi.opencloud.test%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e"),
|
||||
Entry("Collabora chat no lang", "Collabora", "", false, "https://cloud.opencloud.test/hosting/wopi/word/view?WOPISrc=https%3A%2F%2Fwopi.opencloud.test%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e&closebutton=false"),
|
||||
Entry("OnlyOffice chat no lang", "OnlyOffice", "", false, "https://cloud.opencloud.test/hosting/wopi/word/edit?WOPISrc=https%3A%2F%2Fwopi.opencloud.test%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e"),
|
||||
Entry("Microsoft chat lang", "Microsoft", "de", false, "https://cloud.opencloud.test/hosting/wopi/word/edit?UI_LLCC=de-DE&WOPISrc=https%3A%2F%2Fwopi.opencloud.test%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e"),
|
||||
Entry("Collabora chat lang", "Collabora", "de", false, "https://cloud.opencloud.test/hosting/wopi/word/view?WOPISrc=https%3A%2F%2Fwopi.opencloud.test%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e&lang=de-DE"),
|
||||
Entry("Collabora chat lang", "Collabora", "de", false, "https://cloud.opencloud.test/hosting/wopi/word/view?WOPISrc=https%3A%2F%2Fwopi.opencloud.test%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e&closebutton=false&lang=de-DE"),
|
||||
Entry("OnlyOffice chat lang", "OnlyOffice", "de", false, "https://cloud.opencloud.test/hosting/wopi/word/edit?WOPISrc=https%3A%2F%2Fwopi.opencloud.test%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e&ui=de-DE"),
|
||||
Entry("Microsoft no chat no lang", "Microsoft", "", true, "https://cloud.opencloud.test/hosting/wopi/word/edit?WOPISrc=https%3A%2F%2Fwopi.opencloud.test%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e&dchat=1"),
|
||||
Entry("Collabora no chat no lang", "Collabora", "", true, "https://cloud.opencloud.test/hosting/wopi/word/view?WOPISrc=https%3A%2F%2Fwopi.opencloud.test%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e&dchat=1"),
|
||||
Entry("Collabora no chat no lang", "Collabora", "", true, "https://cloud.opencloud.test/hosting/wopi/word/view?WOPISrc=https%3A%2F%2Fwopi.opencloud.test%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e&closebutton=false&dchat=1"),
|
||||
Entry("OnlyOffice no chat no lang", "OnlyOffice", "", true, "https://cloud.opencloud.test/hosting/wopi/word/edit?WOPISrc=https%3A%2F%2Fwopi.opencloud.test%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e&dchat=1"),
|
||||
Entry("Microsoft no chat lang", "Microsoft", "de", true, "https://cloud.opencloud.test/hosting/wopi/word/edit?UI_LLCC=de-DE&WOPISrc=https%3A%2F%2Fwopi.opencloud.test%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e&dchat=1"),
|
||||
Entry("Collabora no chat lang", "Collabora", "de", true, "https://cloud.opencloud.test/hosting/wopi/word/view?WOPISrc=https%3A%2F%2Fwopi.opencloud.test%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e&dchat=1&lang=de-DE"),
|
||||
Entry("Collabora no chat lang", "Collabora", "de", true, "https://cloud.opencloud.test/hosting/wopi/word/view?WOPISrc=https%3A%2F%2Fwopi.opencloud.test%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e&closebutton=false&dchat=1&lang=de-DE"),
|
||||
Entry("OnlyOffice no chat lang", "OnlyOffice", "de", true, "https://cloud.opencloud.test/hosting/wopi/word/edit?WOPISrc=https%3A%2F%2Fwopi.opencloud.test%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e&dchat=1&ui=de-DE"),
|
||||
)
|
||||
It("Success with Wopi Proxy", func() {
|
||||
|
||||
@@ -7,7 +7,8 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/pkg/registry"
|
||||
"github.com/opencloud-eu/opencloud/pkg/version"
|
||||
|
||||
tw "github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter/tw"
|
||||
"github.com/opencloud-eu/opencloud/services/frontend/pkg/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
@@ -35,9 +36,8 @@ func Version(cfg *config.Config) *cli.Command {
|
||||
return nil
|
||||
}
|
||||
|
||||
table := tw.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"Version", "Address", "Id"})
|
||||
table.SetAutoFormatHeaders(false)
|
||||
table := tablewriter.NewTable(os.Stdout, tablewriter.WithHeaderAutoFormat(tw.Off))
|
||||
table.Header([]string{"Version", "Address", "Id"})
|
||||
for _, s := range services {
|
||||
for _, n := range s.Nodes {
|
||||
table.Append([]string{s.Version, n.Address, n.Id})
|
||||
|
||||
@@ -7,7 +7,8 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/pkg/registry"
|
||||
"github.com/opencloud-eu/opencloud/pkg/version"
|
||||
|
||||
tw "github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter/tw"
|
||||
"github.com/opencloud-eu/opencloud/services/gateway/pkg/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
@@ -35,9 +36,8 @@ func Version(cfg *config.Config) *cli.Command {
|
||||
return nil
|
||||
}
|
||||
|
||||
table := tw.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"Version", "Address", "Id"})
|
||||
table.SetAutoFormatHeaders(false)
|
||||
table := tablewriter.NewTable(os.Stdout, tablewriter.WithHeaderAutoFormat(tw.Off))
|
||||
table.Header([]string{"Version", "Address", "Id"})
|
||||
for _, s := range services {
|
||||
for _, n := range s.Nodes {
|
||||
table.Append([]string{s.Version, n.Address, n.Id})
|
||||
|
||||
@@ -16,11 +16,17 @@ packages:
|
||||
HTTPClient:
|
||||
Permissions:
|
||||
RoleService:
|
||||
UsersUserProfilePhotoProvider:
|
||||
github.com/opencloud-eu/reva/v2/pkg/events:
|
||||
config:
|
||||
dir: "mocks"
|
||||
interfaces:
|
||||
Publisher:
|
||||
github.com/opencloud-eu/reva/v2/pkg/storage/utils/metadata:
|
||||
config:
|
||||
dir: "mocks"
|
||||
interfaces:
|
||||
Storage:
|
||||
github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool:
|
||||
config:
|
||||
dir: "mocks"
|
||||
|
||||
@@ -129,9 +129,8 @@ The default language can be defined via the `OC_DEFAULT_LANGUAGE` environment va
|
||||
|
||||
Unified Roles are roles granted a user for sharing and can be enabled or disabled. A CLI command is provided to list existing roles and their state among other data.
|
||||
|
||||
{{< hint info >}}
|
||||
::: info
|
||||
Note that a disabled role does not lose previously assigned permissions. It only means that the role is not available for new assignments.
|
||||
{{< /hint >}}
|
||||
|
||||
The following roles are **enabled** by default:
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ import (
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
providerv1beta1 "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
|
||||
svc "github.com/opencloud-eu/opencloud/services/graph/pkg/service/v0"
|
||||
)
|
||||
|
||||
// DriveItemPermissionsProvider is an autogenerated mock type for the DriveItemPermissionsProvider type
|
||||
@@ -294,9 +296,9 @@ func (_c *DriveItemPermissionsProvider_Invite_Call) RunAndReturn(run func(contex
|
||||
return _c
|
||||
}
|
||||
|
||||
// ListPermissions provides a mock function with given fields: ctx, itemID, listFederatedRoles, selectRoles
|
||||
func (_m *DriveItemPermissionsProvider) ListPermissions(ctx context.Context, itemID *providerv1beta1.ResourceId, listFederatedRoles bool, selectRoles bool) (libregraph.CollectionOfPermissionsWithAllowedValues, error) {
|
||||
ret := _m.Called(ctx, itemID, listFederatedRoles, selectRoles)
|
||||
// ListPermissions provides a mock function with given fields: ctx, itemID, queryOptions
|
||||
func (_m *DriveItemPermissionsProvider) ListPermissions(ctx context.Context, itemID *providerv1beta1.ResourceId, queryOptions svc.ListPermissionsQueryOptions) (libregraph.CollectionOfPermissionsWithAllowedValues, error) {
|
||||
ret := _m.Called(ctx, itemID, queryOptions)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for ListPermissions")
|
||||
@@ -304,17 +306,17 @@ func (_m *DriveItemPermissionsProvider) ListPermissions(ctx context.Context, ite
|
||||
|
||||
var r0 libregraph.CollectionOfPermissionsWithAllowedValues
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *providerv1beta1.ResourceId, bool, bool) (libregraph.CollectionOfPermissionsWithAllowedValues, error)); ok {
|
||||
return rf(ctx, itemID, listFederatedRoles, selectRoles)
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *providerv1beta1.ResourceId, svc.ListPermissionsQueryOptions) (libregraph.CollectionOfPermissionsWithAllowedValues, error)); ok {
|
||||
return rf(ctx, itemID, queryOptions)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *providerv1beta1.ResourceId, bool, bool) libregraph.CollectionOfPermissionsWithAllowedValues); ok {
|
||||
r0 = rf(ctx, itemID, listFederatedRoles, selectRoles)
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *providerv1beta1.ResourceId, svc.ListPermissionsQueryOptions) libregraph.CollectionOfPermissionsWithAllowedValues); ok {
|
||||
r0 = rf(ctx, itemID, queryOptions)
|
||||
} else {
|
||||
r0 = ret.Get(0).(libregraph.CollectionOfPermissionsWithAllowedValues)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *providerv1beta1.ResourceId, bool, bool) error); ok {
|
||||
r1 = rf(ctx, itemID, listFederatedRoles, selectRoles)
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *providerv1beta1.ResourceId, svc.ListPermissionsQueryOptions) error); ok {
|
||||
r1 = rf(ctx, itemID, queryOptions)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
@@ -330,15 +332,14 @@ type DriveItemPermissionsProvider_ListPermissions_Call struct {
|
||||
// ListPermissions is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - itemID *providerv1beta1.ResourceId
|
||||
// - listFederatedRoles bool
|
||||
// - selectRoles bool
|
||||
func (_e *DriveItemPermissionsProvider_Expecter) ListPermissions(ctx interface{}, itemID interface{}, listFederatedRoles interface{}, selectRoles interface{}) *DriveItemPermissionsProvider_ListPermissions_Call {
|
||||
return &DriveItemPermissionsProvider_ListPermissions_Call{Call: _e.mock.On("ListPermissions", ctx, itemID, listFederatedRoles, selectRoles)}
|
||||
// - queryOptions svc.ListPermissionsQueryOptions
|
||||
func (_e *DriveItemPermissionsProvider_Expecter) ListPermissions(ctx interface{}, itemID interface{}, queryOptions interface{}) *DriveItemPermissionsProvider_ListPermissions_Call {
|
||||
return &DriveItemPermissionsProvider_ListPermissions_Call{Call: _e.mock.On("ListPermissions", ctx, itemID, queryOptions)}
|
||||
}
|
||||
|
||||
func (_c *DriveItemPermissionsProvider_ListPermissions_Call) Run(run func(ctx context.Context, itemID *providerv1beta1.ResourceId, listFederatedRoles bool, selectRoles bool)) *DriveItemPermissionsProvider_ListPermissions_Call {
|
||||
func (_c *DriveItemPermissionsProvider_ListPermissions_Call) Run(run func(ctx context.Context, itemID *providerv1beta1.ResourceId, queryOptions svc.ListPermissionsQueryOptions)) *DriveItemPermissionsProvider_ListPermissions_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(*providerv1beta1.ResourceId), args[2].(bool), args[3].(bool))
|
||||
run(args[0].(context.Context), args[1].(*providerv1beta1.ResourceId), args[2].(svc.ListPermissionsQueryOptions))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
@@ -348,14 +349,14 @@ func (_c *DriveItemPermissionsProvider_ListPermissions_Call) Return(_a0 libregra
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *DriveItemPermissionsProvider_ListPermissions_Call) RunAndReturn(run func(context.Context, *providerv1beta1.ResourceId, bool, bool) (libregraph.CollectionOfPermissionsWithAllowedValues, error)) *DriveItemPermissionsProvider_ListPermissions_Call {
|
||||
func (_c *DriveItemPermissionsProvider_ListPermissions_Call) RunAndReturn(run func(context.Context, *providerv1beta1.ResourceId, svc.ListPermissionsQueryOptions) (libregraph.CollectionOfPermissionsWithAllowedValues, error)) *DriveItemPermissionsProvider_ListPermissions_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// ListSpaceRootPermissions provides a mock function with given fields: ctx, driveID
|
||||
func (_m *DriveItemPermissionsProvider) ListSpaceRootPermissions(ctx context.Context, driveID *providerv1beta1.ResourceId) (libregraph.CollectionOfPermissionsWithAllowedValues, error) {
|
||||
ret := _m.Called(ctx, driveID)
|
||||
// ListSpaceRootPermissions provides a mock function with given fields: ctx, driveID, queryOptions
|
||||
func (_m *DriveItemPermissionsProvider) ListSpaceRootPermissions(ctx context.Context, driveID *providerv1beta1.ResourceId, queryOptions svc.ListPermissionsQueryOptions) (libregraph.CollectionOfPermissionsWithAllowedValues, error) {
|
||||
ret := _m.Called(ctx, driveID, queryOptions)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for ListSpaceRootPermissions")
|
||||
@@ -363,17 +364,17 @@ func (_m *DriveItemPermissionsProvider) ListSpaceRootPermissions(ctx context.Con
|
||||
|
||||
var r0 libregraph.CollectionOfPermissionsWithAllowedValues
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *providerv1beta1.ResourceId) (libregraph.CollectionOfPermissionsWithAllowedValues, error)); ok {
|
||||
return rf(ctx, driveID)
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *providerv1beta1.ResourceId, svc.ListPermissionsQueryOptions) (libregraph.CollectionOfPermissionsWithAllowedValues, error)); ok {
|
||||
return rf(ctx, driveID, queryOptions)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *providerv1beta1.ResourceId) libregraph.CollectionOfPermissionsWithAllowedValues); ok {
|
||||
r0 = rf(ctx, driveID)
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *providerv1beta1.ResourceId, svc.ListPermissionsQueryOptions) libregraph.CollectionOfPermissionsWithAllowedValues); ok {
|
||||
r0 = rf(ctx, driveID, queryOptions)
|
||||
} else {
|
||||
r0 = ret.Get(0).(libregraph.CollectionOfPermissionsWithAllowedValues)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *providerv1beta1.ResourceId) error); ok {
|
||||
r1 = rf(ctx, driveID)
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *providerv1beta1.ResourceId, svc.ListPermissionsQueryOptions) error); ok {
|
||||
r1 = rf(ctx, driveID, queryOptions)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
@@ -389,13 +390,14 @@ type DriveItemPermissionsProvider_ListSpaceRootPermissions_Call struct {
|
||||
// ListSpaceRootPermissions is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - driveID *providerv1beta1.ResourceId
|
||||
func (_e *DriveItemPermissionsProvider_Expecter) ListSpaceRootPermissions(ctx interface{}, driveID interface{}) *DriveItemPermissionsProvider_ListSpaceRootPermissions_Call {
|
||||
return &DriveItemPermissionsProvider_ListSpaceRootPermissions_Call{Call: _e.mock.On("ListSpaceRootPermissions", ctx, driveID)}
|
||||
// - queryOptions svc.ListPermissionsQueryOptions
|
||||
func (_e *DriveItemPermissionsProvider_Expecter) ListSpaceRootPermissions(ctx interface{}, driveID interface{}, queryOptions interface{}) *DriveItemPermissionsProvider_ListSpaceRootPermissions_Call {
|
||||
return &DriveItemPermissionsProvider_ListSpaceRootPermissions_Call{Call: _e.mock.On("ListSpaceRootPermissions", ctx, driveID, queryOptions)}
|
||||
}
|
||||
|
||||
func (_c *DriveItemPermissionsProvider_ListSpaceRootPermissions_Call) Run(run func(ctx context.Context, driveID *providerv1beta1.ResourceId)) *DriveItemPermissionsProvider_ListSpaceRootPermissions_Call {
|
||||
func (_c *DriveItemPermissionsProvider_ListSpaceRootPermissions_Call) Run(run func(ctx context.Context, driveID *providerv1beta1.ResourceId, queryOptions svc.ListPermissionsQueryOptions)) *DriveItemPermissionsProvider_ListSpaceRootPermissions_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(*providerv1beta1.ResourceId))
|
||||
run(args[0].(context.Context), args[1].(*providerv1beta1.ResourceId), args[2].(svc.ListPermissionsQueryOptions))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
@@ -405,7 +407,7 @@ func (_c *DriveItemPermissionsProvider_ListSpaceRootPermissions_Call) Return(_a0
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *DriveItemPermissionsProvider_ListSpaceRootPermissions_Call) RunAndReturn(run func(context.Context, *providerv1beta1.ResourceId) (libregraph.CollectionOfPermissionsWithAllowedValues, error)) *DriveItemPermissionsProvider_ListSpaceRootPermissions_Call {
|
||||
func (_c *DriveItemPermissionsProvider_ListSpaceRootPermissions_Call) RunAndReturn(run func(context.Context, *providerv1beta1.ResourceId, svc.ListPermissionsQueryOptions) (libregraph.CollectionOfPermissionsWithAllowedValues, error)) *DriveItemPermissionsProvider_ListSpaceRootPermissions_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
732
services/graph/mocks/storage.go
Normal file
732
services/graph/mocks/storage.go
Normal file
@@ -0,0 +1,732 @@
|
||||
// Code generated by mockery. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
context "context"
|
||||
|
||||
metadata "github.com/opencloud-eu/reva/v2/pkg/storage/utils/metadata"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
providerv1beta1 "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
)
|
||||
|
||||
// Storage is an autogenerated mock type for the Storage type
|
||||
type Storage struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
type Storage_Expecter struct {
|
||||
mock *mock.Mock
|
||||
}
|
||||
|
||||
func (_m *Storage) EXPECT() *Storage_Expecter {
|
||||
return &Storage_Expecter{mock: &_m.Mock}
|
||||
}
|
||||
|
||||
// Backend provides a mock function with no fields
|
||||
func (_m *Storage) Backend() string {
|
||||
ret := _m.Called()
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Backend")
|
||||
}
|
||||
|
||||
var r0 string
|
||||
if rf, ok := ret.Get(0).(func() string); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// Storage_Backend_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Backend'
|
||||
type Storage_Backend_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Backend is a helper method to define mock.On call
|
||||
func (_e *Storage_Expecter) Backend() *Storage_Backend_Call {
|
||||
return &Storage_Backend_Call{Call: _e.mock.On("Backend")}
|
||||
}
|
||||
|
||||
func (_c *Storage_Backend_Call) Run(run func()) *Storage_Backend_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Storage_Backend_Call) Return(_a0 string) *Storage_Backend_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Storage_Backend_Call) RunAndReturn(run func() string) *Storage_Backend_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// CreateSymlink provides a mock function with given fields: ctx, oldname, newname
|
||||
func (_m *Storage) CreateSymlink(ctx context.Context, oldname string, newname string) error {
|
||||
ret := _m.Called(ctx, oldname, newname)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for CreateSymlink")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok {
|
||||
r0 = rf(ctx, oldname, newname)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// Storage_CreateSymlink_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateSymlink'
|
||||
type Storage_CreateSymlink_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// CreateSymlink is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - oldname string
|
||||
// - newname string
|
||||
func (_e *Storage_Expecter) CreateSymlink(ctx interface{}, oldname interface{}, newname interface{}) *Storage_CreateSymlink_Call {
|
||||
return &Storage_CreateSymlink_Call{Call: _e.mock.On("CreateSymlink", ctx, oldname, newname)}
|
||||
}
|
||||
|
||||
func (_c *Storage_CreateSymlink_Call) Run(run func(ctx context.Context, oldname string, newname string)) *Storage_CreateSymlink_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(string), args[2].(string))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Storage_CreateSymlink_Call) Return(_a0 error) *Storage_CreateSymlink_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Storage_CreateSymlink_Call) RunAndReturn(run func(context.Context, string, string) error) *Storage_CreateSymlink_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// Delete provides a mock function with given fields: ctx, path
|
||||
func (_m *Storage) Delete(ctx context.Context, path string) error {
|
||||
ret := _m.Called(ctx, path)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Delete")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) error); ok {
|
||||
r0 = rf(ctx, path)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// Storage_Delete_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Delete'
|
||||
type Storage_Delete_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Delete is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - path string
|
||||
func (_e *Storage_Expecter) Delete(ctx interface{}, path interface{}) *Storage_Delete_Call {
|
||||
return &Storage_Delete_Call{Call: _e.mock.On("Delete", ctx, path)}
|
||||
}
|
||||
|
||||
func (_c *Storage_Delete_Call) Run(run func(ctx context.Context, path string)) *Storage_Delete_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(string))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Storage_Delete_Call) Return(_a0 error) *Storage_Delete_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Storage_Delete_Call) RunAndReturn(run func(context.Context, string) error) *Storage_Delete_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// Download provides a mock function with given fields: ctx, req
|
||||
func (_m *Storage) Download(ctx context.Context, req metadata.DownloadRequest) (*metadata.DownloadResponse, error) {
|
||||
ret := _m.Called(ctx, req)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Download")
|
||||
}
|
||||
|
||||
var r0 *metadata.DownloadResponse
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, metadata.DownloadRequest) (*metadata.DownloadResponse, error)); ok {
|
||||
return rf(ctx, req)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, metadata.DownloadRequest) *metadata.DownloadResponse); ok {
|
||||
r0 = rf(ctx, req)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*metadata.DownloadResponse)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, metadata.DownloadRequest) error); ok {
|
||||
r1 = rf(ctx, req)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Storage_Download_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Download'
|
||||
type Storage_Download_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Download is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - req metadata.DownloadRequest
|
||||
func (_e *Storage_Expecter) Download(ctx interface{}, req interface{}) *Storage_Download_Call {
|
||||
return &Storage_Download_Call{Call: _e.mock.On("Download", ctx, req)}
|
||||
}
|
||||
|
||||
func (_c *Storage_Download_Call) Run(run func(ctx context.Context, req metadata.DownloadRequest)) *Storage_Download_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(metadata.DownloadRequest))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Storage_Download_Call) Return(_a0 *metadata.DownloadResponse, _a1 error) *Storage_Download_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Storage_Download_Call) RunAndReturn(run func(context.Context, metadata.DownloadRequest) (*metadata.DownloadResponse, error)) *Storage_Download_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// Init provides a mock function with given fields: ctx, name
|
||||
func (_m *Storage) Init(ctx context.Context, name string) error {
|
||||
ret := _m.Called(ctx, name)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Init")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) error); ok {
|
||||
r0 = rf(ctx, name)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// Storage_Init_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Init'
|
||||
type Storage_Init_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Init is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - name string
|
||||
func (_e *Storage_Expecter) Init(ctx interface{}, name interface{}) *Storage_Init_Call {
|
||||
return &Storage_Init_Call{Call: _e.mock.On("Init", ctx, name)}
|
||||
}
|
||||
|
||||
func (_c *Storage_Init_Call) Run(run func(ctx context.Context, name string)) *Storage_Init_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(string))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Storage_Init_Call) Return(err error) *Storage_Init_Call {
|
||||
_c.Call.Return(err)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Storage_Init_Call) RunAndReturn(run func(context.Context, string) error) *Storage_Init_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// ListDir provides a mock function with given fields: ctx, path
|
||||
func (_m *Storage) ListDir(ctx context.Context, path string) ([]*providerv1beta1.ResourceInfo, error) {
|
||||
ret := _m.Called(ctx, path)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for ListDir")
|
||||
}
|
||||
|
||||
var r0 []*providerv1beta1.ResourceInfo
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) ([]*providerv1beta1.ResourceInfo, error)); ok {
|
||||
return rf(ctx, path)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) []*providerv1beta1.ResourceInfo); ok {
|
||||
r0 = rf(ctx, path)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*providerv1beta1.ResourceInfo)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
|
||||
r1 = rf(ctx, path)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Storage_ListDir_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListDir'
|
||||
type Storage_ListDir_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// ListDir is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - path string
|
||||
func (_e *Storage_Expecter) ListDir(ctx interface{}, path interface{}) *Storage_ListDir_Call {
|
||||
return &Storage_ListDir_Call{Call: _e.mock.On("ListDir", ctx, path)}
|
||||
}
|
||||
|
||||
func (_c *Storage_ListDir_Call) Run(run func(ctx context.Context, path string)) *Storage_ListDir_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(string))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Storage_ListDir_Call) Return(_a0 []*providerv1beta1.ResourceInfo, _a1 error) *Storage_ListDir_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Storage_ListDir_Call) RunAndReturn(run func(context.Context, string) ([]*providerv1beta1.ResourceInfo, error)) *Storage_ListDir_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// MakeDirIfNotExist provides a mock function with given fields: ctx, name
|
||||
func (_m *Storage) MakeDirIfNotExist(ctx context.Context, name string) error {
|
||||
ret := _m.Called(ctx, name)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for MakeDirIfNotExist")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) error); ok {
|
||||
r0 = rf(ctx, name)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// Storage_MakeDirIfNotExist_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MakeDirIfNotExist'
|
||||
type Storage_MakeDirIfNotExist_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// MakeDirIfNotExist is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - name string
|
||||
func (_e *Storage_Expecter) MakeDirIfNotExist(ctx interface{}, name interface{}) *Storage_MakeDirIfNotExist_Call {
|
||||
return &Storage_MakeDirIfNotExist_Call{Call: _e.mock.On("MakeDirIfNotExist", ctx, name)}
|
||||
}
|
||||
|
||||
func (_c *Storage_MakeDirIfNotExist_Call) Run(run func(ctx context.Context, name string)) *Storage_MakeDirIfNotExist_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(string))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Storage_MakeDirIfNotExist_Call) Return(_a0 error) *Storage_MakeDirIfNotExist_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Storage_MakeDirIfNotExist_Call) RunAndReturn(run func(context.Context, string) error) *Storage_MakeDirIfNotExist_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// ReadDir provides a mock function with given fields: ctx, path
|
||||
func (_m *Storage) ReadDir(ctx context.Context, path string) ([]string, error) {
|
||||
ret := _m.Called(ctx, path)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for ReadDir")
|
||||
}
|
||||
|
||||
var r0 []string
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) ([]string, error)); ok {
|
||||
return rf(ctx, path)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) []string); ok {
|
||||
r0 = rf(ctx, path)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]string)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
|
||||
r1 = rf(ctx, path)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Storage_ReadDir_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ReadDir'
|
||||
type Storage_ReadDir_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// ReadDir is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - path string
|
||||
func (_e *Storage_Expecter) ReadDir(ctx interface{}, path interface{}) *Storage_ReadDir_Call {
|
||||
return &Storage_ReadDir_Call{Call: _e.mock.On("ReadDir", ctx, path)}
|
||||
}
|
||||
|
||||
func (_c *Storage_ReadDir_Call) Run(run func(ctx context.Context, path string)) *Storage_ReadDir_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(string))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Storage_ReadDir_Call) Return(_a0 []string, _a1 error) *Storage_ReadDir_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Storage_ReadDir_Call) RunAndReturn(run func(context.Context, string) ([]string, error)) *Storage_ReadDir_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// ResolveSymlink provides a mock function with given fields: ctx, name
|
||||
func (_m *Storage) ResolveSymlink(ctx context.Context, name string) (string, error) {
|
||||
ret := _m.Called(ctx, name)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for ResolveSymlink")
|
||||
}
|
||||
|
||||
var r0 string
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) (string, error)); ok {
|
||||
return rf(ctx, name)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) string); ok {
|
||||
r0 = rf(ctx, name)
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
|
||||
r1 = rf(ctx, name)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Storage_ResolveSymlink_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ResolveSymlink'
|
||||
type Storage_ResolveSymlink_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// ResolveSymlink is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - name string
|
||||
func (_e *Storage_Expecter) ResolveSymlink(ctx interface{}, name interface{}) *Storage_ResolveSymlink_Call {
|
||||
return &Storage_ResolveSymlink_Call{Call: _e.mock.On("ResolveSymlink", ctx, name)}
|
||||
}
|
||||
|
||||
func (_c *Storage_ResolveSymlink_Call) Run(run func(ctx context.Context, name string)) *Storage_ResolveSymlink_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(string))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Storage_ResolveSymlink_Call) Return(_a0 string, _a1 error) *Storage_ResolveSymlink_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Storage_ResolveSymlink_Call) RunAndReturn(run func(context.Context, string) (string, error)) *Storage_ResolveSymlink_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// SimpleDownload provides a mock function with given fields: ctx, path
|
||||
func (_m *Storage) SimpleDownload(ctx context.Context, path string) ([]byte, error) {
|
||||
ret := _m.Called(ctx, path)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for SimpleDownload")
|
||||
}
|
||||
|
||||
var r0 []byte
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) ([]byte, error)); ok {
|
||||
return rf(ctx, path)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) []byte); ok {
|
||||
r0 = rf(ctx, path)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]byte)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
|
||||
r1 = rf(ctx, path)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Storage_SimpleDownload_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SimpleDownload'
|
||||
type Storage_SimpleDownload_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// SimpleDownload is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - path string
|
||||
func (_e *Storage_Expecter) SimpleDownload(ctx interface{}, path interface{}) *Storage_SimpleDownload_Call {
|
||||
return &Storage_SimpleDownload_Call{Call: _e.mock.On("SimpleDownload", ctx, path)}
|
||||
}
|
||||
|
||||
func (_c *Storage_SimpleDownload_Call) Run(run func(ctx context.Context, path string)) *Storage_SimpleDownload_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(string))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Storage_SimpleDownload_Call) Return(_a0 []byte, _a1 error) *Storage_SimpleDownload_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Storage_SimpleDownload_Call) RunAndReturn(run func(context.Context, string) ([]byte, error)) *Storage_SimpleDownload_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// SimpleUpload provides a mock function with given fields: ctx, uploadpath, content
|
||||
func (_m *Storage) SimpleUpload(ctx context.Context, uploadpath string, content []byte) error {
|
||||
ret := _m.Called(ctx, uploadpath, content)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for SimpleUpload")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, []byte) error); ok {
|
||||
r0 = rf(ctx, uploadpath, content)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// Storage_SimpleUpload_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SimpleUpload'
|
||||
type Storage_SimpleUpload_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// SimpleUpload is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - uploadpath string
|
||||
// - content []byte
|
||||
func (_e *Storage_Expecter) SimpleUpload(ctx interface{}, uploadpath interface{}, content interface{}) *Storage_SimpleUpload_Call {
|
||||
return &Storage_SimpleUpload_Call{Call: _e.mock.On("SimpleUpload", ctx, uploadpath, content)}
|
||||
}
|
||||
|
||||
func (_c *Storage_SimpleUpload_Call) Run(run func(ctx context.Context, uploadpath string, content []byte)) *Storage_SimpleUpload_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(string), args[2].([]byte))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Storage_SimpleUpload_Call) Return(_a0 error) *Storage_SimpleUpload_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Storage_SimpleUpload_Call) RunAndReturn(run func(context.Context, string, []byte) error) *Storage_SimpleUpload_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// Stat provides a mock function with given fields: ctx, path
|
||||
func (_m *Storage) Stat(ctx context.Context, path string) (*providerv1beta1.ResourceInfo, error) {
|
||||
ret := _m.Called(ctx, path)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Stat")
|
||||
}
|
||||
|
||||
var r0 *providerv1beta1.ResourceInfo
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) (*providerv1beta1.ResourceInfo, error)); ok {
|
||||
return rf(ctx, path)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) *providerv1beta1.ResourceInfo); ok {
|
||||
r0 = rf(ctx, path)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*providerv1beta1.ResourceInfo)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
|
||||
r1 = rf(ctx, path)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Storage_Stat_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Stat'
|
||||
type Storage_Stat_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Stat is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - path string
|
||||
func (_e *Storage_Expecter) Stat(ctx interface{}, path interface{}) *Storage_Stat_Call {
|
||||
return &Storage_Stat_Call{Call: _e.mock.On("Stat", ctx, path)}
|
||||
}
|
||||
|
||||
func (_c *Storage_Stat_Call) Run(run func(ctx context.Context, path string)) *Storage_Stat_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(string))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Storage_Stat_Call) Return(_a0 *providerv1beta1.ResourceInfo, _a1 error) *Storage_Stat_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Storage_Stat_Call) RunAndReturn(run func(context.Context, string) (*providerv1beta1.ResourceInfo, error)) *Storage_Stat_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// Upload provides a mock function with given fields: ctx, req
|
||||
func (_m *Storage) Upload(ctx context.Context, req metadata.UploadRequest) (*metadata.UploadResponse, error) {
|
||||
ret := _m.Called(ctx, req)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Upload")
|
||||
}
|
||||
|
||||
var r0 *metadata.UploadResponse
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, metadata.UploadRequest) (*metadata.UploadResponse, error)); ok {
|
||||
return rf(ctx, req)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, metadata.UploadRequest) *metadata.UploadResponse); ok {
|
||||
r0 = rf(ctx, req)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*metadata.UploadResponse)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, metadata.UploadRequest) error); ok {
|
||||
r1 = rf(ctx, req)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Storage_Upload_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Upload'
|
||||
type Storage_Upload_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Upload is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - req metadata.UploadRequest
|
||||
func (_e *Storage_Expecter) Upload(ctx interface{}, req interface{}) *Storage_Upload_Call {
|
||||
return &Storage_Upload_Call{Call: _e.mock.On("Upload", ctx, req)}
|
||||
}
|
||||
|
||||
func (_c *Storage_Upload_Call) Run(run func(ctx context.Context, req metadata.UploadRequest)) *Storage_Upload_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(metadata.UploadRequest))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Storage_Upload_Call) Return(_a0 *metadata.UploadResponse, _a1 error) *Storage_Upload_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Storage_Upload_Call) RunAndReturn(run func(context.Context, metadata.UploadRequest) (*metadata.UploadResponse, error)) *Storage_Upload_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// NewStorage creates a new instance of Storage. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
// The first argument is typically a *testing.T value.
|
||||
func NewStorage(t interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}) *Storage {
|
||||
mock := &Storage{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
||||
191
services/graph/mocks/users_user_profile_photo_provider.go
Normal file
191
services/graph/mocks/users_user_profile_photo_provider.go
Normal file
@@ -0,0 +1,191 @@
|
||||
// Code generated by mockery. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
context "context"
|
||||
io "io"
|
||||
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
// UsersUserProfilePhotoProvider is an autogenerated mock type for the UsersUserProfilePhotoProvider type
|
||||
type UsersUserProfilePhotoProvider struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
type UsersUserProfilePhotoProvider_Expecter struct {
|
||||
mock *mock.Mock
|
||||
}
|
||||
|
||||
func (_m *UsersUserProfilePhotoProvider) EXPECT() *UsersUserProfilePhotoProvider_Expecter {
|
||||
return &UsersUserProfilePhotoProvider_Expecter{mock: &_m.Mock}
|
||||
}
|
||||
|
||||
// DeletePhoto provides a mock function with given fields: ctx, id
|
||||
func (_m *UsersUserProfilePhotoProvider) DeletePhoto(ctx context.Context, id string) error {
|
||||
ret := _m.Called(ctx, id)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for DeletePhoto")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) error); ok {
|
||||
r0 = rf(ctx, id)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// UsersUserProfilePhotoProvider_DeletePhoto_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeletePhoto'
|
||||
type UsersUserProfilePhotoProvider_DeletePhoto_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// DeletePhoto is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - id string
|
||||
func (_e *UsersUserProfilePhotoProvider_Expecter) DeletePhoto(ctx interface{}, id interface{}) *UsersUserProfilePhotoProvider_DeletePhoto_Call {
|
||||
return &UsersUserProfilePhotoProvider_DeletePhoto_Call{Call: _e.mock.On("DeletePhoto", ctx, id)}
|
||||
}
|
||||
|
||||
func (_c *UsersUserProfilePhotoProvider_DeletePhoto_Call) Run(run func(ctx context.Context, id string)) *UsersUserProfilePhotoProvider_DeletePhoto_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(string))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *UsersUserProfilePhotoProvider_DeletePhoto_Call) Return(_a0 error) *UsersUserProfilePhotoProvider_DeletePhoto_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *UsersUserProfilePhotoProvider_DeletePhoto_Call) RunAndReturn(run func(context.Context, string) error) *UsersUserProfilePhotoProvider_DeletePhoto_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// GetPhoto provides a mock function with given fields: ctx, id
|
||||
func (_m *UsersUserProfilePhotoProvider) GetPhoto(ctx context.Context, id string) ([]byte, error) {
|
||||
ret := _m.Called(ctx, id)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetPhoto")
|
||||
}
|
||||
|
||||
var r0 []byte
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) ([]byte, error)); ok {
|
||||
return rf(ctx, id)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) []byte); ok {
|
||||
r0 = rf(ctx, id)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]byte)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
|
||||
r1 = rf(ctx, id)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// UsersUserProfilePhotoProvider_GetPhoto_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPhoto'
|
||||
type UsersUserProfilePhotoProvider_GetPhoto_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// GetPhoto is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - id string
|
||||
func (_e *UsersUserProfilePhotoProvider_Expecter) GetPhoto(ctx interface{}, id interface{}) *UsersUserProfilePhotoProvider_GetPhoto_Call {
|
||||
return &UsersUserProfilePhotoProvider_GetPhoto_Call{Call: _e.mock.On("GetPhoto", ctx, id)}
|
||||
}
|
||||
|
||||
func (_c *UsersUserProfilePhotoProvider_GetPhoto_Call) Run(run func(ctx context.Context, id string)) *UsersUserProfilePhotoProvider_GetPhoto_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(string))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *UsersUserProfilePhotoProvider_GetPhoto_Call) Return(_a0 []byte, _a1 error) *UsersUserProfilePhotoProvider_GetPhoto_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *UsersUserProfilePhotoProvider_GetPhoto_Call) RunAndReturn(run func(context.Context, string) ([]byte, error)) *UsersUserProfilePhotoProvider_GetPhoto_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// UpdatePhoto provides a mock function with given fields: ctx, id, r
|
||||
func (_m *UsersUserProfilePhotoProvider) UpdatePhoto(ctx context.Context, id string, r io.Reader) error {
|
||||
ret := _m.Called(ctx, id, r)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for UpdatePhoto")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, io.Reader) error); ok {
|
||||
r0 = rf(ctx, id, r)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// UsersUserProfilePhotoProvider_UpdatePhoto_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdatePhoto'
|
||||
type UsersUserProfilePhotoProvider_UpdatePhoto_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// UpdatePhoto is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - id string
|
||||
// - r io.Reader
|
||||
func (_e *UsersUserProfilePhotoProvider_Expecter) UpdatePhoto(ctx interface{}, id interface{}, r interface{}) *UsersUserProfilePhotoProvider_UpdatePhoto_Call {
|
||||
return &UsersUserProfilePhotoProvider_UpdatePhoto_Call{Call: _e.mock.On("UpdatePhoto", ctx, id, r)}
|
||||
}
|
||||
|
||||
func (_c *UsersUserProfilePhotoProvider_UpdatePhoto_Call) Run(run func(ctx context.Context, id string, r io.Reader)) *UsersUserProfilePhotoProvider_UpdatePhoto_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(string), args[2].(io.Reader))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *UsersUserProfilePhotoProvider_UpdatePhoto_Call) Return(_a0 error) *UsersUserProfilePhotoProvider_UpdatePhoto_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *UsersUserProfilePhotoProvider_UpdatePhoto_Call) RunAndReturn(run func(context.Context, string, io.Reader) error) *UsersUserProfilePhotoProvider_UpdatePhoto_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// NewUsersUserProfilePhotoProvider creates a new instance of UsersUserProfilePhotoProvider. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
// The first argument is typically a *testing.T value.
|
||||
func NewUsersUserProfilePhotoProvider(t interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}) *UsersUserProfilePhotoProvider {
|
||||
mock := &UsersUserProfilePhotoProvider{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
||||
@@ -6,6 +6,8 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter/renderer"
|
||||
"github.com/olekukonko/tablewriter/tw"
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/config/configlog"
|
||||
@@ -54,12 +56,17 @@ func listUnifiedRoles(cfg *config.Config) *cli.Command {
|
||||
Name: "list",
|
||||
Usage: "list available unified roles",
|
||||
Action: func(c *cli.Context) error {
|
||||
tbl := tablewriter.NewWriter(os.Stdout)
|
||||
tbl.SetRowLine(true)
|
||||
tbl.SetAutoMergeCellsByColumnIndex([]int{0}) // rowspan should only affect the first column
|
||||
r := tw.Rendition{
|
||||
Settings: tw.Settings{
|
||||
Separators: tw.Separators{
|
||||
BetweenRows: tw.On,
|
||||
},
|
||||
},
|
||||
}
|
||||
tbl := tablewriter.NewTable(os.Stdout, tablewriter.WithRenderer(renderer.NewBlueprint(r)))
|
||||
|
||||
headers := []string{"Name", "UID", "Enabled", "Description", "Condition", "Allowed resource actions"}
|
||||
tbl.SetHeader(headers)
|
||||
tbl.Header(headers)
|
||||
|
||||
for _, definition := range unifiedrole.GetRoles(unifiedrole.RoleFilterAll()) {
|
||||
const enabled = "enabled"
|
||||
|
||||
@@ -7,7 +7,8 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/pkg/registry"
|
||||
"github.com/opencloud-eu/opencloud/pkg/version"
|
||||
|
||||
tw "github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter/tw"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
@@ -35,9 +36,8 @@ func Version(cfg *config.Config) *cli.Command {
|
||||
return nil
|
||||
}
|
||||
|
||||
table := tw.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"Version", "Address", "Id"})
|
||||
table.SetAutoFormatHeaders(false)
|
||||
table := tablewriter.NewTable(os.Stdout, tablewriter.WithHeaderAutoFormat(tw.Off))
|
||||
table.Header([]string{"Version", "Address", "Id"})
|
||||
for _, s := range services {
|
||||
for _, n := range s.Nodes {
|
||||
table.Append([]string{s.Version, n.Address, n.Id})
|
||||
|
||||
@@ -37,6 +37,8 @@ type Config struct {
|
||||
ServiceAccount ServiceAccount `yaml:"service_account"`
|
||||
|
||||
Context context.Context `yaml:"-"`
|
||||
|
||||
Metadata Metadata `yaml:"metadata_config"`
|
||||
}
|
||||
|
||||
type Spaces struct {
|
||||
@@ -153,3 +155,13 @@ type ServiceAccount struct {
|
||||
ServiceAccountID string `yaml:"service_account_id" env:"OC_SERVICE_ACCOUNT_ID;GRAPH_SERVICE_ACCOUNT_ID" desc:"The ID of the service account the service should use. See the 'auth-service' service description for more details." introductionVersion:"1.0.0"`
|
||||
ServiceAccountSecret string `yaml:"service_account_secret" env:"OC_SERVICE_ACCOUNT_SECRET;GRAPH_SERVICE_ACCOUNT_SECRET" desc:"The service account secret." introductionVersion:"1.0.0"`
|
||||
}
|
||||
|
||||
// Metadata configures the metadata store to use
|
||||
type Metadata struct {
|
||||
GatewayAddress string `yaml:"gateway_addr" env:"GRAPH_STORAGE_GATEWAY_GRPC_ADDR;STORAGE_GATEWAY_GRPC_ADDR" desc:"GRPC address of the STORAGE-SYSTEM service." introductionVersion:"%%NEXT%%"`
|
||||
StorageAddress string `yaml:"storage_addr" env:"GRAPH_STORAGE_GRPC_ADDR;STORAGE_GRPC_ADDR" desc:"GRPC address of the STORAGE-SYSTEM service." introductionVersion:"%%NEXT%%"`
|
||||
|
||||
SystemUserID string `yaml:"system_user_id" env:"OC_SYSTEM_USER_ID;GRAPH_SYSTEM_USER_ID" desc:"ID of the OpenCloud STORAGE-SYSTEM system user. Admins need to set the ID for the STORAGE-SYSTEM system user in this config option which is then used to reference the user. Any reasonable long string is possible, preferably this would be an UUIDv4 format." introductionVersion:"%%NEXT%%"`
|
||||
SystemUserIDP string `yaml:"system_user_idp" env:"OC_SYSTEM_USER_IDP;GRAPH_SYSTEM_USER_IDP" desc:"IDP of the OpenCloud STORAGE-SYSTEM system user." introductionVersion:"%%NEXT%%"`
|
||||
SystemUserAPIKey string `yaml:"system_user_api_key" env:"OC_SYSTEM_USER_API_KEY" desc:"API key for the STORAGE-SYSTEM system user." introductionVersion:"%%NEXT%%"`
|
||||
}
|
||||
|
||||
@@ -125,6 +125,11 @@ func DefaultConfig() *config.Config {
|
||||
UnifiedRoles: config.UnifiedRoles{
|
||||
AvailableRoles: nil, // will be populated with defaults in EnsureDefaults
|
||||
},
|
||||
Metadata: config.Metadata{
|
||||
GatewayAddress: "eu.opencloud.api.storage-system",
|
||||
StorageAddress: "eu.opencloud.api.storage-system",
|
||||
SystemUserIDP: "internal",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,6 +196,15 @@ func EnsureDefaults(cfg *config.Config) {
|
||||
cfg.UnifiedRoles.AvailableRoles = append(cfg.UnifiedRoles.AvailableRoles, definition.GetId())
|
||||
}
|
||||
}
|
||||
|
||||
if cfg.Metadata.SystemUserAPIKey == "" && cfg.Commons != nil && cfg.Commons.SystemUserAPIKey != "" {
|
||||
cfg.Metadata.SystemUserAPIKey = cfg.Commons.SystemUserAPIKey
|
||||
}
|
||||
|
||||
if cfg.Metadata.SystemUserID == "" && cfg.Commons != nil && cfg.Commons.SystemUserID != "" {
|
||||
cfg.Metadata.SystemUserID = cfg.Commons.SystemUserID
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Sanitize sanitized the configuration
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
"github.com/opencloud-eu/opencloud/pkg/shared"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/errorcode"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/odata"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
)
|
||||
@@ -81,7 +82,7 @@ func (i *CS3) GetUsers(ctx context.Context, oreq *godata.GoDataRequest) ([]*libr
|
||||
return nil, errorcode.New(errorcode.ServiceNotAvailable, err.Error())
|
||||
}
|
||||
|
||||
search, err := GetSearchValues(oreq.Query)
|
||||
search, err := odata.GetSearchValues(oreq.Query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -132,7 +133,7 @@ func (i *CS3) GetGroups(ctx context.Context, oreq *godata.GoDataRequest) ([]*lib
|
||||
return nil, errorcode.New(errorcode.ServiceNotAvailable, err.Error())
|
||||
}
|
||||
|
||||
search, err := GetSearchValues(oreq.Query)
|
||||
search, err := odata.GetSearchValues(oreq.Query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/config"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/errorcode"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/odata"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -563,7 +564,7 @@ func (i *LDAP) GetUser(ctx context.Context, nameOrID string, oreq *godata.GoData
|
||||
}
|
||||
}
|
||||
|
||||
exp, err := GetExpandValues(oreq.Query)
|
||||
exp, err := odata.GetExpandValues(oreq.Query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -593,12 +594,12 @@ func (i *LDAP) FilterUsers(ctx context.Context, oreq *godata.GoDataRequest, filt
|
||||
return nil, err
|
||||
}
|
||||
|
||||
search, err := GetSearchValues(oreq.Query)
|
||||
search, err := odata.GetSearchValues(oreq.Query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
exp, err := GetExpandValues(oreq.Query)
|
||||
exp, err := odata.GetExpandValues(oreq.Query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -1,381 +0,0 @@
|
||||
package ldap
|
||||
|
||||
// LDAP automatic reconnection mechanism, inspired by:
|
||||
// https://gist.github.com/emsearcy/cba3295d1a06d4c432ab4f6173b65e4f#file-ldap_snippet-go
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/go-ldap/ldap/v3"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
)
|
||||
|
||||
var (
|
||||
errMaxRetries = errors.New("max retries")
|
||||
)
|
||||
|
||||
type ldapConnection struct {
|
||||
Conn *ldap.Conn
|
||||
Error error
|
||||
}
|
||||
|
||||
// ConnWithReconnect implements the ldap.Client interface
|
||||
type ConnWithReconnect struct {
|
||||
conn chan ldapConnection
|
||||
reset chan *ldap.Conn
|
||||
retries int
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
URI string
|
||||
BindDN string
|
||||
BindPassword string
|
||||
TLSConfig *tls.Config
|
||||
}
|
||||
|
||||
func NewLDAPWithReconnect(logger *log.Logger, config Config) ConnWithReconnect {
|
||||
conn := ConnWithReconnect{
|
||||
conn: make(chan ldapConnection),
|
||||
reset: make(chan *ldap.Conn),
|
||||
retries: 1,
|
||||
logger: logger,
|
||||
}
|
||||
go conn.ldapAutoConnect(config)
|
||||
return conn
|
||||
}
|
||||
|
||||
func (c ConnWithReconnect) Search(sr *ldap.SearchRequest) (*ldap.SearchResult, error) {
|
||||
conn, err := c.GetConnection()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var res *ldap.SearchResult
|
||||
for try := 0; try <= c.retries; try++ {
|
||||
res, err = conn.Search(sr)
|
||||
if !ldap.IsErrorWithCode(err, ldap.ErrorNetwork) {
|
||||
// non network error, return it to the client
|
||||
return res, err
|
||||
}
|
||||
|
||||
c.logger.Debug().Msgf("Network Error. attempt %d", try)
|
||||
conn, err = c.reconnect(conn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.logger.Debug().Msg("retrying LDAP Search")
|
||||
}
|
||||
// if we get here we reached the maximum retries. So return an error
|
||||
return nil, ldap.NewError(ldap.ErrorNetwork, errMaxRetries)
|
||||
}
|
||||
|
||||
func (c ConnWithReconnect) Add(a *ldap.AddRequest) error {
|
||||
conn, err := c.GetConnection()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for try := 0; try <= c.retries; try++ {
|
||||
err = conn.Add(a)
|
||||
if !ldap.IsErrorWithCode(err, ldap.ErrorNetwork) {
|
||||
// non network error, return it to the client
|
||||
return err
|
||||
}
|
||||
|
||||
c.logger.Debug().Msgf("Network Error. attempt %d", try)
|
||||
conn, err = c.reconnect(conn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.logger.Debug().Msg("retrying LDAP Add")
|
||||
}
|
||||
// if we get here we reached the maximum retries. So return an error
|
||||
return ldap.NewError(ldap.ErrorNetwork, errMaxRetries)
|
||||
}
|
||||
|
||||
func (c ConnWithReconnect) Del(d *ldap.DelRequest) error {
|
||||
conn, err := c.GetConnection()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for try := 0; try <= c.retries; try++ {
|
||||
err = conn.Del(d)
|
||||
if !ldap.IsErrorWithCode(err, ldap.ErrorNetwork) {
|
||||
// non network error, return it to the client
|
||||
return err
|
||||
}
|
||||
|
||||
c.logger.Debug().Msgf("Network Error. attempt %d", try)
|
||||
conn, err = c.reconnect(conn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.logger.Debug().Msg("retrying LDAP Del")
|
||||
}
|
||||
// if we get here we reached the maximum retries. So return an error
|
||||
return ldap.NewError(ldap.ErrorNetwork, errMaxRetries)
|
||||
}
|
||||
|
||||
func (c ConnWithReconnect) Modify(m *ldap.ModifyRequest) error {
|
||||
conn, err := c.GetConnection()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for try := 0; try <= c.retries; try++ {
|
||||
err = conn.Modify(m)
|
||||
if !ldap.IsErrorWithCode(err, ldap.ErrorNetwork) {
|
||||
// non network error, return it to the client
|
||||
return err
|
||||
}
|
||||
|
||||
c.logger.Debug().Msgf("Network Error. attempt %d", try)
|
||||
conn, err = c.reconnect(conn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.logger.Debug().Msg("retrying LDAP Modify")
|
||||
}
|
||||
// if we get here we reached the maximum retries. So return an error
|
||||
return ldap.NewError(ldap.ErrorNetwork, errMaxRetries)
|
||||
}
|
||||
|
||||
func (c ConnWithReconnect) PasswordModify(m *ldap.PasswordModifyRequest) (*ldap.PasswordModifyResult, error) {
|
||||
conn, err := c.GetConnection()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var res *ldap.PasswordModifyResult
|
||||
for try := 0; try <= c.retries; try++ {
|
||||
res, err = conn.PasswordModify(m)
|
||||
if !ldap.IsErrorWithCode(err, ldap.ErrorNetwork) {
|
||||
// non network error, return it to the client
|
||||
return res, err
|
||||
}
|
||||
|
||||
c.logger.Debug().Msgf("Network Error. attempt %d", try)
|
||||
conn, err = c.reconnect(conn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.logger.Debug().Msg("retrying LDAP Password Modify")
|
||||
}
|
||||
// if we get here we reached the maximum retries. So return an error
|
||||
return nil, ldap.NewError(ldap.ErrorNetwork, errMaxRetries)
|
||||
}
|
||||
|
||||
func (c ConnWithReconnect) ModifyDN(m *ldap.ModifyDNRequest) error {
|
||||
conn, err := c.GetConnection()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for try := 0; try <= c.retries; try++ {
|
||||
err = conn.ModifyDN(m)
|
||||
if !ldap.IsErrorWithCode(err, ldap.ErrorNetwork) {
|
||||
// non network error, return it to the client
|
||||
return err
|
||||
}
|
||||
|
||||
c.logger.Debug().Msgf("Network Error. attempt %d", try)
|
||||
conn, err = c.reconnect(conn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.logger.Debug().Msg("retrying LDAP ModifyDN")
|
||||
}
|
||||
// if we get here we reached the maximum retries. So return an error
|
||||
return ldap.NewError(ldap.ErrorNetwork, errMaxRetries)
|
||||
}
|
||||
|
||||
func (c ConnWithReconnect) GetConnection() (*ldap.Conn, error) {
|
||||
conn := <-c.conn
|
||||
if conn.Conn != nil && !ldap.IsErrorWithCode(conn.Error, ldap.ErrorNetwork) {
|
||||
c.logger.Debug().Msg("using existing Connection")
|
||||
return conn.Conn, conn.Error
|
||||
}
|
||||
return c.reconnect(conn.Conn)
|
||||
}
|
||||
|
||||
func (c ConnWithReconnect) ldapAutoConnect(config Config) {
|
||||
var (
|
||||
l *ldap.Conn
|
||||
err error
|
||||
)
|
||||
|
||||
for {
|
||||
select {
|
||||
case resConn := <-c.reset:
|
||||
// Only close the connection and reconnect if the current
|
||||
// connection, matches the one we got via the reset channel.
|
||||
// If they differ we already reconnected
|
||||
if l != nil && l == resConn {
|
||||
c.logger.Debug().Msgf("closing connection %v", &l)
|
||||
l.Close()
|
||||
}
|
||||
if l == resConn || l == nil {
|
||||
c.logger.Debug().Msg("reconnecting to LDAP")
|
||||
l, err = c.ldapConnect(config)
|
||||
} else {
|
||||
c.logger.Debug().Msg("already reconnected")
|
||||
}
|
||||
case c.conn <- ldapConnection{l, err}:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c ConnWithReconnect) ldapConnect(config Config) (*ldap.Conn, error) {
|
||||
c.logger.Debug().Msgf("Connecting to %s", config.URI)
|
||||
|
||||
var err error
|
||||
var l *ldap.Conn
|
||||
if config.TLSConfig != nil {
|
||||
l, err = ldap.DialURL(config.URI, ldap.DialWithTLSConfig(config.TLSConfig))
|
||||
} else {
|
||||
l, err = ldap.DialURL(config.URI)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
c.logger.Error().Err(err).Msg("could not get ldap Connection")
|
||||
} else {
|
||||
c.logger.Debug().Msg("LDAP Connected")
|
||||
if config.BindDN != "" {
|
||||
c.logger.Debug().Msgf("Binding as %s", config.BindDN)
|
||||
err = l.Bind(config.BindDN, config.BindPassword)
|
||||
if err != nil {
|
||||
c.logger.Error().Err(err).Msg("Bind failed")
|
||||
l.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return l, err
|
||||
}
|
||||
|
||||
func (c ConnWithReconnect) reconnect(resetConn *ldap.Conn) (*ldap.Conn, error) {
|
||||
c.logger.Debug().Msg("LDAP connection reset")
|
||||
c.reset <- resetConn
|
||||
c.logger.Debug().Msg("Waiting for new connection")
|
||||
result := <-c.conn
|
||||
return result.Conn, result.Error
|
||||
}
|
||||
|
||||
// Remaining methods to fulfill ldap.Client interface
|
||||
|
||||
func (c ConnWithReconnect) Start() {}
|
||||
|
||||
func (c ConnWithReconnect) StartTLS(*tls.Config) error {
|
||||
return ldap.NewError(ldap.LDAPResultNotSupported, fmt.Errorf("not implemented"))
|
||||
}
|
||||
|
||||
// Close implements the ldap.Client interface
|
||||
func (c ConnWithReconnect) Close() (err error) {
|
||||
conn, err := c.GetConnection()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return conn.Close()
|
||||
}
|
||||
|
||||
// GetLastError implements the ldap.Client interface
|
||||
func (c ConnWithReconnect) GetLastError() error {
|
||||
conn, err := c.GetConnection()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return conn.GetLastError()
|
||||
}
|
||||
|
||||
func (c ConnWithReconnect) IsClosing() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (c ConnWithReconnect) SetTimeout(time.Duration) {}
|
||||
|
||||
func (c ConnWithReconnect) Bind(username, password string) error {
|
||||
return ldap.NewError(ldap.LDAPResultNotSupported, fmt.Errorf("not implemented"))
|
||||
}
|
||||
|
||||
func (c ConnWithReconnect) UnauthenticatedBind(username string) error {
|
||||
return ldap.NewError(ldap.LDAPResultNotSupported, fmt.Errorf("not implemented"))
|
||||
}
|
||||
|
||||
func (c ConnWithReconnect) SimpleBind(*ldap.SimpleBindRequest) (*ldap.SimpleBindResult, error) {
|
||||
return nil, ldap.NewError(ldap.LDAPResultNotSupported, fmt.Errorf("not implemented"))
|
||||
}
|
||||
|
||||
func (c ConnWithReconnect) ExternalBind() error {
|
||||
return ldap.NewError(ldap.LDAPResultNotSupported, fmt.Errorf("not implemented"))
|
||||
}
|
||||
|
||||
func (c ConnWithReconnect) ModifyWithResult(m *ldap.ModifyRequest) (*ldap.ModifyResult, error) {
|
||||
conn, err := c.GetConnection()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return conn.ModifyWithResult(m)
|
||||
}
|
||||
|
||||
func (c ConnWithReconnect) Compare(dn, attribute, value string) (bool, error) {
|
||||
return false, ldap.NewError(ldap.LDAPResultNotSupported, fmt.Errorf("not implemented"))
|
||||
}
|
||||
|
||||
func (c ConnWithReconnect) SearchWithPaging(searchRequest *ldap.SearchRequest, pagingSize uint32) (*ldap.SearchResult, error) {
|
||||
return nil, ldap.NewError(ldap.LDAPResultNotSupported, fmt.Errorf("not implemented"))
|
||||
}
|
||||
|
||||
// SearchAsync implements the ldap.Client interface
|
||||
func (c ConnWithReconnect) SearchAsync(ctx context.Context, searchRequest *ldap.SearchRequest, bufferSize int) ldap.Response {
|
||||
// unimplemented
|
||||
return nil
|
||||
}
|
||||
|
||||
// NTLMUnauthenticatedBind implements the ldap.Client interface
|
||||
func (c ConnWithReconnect) NTLMUnauthenticatedBind(domain, username string) error {
|
||||
return ldap.NewError(ldap.LDAPResultNotSupported, fmt.Errorf("not implemented"))
|
||||
}
|
||||
|
||||
// TLSConnectionState implements the ldap.Client interface
|
||||
func (c ConnWithReconnect) TLSConnectionState() (tls.ConnectionState, bool) {
|
||||
return tls.ConnectionState{}, false
|
||||
}
|
||||
|
||||
// Unbind implements the ldap.Client interface
|
||||
func (c ConnWithReconnect) Unbind() error {
|
||||
return ldap.NewError(ldap.LDAPResultNotSupported, fmt.Errorf("not implemented"))
|
||||
}
|
||||
|
||||
// DirSync implements the ldap.Client interface
|
||||
func (c ConnWithReconnect) DirSync(searchRequest *ldap.SearchRequest, flags, maxAttrCount int64, cookie []byte) (*ldap.SearchResult, error) {
|
||||
return nil, ldap.NewError(ldap.LDAPResultNotSupported, fmt.Errorf("not implemented"))
|
||||
}
|
||||
|
||||
// DirSyncAsync implements the ldap.Client interface
|
||||
func (c ConnWithReconnect) DirSyncAsync(ctx context.Context, searchRequest *ldap.SearchRequest, bufferSize int, flags, maxAttrCount int64, cookie []byte) ldap.Response {
|
||||
// unimplemented
|
||||
return nil
|
||||
}
|
||||
|
||||
// Syncrepl implements the ldap.Client interface
|
||||
func (c ConnWithReconnect) Syncrepl(ctx context.Context, searchRequest *ldap.SearchRequest, bufferSize int, mode ldap.ControlSyncRequestMode, cookie []byte, reloadHint bool) ldap.Response {
|
||||
// unimplemented
|
||||
return nil
|
||||
}
|
||||
|
||||
// Extended implements the ldap.Client interface
|
||||
func (c ConnWithReconnect) Extended(_ *ldap.ExtendedRequest) (*ldap.ExtendedResponse, error) {
|
||||
return nil, ldap.NewError(ldap.LDAPResultNotSupported, fmt.Errorf("not implemented"))
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/errorcode"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/odata"
|
||||
)
|
||||
|
||||
type groupAttributeMap struct {
|
||||
@@ -59,17 +60,17 @@ func (i *LDAP) GetGroups(ctx context.Context, oreq *godata.GoDataRequest) ([]*li
|
||||
logger := i.logger.SubloggerWithRequestID(ctx)
|
||||
logger.Debug().Str("backend", "ldap").Msg("GetGroups")
|
||||
|
||||
search, err := GetSearchValues(oreq.Query)
|
||||
search, err := odata.GetSearchValues(oreq.Query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var expandMembers bool
|
||||
exp, err := GetExpandValues(oreq.Query)
|
||||
exp, err := odata.GetExpandValues(oreq.Query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sel, err := GetSelectValues(oreq.Query)
|
||||
sel, err := odata.GetSelectValues(oreq.Query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -146,7 +147,7 @@ func (i *LDAP) GetGroupMembers(ctx context.Context, groupID string, req *godata.
|
||||
logger := i.logger.SubloggerWithRequestID(ctx)
|
||||
logger.Debug().Str("backend", "ldap").Msg("GetGroupMembers")
|
||||
|
||||
exp, err := GetExpandValues(req.Query)
|
||||
exp, err := odata.GetExpandValues(req.Query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -156,7 +157,7 @@ func (i *LDAP) GetGroupMembers(ctx context.Context, groupID string, req *godata.
|
||||
return nil, err
|
||||
}
|
||||
|
||||
searchTerm, err := GetSearchValues(req.Query)
|
||||
searchTerm, err := odata.GetSearchValues(req.Query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
package identity
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/CiscoM31/godata"
|
||||
)
|
||||
|
||||
// GetExpandValues extracts the values of the $expand query parameter and
|
||||
// returns them in a []string, rejects any $expand value that consists of more
|
||||
// than just a single path segment
|
||||
func GetExpandValues(req *godata.GoDataQuery) ([]string, error) {
|
||||
if req == nil || req.Expand == nil {
|
||||
return []string{}, nil
|
||||
}
|
||||
expand := make([]string, 0, len(req.Expand.ExpandItems))
|
||||
for _, item := range req.Expand.ExpandItems {
|
||||
if item.Filter != nil || item.At != nil || item.Search != nil ||
|
||||
item.OrderBy != nil || item.Skip != nil || item.Top != nil ||
|
||||
item.Select != nil || item.Compute != nil || item.Expand != nil ||
|
||||
item.Levels != 0 {
|
||||
return []string{}, godata.NotImplementedError("options for $expand not supported")
|
||||
}
|
||||
if len(item.Path) > 1 {
|
||||
return []string{}, godata.NotImplementedError("multiple segments in $expand not supported")
|
||||
}
|
||||
expand = append(expand, item.Path[0].Value)
|
||||
}
|
||||
return expand, nil
|
||||
}
|
||||
|
||||
// GetSelectValues extracts the values of the $select query parameter and
|
||||
// returns them in a []string, rejects any $select value that consists of more
|
||||
// than just a single path segment
|
||||
func GetSelectValues(req *godata.GoDataQuery) ([]string, error) {
|
||||
if req == nil || req.Select == nil {
|
||||
return []string{}, nil
|
||||
}
|
||||
sel := make([]string, 0, len(req.Select.SelectItems))
|
||||
for _, item := range req.Select.SelectItems {
|
||||
if len(item.Segments) > 1 {
|
||||
return []string{}, godata.NotImplementedError("multiple segments in $select not supported")
|
||||
}
|
||||
sel = append(sel, item.Segments[0].Value)
|
||||
}
|
||||
return sel, nil
|
||||
}
|
||||
|
||||
// GetSearchValues extracts the value of the $search query parameter and returns
|
||||
// it as a string. Rejects any search query that is more than just a simple string
|
||||
func GetSearchValues(req *godata.GoDataQuery) (string, error) {
|
||||
if req == nil || req.Search == nil {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// Only allow simple search queries for now
|
||||
if len(req.Search.Tree.Children) != 0 {
|
||||
return "", godata.NotImplementedError("complex search queries are not supported")
|
||||
}
|
||||
|
||||
searchValue := strings.Trim(req.Search.Tree.Token.Value, "\"")
|
||||
return searchValue, nil
|
||||
}
|
||||
104
services/graph/pkg/odata/odata.go
Normal file
104
services/graph/pkg/odata/odata.go
Normal file
@@ -0,0 +1,104 @@
|
||||
package odata
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/CiscoM31/godata"
|
||||
)
|
||||
|
||||
// GetExpandValues extracts the values of the $expand query parameter and
|
||||
// returns them in a []string, rejecting any $expand value that consists of more
|
||||
// than just a single path segment.
|
||||
func GetExpandValues(req *godata.GoDataQuery) ([]string, error) {
|
||||
if req == nil || req.Expand == nil {
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
var expand []string
|
||||
for _, item := range req.Expand.ExpandItems {
|
||||
paths, err := collectExpandPaths(item, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
expand = append(expand, paths...)
|
||||
}
|
||||
|
||||
return expand, nil
|
||||
}
|
||||
|
||||
// collectExpandPaths recursively collects all valid expand paths from the given item.
|
||||
func collectExpandPaths(item *godata.ExpandItem, prefix string) ([]string, error) {
|
||||
if err := validateExpandItem(item); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Build the current path
|
||||
currentPath := prefix
|
||||
if len(item.Path) > 1 {
|
||||
return nil, godata.NotImplementedError("multiple segments in $expand not supported")
|
||||
}
|
||||
if len(item.Path) == 1 {
|
||||
if currentPath == "" {
|
||||
currentPath = item.Path[0].Value
|
||||
} else {
|
||||
currentPath += "." + item.Path[0].Value
|
||||
}
|
||||
}
|
||||
|
||||
// Collect all paths, including nested ones
|
||||
paths := []string{currentPath}
|
||||
if item.Expand != nil {
|
||||
for _, subItem := range item.Expand.ExpandItems {
|
||||
subPaths, err := collectExpandPaths(subItem, currentPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
paths = append(paths, subPaths...)
|
||||
}
|
||||
}
|
||||
|
||||
return paths, nil
|
||||
}
|
||||
|
||||
// validateExpandItem checks if an expand item contains unsupported options.
|
||||
func validateExpandItem(item *godata.ExpandItem) error {
|
||||
if item.Filter != nil || item.At != nil || item.Search != nil ||
|
||||
item.OrderBy != nil || item.Skip != nil || item.Top != nil ||
|
||||
item.Select != nil || item.Compute != nil || item.Levels != 0 {
|
||||
return godata.NotImplementedError("options for $expand not supported")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetSelectValues extracts the values of the $select query parameter and
|
||||
// returns them in a []string, rejects any $select value that consists of more
|
||||
// than just a single path segment
|
||||
func GetSelectValues(req *godata.GoDataQuery) ([]string, error) {
|
||||
if req == nil || req.Select == nil {
|
||||
return []string{}, nil
|
||||
}
|
||||
sel := make([]string, 0, len(req.Select.SelectItems))
|
||||
for _, item := range req.Select.SelectItems {
|
||||
if len(item.Segments) > 1 {
|
||||
return []string{}, godata.NotImplementedError("multiple segments in $select not supported")
|
||||
}
|
||||
sel = append(sel, item.Segments[0].Value)
|
||||
}
|
||||
return sel, nil
|
||||
}
|
||||
|
||||
// GetSearchValues extracts the value of the $search query parameter and returns
|
||||
// it as a string. Rejects any search query that is more than just a simple string
|
||||
func GetSearchValues(req *godata.GoDataQuery) (string, error) {
|
||||
if req == nil || req.Search == nil {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// Only allow simple search queries for now
|
||||
if len(req.Search.Tree.Children) != 0 {
|
||||
return "", godata.NotImplementedError("complex search queries are not supported")
|
||||
}
|
||||
|
||||
searchValue := strings.Trim(req.Search.Tree.Token.Value, "\"")
|
||||
return searchValue, nil
|
||||
}
|
||||
160
services/graph/pkg/odata/odata_test.go
Normal file
160
services/graph/pkg/odata/odata_test.go
Normal file
@@ -0,0 +1,160 @@
|
||||
package odata
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/CiscoM31/godata"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGetExpandValues(t *testing.T) {
|
||||
t.Run("NilRequest", func(t *testing.T) {
|
||||
result, err := GetExpandValues(nil)
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, result)
|
||||
})
|
||||
|
||||
t.Run("EmptyExpand", func(t *testing.T) {
|
||||
req := &godata.GoDataQuery{}
|
||||
result, err := GetExpandValues(req)
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, result)
|
||||
})
|
||||
|
||||
t.Run("SinglePathSegment", func(t *testing.T) {
|
||||
req := &godata.GoDataQuery{
|
||||
Expand: &godata.GoDataExpandQuery{
|
||||
ExpandItems: []*godata.ExpandItem{
|
||||
{Path: []*godata.Token{{Value: "orders"}}},
|
||||
},
|
||||
},
|
||||
}
|
||||
result, err := GetExpandValues(req)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []string{"orders"}, result)
|
||||
})
|
||||
|
||||
t.Run("MultiplePathSegments", func(t *testing.T) {
|
||||
req := &godata.GoDataQuery{
|
||||
Expand: &godata.GoDataExpandQuery{
|
||||
ExpandItems: []*godata.ExpandItem{
|
||||
{Path: []*godata.Token{{Value: "orders"}, {Value: "details"}}},
|
||||
},
|
||||
},
|
||||
}
|
||||
result, err := GetExpandValues(req)
|
||||
assert.Error(t, err)
|
||||
assert.Empty(t, result)
|
||||
})
|
||||
|
||||
t.Run("NestedExpand", func(t *testing.T) {
|
||||
req := &godata.GoDataQuery{
|
||||
Expand: &godata.GoDataExpandQuery{
|
||||
ExpandItems: []*godata.ExpandItem{
|
||||
{
|
||||
Path: []*godata.Token{{Value: "items"}},
|
||||
Expand: &godata.GoDataExpandQuery{
|
||||
ExpandItems: []*godata.ExpandItem{
|
||||
{
|
||||
Path: []*godata.Token{{Value: "subitem"}},
|
||||
Expand: &godata.GoDataExpandQuery{
|
||||
ExpandItems: []*godata.ExpandItem{
|
||||
{Path: []*godata.Token{{Value: "subsubitems"}}},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
result, err := GetExpandValues(req)
|
||||
assert.NoError(t, err)
|
||||
assert.Subset(t, result, []string{"items", "items.subitem", "items.subitem.subsubitems"}, "must contain all levels of expansion")
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetSelectValues(t *testing.T) {
|
||||
t.Run("NilRequest", func(t *testing.T) {
|
||||
result, err := GetSelectValues(nil)
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, result)
|
||||
})
|
||||
|
||||
t.Run("EmptySelect", func(t *testing.T) {
|
||||
req := &godata.GoDataQuery{}
|
||||
result, err := GetSelectValues(req)
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, result)
|
||||
})
|
||||
|
||||
t.Run("SinglePathSegment", func(t *testing.T) {
|
||||
req := &godata.GoDataQuery{
|
||||
Select: &godata.GoDataSelectQuery{
|
||||
SelectItems: []*godata.SelectItem{
|
||||
{Segments: []*godata.Token{{Value: "name"}}},
|
||||
},
|
||||
},
|
||||
}
|
||||
result, err := GetSelectValues(req)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []string{"name"}, result)
|
||||
})
|
||||
|
||||
t.Run("MultiplePathSegments", func(t *testing.T) {
|
||||
req := &godata.GoDataQuery{
|
||||
Select: &godata.GoDataSelectQuery{
|
||||
SelectItems: []*godata.SelectItem{
|
||||
{Segments: []*godata.Token{{Value: "name"}, {Value: "first"}}},
|
||||
},
|
||||
},
|
||||
}
|
||||
result, err := GetSelectValues(req)
|
||||
assert.Error(t, err)
|
||||
assert.Empty(t, result)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetSearchValues(t *testing.T) {
|
||||
t.Run("NilRequest", func(t *testing.T) {
|
||||
result, err := GetSearchValues(nil)
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, result)
|
||||
})
|
||||
|
||||
t.Run("EmptySearch", func(t *testing.T) {
|
||||
req := &godata.GoDataQuery{}
|
||||
result, err := GetSearchValues(req)
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, result)
|
||||
})
|
||||
|
||||
t.Run("SimpleSearch", func(t *testing.T) {
|
||||
req := &godata.GoDataQuery{
|
||||
Search: &godata.GoDataSearchQuery{
|
||||
Tree: &godata.ParseNode{
|
||||
Token: &godata.Token{Value: "test"},
|
||||
},
|
||||
},
|
||||
}
|
||||
result, err := GetSearchValues(req)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "test", result)
|
||||
})
|
||||
|
||||
t.Run("ComplexSearch", func(t *testing.T) {
|
||||
req := &godata.GoDataQuery{
|
||||
Search: &godata.GoDataSearchQuery{
|
||||
Tree: &godata.ParseNode{
|
||||
Children: []*godata.ParseNode{
|
||||
{Token: &godata.Token{Value: "test"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
result, err := GetSearchValues(req)
|
||||
assert.Error(t, err)
|
||||
assert.Empty(t, result)
|
||||
})
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
stdhttp "net/http"
|
||||
|
||||
@@ -8,7 +10,7 @@ import (
|
||||
chimiddleware "github.com/go-chi/chi/v5/middleware"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/events/stream"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
|
||||
"github.com/pkg/errors"
|
||||
revaMetadata "github.com/opencloud-eu/reva/v2/pkg/storage/utils/metadata"
|
||||
"go-micro.dev/v4"
|
||||
"go-micro.dev/v4/events"
|
||||
|
||||
@@ -19,6 +21,7 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/pkg/registry"
|
||||
"github.com/opencloud-eu/opencloud/pkg/service/grpc"
|
||||
"github.com/opencloud-eu/opencloud/pkg/service/http"
|
||||
"github.com/opencloud-eu/opencloud/pkg/storage/metadata"
|
||||
"github.com/opencloud-eu/opencloud/pkg/version"
|
||||
ehsvc "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/services/eventhistory/v0"
|
||||
searchsvc "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/services/search/v0"
|
||||
@@ -58,7 +61,7 @@ func Server(opts ...Option) (http.Service, error) {
|
||||
options.Logger.Error().
|
||||
Err(err).
|
||||
Msg("Error initializing events publisher")
|
||||
return http.Service{}, errors.Wrap(err, "could not initialize events publisher")
|
||||
return http.Service{}, fmt.Errorf("could not initialize events publisher: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +108,7 @@ func Server(opts ...Option) (http.Service, error) {
|
||||
pool.WithTracerProvider(options.TraceProvider),
|
||||
)...)
|
||||
if err != nil {
|
||||
return http.Service{}, errors.Wrap(err, "could not initialize gateway selector")
|
||||
return http.Service{}, fmt.Errorf("could not initialize gateway selector: %w", err)
|
||||
}
|
||||
} else {
|
||||
middlewares = append(middlewares, graphMiddleware.Token(options.Config.HTTP.APIToken))
|
||||
@@ -128,9 +131,38 @@ func Server(opts ...Option) (http.Service, error) {
|
||||
|
||||
hClient := ehsvc.NewEventHistoryService("eu.opencloud.api.eventhistory", grpcClient)
|
||||
|
||||
var userProfilePhotoService svc.UsersUserProfilePhotoProvider
|
||||
{
|
||||
photoStorage, err := revaMetadata.NewCS3Storage(
|
||||
options.Config.Metadata.GatewayAddress,
|
||||
options.Config.Metadata.StorageAddress,
|
||||
options.Config.Metadata.SystemUserID,
|
||||
options.Config.Metadata.SystemUserIDP,
|
||||
options.Config.Metadata.SystemUserAPIKey,
|
||||
)
|
||||
if err != nil {
|
||||
return http.Service{}, fmt.Errorf("could not initialize reva metadata storage: %w", err)
|
||||
}
|
||||
|
||||
photoStorage, err = metadata.NewLazyStorage(photoStorage)
|
||||
if err != nil {
|
||||
return http.Service{}, fmt.Errorf("could not initialize lazy metadata storage: %w", err)
|
||||
}
|
||||
|
||||
if err := photoStorage.Init(context.Background(), "f2bdd61a-da7c-49fc-8203-0558109d1b4f"); err != nil {
|
||||
return http.Service{}, fmt.Errorf("could not initialize metadata storage: %w", err)
|
||||
}
|
||||
|
||||
userProfilePhotoService, err = svc.NewUsersUserProfilePhotoService(photoStorage)
|
||||
if err != nil {
|
||||
return http.Service{}, fmt.Errorf("could not initialize user profile photo service: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
var handle svc.Service
|
||||
handle, err = svc.NewService(
|
||||
svc.Context(options.Context),
|
||||
svc.UserProfilePhotoService(userProfilePhotoService),
|
||||
svc.Logger(options.Logger),
|
||||
svc.Config(options.Config),
|
||||
svc.Middleware(middlewares...),
|
||||
@@ -147,11 +179,11 @@ func Server(opts ...Option) (http.Service, error) {
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return http.Service{}, errors.New("could not initialize graph service")
|
||||
return http.Service{}, fmt.Errorf("could not initialize graph service: %w", err)
|
||||
}
|
||||
|
||||
if err := micro.RegisterHandler(service.Server(), handle); err != nil {
|
||||
return http.Service{}, err
|
||||
return http.Service{}, fmt.Errorf("could not register graph service handler: %w", err)
|
||||
}
|
||||
|
||||
return service, nil
|
||||
|
||||
@@ -6,7 +6,9 @@ import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/CiscoM31/godata"
|
||||
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
|
||||
grouppb "github.com/cs3org/go-cs3apis/cs3/identity/group/v1beta1"
|
||||
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
|
||||
@@ -29,6 +31,7 @@ import (
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/l10n"
|
||||
l10n_pkg "github.com/opencloud-eu/opencloud/services/graph/pkg/l10n"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/odata"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/conversions"
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
@@ -40,16 +43,18 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
invalidIdMsg = "invalid driveID or itemID"
|
||||
parseDriveIDErrMsg = "could not parse driveID"
|
||||
invalidIdMsg = "invalid driveID or itemID"
|
||||
parseDriveIDErrMsg = "could not parse driveID"
|
||||
federatedRolesODataFilter = "@libre.graph.permissions.roles.allowedValues/rolePermissions/any(p:contains(p/condition, '@Subject.UserType==\"Federated\"'))"
|
||||
noLinksODataFilter = "grantedToV2 ne ''"
|
||||
)
|
||||
|
||||
// DriveItemPermissionsProvider contains the methods related to handling permissions on drive items
|
||||
type DriveItemPermissionsProvider interface {
|
||||
Invite(ctx context.Context, resourceId *storageprovider.ResourceId, invite libregraph.DriveItemInvite) (libregraph.Permission, error)
|
||||
SpaceRootInvite(ctx context.Context, driveID *storageprovider.ResourceId, invite libregraph.DriveItemInvite) (libregraph.Permission, error)
|
||||
ListPermissions(ctx context.Context, itemID *storageprovider.ResourceId, listFederatedRoles, selectRoles bool) (libregraph.CollectionOfPermissionsWithAllowedValues, error)
|
||||
ListSpaceRootPermissions(ctx context.Context, driveID *storageprovider.ResourceId) (libregraph.CollectionOfPermissionsWithAllowedValues, error)
|
||||
ListPermissions(ctx context.Context, itemID *storageprovider.ResourceId, queryOptions ListPermissionsQueryOptions) (libregraph.CollectionOfPermissionsWithAllowedValues, error)
|
||||
ListSpaceRootPermissions(ctx context.Context, driveID *storageprovider.ResourceId, queryOptions ListPermissionsQueryOptions) (libregraph.CollectionOfPermissionsWithAllowedValues, error)
|
||||
DeletePermission(ctx context.Context, itemID *storageprovider.ResourceId, permissionID string) error
|
||||
DeleteSpaceRootPermission(ctx context.Context, driveID *storageprovider.ResourceId, permissionID string) error
|
||||
UpdatePermission(ctx context.Context, itemID *storageprovider.ResourceId, permissionID string, newPermission libregraph.Permission) (libregraph.Permission, error)
|
||||
@@ -75,6 +80,14 @@ const (
|
||||
OCM
|
||||
)
|
||||
|
||||
type ListPermissionsQueryOptions struct {
|
||||
Count bool
|
||||
NoValues bool
|
||||
NoLinkPermissions bool
|
||||
FilterFederatedRoles bool
|
||||
SelectedAttrs []string
|
||||
}
|
||||
|
||||
// NewDriveItemPermissionsService creates a new DriveItemPermissionsService
|
||||
func NewDriveItemPermissionsService(logger log.Logger, gatewaySelector pool.Selectable[gateway.GatewayAPIClient], identityCache identity.IdentityCache, config *config.Config) (DriveItemPermissionsService, error) {
|
||||
return DriveItemPermissionsService{
|
||||
@@ -341,7 +354,7 @@ func (s DriveItemPermissionsService) SpaceRootInvite(ctx context.Context, driveI
|
||||
}
|
||||
|
||||
// ListPermissions lists the permissions of a driveItem
|
||||
func (s DriveItemPermissionsService) ListPermissions(ctx context.Context, itemID *storageprovider.ResourceId, listFederatedRoles, selectRoles bool) (libregraph.CollectionOfPermissionsWithAllowedValues, error) {
|
||||
func (s DriveItemPermissionsService) ListPermissions(ctx context.Context, itemID *storageprovider.ResourceId, queryOptions ListPermissionsQueryOptions) (libregraph.CollectionOfPermissionsWithAllowedValues, error) {
|
||||
collectionOfPermissions := libregraph.CollectionOfPermissionsWithAllowedValues{}
|
||||
gatewayClient, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
@@ -362,17 +375,22 @@ func (s DriveItemPermissionsService) ListPermissions(ctx context.Context, itemID
|
||||
permissionSet := statResponse.GetInfo().GetPermissionSet()
|
||||
allowedActions := unifiedrole.CS3ResourcePermissionsToLibregraphActions(permissionSet)
|
||||
|
||||
collectionOfPermissions = libregraph.CollectionOfPermissionsWithAllowedValues{
|
||||
LibreGraphPermissionsActionsAllowedValues: allowedActions,
|
||||
LibreGraphPermissionsRolesAllowedValues: conversions.ToValueSlice(
|
||||
collectionOfPermissions = libregraph.CollectionOfPermissionsWithAllowedValues{}
|
||||
|
||||
if len(queryOptions.SelectedAttrs) == 0 || slices.Contains(queryOptions.SelectedAttrs, "@libre.graph.permissions.actions.allowedValues") {
|
||||
collectionOfPermissions.LibreGraphPermissionsActionsAllowedValues = allowedActions
|
||||
}
|
||||
|
||||
if len(queryOptions.SelectedAttrs) == 0 || slices.Contains(queryOptions.SelectedAttrs, "@libre.graph.permissions.roles.allowedValues") {
|
||||
collectionOfPermissions.LibreGraphPermissionsRolesAllowedValues = conversions.ToValueSlice(
|
||||
unifiedrole.GetRolesByPermissions(
|
||||
unifiedrole.GetRoles(unifiedrole.RoleFilterIDs(s.config.UnifiedRoles.AvailableRoles...)),
|
||||
allowedActions,
|
||||
condition,
|
||||
listFederatedRoles,
|
||||
queryOptions.FilterFederatedRoles,
|
||||
false,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
for i, definition := range collectionOfPermissions.LibreGraphPermissionsRolesAllowedValues {
|
||||
@@ -381,10 +399,8 @@ func (s DriveItemPermissionsService) ListPermissions(ctx context.Context, itemID
|
||||
collectionOfPermissions.LibreGraphPermissionsRolesAllowedValues[i] = definition
|
||||
}
|
||||
|
||||
if selectRoles {
|
||||
// drop the actions
|
||||
collectionOfPermissions.LibreGraphPermissionsActionsAllowedValues = nil
|
||||
// no need to fetch shares, we are only interested in the roles
|
||||
if len(queryOptions.SelectedAttrs) > 0 {
|
||||
// no need to fetch shares, we are only interested allowedActions and/or allowedRoles
|
||||
return collectionOfPermissions, nil
|
||||
}
|
||||
|
||||
@@ -396,8 +412,11 @@ func (s DriveItemPermissionsService) ListPermissions(ctx context.Context, itemID
|
||||
}
|
||||
driveItems[storagespace.FormatResourceID(statResponse.GetInfo().GetId())] = *item
|
||||
|
||||
var permissionsCount int
|
||||
|
||||
if IsSpaceRoot(statResponse.GetInfo().GetId()) {
|
||||
permissions, err := s.getSpaceRootPermissions(ctx, statResponse.GetInfo().GetSpace().GetId())
|
||||
var permissions []libregraph.Permission
|
||||
permissions, permissionsCount, err = s.getSpaceRootPermissions(ctx, statResponse.GetInfo().GetSpace().GetId(), queryOptions.NoValues)
|
||||
if err != nil {
|
||||
return collectionOfPermissions, err
|
||||
}
|
||||
@@ -422,23 +441,33 @@ func (s DriveItemPermissionsService) ListPermissions(ctx context.Context, itemID
|
||||
}
|
||||
}
|
||||
}
|
||||
// finally get public shares, which are possible for spaceroots and "normal" resources
|
||||
driveItems, err = s.listPublicShares(ctx, []*link.ListPublicSharesRequest_Filter{
|
||||
publicshare.ResourceIDFilter(itemID),
|
||||
}, driveItems)
|
||||
if err != nil {
|
||||
return collectionOfPermissions, err
|
||||
|
||||
if !queryOptions.NoLinkPermissions {
|
||||
// finally get public shares, which are possible for spaceroots and "normal" resources
|
||||
driveItems, err = s.listPublicShares(ctx, []*link.ListPublicSharesRequest_Filter{
|
||||
publicshare.ResourceIDFilter(itemID),
|
||||
}, driveItems)
|
||||
if err != nil {
|
||||
return collectionOfPermissions, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, driveItem := range driveItems {
|
||||
collectionOfPermissions.Value = append(collectionOfPermissions.Value, driveItem.Permissions...)
|
||||
permissionsCount += len(driveItem.Permissions)
|
||||
if !queryOptions.NoValues {
|
||||
collectionOfPermissions.Value = append(collectionOfPermissions.Value, driveItem.Permissions...)
|
||||
}
|
||||
}
|
||||
|
||||
if queryOptions.Count {
|
||||
collectionOfPermissions.SetOdataCount(int32(permissionsCount))
|
||||
}
|
||||
|
||||
return collectionOfPermissions, nil
|
||||
}
|
||||
|
||||
// ListSpaceRootPermissions handles ListPermissions request on project spaces
|
||||
func (s DriveItemPermissionsService) ListSpaceRootPermissions(ctx context.Context, driveID *storageprovider.ResourceId) (libregraph.CollectionOfPermissionsWithAllowedValues, error) {
|
||||
func (s DriveItemPermissionsService) ListSpaceRootPermissions(ctx context.Context, driveID *storageprovider.ResourceId, queryOptions ListPermissionsQueryOptions) (libregraph.CollectionOfPermissionsWithAllowedValues, error) {
|
||||
collectionOfPermissions := libregraph.CollectionOfPermissionsWithAllowedValues{}
|
||||
gatewayClient, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
@@ -456,7 +485,7 @@ func (s DriveItemPermissionsService) ListSpaceRootPermissions(ctx context.Contex
|
||||
}
|
||||
|
||||
rootResourceID := space.GetRoot()
|
||||
return s.ListPermissions(ctx, rootResourceID, false, false) // federated roles are not supported for spaces
|
||||
return s.ListPermissions(ctx, rootResourceID, queryOptions) // federated roles are not supported for spaces
|
||||
}
|
||||
|
||||
// DeletePermission deletes a permission from a drive item
|
||||
@@ -701,19 +730,25 @@ func (api DriveItemPermissionsApi) ListPermissions(w http.ResponseWriter, r *htt
|
||||
return
|
||||
}
|
||||
|
||||
var listFederatedRoles bool
|
||||
if GetFilterParam(r) == "@libre.graph.permissions.roles.allowedValues/rolePermissions/any(p:contains(p/condition, '@Subject.UserType==\"Federated\"'))" {
|
||||
listFederatedRoles = true
|
||||
sanitizedPath := strings.TrimPrefix(r.URL.Path, "/graph/v1.0/")
|
||||
odataReq, err := godata.ParseRequest(r.Context(), sanitizedPath, r.URL.Query())
|
||||
if err != nil {
|
||||
api.logger.Debug().Err(err).Interface("query", r.URL.Query()).Msg("Error parsing ListPermissionRequest: query error")
|
||||
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
var selectRoles bool
|
||||
if GetSelectParam(r) == "@libre.graph.permissions.roles.allowedValues" {
|
||||
selectRoles = true
|
||||
var queryOptions ListPermissionsQueryOptions
|
||||
queryOptions, err = api.getListPermissionsQueryOptions(odataReq)
|
||||
if err != nil {
|
||||
api.logger.Debug().Err(err).Interface("query", r.URL.Query()).Msg("Error parsing ListPermissionRequest query options")
|
||||
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
ctx := r.Context()
|
||||
|
||||
permissions, err := api.driveItemPermissionsService.ListPermissions(ctx, itemID, listFederatedRoles, selectRoles)
|
||||
permissions, err := api.driveItemPermissionsService.ListPermissions(ctx, itemID, queryOptions)
|
||||
if err != nil {
|
||||
errorcode.RenderError(w, r, err)
|
||||
return
|
||||
@@ -746,8 +781,24 @@ func (api DriveItemPermissionsApi) ListSpaceRootPermissions(w http.ResponseWrite
|
||||
return
|
||||
}
|
||||
|
||||
sanitizedPath := strings.TrimPrefix(r.URL.Path, "/graph/v1.0/")
|
||||
odataReq, err := godata.ParseRequest(r.Context(), sanitizedPath, r.URL.Query())
|
||||
if err != nil {
|
||||
api.logger.Debug().Err(err).Interface("query", r.URL.Query()).Msg("Error parsing ListPermissionRequest: query error")
|
||||
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
var queryOptions ListPermissionsQueryOptions
|
||||
queryOptions, err = api.getListPermissionsQueryOptions(odataReq)
|
||||
if err != nil {
|
||||
api.logger.Debug().Err(err).Interface("query", r.URL.Query()).Msg("Error parsing ListPermissionRequest query options")
|
||||
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
ctx := r.Context()
|
||||
permissions, err := api.driveItemPermissionsService.ListSpaceRootPermissions(ctx, &driveID)
|
||||
permissions, err := api.driveItemPermissionsService.ListSpaceRootPermissions(ctx, &driveID, queryOptions)
|
||||
|
||||
if err != nil {
|
||||
errorcode.RenderError(w, r, err)
|
||||
@@ -772,6 +823,42 @@ func (api DriveItemPermissionsApi) ListSpaceRootPermissions(w http.ResponseWrite
|
||||
render.JSON(w, r, permissions)
|
||||
}
|
||||
|
||||
func (api DriveItemPermissionsApi) getListPermissionsQueryOptions(odataReq *godata.GoDataRequest) (ListPermissionsQueryOptions, error) {
|
||||
queryOptions := ListPermissionsQueryOptions{}
|
||||
if odataReq.Query.Filter != nil {
|
||||
switch odataReq.Query.Filter.RawValue {
|
||||
case federatedRolesODataFilter:
|
||||
queryOptions.FilterFederatedRoles = true
|
||||
case noLinksODataFilter:
|
||||
queryOptions.NoLinkPermissions = true
|
||||
default:
|
||||
return ListPermissionsQueryOptions{}, errorcode.New(errorcode.InvalidRequest, "invalid filter value")
|
||||
}
|
||||
}
|
||||
|
||||
selectAttrs, err := odata.GetSelectValues(odataReq.Query)
|
||||
if err != nil {
|
||||
return ListPermissionsQueryOptions{}, err
|
||||
}
|
||||
|
||||
queryOptions.SelectedAttrs = selectAttrs
|
||||
if odataReq.Query.Count != nil {
|
||||
queryOptions.Count = bool(*odataReq.Query.Count)
|
||||
}
|
||||
if odataReq.Query.Top != nil {
|
||||
top := int(*odataReq.Query.Top)
|
||||
switch {
|
||||
case top != 0:
|
||||
return ListPermissionsQueryOptions{}, err
|
||||
case top == 0 && !queryOptions.Count:
|
||||
return ListPermissionsQueryOptions{}, err
|
||||
default:
|
||||
queryOptions.NoValues = true
|
||||
}
|
||||
}
|
||||
return queryOptions, nil
|
||||
}
|
||||
|
||||
// DeletePermission handles DeletePermission requests
|
||||
func (api DriveItemPermissionsApi) DeletePermission(w http.ResponseWriter, r *http.Request) {
|
||||
_, itemID, err := GetDriveAndItemIDParam(r, &api.logger)
|
||||
|
||||
@@ -20,8 +20,8 @@ import (
|
||||
"github.com/go-chi/chi/v5"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/config"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/config"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/tidwall/gjson"
|
||||
"google.golang.org/grpc"
|
||||
@@ -385,7 +385,7 @@ var _ = Describe("DriveItemPermissionsService", func() {
|
||||
gatewayClient.On("Stat", mock.Anything, mock.Anything).Return(statResponse, nil)
|
||||
gatewayClient.On("ListShares", mock.Anything, mock.Anything).Return(listSharesResponse, nil)
|
||||
gatewayClient.On("ListPublicShares", mock.Anything, mock.Anything).Return(listPublicSharesResponse, nil)
|
||||
permissions, err := driveItemPermissionsService.ListPermissions(context.Background(), itemID, false, false)
|
||||
permissions, err := driveItemPermissionsService.ListPermissions(context.Background(), itemID, svc.ListPermissionsQueryOptions{})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(len(permissions.LibreGraphPermissionsActionsAllowedValues)).ToNot(BeZero())
|
||||
Expect(len(permissions.LibreGraphPermissionsRolesAllowedValues)).ToNot(BeZero())
|
||||
@@ -433,7 +433,7 @@ var _ = Describe("DriveItemPermissionsService", func() {
|
||||
gatewayClient.On("ListShares", mock.Anything, mock.Anything).Return(listSharesResponse, nil)
|
||||
gatewayClient.On("GetUser", mock.Anything, mock.Anything).Return(getUserResponse, nil)
|
||||
gatewayClient.On("ListPublicShares", mock.Anything, mock.Anything).Return(listPublicSharesResponse, nil)
|
||||
permissions, err := driveItemPermissionsService.ListPermissions(context.Background(), itemID, false, false)
|
||||
permissions, err := driveItemPermissionsService.ListPermissions(context.Background(), itemID, svc.ListPermissionsQueryOptions{})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(len(permissions.LibreGraphPermissionsActionsAllowedValues)).ToNot(BeZero())
|
||||
Expect(len(permissions.LibreGraphPermissionsRolesAllowedValues)).ToNot(BeZero())
|
||||
@@ -472,7 +472,7 @@ var _ = Describe("DriveItemPermissionsService", func() {
|
||||
gatewayClient.On("ListShares", mock.Anything, mock.Anything).Return(listSharesResponse, nil)
|
||||
gatewayClient.On("GetUser", mock.Anything, mock.Anything).Return(getUserResponse, nil)
|
||||
gatewayClient.On("ListPublicShares", mock.Anything, mock.Anything).Return(listPublicSharesResponse, nil)
|
||||
permissions, err := service.ListPermissions(context.Background(), itemID, false, false)
|
||||
permissions, err := service.ListPermissions(context.Background(), itemID, svc.ListPermissionsQueryOptions{})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(len(permissions.LibreGraphPermissionsActionsAllowedValues)).ToNot(BeZero())
|
||||
Expect(len(permissions.LibreGraphPermissionsRolesAllowedValues)).ToNot(BeZero())
|
||||
@@ -508,13 +508,126 @@ var _ = Describe("DriveItemPermissionsService", func() {
|
||||
gatewayClient.On("ListShares", mock.Anything, mock.Anything).Return(listSharesResponse, nil)
|
||||
gatewayClient.On("GetUser", mock.Anything, mock.Anything).Return(getUserResponse, nil)
|
||||
gatewayClient.On("ListPublicShares", mock.Anything, mock.Anything).Return(listPublicSharesResponse, nil)
|
||||
permissions, err := driveItemPermissionsService.ListPermissions(context.Background(), itemID, false, false)
|
||||
permissions, err := driveItemPermissionsService.ListPermissions(context.Background(), itemID, svc.ListPermissionsQueryOptions{})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(len(permissions.LibreGraphPermissionsActionsAllowedValues)).ToNot(BeZero())
|
||||
Expect(len(permissions.LibreGraphPermissionsRolesAllowedValues)).ToNot(BeZero())
|
||||
Expect(len(permissions.Value)).To(Equal(1))
|
||||
Expect(permissions.Value[0].GetLibreGraphPermissionsActions()[0]).To(Equal("none"))
|
||||
})
|
||||
It("Does not list public shares when requested so", func() {
|
||||
opt := svc.ListPermissionsQueryOptions{
|
||||
NoLinkPermissions: true,
|
||||
}
|
||||
gatewayClient.On("Stat", mock.Anything, mock.Anything).Return(statResponse, nil)
|
||||
gatewayClient.On("ListShares", mock.Anything, mock.Anything).Return(listSharesResponse, nil)
|
||||
permissions, err := driveItemPermissionsService.ListPermissions(context.Background(), itemID, opt)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(len(permissions.LibreGraphPermissionsActionsAllowedValues)).ToNot(BeZero())
|
||||
Expect(len(permissions.LibreGraphPermissionsRolesAllowedValues)).ToNot(BeZero())
|
||||
})
|
||||
It("Does not return permissions when the NoValues option is set", func() {
|
||||
opt := svc.ListPermissionsQueryOptions{
|
||||
NoValues: true,
|
||||
}
|
||||
listSharesResponse.Shares = []*collaboration.Share{
|
||||
{
|
||||
Id: &collaboration.ShareId{OpaqueId: "1"},
|
||||
Permissions: &collaboration.SharePermissions{
|
||||
Permissions: roleconversions.NewViewerRole().CS3ResourcePermissions(),
|
||||
},
|
||||
ResourceId: &provider.ResourceId{
|
||||
StorageId: "1",
|
||||
SpaceId: "2",
|
||||
OpaqueId: "3",
|
||||
},
|
||||
Grantee: &provider.Grantee{
|
||||
Type: provider.GranteeType_GRANTEE_TYPE_USER,
|
||||
Id: &provider.Grantee_UserId{
|
||||
UserId: &userpb.UserId{
|
||||
OpaqueId: "user-id",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
listPublicSharesResponse.Share = []*link.PublicShare{
|
||||
{
|
||||
Id: &link.PublicShareId{
|
||||
OpaqueId: "public-share-id",
|
||||
},
|
||||
Token: "public-share-token",
|
||||
// the link shares the same resource id
|
||||
ResourceId: &provider.ResourceId{
|
||||
StorageId: "1",
|
||||
SpaceId: "2",
|
||||
OpaqueId: "3",
|
||||
},
|
||||
Permissions: &link.PublicSharePermissions{Permissions: roleconversions.NewViewerRole().CS3ResourcePermissions()},
|
||||
},
|
||||
}
|
||||
gatewayClient.On("Stat", mock.Anything, mock.Anything).Return(statResponse, nil)
|
||||
gatewayClient.On("ListShares", mock.Anything, mock.Anything).Return(listSharesResponse, nil)
|
||||
gatewayClient.On("GetUser", mock.Anything, mock.Anything).Return(getUserResponse, nil)
|
||||
gatewayClient.On("ListPublicShares", mock.Anything, mock.Anything).Return(listPublicSharesResponse, nil)
|
||||
permissions, err := driveItemPermissionsService.ListPermissions(context.Background(), itemID, opt)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(len(permissions.LibreGraphPermissionsActionsAllowedValues)).ToNot(BeZero())
|
||||
Expect(len(permissions.LibreGraphPermissionsRolesAllowedValues)).ToNot(BeZero())
|
||||
Expect(len(permissions.Value)).To(BeZero())
|
||||
})
|
||||
It("Returns a count when the Count option is set", func() {
|
||||
opt := svc.ListPermissionsQueryOptions{
|
||||
Count: true,
|
||||
}
|
||||
listSharesResponse.Shares = []*collaboration.Share{
|
||||
{
|
||||
Id: &collaboration.ShareId{OpaqueId: "1"},
|
||||
Permissions: &collaboration.SharePermissions{
|
||||
Permissions: roleconversions.NewViewerRole().CS3ResourcePermissions(),
|
||||
},
|
||||
ResourceId: &provider.ResourceId{
|
||||
StorageId: "1",
|
||||
SpaceId: "2",
|
||||
OpaqueId: "3",
|
||||
},
|
||||
Grantee: &provider.Grantee{
|
||||
Type: provider.GranteeType_GRANTEE_TYPE_USER,
|
||||
Id: &provider.Grantee_UserId{
|
||||
UserId: &userpb.UserId{
|
||||
OpaqueId: "user-id",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
listPublicSharesResponse.Share = []*link.PublicShare{
|
||||
{
|
||||
Id: &link.PublicShareId{
|
||||
OpaqueId: "public-share-id",
|
||||
},
|
||||
Token: "public-share-token",
|
||||
// the link shares the same resource id
|
||||
ResourceId: &provider.ResourceId{
|
||||
StorageId: "1",
|
||||
SpaceId: "2",
|
||||
OpaqueId: "3",
|
||||
},
|
||||
Permissions: &link.PublicSharePermissions{Permissions: roleconversions.NewViewerRole().CS3ResourcePermissions()},
|
||||
},
|
||||
}
|
||||
gatewayClient.On("Stat", mock.Anything, mock.Anything).Return(statResponse, nil)
|
||||
gatewayClient.On("ListShares", mock.Anything, mock.Anything).Return(listSharesResponse, nil)
|
||||
gatewayClient.On("GetUser", mock.Anything, mock.Anything).Return(getUserResponse, nil)
|
||||
gatewayClient.On("ListPublicShares", mock.Anything, mock.Anything).Return(listPublicSharesResponse, nil)
|
||||
permissions, err := driveItemPermissionsService.ListPermissions(context.Background(), itemID, opt)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(len(permissions.LibreGraphPermissionsActionsAllowedValues)).ToNot(BeZero())
|
||||
Expect(len(permissions.LibreGraphPermissionsRolesAllowedValues)).ToNot(BeZero())
|
||||
count := int(permissions.GetOdataCount())
|
||||
Expect(count).To(Equal(2)) // 1 share + 1 public share
|
||||
Expect(len(permissions.Value)).To(Equal(count))
|
||||
})
|
||||
})
|
||||
Describe("ListSpaceRootPermissions", func() {
|
||||
var (
|
||||
@@ -555,7 +668,7 @@ var _ = Describe("DriveItemPermissionsService", func() {
|
||||
gatewayClient.On("ListPublicShares", mock.Anything, mock.Anything).Return(listPublicSharesResponse, nil)
|
||||
statResponse.Info.Id = listSpacesResponse.StorageSpaces[0].Root
|
||||
gatewayClient.On("Stat", mock.Anything, mock.Anything).Return(statResponse, nil)
|
||||
permissions, err := driveItemPermissionsService.ListSpaceRootPermissions(context.Background(), driveId)
|
||||
permissions, err := driveItemPermissionsService.ListSpaceRootPermissions(context.Background(), driveId, svc.ListPermissionsQueryOptions{})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(len(permissions.LibreGraphPermissionsActionsAllowedValues)).ToNot(BeZero())
|
||||
})
|
||||
@@ -1268,8 +1381,7 @@ var _ = Describe("DriveItemPermissionsApi", func() {
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
mockProvider.On("ListPermissions", mock.Anything, mock.Anything, mock.Anything, mock.Anything).
|
||||
Return(func(ctx context.Context, itemid *provider.ResourceId, listFederatedRoles, selectRoles bool) (libregraph.CollectionOfPermissionsWithAllowedValues, error) {
|
||||
Expect(listFederatedRoles).To(Equal(false))
|
||||
Return(func(ctx context.Context, itemid *provider.ResourceId, opt svc.ListPermissionsQueryOptions) (libregraph.CollectionOfPermissionsWithAllowedValues, error) {
|
||||
Expect(storagespace.FormatResourceID(itemid)).To(Equal("1$2!3"))
|
||||
return libregraph.CollectionOfPermissionsWithAllowedValues{}, nil
|
||||
}).Once()
|
||||
|
||||
159
services/graph/pkg/service/v0/api_users_user_profile_photo.go
Normal file
159
services/graph/pkg/service/v0/api_users_user_profile_photo.go
Normal file
@@ -0,0 +1,159 @@
|
||||
package svc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/go-chi/render"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/utils/metadata"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/errorcode"
|
||||
)
|
||||
|
||||
type (
|
||||
// UsersUserProfilePhotoProvider is the interface that defines the methods for the user profile photo service
|
||||
UsersUserProfilePhotoProvider interface {
|
||||
// GetPhoto retrieves the requested photo
|
||||
GetPhoto(ctx context.Context, id string) ([]byte, error)
|
||||
|
||||
// UpdatePhoto retrieves the requested photo
|
||||
UpdatePhoto(ctx context.Context, id string, r io.Reader) error
|
||||
|
||||
// DeletePhoto deletes the requested photo
|
||||
DeletePhoto(ctx context.Context, id string) error
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNoBytes is returned when no bytes are found
|
||||
ErrNoBytes = errors.New("no bytes")
|
||||
|
||||
// ErrInvalidContentType is returned when the content type is invalid
|
||||
ErrInvalidContentType = errors.New("invalid content type")
|
||||
|
||||
// ErrMissingArgument is returned when a required argument is missing
|
||||
ErrMissingArgument = errors.New("required argument is missing")
|
||||
)
|
||||
|
||||
// UsersUserProfilePhotoService is the implementation of the UsersUserProfilePhotoProvider interface
|
||||
type UsersUserProfilePhotoService struct {
|
||||
storage metadata.Storage
|
||||
}
|
||||
|
||||
// NewUsersUserProfilePhotoService creates a new UsersUserProfilePhotoService
|
||||
func NewUsersUserProfilePhotoService(storage metadata.Storage) (UsersUserProfilePhotoService, error) {
|
||||
return UsersUserProfilePhotoService{
|
||||
storage: storage,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetPhoto retrieves the requested photo
|
||||
func (s UsersUserProfilePhotoService) GetPhoto(ctx context.Context, id string) ([]byte, error) {
|
||||
return s.storage.SimpleDownload(ctx, id)
|
||||
}
|
||||
|
||||
// DeletePhoto deletes the requested photo
|
||||
func (s UsersUserProfilePhotoService) DeletePhoto(ctx context.Context, id string) error {
|
||||
return s.storage.Delete(ctx, id)
|
||||
}
|
||||
|
||||
// UpdatePhoto updates the requested photo
|
||||
func (s UsersUserProfilePhotoService) UpdatePhoto(ctx context.Context, id string, r io.Reader) error {
|
||||
if id == "" {
|
||||
return fmt.Errorf("%w: %s", ErrMissingArgument, "id")
|
||||
}
|
||||
|
||||
photo, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(photo) == 0 {
|
||||
return ErrNoBytes
|
||||
}
|
||||
|
||||
contentType := http.DetectContentType(photo)
|
||||
if !strings.HasPrefix(contentType, "image/") {
|
||||
return fmt.Errorf("%w: %s", ErrInvalidContentType, contentType)
|
||||
}
|
||||
|
||||
return s.storage.SimpleUpload(ctx, id, photo)
|
||||
}
|
||||
|
||||
// UsersUserProfilePhotoApi contains all photo related api endpoints
|
||||
type UsersUserProfilePhotoApi struct {
|
||||
logger log.Logger
|
||||
usersUserProfilePhotoService UsersUserProfilePhotoProvider
|
||||
}
|
||||
|
||||
// NewUsersUserProfilePhotoApi creates a new UsersUserProfilePhotoApi
|
||||
func NewUsersUserProfilePhotoApi(usersUserProfilePhotoService UsersUserProfilePhotoProvider, logger log.Logger) (UsersUserProfilePhotoApi, error) {
|
||||
return UsersUserProfilePhotoApi{
|
||||
logger: log.Logger{Logger: logger.With().Str("graph api", "UsersUserProfilePhotoApi").Logger()},
|
||||
usersUserProfilePhotoService: usersUserProfilePhotoService,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetProfilePhoto creates a handler which renders the corresponding photo
|
||||
func (api UsersUserProfilePhotoApi) GetProfilePhoto(h HTTPDataHandler[string]) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
v, ok := h(w, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
photo, err := api.usersUserProfilePhotoService.GetPhoto(r.Context(), v)
|
||||
if err != nil {
|
||||
api.logger.Debug().Err(err)
|
||||
errorcode.GeneralException.Render(w, r, http.StatusNotFound, "failed to get photo")
|
||||
return
|
||||
}
|
||||
|
||||
render.Status(r, http.StatusOK)
|
||||
_, _ = w.Write(photo)
|
||||
}
|
||||
}
|
||||
|
||||
// UpsertProfilePhoto creates a handler which updates or creates the corresponding photo
|
||||
func (api UsersUserProfilePhotoApi) UpsertProfilePhoto(h HTTPDataHandler[string]) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
v, ok := h(w, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
if err := api.usersUserProfilePhotoService.UpdatePhoto(r.Context(), v, r.Body); err != nil {
|
||||
api.logger.Debug().Err(err)
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, "failed to update photo")
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
_ = r.Body.Close()
|
||||
}()
|
||||
|
||||
render.Status(r, http.StatusOK)
|
||||
}
|
||||
}
|
||||
|
||||
// DeleteProfilePhoto creates a handler which deletes the corresponding photo
|
||||
func (api UsersUserProfilePhotoApi) DeleteProfilePhoto(h HTTPDataHandler[string]) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
v, ok := h(w, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
if err := api.usersUserProfilePhotoService.DeletePhoto(r.Context(), v); err != nil {
|
||||
api.logger.Debug().Err(err)
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, "failed to delete photo")
|
||||
return
|
||||
}
|
||||
|
||||
render.Status(r, http.StatusOK)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
package svc_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/mocks"
|
||||
svc "github.com/opencloud-eu/opencloud/services/graph/pkg/service/v0"
|
||||
)
|
||||
|
||||
func TestNewUsersUserProfilePhotoService(t *testing.T) {
|
||||
service, err := svc.NewUsersUserProfilePhotoService(mocks.NewStorage(t))
|
||||
assert.NoError(t, err)
|
||||
|
||||
t.Run("UpdatePhoto", func(t *testing.T) {
|
||||
t.Run("reports an error if id is empty", func(t *testing.T) {
|
||||
err := service.UpdatePhoto(context.Background(), "", bytes.NewReader([]byte{}))
|
||||
assert.ErrorIs(t, err, svc.ErrMissingArgument)
|
||||
})
|
||||
|
||||
t.Run("reports an error if the reader does not contain any bytes", func(t *testing.T) {
|
||||
err := service.UpdatePhoto(context.Background(), "123", bytes.NewReader([]byte{}))
|
||||
assert.ErrorIs(t, err, svc.ErrNoBytes)
|
||||
})
|
||||
|
||||
t.Run("reports an error if data is not an image", func(t *testing.T) {
|
||||
err := service.UpdatePhoto(context.Background(), "234", bytes.NewReader([]byte("not an image")))
|
||||
assert.ErrorIs(t, err, svc.ErrInvalidContentType)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestUsersUserProfilePhotoApi(t *testing.T) {
|
||||
var (
|
||||
serviceProvider = mocks.NewUsersUserProfilePhotoProvider(t)
|
||||
dataProvider = func(w http.ResponseWriter, r *http.Request) (string, bool) {
|
||||
return "123", true
|
||||
}
|
||||
)
|
||||
|
||||
api, err := svc.NewUsersUserProfilePhotoApi(serviceProvider, log.NopLogger())
|
||||
assert.NoError(t, err)
|
||||
|
||||
t.Run("GetProfilePhoto", func(t *testing.T) {
|
||||
r := httptest.NewRequest(http.MethodGet, "/", nil)
|
||||
ep := api.GetProfilePhoto(dataProvider)
|
||||
|
||||
t.Run("fails if photo provider errors", func(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
serviceProvider.EXPECT().GetPhoto(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, s string) ([]byte, error) {
|
||||
return nil, errors.New("any")
|
||||
}).Once()
|
||||
|
||||
ep.ServeHTTP(w, r)
|
||||
|
||||
assert.Equal(t, http.StatusNotFound, w.Code)
|
||||
})
|
||||
|
||||
t.Run("successfully returns the requested photo", func(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
serviceProvider.EXPECT().GetPhoto(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, s string) ([]byte, error) {
|
||||
return []byte("photo"), nil
|
||||
}).Once()
|
||||
|
||||
ep.ServeHTTP(w, r)
|
||||
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
assert.Equal(t, "photo", w.Body.String())
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("DeleteProfilePhoto", func(t *testing.T) {
|
||||
r := httptest.NewRequest(http.MethodDelete, "/", nil)
|
||||
ep := api.DeleteProfilePhoto(dataProvider)
|
||||
|
||||
t.Run("fails if photo provider errors", func(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
serviceProvider.EXPECT().DeletePhoto(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, s string) error {
|
||||
return errors.New("any")
|
||||
}).Once()
|
||||
|
||||
ep.ServeHTTP(w, r)
|
||||
|
||||
assert.Equal(t, http.StatusInternalServerError, w.Code)
|
||||
})
|
||||
|
||||
t.Run("successfully deletes the requested photo", func(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
serviceProvider.EXPECT().DeletePhoto(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, s string) error {
|
||||
return nil
|
||||
}).Once()
|
||||
|
||||
ep.ServeHTTP(w, r)
|
||||
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("UpsertProfilePhoto", func(t *testing.T) {
|
||||
r := httptest.NewRequest(http.MethodPut, "/", strings.NewReader("body"))
|
||||
ep := api.UpsertProfilePhoto(dataProvider)
|
||||
|
||||
t.Run("fails if photo provider errors", func(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
serviceProvider.EXPECT().UpdatePhoto(mock.Anything, mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, s string, r io.Reader) error {
|
||||
return errors.New("any")
|
||||
}).Once()
|
||||
|
||||
ep.ServeHTTP(w, r)
|
||||
|
||||
assert.Equal(t, http.StatusInternalServerError, w.Code)
|
||||
})
|
||||
|
||||
t.Run("successfully upserts the photo", func(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
serviceProvider.EXPECT().UpdatePhoto(mock.Anything, mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, s string, r io.Reader) error {
|
||||
return nil
|
||||
}).Once()
|
||||
|
||||
ep.ServeHTTP(w, r)
|
||||
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -11,6 +11,12 @@ import (
|
||||
"github.com/go-chi/chi/v5"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
|
||||
cs3mocks "github.com/opencloud-eu/reva/v2/tests/cs3mocks/mocks"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/shared"
|
||||
settingsmsg "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/messages/settings/v0"
|
||||
settings "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/services/settings/v0"
|
||||
@@ -19,11 +25,6 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/config/defaults"
|
||||
identitymocks "github.com/opencloud-eu/opencloud/services/graph/pkg/identity/mocks"
|
||||
service "github.com/opencloud-eu/opencloud/services/graph/pkg/service/v0"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
|
||||
cs3mocks "github.com/opencloud-eu/reva/v2/tests/cs3mocks/mocks"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type applicationList struct {
|
||||
@@ -70,13 +71,15 @@ var _ = Describe("Applications", func() {
|
||||
cfg.GRPCClientTLS = &shared.GRPCClientTLS{}
|
||||
cfg.Application.ID = "some-application-ID"
|
||||
|
||||
svc, _ = service.NewService(
|
||||
var err error
|
||||
svc, err = service.NewService(
|
||||
service.Config(cfg),
|
||||
service.WithGatewaySelector(gatewaySelector),
|
||||
service.EventsPublisher(&eventsPublisher),
|
||||
service.WithIdentityBackend(identityBackend),
|
||||
service.WithRoleService(roleService),
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
Describe("ListApplications", func() {
|
||||
|
||||
@@ -14,6 +14,13 @@ import (
|
||||
"github.com/golang/protobuf/ptypes/empty"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
revactx "github.com/opencloud-eu/reva/v2/pkg/ctx"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
|
||||
cs3mocks "github.com/opencloud-eu/reva/v2/tests/cs3mocks/mocks"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/shared"
|
||||
settingsmsg "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/messages/settings/v0"
|
||||
settings "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/services/settings/v0"
|
||||
@@ -22,12 +29,6 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/config/defaults"
|
||||
identitymocks "github.com/opencloud-eu/opencloud/services/graph/pkg/identity/mocks"
|
||||
service "github.com/opencloud-eu/opencloud/services/graph/pkg/service/v0"
|
||||
revactx "github.com/opencloud-eu/reva/v2/pkg/ctx"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
|
||||
cs3mocks "github.com/opencloud-eu/reva/v2/tests/cs3mocks/mocks"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type assignmentList struct {
|
||||
@@ -80,13 +81,15 @@ var _ = Describe("AppRoleAssignments", func() {
|
||||
cfg.GRPCClientTLS = &shared.GRPCClientTLS{}
|
||||
cfg.Application.ID = "some-application-ID"
|
||||
|
||||
svc, _ = service.NewService(
|
||||
var err error
|
||||
svc, err = service.NewService(
|
||||
service.Config(cfg),
|
||||
service.WithGatewaySelector(gatewaySelector),
|
||||
service.EventsPublisher(&eventsPublisher),
|
||||
service.WithIdentityBackend(identityBackend),
|
||||
service.WithRoleService(roleService),
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
Describe("ListAppRoleAssignments", func() {
|
||||
|
||||
@@ -49,19 +49,20 @@ type BaseGraphService struct {
|
||||
availableRoles []*libregraph.UnifiedRoleDefinition
|
||||
}
|
||||
|
||||
func (g BaseGraphService) getSpaceRootPermissions(ctx context.Context, spaceID *storageprovider.StorageSpaceId) ([]libregraph.Permission, error) {
|
||||
func (g BaseGraphService) getSpaceRootPermissions(ctx context.Context, spaceID *storageprovider.StorageSpaceId, countOnly bool) ([]libregraph.Permission, int, error) {
|
||||
gatewayClient, err := g.gatewaySelector.Next()
|
||||
|
||||
if err != nil {
|
||||
g.logger.Debug().Err(err).Msg("selecting gatewaySelector failed")
|
||||
return nil, err
|
||||
return nil, 0, err
|
||||
}
|
||||
space, err := utils.GetSpace(ctx, spaceID.GetOpaqueId(), gatewayClient)
|
||||
if err != nil {
|
||||
return nil, errorcode.FromUtilsStatusCodeError(err)
|
||||
return nil, 0, errorcode.FromUtilsStatusCodeError(err)
|
||||
}
|
||||
|
||||
return g.cs3SpacePermissionsToLibreGraph(ctx, space, APIVersion_1_Beta_1), nil
|
||||
perm, count := g.cs3SpacePermissionsToLibreGraph(ctx, space, countOnly, APIVersion_1_Beta_1)
|
||||
return perm, count, nil
|
||||
}
|
||||
|
||||
func (g BaseGraphService) getDriveItem(ctx context.Context, ref *storageprovider.Reference) (*libregraph.DriveItem, error) {
|
||||
@@ -99,9 +100,9 @@ func (g BaseGraphService) CS3ReceivedOCMSharesToDriveItems(ctx context.Context,
|
||||
return cs3ReceivedOCMSharesToDriveItems(ctx, g.logger, gatewayClient, g.identityCache, receivedShares, g.availableRoles)
|
||||
}
|
||||
|
||||
func (g BaseGraphService) cs3SpacePermissionsToLibreGraph(ctx context.Context, space *storageprovider.StorageSpace, apiVersion APIVersion) []libregraph.Permission {
|
||||
func (g BaseGraphService) cs3SpacePermissionsToLibreGraph(ctx context.Context, space *storageprovider.StorageSpace, countOnly bool, apiVersion APIVersion) ([]libregraph.Permission, int) {
|
||||
if space.Opaque == nil {
|
||||
return nil
|
||||
return nil, 0
|
||||
}
|
||||
logger := g.logger.SubloggerWithRequestID(ctx)
|
||||
|
||||
@@ -118,7 +119,12 @@ func (g BaseGraphService) cs3SpacePermissionsToLibreGraph(ctx context.Context, s
|
||||
}
|
||||
}
|
||||
if len(permissionsMap) == 0 {
|
||||
return nil
|
||||
return nil, 0
|
||||
}
|
||||
|
||||
if countOnly {
|
||||
// If we only need the count, we can return early
|
||||
return nil, len(permissionsMap)
|
||||
}
|
||||
|
||||
var permissionsExpirations map[string]*types.Timestamp
|
||||
@@ -219,7 +225,7 @@ func (g BaseGraphService) cs3SpacePermissionsToLibreGraph(ctx context.Context, s
|
||||
|
||||
permissions = append(permissions, p)
|
||||
}
|
||||
return permissions
|
||||
return permissions, len(permissions)
|
||||
}
|
||||
|
||||
func (g BaseGraphService) libreGraphPermissionFromCS3PublicShare(createdLink *link.PublicShare) (*libregraph.Permission, error) {
|
||||
@@ -1068,7 +1074,7 @@ func (g BaseGraphService) getPermissionByID(ctx context.Context, permissionID st
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
perms, err := g.getSpaceRootPermissions(ctx, resourceInfo.GetSpace().GetId())
|
||||
perms, _, err := g.getSpaceRootPermissions(ctx, resourceInfo.GetSpace().GetId(), false)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
42
services/graph/pkg/service/v0/data.go
Normal file
42
services/graph/pkg/service/v0/data.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package svc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
revactx "github.com/opencloud-eu/reva/v2/pkg/ctx"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/errorcode"
|
||||
)
|
||||
|
||||
// HTTPDataHandler returns data from the request, it should exit early and return false in the case of any error
|
||||
type HTTPDataHandler[T any] func(w http.ResponseWriter, r *http.Request) (T, bool)
|
||||
|
||||
var (
|
||||
// ErrNoUser is returned when no user is found
|
||||
ErrNoUser = errors.New("no user found")
|
||||
)
|
||||
|
||||
// GetUserIDFromCTX extracts the user from the request
|
||||
func GetUserIDFromCTX(w http.ResponseWriter, r *http.Request) (string, bool) {
|
||||
u, ok := revactx.ContextGetUser(r.Context())
|
||||
if !ok {
|
||||
errorcode.GeneralException.Render(w, r, http.StatusMethodNotAllowed, ErrNoUser.Error())
|
||||
}
|
||||
|
||||
return u.GetId().GetOpaqueId(), ok
|
||||
}
|
||||
|
||||
func GetSlugValue(key string) HTTPDataHandler[string] {
|
||||
return func(w http.ResponseWriter, r *http.Request) (string, bool) {
|
||||
v, err := url.PathUnescape(chi.URLParam(r, key))
|
||||
if err != nil {
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, fmt.Sprintf(`failed to get slug: "%s"`, key))
|
||||
}
|
||||
|
||||
return v, err == nil
|
||||
}
|
||||
}
|
||||
@@ -85,12 +85,14 @@ var _ = Describe("Driveitems", func() {
|
||||
cfg.Commons = &shared.Commons{}
|
||||
cfg.GRPCClientTLS = &shared.GRPCClientTLS{}
|
||||
|
||||
svc, _ = service.NewService(
|
||||
var err error
|
||||
svc, err = service.NewService(
|
||||
service.Config(cfg),
|
||||
service.WithGatewaySelector(gatewaySelector),
|
||||
service.EventsPublisher(&eventsPublisher),
|
||||
service.WithIdentityBackend(identityBackend),
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
Describe("GetRootDriveChildren", func() {
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"slices"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -19,10 +20,10 @@ import (
|
||||
storageprovider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
|
||||
"github.com/go-chi/render"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
revactx "github.com/opencloud-eu/reva/v2/pkg/ctx"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storagespace"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/utils"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
"github.com/pkg/errors"
|
||||
merrors "go-micro.dev/v4/errors"
|
||||
"golang.org/x/sync/errgroup"
|
||||
@@ -32,6 +33,7 @@ import (
|
||||
v0 "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/messages/settings/v0"
|
||||
settingssvc "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/services/settings/v0"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/errorcode"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/odata"
|
||||
settingsServiceExt "github.com/opencloud-eu/opencloud/services/settings/pkg/store/defaults"
|
||||
)
|
||||
|
||||
@@ -168,31 +170,60 @@ func (g Graph) GetAllDrivesV1Beta1(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
func sanitizePath(path string, apiVersion APIVersion) string {
|
||||
switch apiVersion {
|
||||
case APIVersion_1:
|
||||
return strings.TrimPrefix(path, "/graph/v1.0/")
|
||||
case APIVersion_1_Beta_1:
|
||||
return strings.TrimPrefix(path, "/graph/v1beta1/")
|
||||
default:
|
||||
return path
|
||||
}
|
||||
}
|
||||
|
||||
// parseDriveRequest parses the odata request and returns the parsed request and a boolean indicating if the request should expand root driveItems.
|
||||
func parseDriveRequest(r *http.Request) (*godata.GoDataRequest, bool, error) {
|
||||
odataReq, err := godata.ParseRequest(r.Context(), sanitizePath(r.URL.Path, APIVersion_1), r.URL.Query())
|
||||
if err != nil {
|
||||
return nil, false, errorcode.New(errorcode.InvalidRequest, err.Error())
|
||||
}
|
||||
exp, err := odata.GetExpandValues(odataReq.Query)
|
||||
if err != nil {
|
||||
return nil, false, errorcode.New(errorcode.InvalidRequest, err.Error())
|
||||
}
|
||||
expandPermissions := slices.Contains(exp, "root.permissions")
|
||||
return odataReq, expandPermissions, nil
|
||||
}
|
||||
|
||||
// getDrives implements the Service interface.
|
||||
func (g Graph) getDrives(r *http.Request, unrestricted bool, apiVersion APIVersion) ([]*libregraph.Drive, error) {
|
||||
logger := g.logger.SubloggerWithRequestID(r.Context())
|
||||
logger.Info().
|
||||
Interface("query", r.URL.Query()).
|
||||
Bool("unrestricted", unrestricted).
|
||||
Msg("calling get drives")
|
||||
sanitizedPath := strings.TrimPrefix(r.URL.Path, "/graph/v1.0/")
|
||||
// Parse the request with odata parser
|
||||
odataReq, err := godata.ParseRequest(r.Context(), sanitizedPath, r.URL.Query())
|
||||
if err != nil {
|
||||
logger.Debug().Err(err).Interface("query", r.URL.Query()).Msg("could not get drives: query error")
|
||||
return nil, errorcode.New(errorcode.InvalidRequest, err.Error())
|
||||
}
|
||||
ctx := r.Context()
|
||||
log := g.logger.SubloggerWithRequestID(ctx).With().Interface("query", r.URL.Query()).Bool("unrestricted", unrestricted).Logger()
|
||||
log.Debug().Msg("calling get drives")
|
||||
|
||||
webDavBaseURL, err := g.getWebDavBaseURL()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("could not get drives: error parsing url")
|
||||
return nil, errorcode.New(errorcode.GeneralException, err.Error())
|
||||
}
|
||||
|
||||
log = log.With().Str("url", webDavBaseURL.String()).Logger()
|
||||
|
||||
odataReq, expandPermissions, err := parseDriveRequest(r)
|
||||
if err != nil {
|
||||
log.Debug().Err(err).Msg("could not get drives: error parsing odata request")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
filters, err := generateCs3Filters(odataReq)
|
||||
if err != nil {
|
||||
logger.Debug().Err(err).Interface("query", r.URL.Query()).Msg("could not get drives: error parsing filters")
|
||||
log.Debug().Err(err).Msg("could not get drives: error parsing filters")
|
||||
return nil, errorcode.New(errorcode.NotSupported, err.Error())
|
||||
}
|
||||
if !unrestricted {
|
||||
user, ok := revactx.ContextGetUser(r.Context())
|
||||
if !ok {
|
||||
logger.Debug().Msg("could not create drive: invalid user")
|
||||
log.Debug().Msg("could not create drive: invalid user")
|
||||
return nil, errorcode.New(errorcode.AccessDenied, "invalid user")
|
||||
}
|
||||
filters = append(filters, &storageprovider.ListStorageSpacesRequest_Filter{
|
||||
@@ -203,39 +234,32 @@ func (g Graph) getDrives(r *http.Request, unrestricted bool, apiVersion APIVersi
|
||||
})
|
||||
}
|
||||
|
||||
logger.Debug().
|
||||
log.Debug().
|
||||
Interface("filters", filters).
|
||||
Bool("unrestricted", unrestricted).
|
||||
Msg("calling list storage spaces on backend")
|
||||
res, err := g.ListStorageSpacesWithFilters(ctx, filters, unrestricted)
|
||||
switch {
|
||||
case err != nil:
|
||||
logger.Error().Err(err).Msg("could not get drives: transport error")
|
||||
log.Error().Err(err).Msg("could not get drives: transport error")
|
||||
return nil, errorcode.New(errorcode.GeneralException, err.Error())
|
||||
case res.Status.Code != cs3rpc.Code_CODE_OK:
|
||||
if res.Status.Code == cs3rpc.Code_CODE_NOT_FOUND {
|
||||
// ok, empty return
|
||||
return nil, nil
|
||||
}
|
||||
logger.Debug().Str("message", res.GetStatus().GetMessage()).Msg("could not get drives: grpc error")
|
||||
log.Debug().Str("message", res.GetStatus().GetMessage()).Msg("could not get drives: grpc error")
|
||||
return nil, errorcode.New(errorcode.GeneralException, res.Status.Message)
|
||||
}
|
||||
|
||||
webDavBaseURL, err := g.getWebDavBaseURL()
|
||||
spaces, err := g.formatDrives(ctx, webDavBaseURL, res.StorageSpaces, apiVersion, expandPermissions)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Str("url", webDavBaseURL.String()).Msg("could not get drives: error parsing url")
|
||||
return nil, errorcode.New(errorcode.GeneralException, err.Error())
|
||||
}
|
||||
|
||||
spaces, err := g.formatDrives(ctx, webDavBaseURL, res.StorageSpaces, apiVersion)
|
||||
if err != nil {
|
||||
logger.Debug().Err(err).Msg("could not get drives: error parsing grpc response")
|
||||
log.Debug().Err(err).Msg("could not get drives: error parsing grpc response")
|
||||
return nil, errorcode.New(errorcode.GeneralException, err.Error())
|
||||
}
|
||||
|
||||
spaces, err = sortSpaces(odataReq, spaces)
|
||||
if err != nil {
|
||||
logger.Debug().Err(err).Msg("could not get drives: error sorting the spaces list according to query")
|
||||
log.Debug().Err(err).Msg("could not get drives: error sorting the spaces list according to query")
|
||||
return nil, errorcode.New(errorcode.InvalidRequest, err.Error())
|
||||
}
|
||||
|
||||
@@ -245,15 +269,32 @@ func (g Graph) getDrives(r *http.Request, unrestricted bool, apiVersion APIVersi
|
||||
// GetSingleDrive does a lookup of a single space by spaceId
|
||||
func (g Graph) GetSingleDrive(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
logger := g.logger.SubloggerWithRequestID(ctx)
|
||||
logger.Info().Interface("query", r.URL.Query()).Msg("calling get drive")
|
||||
log := g.logger.SubloggerWithRequestID(ctx).With().Interface("query", r.URL.Query()).Logger()
|
||||
log.Debug().Msg("calling get drive")
|
||||
|
||||
rid, err := parseIDParam(r, "driveID")
|
||||
if err != nil {
|
||||
errorcode.RenderError(w, r, err)
|
||||
return
|
||||
}
|
||||
log := logger.With().Str("storage", rid.StorageId).Str("space", rid.SpaceId).Str("node", rid.OpaqueId).Logger()
|
||||
|
||||
log = log.With().Str("storage", rid.StorageId).Str("space", rid.SpaceId).Str("node", rid.OpaqueId).Logger()
|
||||
|
||||
webDavBaseURL, err := g.getWebDavBaseURL()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("could not get drive: error parsing webdav base url")
|
||||
errorcode.RenderError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
log = log.With().Str("url", webDavBaseURL.String()).Logger()
|
||||
|
||||
_, expandPermissions, err := parseDriveRequest(r)
|
||||
if err != nil {
|
||||
log.Debug().Err(err).Msg("could not get drives: error parsing odata request")
|
||||
errorcode.RenderError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Debug().Msg("calling list storage spaces with id filter")
|
||||
|
||||
@@ -281,13 +322,7 @@ func (g Graph) GetSingleDrive(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
webDavBaseURL, err := g.getWebDavBaseURL()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Str("url", webDavBaseURL.String()).Msg("could not get drive: error parsing webdav base url")
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
spaces, err := g.formatDrives(ctx, webDavBaseURL, res.StorageSpaces, APIVersion_1)
|
||||
spaces, err := g.formatDrives(ctx, webDavBaseURL, res.StorageSpaces, APIVersion_1, expandPermissions)
|
||||
if err != nil {
|
||||
log.Debug().Err(err).Msg("could not get drive: error parsing grpc response")
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
|
||||
@@ -324,14 +359,22 @@ func (g Graph) canCreateSpace(ctx context.Context, ownPersonalHome bool) bool {
|
||||
|
||||
// CreateDrive creates a storage drive (space).
|
||||
func (g Graph) CreateDrive(w http.ResponseWriter, r *http.Request) {
|
||||
logger := g.logger.SubloggerWithRequestID(r.Context())
|
||||
logger.Info().Msg("calling create drive")
|
||||
|
||||
ctx := r.Context()
|
||||
log := g.logger.SubloggerWithRequestID(ctx).With().Interface("query", r.URL.Query()).Logger()
|
||||
log.Debug().Msg("calling create drive")
|
||||
|
||||
webDavBaseURL, err := g.getWebDavBaseURL()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("could not create drive: error parsing webdav base url")
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
log = log.With().Str("url", webDavBaseURL.String()).Logger()
|
||||
|
||||
us, ok := revactx.ContextGetUser(ctx)
|
||||
if !ok {
|
||||
logger.Debug().Msg("could not create drive: invalid user")
|
||||
log.Debug().Msg("could not create drive: invalid user")
|
||||
errorcode.NotAllowed.Render(w, r, http.StatusUnauthorized, "invalid user")
|
||||
return
|
||||
}
|
||||
@@ -339,7 +382,7 @@ func (g Graph) CreateDrive(w http.ResponseWriter, r *http.Request) {
|
||||
// TODO determine if the user tries to create his own personal space and pass that as a boolean
|
||||
canCreateSpace := g.canCreateSpace(ctx, false)
|
||||
if !canCreateSpace {
|
||||
logger.Debug().Bool("cancreatespace", canCreateSpace).Msg("could not create drive: insufficient permissions")
|
||||
log.Debug().Bool("cancreatespace", canCreateSpace).Msg("could not create drive: insufficient permissions")
|
||||
// if the permission is not existing for the user in context we can assume we don't have it. Return 401.
|
||||
errorcode.NotAllowed.Render(w, r, http.StatusForbidden, "insufficient permissions to create a space.")
|
||||
return
|
||||
@@ -347,20 +390,20 @@ func (g Graph) CreateDrive(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
gatewayClient, err := g.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Msg("could not select next gateway client")
|
||||
log.Error().Err(err).Msg("could not select next gateway client")
|
||||
errorcode.ServiceNotAvailable.Render(w, r, http.StatusInternalServerError, "could not select next gateway client, aborting")
|
||||
return
|
||||
}
|
||||
|
||||
drive := libregraph.Drive{}
|
||||
if err := StrictJSONUnmarshal(r.Body, &drive); err != nil {
|
||||
logger.Debug().Err(err).Interface("body", r.Body).Msg("could not create drive: invalid body schema definition")
|
||||
log.Debug().Err(err).Interface("body", r.Body).Msg("could not create drive: invalid body schema definition")
|
||||
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "invalid body schema definition")
|
||||
return
|
||||
}
|
||||
spaceName := strings.TrimSpace(drive.Name)
|
||||
if err := validateSpaceName(spaceName); err != nil {
|
||||
logger.Debug().Str("name", spaceName).Err(err).Msg("could not create drive: name validation failed")
|
||||
log.Debug().Str("name", spaceName).Err(err).Msg("could not create drive: name validation failed")
|
||||
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, fmt.Sprintf("invalid spacename: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
@@ -373,7 +416,7 @@ func (g Graph) CreateDrive(w http.ResponseWriter, r *http.Request) {
|
||||
case "", _spaceTypeProject:
|
||||
driveType = _spaceTypeProject
|
||||
default:
|
||||
logger.Debug().Str("type", driveType).Msg("could not create drive: drives of this type cannot be created via this api")
|
||||
log.Debug().Str("type", driveType).Msg("could not create drive: drives of this type cannot be created via this api")
|
||||
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "drives of this type cannot be created via this api")
|
||||
return
|
||||
}
|
||||
@@ -398,39 +441,32 @@ func (g Graph) CreateDrive(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
resp, err := gatewayClient.CreateStorageSpace(ctx, &csr)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Msg("could not create drive: transport error")
|
||||
log.Error().Err(err).Msg("could not create drive: transport error")
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if resp.GetStatus().GetCode() != cs3rpc.Code_CODE_OK {
|
||||
if resp.GetStatus().GetCode() == cs3rpc.Code_CODE_PERMISSION_DENIED {
|
||||
logger.Debug().Str("grpcmessage", resp.GetStatus().GetMessage()).Msg("could not create drive: permission denied")
|
||||
log.Debug().Str("grpcmessage", resp.GetStatus().GetMessage()).Msg("could not create drive: permission denied")
|
||||
errorcode.NotAllowed.Render(w, r, http.StatusForbidden, "permission denied")
|
||||
return
|
||||
}
|
||||
if resp.GetStatus().GetCode() == cs3rpc.Code_CODE_INVALID_ARGUMENT {
|
||||
logger.Debug().Str("grpcmessage", resp.GetStatus().GetMessage()).Msg("could not create drive: bad request")
|
||||
log.Debug().Str("grpcmessage", resp.GetStatus().GetMessage()).Msg("could not create drive: bad request")
|
||||
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, resp.GetStatus().GetMessage())
|
||||
return
|
||||
}
|
||||
logger.Debug().Interface("grpcmessage", csr).Str("grpc", resp.GetStatus().GetMessage()).Msg("could not create drive: grpc error")
|
||||
log.Debug().Interface("grpcmessage", csr).Str("grpc", resp.GetStatus().GetMessage()).Msg("could not create drive: grpc error")
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, resp.GetStatus().GetMessage())
|
||||
return
|
||||
}
|
||||
|
||||
webDavBaseURL, err := g.getWebDavBaseURL()
|
||||
if err != nil {
|
||||
logger.Error().Str("url", webDavBaseURL.String()).Err(err).Msg("could not create drive: error parsing webdav base url")
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
space := resp.GetStorageSpace()
|
||||
if t := r.URL.Query().Get(TemplateParameter); t != "" && driveType == _spaceTypeProject {
|
||||
loc := l10n.MustGetUserLocale(ctx, us.GetId().GetOpaqueId(), r.Header.Get(HeaderAcceptLanguage), g.valueService)
|
||||
if err := g.applySpaceTemplate(ctx, gatewayClient, space.GetRoot(), t, loc); err != nil {
|
||||
logger.Error().Err(err).Msg("could not apply template to space")
|
||||
log.Error().Err(err).Msg("could not apply template to space")
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
@@ -438,20 +474,20 @@ func (g Graph) CreateDrive(w http.ResponseWriter, r *http.Request) {
|
||||
// refetch the drive to get quota information - should we calculate this ourselves to avoid the extra call?
|
||||
space, err = utils.GetSpace(ctx, space.GetId().GetOpaqueId(), gatewayClient)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Msg("could not refetch space")
|
||||
log.Error().Err(err).Msg("could not refetch space")
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
spaces, err := g.formatDrives(ctx, webDavBaseURL, []*storageprovider.StorageSpace{space}, APIVersion_1)
|
||||
spaces, err := g.formatDrives(ctx, webDavBaseURL, []*storageprovider.StorageSpace{space}, APIVersion_1, false)
|
||||
if err != nil {
|
||||
logger.Debug().Err(err).Msg("could not get drive: error parsing grpc response")
|
||||
log.Debug().Err(err).Msg("could not get drive: error parsing grpc response")
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
if len(spaces) == 0 {
|
||||
logger.Error().Msg("could not convert space")
|
||||
log.Error().Msg("could not convert space")
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, "could not convert space")
|
||||
return
|
||||
}
|
||||
@@ -462,8 +498,8 @@ func (g Graph) CreateDrive(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// UpdateDrive updates the properties of a storage drive (space).
|
||||
func (g Graph) UpdateDrive(w http.ResponseWriter, r *http.Request) {
|
||||
logger := g.logger.SubloggerWithRequestID(r.Context())
|
||||
logger.Info().Msg("calling update drive")
|
||||
log := g.logger.SubloggerWithRequestID(r.Context()).With().Interface("query", r.URL.Query()).Logger()
|
||||
log.Debug().Msg("calling update drive")
|
||||
|
||||
rid, err := parseIDParam(r, "driveID")
|
||||
if err != nil {
|
||||
@@ -471,9 +507,20 @@ func (g Graph) UpdateDrive(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
log = log.With().Str("storage", rid.StorageId).Str("space", rid.SpaceId).Str("node", rid.OpaqueId).Logger()
|
||||
|
||||
webDavBaseURL, err := g.getWebDavBaseURL()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Interface("url", webDavBaseURL.String()).Msg("could not update drive: error parsing url")
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
log = log.With().Str("url", webDavBaseURL.String()).Logger()
|
||||
|
||||
drive := libregraph.DriveUpdate{}
|
||||
if err = StrictJSONUnmarshal(r.Body, &drive); err != nil {
|
||||
logger.Debug().Err(err).Interface("body", r.Body).Msg("could not update drive, invalid request body")
|
||||
log.Debug().Err(err).Interface("body", r.Body).Msg("could not update drive, invalid request body")
|
||||
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, fmt.Sprintf("invalid request body: error: %v", err.Error()))
|
||||
return
|
||||
}
|
||||
@@ -526,7 +573,7 @@ func (g Graph) UpdateDrive(w http.ResponseWriter, r *http.Request) {
|
||||
if drive.GetName() != "" {
|
||||
spacename := strings.TrimSpace(drive.GetName())
|
||||
if err := validateSpaceName(spacename); err != nil {
|
||||
logger.Info().Err(err).Msg("could not update drive: spacename invalid")
|
||||
log.Info().Err(err).Msg("could not update drive: spacename invalid")
|
||||
errorcode.GeneralException.Render(w, r, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
@@ -552,12 +599,12 @@ func (g Graph) UpdateDrive(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
canSetSpaceQuota, err := g.canSetSpaceQuota(r.Context(), user, dt)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Msg("could not update drive: failed to check if the user can set space quota")
|
||||
log.Error().Err(err).Msg("could not update drive: failed to check if the user can set space quota")
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
if !canSetSpaceQuota {
|
||||
logger.Debug().
|
||||
log.Debug().
|
||||
Bool("cansetspacequota", canSetSpaceQuota).
|
||||
Msg("could not update drive: user is not allowed to set the space quota")
|
||||
errorcode.NotAllowed.Render(w, r, http.StatusForbidden, "user is not allowed to set the space quota")
|
||||
@@ -568,10 +615,10 @@ func (g Graph) UpdateDrive(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
logger.Debug().Interface("payload", updateSpaceRequest).Msg("calling update space on backend")
|
||||
log.Debug().Interface("payload", updateSpaceRequest).Msg("calling update space on backend")
|
||||
resp, err := gatewayClient.UpdateStorageSpace(r.Context(), updateSpaceRequest)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Msg("could not update drive: transport error")
|
||||
log.Error().Err(err).Msg("could not update drive: transport error")
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, "transport error")
|
||||
return
|
||||
}
|
||||
@@ -579,38 +626,31 @@ func (g Graph) UpdateDrive(w http.ResponseWriter, r *http.Request) {
|
||||
if resp.GetStatus().GetCode() != cs3rpc.Code_CODE_OK {
|
||||
switch resp.Status.GetCode() {
|
||||
case cs3rpc.Code_CODE_NOT_FOUND:
|
||||
logger.Debug().Interface("id", rid).Msg("could not update drive: drive not found")
|
||||
log.Debug().Msg("could not update drive: drive not found")
|
||||
errorcode.ItemNotFound.Render(w, r, http.StatusNotFound, "drive not found")
|
||||
return
|
||||
case cs3rpc.Code_CODE_PERMISSION_DENIED:
|
||||
logger.Debug().Interface("id", rid).Msg("could not update drive, permission denied")
|
||||
log.Debug().Msg("could not update drive, permission denied")
|
||||
errorcode.ItemNotFound.Render(w, r, http.StatusNotFound, "drive not found")
|
||||
return
|
||||
case cs3rpc.Code_CODE_INVALID_ARGUMENT:
|
||||
logger.Debug().Interface("id", rid).Msg("could not update drive, invalid argument")
|
||||
log.Debug().Msg("could not update drive, invalid argument")
|
||||
errorcode.NotAllowed.Render(w, r, http.StatusBadRequest, resp.GetStatus().GetMessage())
|
||||
return
|
||||
case cs3rpc.Code_CODE_UNIMPLEMENTED:
|
||||
logger.Debug().Interface("id", rid).Msg("could not delete drive: delete not implemented for this type of drive")
|
||||
log.Debug().Msg("could not delete drive: delete not implemented for this type of drive")
|
||||
errorcode.NotAllowed.Render(w, r, http.StatusMethodNotAllowed, "drive cannot be updated")
|
||||
return
|
||||
default:
|
||||
logger.Debug().Interface("id", rid).Str("grpc", resp.GetStatus().GetMessage()).Msg("could not update drive: grpc error")
|
||||
log.Debug().Str("grpc", resp.GetStatus().GetMessage()).Msg("could not update drive: grpc error")
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, "grpc error")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
webDavBaseURL, err := g.getWebDavBaseURL()
|
||||
spaces, err := g.formatDrives(r.Context(), webDavBaseURL, []*storageprovider.StorageSpace{resp.StorageSpace}, APIVersion_1, false)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Interface("url", webDavBaseURL.String()).Msg("could not update drive: error parsing url")
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
spaces, err := g.formatDrives(r.Context(), webDavBaseURL, []*storageprovider.StorageSpace{resp.StorageSpace}, APIVersion_1)
|
||||
if err != nil {
|
||||
logger.Debug().Err(err).Msg("could not update drive: error parsing grpc response")
|
||||
log.Debug().Err(err).Msg("could not update drive: error parsing grpc response")
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
@@ -619,7 +659,7 @@ func (g Graph) UpdateDrive(w http.ResponseWriter, r *http.Request) {
|
||||
render.JSON(w, r, spaces[0])
|
||||
}
|
||||
|
||||
func (g Graph) formatDrives(ctx context.Context, baseURL *url.URL, storageSpaces []*storageprovider.StorageSpace, apiVersion APIVersion) ([]*libregraph.Drive, error) {
|
||||
func (g Graph) formatDrives(ctx context.Context, baseURL *url.URL, storageSpaces []*storageprovider.StorageSpace, apiVersion APIVersion, expandPermissions bool) ([]*libregraph.Drive, error) {
|
||||
errg, ctx := errgroup.WithContext(ctx)
|
||||
work := make(chan *storageprovider.StorageSpace, len(storageSpaces))
|
||||
results := make(chan *libregraph.Drive, len(storageSpaces))
|
||||
@@ -649,7 +689,7 @@ func (g Graph) formatDrives(ctx context.Context, baseURL *url.URL, storageSpaces
|
||||
// skip OCM shares they are no supposed to show up in the drives list
|
||||
continue
|
||||
}
|
||||
res, err := g.cs3StorageSpaceToDrive(ctx, baseURL, storageSpace, apiVersion)
|
||||
res, err := g.cs3StorageSpaceToDrive(ctx, baseURL, storageSpace, apiVersion, expandPermissions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -733,7 +773,7 @@ func (g Graph) ListStorageSpacesWithFilters(ctx context.Context, filters []*stor
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (g Graph) cs3StorageSpaceToDrive(ctx context.Context, baseURL *url.URL, space *storageprovider.StorageSpace, apiVersion APIVersion) (*libregraph.Drive, error) {
|
||||
func (g Graph) cs3StorageSpaceToDrive(ctx context.Context, baseURL *url.URL, space *storageprovider.StorageSpace, apiVersion APIVersion, expandPermissions bool) (*libregraph.Drive, error) {
|
||||
logger := g.logger.SubloggerWithRequestID(ctx)
|
||||
if space.Root == nil {
|
||||
logger.Error().Msg("unable to parse space: space has no root")
|
||||
@@ -745,18 +785,20 @@ func (g Graph) cs3StorageSpaceToDrive(ctx context.Context, baseURL *url.URL, spa
|
||||
}
|
||||
spaceID := storagespace.FormatResourceID(spaceRid)
|
||||
|
||||
permissions := g.cs3SpacePermissionsToLibreGraph(ctx, space, apiVersion)
|
||||
|
||||
drive := &libregraph.Drive{
|
||||
Id: libregraph.PtrString(spaceID),
|
||||
Name: space.Name,
|
||||
//"createdDateTime": "string (timestamp)", // TODO read from StorageSpace ... needs Opaque for now
|
||||
DriveType: &space.SpaceType,
|
||||
// we currently always expandt the root because it carries the deleted property that indiccates if a space is trashed
|
||||
Root: &libregraph.DriveItem{
|
||||
Id: libregraph.PtrString(storagespace.FormatResourceID(spaceRid)),
|
||||
Permissions: permissions,
|
||||
Id: libregraph.PtrString(storagespace.FormatResourceID(spaceRid)),
|
||||
},
|
||||
}
|
||||
if expandPermissions {
|
||||
drive.Root.Permissions, _ = g.cs3SpacePermissionsToLibreGraph(ctx, space, false, apiVersion)
|
||||
}
|
||||
|
||||
if space.SpaceType == _spaceTypeMountpoint {
|
||||
var remoteItem *libregraph.RemoteItem
|
||||
grantID := storageprovider.ResourceId{
|
||||
|
||||
@@ -14,6 +14,13 @@ import (
|
||||
"github.com/go-chi/chi/v5"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
revactx "github.com/opencloud-eu/reva/v2/pkg/ctx"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
|
||||
cs3mocks "github.com/opencloud-eu/reva/v2/tests/cs3mocks/mocks"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/shared"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/mocks"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/config"
|
||||
@@ -21,12 +28,6 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/errorcode"
|
||||
identitymocks "github.com/opencloud-eu/opencloud/services/graph/pkg/identity/mocks"
|
||||
service "github.com/opencloud-eu/opencloud/services/graph/pkg/service/v0"
|
||||
revactx "github.com/opencloud-eu/reva/v2/pkg/ctx"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
|
||||
cs3mocks "github.com/opencloud-eu/reva/v2/tests/cs3mocks/mocks"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
var _ = Describe("EducationClass", func() {
|
||||
@@ -78,13 +79,15 @@ var _ = Describe("EducationClass", func() {
|
||||
cfg.Commons = &shared.Commons{}
|
||||
cfg.GRPCClientTLS = &shared.GRPCClientTLS{}
|
||||
|
||||
svc, _ = service.NewService(
|
||||
var err error
|
||||
svc, err = service.NewService(
|
||||
service.Config(cfg),
|
||||
service.WithGatewaySelector(gatewaySelector),
|
||||
service.EventsPublisher(&eventsPublisher),
|
||||
service.WithIdentityBackend(identityBackend),
|
||||
service.WithIdentityEducationBackend(identityEducationBackend),
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
Describe("GetEducationClasses", func() {
|
||||
@@ -326,13 +329,15 @@ var _ = Describe("EducationClass", func() {
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
cfg.API.GroupMembersPatchLimit = 21
|
||||
svc, _ = service.NewService(
|
||||
|
||||
svc, err = service.NewService(
|
||||
service.Config(cfg),
|
||||
service.WithGatewaySelector(gatewaySelector),
|
||||
service.EventsPublisher(&eventsPublisher),
|
||||
service.WithIdentityBackend(identityBackend),
|
||||
service.WithIdentityEducationBackend(identityEducationBackend),
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
r := httptest.NewRequest(http.MethodPatch, "/graph/v1.0/education/classes", bytes.NewBuffer(updatedClassJson))
|
||||
rctx := chi.NewRouteContext()
|
||||
|
||||
@@ -21,13 +21,14 @@ import (
|
||||
"github.com/stretchr/testify/mock"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/shared"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/config"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/config/defaults"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/errorcode"
|
||||
identitymocks "github.com/opencloud-eu/opencloud/services/graph/pkg/identity/mocks"
|
||||
service "github.com/opencloud-eu/opencloud/services/graph/pkg/service/v0"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
)
|
||||
|
||||
type schoolList struct {
|
||||
@@ -78,11 +79,13 @@ var _ = Describe("Schools", func() {
|
||||
cfg.Commons = &shared.Commons{}
|
||||
cfg.GRPCClientTLS = &shared.GRPCClientTLS{}
|
||||
|
||||
svc, _ = service.NewService(
|
||||
var err error
|
||||
svc, err = service.NewService(
|
||||
service.Config(cfg),
|
||||
service.WithGatewaySelector(gatewaySelector),
|
||||
service.WithIdentityEducationBackend(identityEducationBackend),
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
Describe("GetEducationSchools", func() {
|
||||
|
||||
@@ -15,6 +15,14 @@ import (
|
||||
"github.com/go-chi/chi/v5"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
revactx "github.com/opencloud-eu/reva/v2/pkg/ctx"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/status"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
|
||||
cs3mocks "github.com/opencloud-eu/reva/v2/tests/cs3mocks/mocks"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/shared"
|
||||
settingssvc "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/services/settings/v0"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/mocks"
|
||||
@@ -22,13 +30,6 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/config/defaults"
|
||||
identitymocks "github.com/opencloud-eu/opencloud/services/graph/pkg/identity/mocks"
|
||||
service "github.com/opencloud-eu/opencloud/services/graph/pkg/service/v0"
|
||||
revactx "github.com/opencloud-eu/reva/v2/pkg/ctx"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/status"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
|
||||
cs3mocks "github.com/opencloud-eu/reva/v2/tests/cs3mocks/mocks"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type educationUserList struct {
|
||||
@@ -80,13 +81,15 @@ var _ = Describe("EducationUsers", func() {
|
||||
cfg.Commons = &shared.Commons{}
|
||||
cfg.GRPCClientTLS = &shared.GRPCClientTLS{}
|
||||
|
||||
svc, _ = service.NewService(
|
||||
var err error
|
||||
svc, err = service.NewService(
|
||||
service.Config(cfg),
|
||||
service.WithGatewaySelector(gatewaySelector),
|
||||
service.EventsPublisher(&eventsPublisher),
|
||||
service.WithIdentityEducationBackend(identityEducationBackend),
|
||||
service.WithRoleService(roleService),
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
Describe("GetEducationUsers", func() {
|
||||
|
||||
@@ -17,13 +17,13 @@ import (
|
||||
"github.com/go-chi/chi/v5"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/conversions"
|
||||
revactx "github.com/opencloud-eu/reva/v2/pkg/ctx"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/status"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/utils"
|
||||
cs3mocks "github.com/opencloud-eu/reva/v2/tests/cs3mocks/mocks"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/tidwall/gjson"
|
||||
@@ -80,12 +80,15 @@ var _ = Describe("Graph", func() {
|
||||
|
||||
eventsPublisher = mocks.Publisher{}
|
||||
permissionService = mocks.Permissions{}
|
||||
svc, _ = service.NewService(
|
||||
|
||||
var err error
|
||||
svc, err = service.NewService(
|
||||
service.Config(cfg),
|
||||
service.WithGatewaySelector(gatewaySelector),
|
||||
service.EventsPublisher(&eventsPublisher),
|
||||
service.PermissionService(&permissionService),
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
Describe("NewService", func() {
|
||||
@@ -486,8 +489,42 @@ var _ = Describe("Graph", func() {
|
||||
Expect(libreError.Error.Message).To(Equal("internal quota error"))
|
||||
Expect(libreError.Error.Code).To(Equal(errorcode.GeneralException.String()))
|
||||
})
|
||||
It("omit permissions by default", func() {
|
||||
gatewayClient.On("ListStorageSpaces", mock.Anything, mock.Anything).Times(1).Return(&provider.ListStorageSpacesResponse{
|
||||
Status: status.NewOK(ctx),
|
||||
StorageSpaces: []*provider.StorageSpace{
|
||||
{
|
||||
Opaque: utils.AppendJSONToOpaque(nil, "grants", map[string]provider.ResourcePermissions{
|
||||
"1": *conversions.NewManagerRole().CS3ResourcePermissions(),
|
||||
}),
|
||||
Root: &provider.ResourceId{},
|
||||
},
|
||||
},
|
||||
}, nil)
|
||||
gatewayClient.On("InitiateFileDownload", mock.Anything, mock.Anything).Return(&gateway.InitiateFileDownloadResponse{
|
||||
Status: status.NewNotFound(ctx, "not found"),
|
||||
}, nil)
|
||||
gatewayClient.On("GetQuota", mock.Anything, mock.Anything).Return(&provider.GetQuotaResponse{
|
||||
Status: status.NewUnimplemented(ctx, fmt.Errorf("not supported"), "not supported"),
|
||||
}, nil)
|
||||
gatewayClient.On("GetUser", mock.Anything, mock.Anything).Return(&userprovider.GetUserResponse{
|
||||
Status: status.NewUnimplemented(ctx, fmt.Errorf("not supported"), "not supported"),
|
||||
}, nil)
|
||||
|
||||
r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/me/drives", nil)
|
||||
r = r.WithContext(ctx)
|
||||
rr := httptest.NewRecorder()
|
||||
svc.GetDrivesV1(rr, r)
|
||||
|
||||
Expect(rr.Code).To(Equal(http.StatusOK))
|
||||
|
||||
jsonData := gjson.Get(rr.Body.String(), "value")
|
||||
|
||||
Expect(jsonData.Get("#").Num).To(Equal(float64(1)))
|
||||
Expect(jsonData.Get("0.root.permissions").Exists()).To(BeFalse())
|
||||
})
|
||||
})
|
||||
DescribeTable("GetDrivesV1Beta1 and GetAllDrivesV1Beta1",
|
||||
DescribeTable("GetDrivesV1Beta1 and GetAllDrivesV1Beta1 expands root permissions",
|
||||
func(check func(gjson.Result), resourcePermissions provider.ResourcePermissions) {
|
||||
permissionService.On("GetPermissionByID", mock.Anything, mock.Anything).Return(&settingssvc.GetPermissionByIDResponse{
|
||||
Permission: &v0.Permission{
|
||||
@@ -515,7 +552,7 @@ var _ = Describe("Graph", func() {
|
||||
Status: status.NewUnimplemented(ctx, fmt.Errorf("not supported"), "not supported"),
|
||||
}, nil)
|
||||
|
||||
r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/me/drives", nil)
|
||||
r := httptest.NewRequest(http.MethodGet, "/graph/v1beta1.0/me/drives?$expand=root($expand=permissions)", nil)
|
||||
r = r.WithContext(ctx)
|
||||
rr := httptest.NewRecorder()
|
||||
svc.GetDrivesV1Beta1(rr, r)
|
||||
|
||||
@@ -14,6 +14,13 @@ import (
|
||||
"github.com/go-chi/chi/v5"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
revactx "github.com/opencloud-eu/reva/v2/pkg/ctx"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
|
||||
cs3mocks "github.com/opencloud-eu/reva/v2/tests/cs3mocks/mocks"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/shared"
|
||||
settingsmsg "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/messages/settings/v0"
|
||||
settings "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/services/settings/v0"
|
||||
@@ -23,12 +30,6 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/errorcode"
|
||||
identitymocks "github.com/opencloud-eu/opencloud/services/graph/pkg/identity/mocks"
|
||||
service "github.com/opencloud-eu/opencloud/services/graph/pkg/service/v0"
|
||||
revactx "github.com/opencloud-eu/reva/v2/pkg/ctx"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
|
||||
cs3mocks "github.com/opencloud-eu/reva/v2/tests/cs3mocks/mocks"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type groupList struct {
|
||||
@@ -84,13 +85,15 @@ var _ = Describe("Groups", func() {
|
||||
cfg.Commons = &shared.Commons{}
|
||||
cfg.GRPCClientTLS = &shared.GRPCClientTLS{}
|
||||
|
||||
svc, _ = service.NewService(
|
||||
var err error
|
||||
svc, err = service.NewService(
|
||||
service.Config(cfg),
|
||||
service.WithGatewaySelector(gatewaySelector),
|
||||
service.EventsPublisher(&eventsPublisher),
|
||||
service.WithIdentityBackend(identityBackend),
|
||||
service.PermissionService(permissionService),
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
Describe("GetGroups", func() {
|
||||
@@ -411,12 +414,13 @@ var _ = Describe("Groups", func() {
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
cfg.API.GroupMembersPatchLimit = 21
|
||||
svc, _ = service.NewService(
|
||||
svc, err = service.NewService(
|
||||
service.Config(cfg),
|
||||
service.WithGatewaySelector(gatewaySelector),
|
||||
service.EventsPublisher(&eventsPublisher),
|
||||
service.WithIdentityBackend(identityBackend),
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
r := httptest.NewRequest(http.MethodPatch, "/graph/v1.0/groups", bytes.NewBuffer(updatedGroupJson))
|
||||
rctx := chi.NewRouteContext()
|
||||
|
||||
@@ -5,6 +5,10 @@ import (
|
||||
"net/http"
|
||||
|
||||
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/events"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/keycloak"
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
"github.com/opencloud-eu/opencloud/pkg/roles"
|
||||
@@ -13,9 +17,6 @@ import (
|
||||
settingssvc "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/services/settings/v0"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/config"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/identity"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/events"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
// Option defines a single option function.
|
||||
@@ -32,6 +33,7 @@ type Options struct {
|
||||
IdentityBackend identity.Backend
|
||||
IdentityEducationBackend identity.EducationBackend
|
||||
RoleService RoleService
|
||||
UserProfilePhotoService UsersUserProfilePhotoProvider
|
||||
PermissionService Permissions
|
||||
ValueService settingssvc.ValueService
|
||||
RoleManager *roles.Manager
|
||||
@@ -179,3 +181,10 @@ func TraceProvider(val trace.TracerProvider) Option {
|
||||
o.TraceProvider = val
|
||||
}
|
||||
}
|
||||
|
||||
// UserProfilePhotoService provides a function to set the UserProfilePhotoService option.
|
||||
func UserProfilePhotoService(p UsersUserProfilePhotoProvider) Option {
|
||||
return func(o *Options) {
|
||||
o.UserProfilePhotoService = p
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,14 @@ import (
|
||||
"github.com/go-ldap/ldap/v3"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
revactx "github.com/opencloud-eu/reva/v2/pkg/ctx"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/status"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
|
||||
cs3mocks "github.com/opencloud-eu/reva/v2/tests/cs3mocks/mocks"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
"github.com/opencloud-eu/opencloud/pkg/shared"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/mocks"
|
||||
@@ -21,13 +29,6 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/identity"
|
||||
identitymocks "github.com/opencloud-eu/opencloud/services/graph/pkg/identity/mocks"
|
||||
service "github.com/opencloud-eu/opencloud/services/graph/pkg/service/v0"
|
||||
revactx "github.com/opencloud-eu/reva/v2/pkg/ctx"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/status"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
|
||||
cs3mocks "github.com/opencloud-eu/reva/v2/tests/cs3mocks/mocks"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
var _ = Describe("Users changing their own password", func() {
|
||||
@@ -74,17 +75,21 @@ var _ = Describe("Users changing their own password", func() {
|
||||
GroupIDAttribute: "openCloudUUID",
|
||||
GroupSearchScope: "sub",
|
||||
}
|
||||
loggger := log.NewLogger()
|
||||
identityBackend, err = identity.NewLDAPBackend(ldapClient, ldapConfig, &loggger)
|
||||
logger := log.NewLogger()
|
||||
identityBackend, err = identity.NewLDAPBackend(ldapClient, ldapConfig, &logger)
|
||||
Expect(err).To(BeNil())
|
||||
|
||||
eventsPublisher = mocks.Publisher{}
|
||||
svc, _ = service.NewService(
|
||||
|
||||
var err error
|
||||
svc, err = service.NewService(
|
||||
service.Config(cfg),
|
||||
service.WithGatewaySelector(gatewaySelector),
|
||||
service.WithIdentityBackend(identityBackend),
|
||||
service.EventsPublisher(&eventsPublisher),
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
user = &userv1beta1.User{
|
||||
Id: &userv1beta1.UserId{
|
||||
OpaqueId: "user",
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/store"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/utils"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/utils/ldap"
|
||||
|
||||
ocldap "github.com/opencloud-eu/opencloud/pkg/ldap"
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
@@ -29,7 +30,6 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/pkg/service/grpc"
|
||||
settingssvc "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/services/settings/v0"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/identity"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/identity/ldap"
|
||||
graphm "github.com/opencloud-eu/opencloud/services/graph/pkg/middleware"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/unifiedrole"
|
||||
)
|
||||
@@ -143,14 +143,41 @@ func NewService(opts ...Option) (Graph, error) { //nolint:maintidx
|
||||
identity.IdentityCacheWithGroupsTTL(time.Duration(options.Config.Spaces.GroupsCacheTTL)),
|
||||
)
|
||||
|
||||
baseGraphService := BaseGraphService{
|
||||
logger: &options.Logger,
|
||||
identityCache: identityCache,
|
||||
gatewaySelector: options.GatewaySelector,
|
||||
config: options.Config,
|
||||
availableRoles: unifiedrole.GetRoles(unifiedrole.RoleFilterIDs(options.Config.UnifiedRoles.AvailableRoles...)),
|
||||
}
|
||||
|
||||
drivesDriveItemService, err := NewDrivesDriveItemService(options.Logger, options.GatewaySelector)
|
||||
if err != nil {
|
||||
return Graph{}, err
|
||||
}
|
||||
|
||||
drivesDriveItemApi, err := NewDrivesDriveItemApi(drivesDriveItemService, baseGraphService, options.Logger)
|
||||
if err != nil {
|
||||
return Graph{}, err
|
||||
}
|
||||
|
||||
driveItemPermissionsService, err := NewDriveItemPermissionsService(options.Logger, options.GatewaySelector, identityCache, options.Config)
|
||||
if err != nil {
|
||||
return Graph{}, err
|
||||
}
|
||||
|
||||
driveItemPermissionsApi, err := NewDriveItemPermissionsApi(driveItemPermissionsService, options.Logger, options.Config)
|
||||
if err != nil {
|
||||
return Graph{}, err
|
||||
}
|
||||
|
||||
usersUserProfilePhotoApi, err := NewUsersUserProfilePhotoApi(options.UserProfilePhotoService, options.Logger)
|
||||
if err != nil {
|
||||
return Graph{}, err
|
||||
}
|
||||
|
||||
svc := Graph{
|
||||
BaseGraphService: BaseGraphService{
|
||||
logger: &options.Logger,
|
||||
identityCache: identityCache,
|
||||
gatewaySelector: options.GatewaySelector,
|
||||
config: options.Config,
|
||||
availableRoles: unifiedrole.GetRoles(unifiedrole.RoleFilterIDs(options.Config.UnifiedRoles.AvailableRoles...)),
|
||||
},
|
||||
BaseGraphService: baseGraphService,
|
||||
mux: m,
|
||||
specialDriveItemsCache: spacePropertiesCache,
|
||||
eventsPublisher: options.EventsPublisher,
|
||||
@@ -205,26 +232,6 @@ func NewService(opts ...Option) (Graph, error) { //nolint:maintidx
|
||||
requireAdmin = options.RequireAdminMiddleware
|
||||
}
|
||||
|
||||
drivesDriveItemService, err := NewDrivesDriveItemService(options.Logger, options.GatewaySelector)
|
||||
if err != nil {
|
||||
return svc, err
|
||||
}
|
||||
|
||||
drivesDriveItemApi, err := NewDrivesDriveItemApi(drivesDriveItemService, svc.BaseGraphService, options.Logger)
|
||||
if err != nil {
|
||||
return svc, err
|
||||
}
|
||||
|
||||
driveItemPermissionsService, err := NewDriveItemPermissionsService(options.Logger, options.GatewaySelector, identityCache, options.Config)
|
||||
if err != nil {
|
||||
return svc, err
|
||||
}
|
||||
|
||||
driveItemPermissionsApi, err := NewDriveItemPermissionsApi(driveItemPermissionsService, options.Logger, options.Config)
|
||||
if err != nil {
|
||||
return svc, err
|
||||
}
|
||||
|
||||
m.Route(options.Config.HTTP.Root, func(r chi.Router) {
|
||||
r.Use(middleware.StripSlashes)
|
||||
|
||||
@@ -293,6 +300,12 @@ func NewService(opts ...Option) (Graph, error) { //nolint:maintidx
|
||||
})
|
||||
r.Get("/drives", svc.GetDrives(APIVersion_1))
|
||||
r.Post("/changePassword", svc.ChangeOwnPassword)
|
||||
r.Route("/photo/$value", func(r chi.Router) {
|
||||
r.Get("/", usersUserProfilePhotoApi.GetProfilePhoto(GetUserIDFromCTX))
|
||||
r.Put("/", usersUserProfilePhotoApi.UpsertProfilePhoto(GetUserIDFromCTX))
|
||||
r.Patch("/", usersUserProfilePhotoApi.UpsertProfilePhoto(GetUserIDFromCTX))
|
||||
r.Delete("/", usersUserProfilePhotoApi.DeleteProfilePhoto(GetUserIDFromCTX))
|
||||
})
|
||||
})
|
||||
r.Route("/users", func(r chi.Router) {
|
||||
r.Get("/", svc.GetUsers)
|
||||
@@ -301,6 +314,9 @@ func NewService(opts ...Option) (Graph, error) { //nolint:maintidx
|
||||
r.Get("/", svc.GetUser)
|
||||
r.Get("/drive", svc.GetUserDrive)
|
||||
r.Post("/exportPersonalData", svc.ExportPersonalData)
|
||||
r.Route("/photo/$value", func(r chi.Router) {
|
||||
r.Get("/", usersUserProfilePhotoApi.GetProfilePhoto(GetSlugValue("userID")))
|
||||
})
|
||||
r.With(requireAdmin).Delete("/", svc.DeleteUser)
|
||||
r.With(requireAdmin).Patch("/", svc.PatchUser)
|
||||
if svc.roleService != nil {
|
||||
@@ -461,7 +477,7 @@ func setIdentityBackends(options Options, svc *Graph) error {
|
||||
tlsConf.RootCAs = certs
|
||||
}
|
||||
|
||||
conn := ldap.NewLDAPWithReconnect(&options.Logger,
|
||||
conn := ldap.NewLDAPWithReconnect(
|
||||
ldap.Config{
|
||||
URI: options.Config.Identity.LDAP.URI,
|
||||
BindDN: options.Config.Identity.LDAP.BindDN,
|
||||
@@ -469,6 +485,7 @@ func setIdentityBackends(options Options, svc *Graph) error {
|
||||
TLSConfig: tlsConf,
|
||||
},
|
||||
)
|
||||
conn.SetLogger(&options.Logger.Logger)
|
||||
lb, err := identity.NewLDAPBackend(conn, options.Config.Identity.LDAP, &options.Logger)
|
||||
if err != nil {
|
||||
options.Logger.Error().Err(err).Msg("Error initializing LDAP Backend")
|
||||
|
||||
@@ -17,6 +17,16 @@ import (
|
||||
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/conversions"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/status"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storagespace"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/utils"
|
||||
cs3mocks "github.com/opencloud-eu/reva/v2/tests/cs3mocks/mocks"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/shared"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/mocks"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/config"
|
||||
@@ -25,15 +35,6 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/linktype"
|
||||
service "github.com/opencloud-eu/opencloud/services/graph/pkg/service/v0"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/unifiedrole"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/conversions"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/status"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storagespace"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/utils"
|
||||
cs3mocks "github.com/opencloud-eu/reva/v2/tests/cs3mocks/mocks"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
var _ = Describe("sharedbyme", func() {
|
||||
@@ -245,12 +246,13 @@ var _ = Describe("sharedbyme", func() {
|
||||
cfg.Commons = &shared.Commons{}
|
||||
cfg.GRPCClientTLS = &shared.GRPCClientTLS{}
|
||||
|
||||
svc, _ = service.NewService(
|
||||
svc, err = service.NewService(
|
||||
service.Config(cfg),
|
||||
service.WithGatewaySelector(gatewaySelector),
|
||||
service.EventsPublisher(&eventsPublisher),
|
||||
service.WithIdentityBackend(identityBackend),
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
emptyListPublicSharesMock := func() {
|
||||
|
||||
@@ -26,13 +26,14 @@ import (
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/shared"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/config"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/config/defaults"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/errorcode"
|
||||
identitymocks "github.com/opencloud-eu/opencloud/services/graph/pkg/identity/mocks"
|
||||
service "github.com/opencloud-eu/opencloud/services/graph/pkg/service/v0"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
// "github.com/opencloud-eu/opencloud/services/graph/pkg/unifiedrole"
|
||||
)
|
||||
|
||||
@@ -69,11 +70,13 @@ var _ = Describe("SharedWithMe", func() {
|
||||
cfg.Commons = &shared.Commons{}
|
||||
cfg.GRPCClientTLS = &shared.GRPCClientTLS{}
|
||||
|
||||
svc, _ = service.NewService(
|
||||
var err error
|
||||
svc, err = service.NewService(
|
||||
service.Config(cfg),
|
||||
service.WithGatewaySelector(gatewaySelector),
|
||||
service.WithIdentityBackend(identityBackend),
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
Describe("ListSharedWithMe", func() {
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
settingssvc "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/services/settings/v0"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/errorcode"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/identity"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/odata"
|
||||
ocsettingssvc "github.com/opencloud-eu/opencloud/services/settings/pkg/service/v0"
|
||||
"github.com/opencloud-eu/opencloud/services/settings/pkg/store/defaults"
|
||||
revactx "github.com/opencloud-eu/reva/v2/pkg/ctx"
|
||||
@@ -53,7 +54,7 @@ func (g Graph) GetMe(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
exp, err := identity.GetExpandValues(odataReq.Query)
|
||||
exp, err := odata.GetExpandValues(odataReq.Query)
|
||||
if err != nil {
|
||||
logger.Debug().Err(err).Interface("query", r.URL.Query()).Msg("could not get users: $expand error")
|
||||
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, err.Error())
|
||||
@@ -119,74 +120,85 @@ func (g Graph) fetchAppRoleAssignments(ctx context.Context, accountuuid string)
|
||||
|
||||
// GetUserDrive implements the Service interface.
|
||||
func (g Graph) GetUserDrive(w http.ResponseWriter, r *http.Request) {
|
||||
logger := g.logger.SubloggerWithRequestID(r.Context())
|
||||
logger.Debug().Interface("query", r.URL.Query()).Msg("calling get user drive")
|
||||
ctx := r.Context()
|
||||
log := g.logger.SubloggerWithRequestID(ctx).With().Interface("query", r.URL.Query()).Logger()
|
||||
log.Debug().Msg("calling get user drive")
|
||||
|
||||
webDavBaseURL, err := g.getWebDavBaseURL()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("could not get personal drive: error parsing webdav base url")
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
log = log.With().Str("url", webDavBaseURL.String()).Logger()
|
||||
|
||||
userID, err := url.PathUnescape(chi.URLParam(r, "userID"))
|
||||
if err != nil {
|
||||
logger.Debug().Err(err).Str("userID", chi.URLParam(r, "userID")).Msg("could not get drive: unescaping drive id failed")
|
||||
log.Debug().Err(err).Str("userID", chi.URLParam(r, "userID")).Msg("could not get drive: unescaping drive id failed")
|
||||
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "unescaping user id failed")
|
||||
return
|
||||
}
|
||||
|
||||
log = log.With().Str("userID", userID).Logger()
|
||||
|
||||
_, expandPermissions, err := parseDriveRequest(r)
|
||||
if err != nil {
|
||||
log.Debug().Err(err).Msg("could not get drives: error parsing odata request")
|
||||
errorcode.RenderError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
if userID == "" {
|
||||
u, ok := revactx.ContextGetUser(r.Context())
|
||||
u, ok := revactx.ContextGetUser(ctx)
|
||||
if !ok {
|
||||
logger.Debug().Msg("could not get user: user not in context")
|
||||
log.Debug().Msg("could not get user: user not in context")
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, "user not in context")
|
||||
return
|
||||
}
|
||||
userID = u.GetId().GetOpaqueId()
|
||||
}
|
||||
|
||||
logger.Debug().Str("userID", userID).Msg("calling list storage spaces with user and personal filter")
|
||||
ctx := r.Context()
|
||||
log.Debug().Msg("calling list storage spaces with user and personal filter")
|
||||
|
||||
filters := []*storageprovider.ListStorageSpacesRequest_Filter{listStorageSpacesTypeFilter("personal"), listStorageSpacesUserFilter(userID)}
|
||||
res, err := g.ListStorageSpacesWithFilters(ctx, filters, true)
|
||||
switch {
|
||||
case err != nil:
|
||||
logger.Error().Err(err).Msg("could not get drive: transport error")
|
||||
log.Error().Err(err).Msg("could not get drive: transport error")
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
case res.Status.Code != cs3rpc.Code_CODE_OK:
|
||||
if res.Status.Code == cs3rpc.Code_CODE_NOT_FOUND {
|
||||
// the client is doing a lookup for a specific space, therefore we need to return
|
||||
// not found to the caller
|
||||
logger.Debug().Str("userID", userID).Msg("could not get personal drive for user: not found")
|
||||
log.Debug().Msg("could not get personal drive for user: not found")
|
||||
errorcode.ItemNotFound.Render(w, r, http.StatusNotFound, "drive not found")
|
||||
return
|
||||
}
|
||||
logger.Debug().
|
||||
Str("userID", userID).
|
||||
log.Debug().
|
||||
Str("grpcmessage", res.GetStatus().GetMessage()).
|
||||
Msg("could not get personal drive for user: grpc error")
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, res.Status.Message)
|
||||
return
|
||||
}
|
||||
|
||||
webDavBaseURL, err := g.getWebDavBaseURL()
|
||||
spaces, err := g.formatDrives(ctx, webDavBaseURL, res.StorageSpaces, APIVersion_1, expandPermissions)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Str("url", webDavBaseURL.String()).Msg("could not get personal drive: error parsing webdav base url")
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
spaces, err := g.formatDrives(ctx, webDavBaseURL, res.StorageSpaces, APIVersion_1)
|
||||
if err != nil {
|
||||
logger.Debug().Err(err).Msg("could not get personal drive: error parsing grpc response")
|
||||
log.Debug().Err(err).Msg("could not get personal drive: error parsing grpc response")
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
switch num := len(spaces); {
|
||||
case num == 0:
|
||||
logger.Debug().Str("userID", userID).Msg("could not get personal drive: no drive returned from storage")
|
||||
log.Debug().Msg("could not get personal drive: no drive returned from storage")
|
||||
errorcode.ItemNotFound.Render(w, r, http.StatusNotFound, "no drive returned from storage")
|
||||
return
|
||||
case num == 1:
|
||||
render.Status(r, http.StatusOK)
|
||||
render.JSON(w, r, spaces[0])
|
||||
default:
|
||||
logger.Debug().Int("number", num).Msg("could not get personal drive: expected to find a single drive but fetched more")
|
||||
log.Debug().Int("number", num).Msg("could not get personal drive: expected to find a single drive but fetched more")
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, "could not get personal drive: expected to find a single drive but fetched more")
|
||||
return
|
||||
}
|
||||
@@ -301,7 +313,7 @@ func (g Graph) GetUsers(w http.ResponseWriter, r *http.Request) {
|
||||
users = finalUsers
|
||||
}
|
||||
|
||||
exp, err := identity.GetExpandValues(odataReq.Query)
|
||||
exp, err := odata.GetExpandValues(odataReq.Query)
|
||||
if err != nil {
|
||||
logger.Debug().Err(err).Interface("query", r.URL.Query()).Msg("could not get users: $expand error")
|
||||
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, err.Error())
|
||||
@@ -449,7 +461,7 @@ func (g Graph) GetUser(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
exp, err := identity.GetExpandValues(odataReq.Query)
|
||||
exp, err := odata.GetExpandValues(odataReq.Query)
|
||||
if err != nil {
|
||||
logger.Debug().Err(err).Interface("query", r.URL.Query()).Msg("could not get users: $expand error")
|
||||
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, err.Error())
|
||||
@@ -466,6 +478,8 @@ func (g Graph) GetUser(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
listDrives := slices.Contains(exp, "drives")
|
||||
listDrive := slices.Contains(exp, "drive")
|
||||
expandDrivePermissions := slices.Contains(exp, "drive.root.permissions")
|
||||
expandDrivesPermissions := slices.Contains(exp, "drives.root.permissions")
|
||||
|
||||
// do we need to list all or only the personal drive
|
||||
filters := []*storageprovider.ListStorageSpacesRequest_Filter{}
|
||||
@@ -526,7 +540,13 @@ func (g Graph) GetUser(w http.ResponseWriter, r *http.Request) {
|
||||
user.Drive = &libregraph.Drive{}
|
||||
}
|
||||
for _, sp := range lspr.GetStorageSpaces() {
|
||||
d, err := g.cs3StorageSpaceToDrive(r.Context(), wdu, sp, APIVersion_1)
|
||||
expandPermissions := false
|
||||
if sp.GetSpaceType() == "personal" && sp.GetOwner().GetId().GetOpaqueId() != user.GetId() {
|
||||
expandPermissions = expandDrivePermissions
|
||||
} else {
|
||||
expandPermissions = expandDrivesPermissions
|
||||
}
|
||||
d, err := g.cs3StorageSpaceToDrive(r.Context(), wdu, sp, APIVersion_1, expandPermissions)
|
||||
if err != nil {
|
||||
logger.Debug().Err(err).Interface("id", sp.Id).Msg("error converting space to drive")
|
||||
continue
|
||||
@@ -557,8 +577,9 @@ func (g Graph) GetUser(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if !g.config.API.ShowUserEmailInResults {
|
||||
|
||||
ctxHasFullPerms := g.contextUserHasFullAccountPerms(r.Context())
|
||||
if !ctxHasFullPerms && !g.config.API.ShowUserEmailInResults {
|
||||
user.Mail = nil
|
||||
}
|
||||
|
||||
@@ -1022,7 +1043,7 @@ func (g Graph) searchOCMAcceptedUsers(ctx context.Context, odataReq *godata.GoDa
|
||||
if err != nil {
|
||||
return nil, errorcode.New(errorcode.GeneralException, err.Error())
|
||||
}
|
||||
term, err := identity.GetSearchValues(odataReq.Query)
|
||||
term, err := odata.GetSearchValues(odataReq.Query)
|
||||
if err != nil {
|
||||
return nil, errorcode.New(errorcode.InvalidRequest, err.Error())
|
||||
}
|
||||
|
||||
@@ -17,11 +17,11 @@ import (
|
||||
"github.com/go-chi/chi/v5"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
revactx "github.com/opencloud-eu/reva/v2/pkg/ctx"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/status"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
|
||||
cs3mocks "github.com/opencloud-eu/reva/v2/tests/cs3mocks/mocks"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"go-micro.dev/v4/client"
|
||||
"google.golang.org/grpc"
|
||||
@@ -95,7 +95,8 @@ var _ = Describe("Users", func() {
|
||||
|
||||
When("OCM is disabled", func() {
|
||||
BeforeEach(func() {
|
||||
svc, _ = service.NewService(
|
||||
var err error
|
||||
svc, err = service.NewService(
|
||||
service.Config(cfg),
|
||||
service.WithGatewaySelector(gatewaySelector),
|
||||
service.EventsPublisher(&eventsPublisher),
|
||||
@@ -104,6 +105,7 @@ var _ = Describe("Users", func() {
|
||||
service.WithValueService(valueService),
|
||||
service.PermissionService(permissionService),
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
Describe("GetMe", func() {
|
||||
@@ -581,6 +583,7 @@ var _ = Describe("Users", func() {
|
||||
user := &libregraph.User{}
|
||||
user.SetId("user1")
|
||||
|
||||
permissionService.On("GetPermissionByID", mock.Anything, mock.Anything).Return(&settings.GetPermissionByIDResponse{}, nil)
|
||||
identityBackend.On("GetUser", mock.Anything, mock.Anything, mock.Anything).Return(user, nil)
|
||||
valueService.On("GetValueByUniqueIdentifiers", mock.Anything, mock.Anything, mock.Anything).
|
||||
Return(&settings.GetValueResponse{
|
||||
@@ -621,6 +624,7 @@ var _ = Describe("Users", func() {
|
||||
user := &libregraph.User{}
|
||||
user.SetId("user1")
|
||||
|
||||
permissionService.On("GetPermissionByID", mock.Anything, mock.Anything).Return(&settings.GetPermissionByIDResponse{}, nil)
|
||||
identityBackend.On("GetUser", mock.Anything, mock.Anything, mock.Anything).Return(user, nil)
|
||||
gatewayClient.On("GetQuota", mock.Anything, mock.Anything, mock.Anything).Return(&provider.GetQuotaResponse{
|
||||
Status: status.NewOK(ctx),
|
||||
@@ -680,6 +684,7 @@ var _ = Describe("Users", func() {
|
||||
user := &libregraph.User{}
|
||||
user.SetId("user1")
|
||||
|
||||
permissionService.On("GetPermissionByID", mock.Anything, mock.Anything).Return(&settings.GetPermissionByIDResponse{}, nil)
|
||||
identityBackend.On("GetUser", mock.Anything, mock.Anything, mock.Anything).Return(user, nil)
|
||||
gatewayClient.On("GetQuota", mock.Anything, mock.Anything, mock.Anything).Return(&provider.GetQuotaResponse{
|
||||
Status: status.NewOK(ctx),
|
||||
@@ -732,6 +737,7 @@ var _ = Describe("Users", func() {
|
||||
user := &libregraph.User{}
|
||||
user.SetId("user1")
|
||||
|
||||
permissionService.On("GetPermissionByID", mock.Anything, mock.Anything).Return(&settings.GetPermissionByIDResponse{}, nil)
|
||||
identityBackend.On("GetUser", mock.Anything, mock.Anything, mock.Anything).Return(user, nil)
|
||||
|
||||
assignments := []*settingsmsg.UserRoleAssignment{
|
||||
@@ -901,13 +907,14 @@ var _ = Describe("Users", func() {
|
||||
|
||||
localCfg.API.UsernameMatch = usernameMatch
|
||||
|
||||
localSvc, _ := service.NewService(
|
||||
localSvc, err := service.NewService(
|
||||
service.Config(localCfg),
|
||||
service.WithGatewaySelector(gatewaySelector),
|
||||
service.EventsPublisher(&eventsPublisher),
|
||||
service.WithIdentityBackend(identityBackend),
|
||||
service.WithRoleService(roleService),
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
return localSvc
|
||||
}
|
||||
@@ -1121,7 +1128,9 @@ var _ = Describe("Users", func() {
|
||||
When("OCM is enabled", func() {
|
||||
BeforeEach(func() {
|
||||
cfg.IncludeOCMSharees = true
|
||||
svc, _ = service.NewService(
|
||||
|
||||
var err error
|
||||
svc, err = service.NewService(
|
||||
service.Config(cfg),
|
||||
service.WithGatewaySelector(gatewaySelector),
|
||||
service.EventsPublisher(&eventsPublisher),
|
||||
@@ -1130,6 +1139,7 @@ var _ = Describe("Users", func() {
|
||||
service.WithValueService(valueService),
|
||||
service.PermissionService(permissionService),
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
Describe("GetUsers", func() {
|
||||
It("does not list the federated users without a filter", func() {
|
||||
|
||||
@@ -13,9 +13,9 @@ import (
|
||||
collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1"
|
||||
ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
|
||||
storageprovider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storagespace"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/utils"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
@@ -73,16 +73,6 @@ func GetDriveAndItemIDParam(r *http.Request, logger *log.Logger) (*storageprovid
|
||||
return &driveID, &itemID, nil
|
||||
}
|
||||
|
||||
// GetFilterParam returns the $filter query parameter from the request. If you need to parse the filter use godata.ParseRequest
|
||||
func GetFilterParam(r *http.Request) string {
|
||||
return r.URL.Query().Get("$filter")
|
||||
}
|
||||
|
||||
// GetSelectParam returns the $select query parameter from the request. If you need to parse the select filter use godata.ParseRequest
|
||||
func GetSelectParam(r *http.Request) string {
|
||||
return r.URL.Query().Get("$select")
|
||||
}
|
||||
|
||||
// GetGatewayClient returns a gateway client from the gatewaySelector.
|
||||
func (g Graph) GetGatewayClient(w http.ResponseWriter, r *http.Request) (gateway.GatewayAPIClient, bool) {
|
||||
gatewayClient, err := g.gatewaySelector.Next()
|
||||
|
||||
@@ -7,7 +7,8 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/pkg/registry"
|
||||
"github.com/opencloud-eu/opencloud/pkg/version"
|
||||
|
||||
tw "github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter/tw"
|
||||
"github.com/opencloud-eu/opencloud/services/groups/pkg/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
@@ -35,9 +36,8 @@ func Version(cfg *config.Config) *cli.Command {
|
||||
return nil
|
||||
}
|
||||
|
||||
table := tw.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"Version", "Address", "Id"})
|
||||
table.SetAutoFormatHeaders(false)
|
||||
table := tablewriter.NewTable(os.Stdout, tablewriter.WithHeaderAutoFormat(tw.Off))
|
||||
table.Header([]string{"Version", "Address", "Id"})
|
||||
for _, s := range services {
|
||||
for _, n := range s.Nodes {
|
||||
table.Append([]string{s.Version, n.Address, n.Id})
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"i18next-conv@14.1.0": {
|
||||
"i18next-conv@15.1.1": {
|
||||
"licenses": "MIT",
|
||||
"licenseFile": "LICENSE.md",
|
||||
"licenseStart": "# MIT License",
|
||||
"licenseEnd": "========="
|
||||
},
|
||||
"p-from-callback@1.0.1": {
|
||||
"p-from-callback@2.0.0": {
|
||||
"licenses": "MIT",
|
||||
"licenseFile": "LICENSE.md",
|
||||
"licenseStart": "# MIT License",
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"analyze": "source-map-explorer 'build/static/js/*.js'",
|
||||
"build": "node --openssl-legacy-provider scripts/build.js && rm -f build/service-worker.js",
|
||||
"licenses": "NODE_PATH=./node_modules node ../scripts/js-license-ranger.js",
|
||||
"licenses:check": "license-checker-rseidelsohn --summary --relativeLicensePath --onlyAllow 'Python-2.0;Apache*;Apache License, Version 2.0;Apache-2.0;Apache 2.0;Artistic-2.0;BSD;BSD-3-Clause;CC-BY-3.0;CC-BY-4.0;CC0-1.0;ISC;MIT;MPL-2.0;Public Domain;Unicode-TOU;Unlicense;WTFPL;ODC-By-1.0;BlueOak-1.0.0' --excludePackages 'identifier;kpop;unicoderegexp' --clarificationsFile license-checker-clarifications.json",
|
||||
"licenses:check": "license-checker-rseidelsohn --summary --relativeLicensePath --onlyAllow 'Python-2.0;Apache*;Apache License, Version 2.0;Apache-2.0;Apache 2.0;Artistic-2.0;BSD;BSD-3-Clause;CC-BY-3.0;CC-BY-4.0;CC0-1.0;ISC;MIT;MPL-2.0;Public Domain;Unicode-TOU;Unlicense;WTFPL;ODC-By-1.0;BlueOak-1.0.0;OFL-1.1' --excludePackages 'identifier;kpop;unicoderegexp' --clarificationsFile license-checker-clarifications.json",
|
||||
"licenses:csv": "license-checker-rseidelsohn --relativeLicensePath --csv --out ../../third-party-licenses/node/idp/third-party-licenses.csv",
|
||||
"licenses:save": "license-checker-rseidelsohn --relativeLicensePath --out /dev/null --files ../../third-party-licenses/node/idp/third-party-licenses",
|
||||
"lint": "eslint ./**/*.{tsx,ts,jsx,js}",
|
||||
@@ -71,22 +71,22 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@fontsource/roboto": "^5.1.0",
|
||||
"@fontsource/roboto": "^5.2.5",
|
||||
"@material-ui/core": "^4.12.4",
|
||||
"@material-ui/icons": "^4.11.3",
|
||||
"@testing-library/jest-dom": "^6.6.3",
|
||||
"@testing-library/react": "^11.2.7",
|
||||
"@testing-library/user-event": "^14.5.2",
|
||||
"@types/jest": "^29.5.12",
|
||||
"@types/node": "^20.14.11",
|
||||
"@testing-library/react": "^12.1.5",
|
||||
"@testing-library/user-event": "^14.6.1",
|
||||
"@types/jest": "^29.5.14",
|
||||
"@types/node": "^22.15.30",
|
||||
"@types/react": "^17.0.80",
|
||||
"@types/react-dom": "^17.0.25",
|
||||
"@types/react-redux": "^7.1.33",
|
||||
"@types/redux-logger": "^3.0.13",
|
||||
"axios": "^1.7.7",
|
||||
"axios": "^1.8.2",
|
||||
"classnames": "^2.5.1",
|
||||
"i18next": "^25.1.2",
|
||||
"i18next-browser-languagedetector": "^7.2.1",
|
||||
"i18next": "^25.2.1",
|
||||
"i18next-browser-languagedetector": "^8.1.0",
|
||||
"i18next-http-backend": "^3.0.2",
|
||||
"i18next-resources-to-backend": "^1.2.1",
|
||||
"kpop": "https://download.kopano.io/community/kapp:/kpop-2.7.2.tgz",
|
||||
@@ -102,7 +102,7 @@
|
||||
"redux-logger": "^3.0.6",
|
||||
"redux-thunk": "^2.4.2",
|
||||
"render-if": "^0.1.1",
|
||||
"web-vitals": "^4.2.4"
|
||||
"web-vitals": "^5.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.26.10",
|
||||
@@ -113,7 +113,7 @@
|
||||
"babel-plugin-named-asset-import": "^0.3.8",
|
||||
"babel-preset-react-app": "^10.1.0",
|
||||
"case-sensitive-paths-webpack-plugin": "2.4.0",
|
||||
"cldr": "^7.5.0",
|
||||
"cldr": "^7.9.0",
|
||||
"css-loader": "7.1.2",
|
||||
"css-minimizer-webpack-plugin": "^7.0.0",
|
||||
"dotenv": "16.4.7",
|
||||
@@ -126,27 +126,27 @@
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
"eslint-plugin-jest": "^24.7.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.10.2",
|
||||
"eslint-plugin-react": "^7.37.2",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"eslint-plugin-react-hooks": "^4.6.2",
|
||||
"eslint-plugin-testing-library": "^3.10.2",
|
||||
"eslint-webpack-plugin": "^3.2.0",
|
||||
"file-loader": "6.2.0",
|
||||
"html-webpack-plugin": "5.6.3",
|
||||
"i18next-conv": "^14.1.0",
|
||||
"i18next-parser": "^9.0.2",
|
||||
"i18next-conv": "^15.1.1",
|
||||
"i18next-parser": "^9.3.0",
|
||||
"jest": "29.7.0",
|
||||
"license-checker-rseidelsohn": "4.4.2",
|
||||
"mini-css-extract-plugin": "2.9.2",
|
||||
"pnp-webpack-plugin": "1.7.0",
|
||||
"postcss-flexbugs-fixes": "5.0.2",
|
||||
"postcss-loader": "4.3.0",
|
||||
"postcss-normalize": "13.0.0",
|
||||
"postcss-normalize": "13.0.1",
|
||||
"postcss-preset-env": "10.1.3",
|
||||
"postcss-safe-parser": "7.0.1",
|
||||
"react-dev-utils": "^12.0.1",
|
||||
"resolve": "1.22.8",
|
||||
"resolve-url-loader": "^5.0.0",
|
||||
"sass-loader": "^16.0.4",
|
||||
"sass-loader": "^16.0.5",
|
||||
"source-map-explorer": "^2.5.3",
|
||||
"typescript": "^5.8.3",
|
||||
"url-loader": "4.1.1",
|
||||
|
||||
@@ -7,7 +7,8 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/pkg/registry"
|
||||
"github.com/opencloud-eu/opencloud/pkg/version"
|
||||
|
||||
tw "github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter/tw"
|
||||
"github.com/opencloud-eu/opencloud/services/idp/pkg/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
@@ -35,9 +36,8 @@ func Version(cfg *config.Config) *cli.Command {
|
||||
return nil
|
||||
}
|
||||
|
||||
table := tw.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"Version", "Address", "Id"})
|
||||
table.SetAutoFormatHeaders(false)
|
||||
table := tablewriter.NewTable(os.Stdout, tablewriter.WithHeaderAutoFormat(tw.Off))
|
||||
table.Header([]string{"Version", "Address", "Id"})
|
||||
for _, s := range services {
|
||||
for _, n := range s.Nodes {
|
||||
table.Append([]string{s.Version, n.Address, n.Id})
|
||||
|
||||
1624
services/idp/pnpm-lock.yaml
generated
1624
services/idp/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,8 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/pkg/registry"
|
||||
"github.com/opencloud-eu/opencloud/pkg/version"
|
||||
|
||||
tw "github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter/tw"
|
||||
"github.com/opencloud-eu/opencloud/services/invitations/pkg/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
@@ -35,9 +36,8 @@ func Version(cfg *config.Config) *cli.Command {
|
||||
return nil
|
||||
}
|
||||
|
||||
table := tw.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"Version", "Address", "Id"})
|
||||
table.SetAutoFormatHeaders(false)
|
||||
table := tablewriter.NewTable(os.Stdout, tablewriter.WithHeaderAutoFormat(tw.Off))
|
||||
table.Header([]string{"Version", "Address", "Id"})
|
||||
for _, s := range services {
|
||||
for _, n := range s.Nodes {
|
||||
table.Append([]string{s.Version, n.Address, n.Id})
|
||||
|
||||
@@ -7,7 +7,8 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/pkg/registry"
|
||||
"github.com/opencloud-eu/opencloud/pkg/version"
|
||||
|
||||
tw "github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter/tw"
|
||||
"github.com/opencloud-eu/opencloud/services/ocdav/pkg/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
@@ -35,9 +36,8 @@ func Version(cfg *config.Config) *cli.Command {
|
||||
return nil
|
||||
}
|
||||
|
||||
table := tw.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"Version", "Address", "Id"})
|
||||
table.SetAutoFormatHeaders(false)
|
||||
table := tablewriter.NewTable(os.Stdout, tablewriter.WithHeaderAutoFormat(tw.Off))
|
||||
table.Header([]string{"Version", "Address", "Id"})
|
||||
for _, s := range services {
|
||||
for _, n := range s.Nodes {
|
||||
table.Append([]string{s.Version, n.Address, n.Id})
|
||||
|
||||
@@ -105,9 +105,8 @@ When all instances of a federation should trust each other, an `ocmproviders.jso
|
||||
]
|
||||
```
|
||||
|
||||
{{< hint info >}}
|
||||
::: info
|
||||
Note: the `domain` must not contain the protocol as it has to match the [GOCDB site object domain](https://developer.sciencemesh.io/docs/technical-documentation/central-database/#site-object).
|
||||
{{< /hint >}}
|
||||
|
||||
The above federation consists of two instances: `cloud1.opencloud.test` and `cloud2.opencloud.test` that can use the Invitation workflow described below to generate, send and accept invitations.
|
||||
|
||||
@@ -121,9 +120,8 @@ The data backend of the `ocminvitemanager` is configurable. The only supported b
|
||||
|
||||
## Creating Shares
|
||||
|
||||
{{< hint info >}}
|
||||
::: info
|
||||
The below info is outdated as we allow creating federated shares using the graph API. Clients can now discover the available sharing roles and invite federated users using the graph API.
|
||||
{{< /hint >}}
|
||||
|
||||
OCM Shares are currently created using the ocs API, just like regular shares. The difference is the share type, which is 6 (ShareTypeFederatedCloudShare) in this case, and a few additional parameters required for identifying the remote user.
|
||||
|
||||
|
||||
@@ -7,7 +7,8 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/pkg/registry"
|
||||
"github.com/opencloud-eu/opencloud/pkg/version"
|
||||
|
||||
tw "github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter/tw"
|
||||
"github.com/opencloud-eu/opencloud/services/ocs/pkg/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
@@ -35,9 +36,8 @@ func Version(cfg *config.Config) *cli.Command {
|
||||
return nil
|
||||
}
|
||||
|
||||
table := tw.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"Version", "Address", "Id"})
|
||||
table.SetAutoFormatHeaders(false)
|
||||
table := tablewriter.NewTable(os.Stdout, tablewriter.WithHeaderAutoFormat(tw.Off))
|
||||
table.Header([]string{"Version", "Address", "Id"})
|
||||
for _, s := range services {
|
||||
for _, n := range s.Nodes {
|
||||
table.Append([]string{s.Version, n.Address, n.Id})
|
||||
|
||||
@@ -7,7 +7,8 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/pkg/registry"
|
||||
"github.com/opencloud-eu/opencloud/pkg/version"
|
||||
|
||||
tw "github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter/tw"
|
||||
"github.com/opencloud-eu/opencloud/services/policies/pkg/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
@@ -35,9 +36,8 @@ func Version(cfg *config.Config) *cli.Command {
|
||||
return nil
|
||||
}
|
||||
|
||||
table := tw.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"Version", "Address", "Id"})
|
||||
table.SetAutoFormatHeaders(false)
|
||||
table := tablewriter.NewTable(os.Stdout, tablewriter.WithHeaderAutoFormat(tw.Off))
|
||||
table.Header([]string{"Version", "Address", "Id"})
|
||||
for _, s := range services {
|
||||
for _, n := range s.Nodes {
|
||||
table.Append([]string{s.Version, n.Address, n.Id})
|
||||
|
||||
@@ -7,7 +7,8 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/pkg/registry"
|
||||
"github.com/opencloud-eu/opencloud/pkg/version"
|
||||
|
||||
tw "github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter/tw"
|
||||
"github.com/opencloud-eu/opencloud/services/proxy/pkg/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
@@ -35,9 +36,8 @@ func Version(cfg *config.Config) *cli.Command {
|
||||
return nil
|
||||
}
|
||||
|
||||
table := tw.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"Version", "Address", "Id"})
|
||||
table.SetAutoFormatHeaders(false)
|
||||
table := tablewriter.NewTable(os.Stdout, tablewriter.WithHeaderAutoFormat(tw.Off))
|
||||
table.Header([]string{"Version", "Address", "Id"})
|
||||
for _, s := range services {
|
||||
for _, n := range s.Nodes {
|
||||
table.Append([]string{s.Version, n.Address, n.Id})
|
||||
|
||||
@@ -7,7 +7,8 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/pkg/registry"
|
||||
"github.com/opencloud-eu/opencloud/pkg/version"
|
||||
|
||||
tw "github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter/tw"
|
||||
"github.com/opencloud-eu/opencloud/services/search/pkg/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
@@ -35,9 +36,8 @@ func Version(cfg *config.Config) *cli.Command {
|
||||
return nil
|
||||
}
|
||||
|
||||
table := tw.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"Version", "Address", "Id"})
|
||||
table.SetAutoFormatHeaders(false)
|
||||
table := tablewriter.NewTable(os.Stdout, tablewriter.WithHeaderAutoFormat(tw.Off))
|
||||
table.Header([]string{"Version", "Address", "Id"})
|
||||
for _, s := range services {
|
||||
for _, n := range s.Nodes {
|
||||
table.Append([]string{s.Version, n.Address, n.Id})
|
||||
|
||||
@@ -7,7 +7,8 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/pkg/registry"
|
||||
"github.com/opencloud-eu/opencloud/pkg/version"
|
||||
|
||||
tw "github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter/tw"
|
||||
"github.com/opencloud-eu/opencloud/services/settings/pkg/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
@@ -35,9 +36,8 @@ func Version(cfg *config.Config) *cli.Command {
|
||||
return nil
|
||||
}
|
||||
|
||||
table := tw.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"Version", "Address", "Id"})
|
||||
table.SetAutoFormatHeaders(false)
|
||||
table := tablewriter.NewTable(os.Stdout, tablewriter.WithHeaderAutoFormat(tw.Off))
|
||||
table.Header([]string{"Version", "Address", "Id"})
|
||||
for _, s := range services {
|
||||
for _, n := range s.Nodes {
|
||||
table.Append([]string{s.Version, n.Address, n.Id})
|
||||
|
||||
@@ -7,7 +7,8 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/pkg/registry"
|
||||
"github.com/opencloud-eu/opencloud/pkg/version"
|
||||
|
||||
tw "github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter/tw"
|
||||
"github.com/opencloud-eu/opencloud/services/sharing/pkg/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
@@ -35,9 +36,8 @@ func Version(cfg *config.Config) *cli.Command {
|
||||
return nil
|
||||
}
|
||||
|
||||
table := tw.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"Version", "Address", "Id"})
|
||||
table.SetAutoFormatHeaders(false)
|
||||
table := tablewriter.NewTable(os.Stdout, tablewriter.WithHeaderAutoFormat(tw.Off))
|
||||
table.Header([]string{"Version", "Address", "Id"})
|
||||
for _, s := range services {
|
||||
for _, n := range s.Nodes {
|
||||
table.Append([]string{s.Version, n.Address, n.Id})
|
||||
|
||||
@@ -7,7 +7,8 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/pkg/registry"
|
||||
"github.com/opencloud-eu/opencloud/pkg/version"
|
||||
|
||||
tw "github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter/tw"
|
||||
"github.com/opencloud-eu/opencloud/services/storage-publiclink/pkg/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
@@ -35,9 +36,8 @@ func Version(cfg *config.Config) *cli.Command {
|
||||
return nil
|
||||
}
|
||||
|
||||
table := tw.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"Version", "Address", "Id"})
|
||||
table.SetAutoFormatHeaders(false)
|
||||
table := tablewriter.NewTable(os.Stdout, tablewriter.WithHeaderAutoFormat(tw.Off))
|
||||
table.Header([]string{"Version", "Address", "Id"})
|
||||
for _, s := range services {
|
||||
for _, n := range s.Nodes {
|
||||
table.Append([]string{s.Version, n.Address, n.Id})
|
||||
|
||||
@@ -7,7 +7,8 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/pkg/registry"
|
||||
"github.com/opencloud-eu/opencloud/pkg/version"
|
||||
|
||||
tw "github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter/tw"
|
||||
"github.com/opencloud-eu/opencloud/services/storage-shares/pkg/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
@@ -35,9 +36,8 @@ func Version(cfg *config.Config) *cli.Command {
|
||||
return nil
|
||||
}
|
||||
|
||||
table := tw.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"Version", "Address", "Id"})
|
||||
table.SetAutoFormatHeaders(false)
|
||||
table := tablewriter.NewTable(os.Stdout, tablewriter.WithHeaderAutoFormat(tw.Off))
|
||||
table.Header([]string{"Version", "Address", "Id"})
|
||||
for _, s := range services {
|
||||
for _, n := range s.Nodes {
|
||||
table.Append([]string{s.Version, n.Address, n.Id})
|
||||
|
||||
@@ -7,7 +7,8 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/pkg/registry"
|
||||
"github.com/opencloud-eu/opencloud/pkg/version"
|
||||
|
||||
tw "github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter/tw"
|
||||
"github.com/opencloud-eu/opencloud/services/storage-system/pkg/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
@@ -35,9 +36,8 @@ func Version(cfg *config.Config) *cli.Command {
|
||||
return nil
|
||||
}
|
||||
|
||||
table := tw.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"Version", "Address", "Id"})
|
||||
table.SetAutoFormatHeaders(false)
|
||||
table := tablewriter.NewTable(os.Stdout, tablewriter.WithHeaderAutoFormat(tw.Off))
|
||||
table.Header([]string{"Version", "Address", "Id"})
|
||||
for _, s := range services {
|
||||
for _, n := range s.Nodes {
|
||||
table.Append([]string{s.Version, n.Address, n.Id})
|
||||
|
||||
@@ -14,7 +14,8 @@ import (
|
||||
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
|
||||
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
"github.com/mohae/deepcopy"
|
||||
tw "github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter/tw"
|
||||
"github.com/opencloud-eu/opencloud/pkg/config/configlog"
|
||||
zlog "github.com/opencloud-eu/opencloud/pkg/log"
|
||||
"github.com/opencloud-eu/opencloud/services/storage-users/pkg/config"
|
||||
@@ -469,11 +470,10 @@ func itemType(it provider.ResourceType) string {
|
||||
return itemType
|
||||
}
|
||||
|
||||
func itemsTable(total int) *tw.Table {
|
||||
table := tw.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"itemID", "path", "type", "delete at"})
|
||||
table.SetAutoFormatHeaders(false)
|
||||
table.SetFooter([]string{"", "", "", "total count: " + strconv.Itoa(total)})
|
||||
func itemsTable(total int) *tablewriter.Table {
|
||||
table := tablewriter.NewTable(os.Stdout, tablewriter.WithHeaderAutoFormat(tw.Off))
|
||||
table.Header([]string{"itemID", "path", "type", "delete at"})
|
||||
table.Footer([]string{"", "", "", "total count: " + strconv.Itoa(total)})
|
||||
return table
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
tw "github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter/tw"
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
|
||||
@@ -145,16 +146,15 @@ func ListUploadSessions(cfg *config.Config) *cli.Command {
|
||||
}
|
||||
|
||||
var (
|
||||
table *tw.Table
|
||||
table *tablewriter.Table
|
||||
raw []Session
|
||||
)
|
||||
|
||||
if !c.Bool("json") {
|
||||
fmt.Println(buildInfo(filter))
|
||||
|
||||
table = tw.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"Space", "Upload Id", "Name", "Offset", "Size", "Executant", "Owner", "Expires", "Processing", "Scan Date", "Scan Result"})
|
||||
table.SetAutoFormatHeaders(false)
|
||||
table = tablewriter.NewTable(os.Stdout, tablewriter.WithHeaderAutoFormat(tw.Off))
|
||||
table.Header([]string{"Space", "Upload Id", "Name", "Offset", "Size", "Executant", "Owner", "Expires", "Processing", "Scan Date", "Scan Result"})
|
||||
}
|
||||
|
||||
for _, u := range uploads {
|
||||
|
||||
@@ -7,7 +7,8 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/pkg/registry"
|
||||
"github.com/opencloud-eu/opencloud/pkg/version"
|
||||
|
||||
tw "github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter/tw"
|
||||
"github.com/opencloud-eu/opencloud/services/storage-users/pkg/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
@@ -35,9 +36,8 @@ func Version(cfg *config.Config) *cli.Command {
|
||||
return nil
|
||||
}
|
||||
|
||||
table := tw.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"Version", "Address", "Id"})
|
||||
table.SetAutoFormatHeaders(false)
|
||||
table := tablewriter.NewTable(os.Stdout, tablewriter.WithHeaderAutoFormat(tw.Off))
|
||||
table.Header([]string{"Version", "Address", "Id"})
|
||||
for _, s := range services {
|
||||
for _, n := range s.Nodes {
|
||||
table.Append([]string{s.Version, n.Address, n.Id})
|
||||
|
||||
@@ -7,7 +7,8 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/pkg/registry"
|
||||
"github.com/opencloud-eu/opencloud/pkg/version"
|
||||
|
||||
tw "github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter/tw"
|
||||
"github.com/opencloud-eu/opencloud/services/thumbnails/pkg/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
@@ -35,9 +36,8 @@ func Version(cfg *config.Config) *cli.Command {
|
||||
return nil
|
||||
}
|
||||
|
||||
table := tw.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"Version", "Address", "Id"})
|
||||
table.SetAutoFormatHeaders(false)
|
||||
table := tablewriter.NewTable(os.Stdout, tablewriter.WithHeaderAutoFormat(tw.Off))
|
||||
table.Header([]string{"Version", "Address", "Id"})
|
||||
for _, s := range services {
|
||||
for _, n := range s.Nodes {
|
||||
table.Append([]string{s.Version, n.Address, n.Id})
|
||||
|
||||
@@ -15,6 +15,7 @@ const (
|
||||
typeGif = "gif"
|
||||
typeGgs = "ggs"
|
||||
typeGgp = "ggp"
|
||||
typeWebp = "webp"
|
||||
)
|
||||
|
||||
// Encoder encodes the thumbnail to a specific format.
|
||||
@@ -55,7 +56,7 @@ func EncoderForType(fileType string) (Encoder, error) {
|
||||
switch strings.ToLower(fileType) {
|
||||
case typePng, typeGgs, typeGgp:
|
||||
return PngEncoder{}, nil
|
||||
case typeJpg, typeJpeg:
|
||||
case typeJpg, typeJpeg, typeWebp:
|
||||
return JpegEncoder{}, nil
|
||||
case typeGif:
|
||||
return GifEncoder{}, nil
|
||||
@@ -68,7 +69,7 @@ func EncoderForType(fileType string) (Encoder, error) {
|
||||
func GetExtForMime(fileType string) string {
|
||||
ext := strings.TrimPrefix(strings.TrimSpace(strings.ToLower(fileType)), "image/")
|
||||
switch ext {
|
||||
case typeJpg, typeJpeg, typePng, typeGif:
|
||||
case typeJpg, typeJpeg, typePng, typeGif, typeWebp:
|
||||
return ext
|
||||
case "application/vnd.geogebra.slides":
|
||||
return typeGgs
|
||||
|
||||
@@ -89,7 +89,7 @@ func (g GifGenerator) imageToPaletted(img image.Image, p color.Palette) *image.P
|
||||
// or nil if the type is not supported.
|
||||
func GeneratorFor(fileType, processorID string) (Generator, error) {
|
||||
switch strings.ToLower(fileType) {
|
||||
case typePng, typeJpg, typeJpeg, typeGgs, typeGgp:
|
||||
case typePng, typeJpg, typeJpeg, typeGgs, typeGgp, typeWebp:
|
||||
return NewSimpleGenerator(fileType, processorID)
|
||||
case typeGif:
|
||||
return NewGifGenerator(fileType, processorID)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user