mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2025-12-24 22:59:51 -05:00
Compare commits
244 Commits
caseSearch
...
v3.0.0
| 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 | ||
|
|
58354ff232 | ||
|
|
96684df32d | ||
|
|
48bdf342ab | ||
|
|
2b07b6bb47 | ||
|
|
7df53677d4 | ||
|
|
2e281aae62 | ||
|
|
70fc6eb40b | ||
|
|
13049b7b9d | ||
|
|
bf9e80a335 | ||
|
|
104d1b66f7 | ||
|
|
d2da6a6b2e | ||
|
|
c473515ec1 | ||
|
|
7feaeeab6c | ||
|
|
daa650123c | ||
|
|
4b5c45254e | ||
|
|
b9301b7ac1 | ||
|
|
cbac5f1555 | ||
|
|
66e79044b6 | ||
|
|
77aa702d23 | ||
|
|
400fc0b4c2 | ||
|
|
c618c7436a | ||
|
|
b3017dc774 | ||
|
|
e602ea40a7 | ||
|
|
e826b778c7 | ||
|
|
4a98077e20 | ||
|
|
3b6de607ff | ||
|
|
94a973f8a3 | ||
|
|
0ec8ff56c4 | ||
|
|
0980c52056 | ||
|
|
3dc9c0cb9a | ||
|
|
fee393a6ab | ||
|
|
bb59f16e31 | ||
|
|
daf45c10e5 | ||
|
|
b0f63b8db6 | ||
|
|
0754479219 | ||
|
|
11aa6440fa | ||
|
|
be06000c13 | ||
|
|
b0809eab95 | ||
|
|
bcba82414f | ||
|
|
6aee5d17f7 | ||
|
|
ca9ccf65af | ||
|
|
0cfc7eb549 | ||
|
|
d7c87a0dd5 | ||
|
|
f0971d9fe4 | ||
|
|
be1e328ded | ||
|
|
d2f28c3464 | ||
|
|
07fa4b9aa3 | ||
|
|
72bc94d0c9 | ||
|
|
4d52257558 | ||
|
|
abd6773fbd | ||
|
|
990426ca68 | ||
|
|
96cbff74b7 | ||
|
|
cacba3ee39 | ||
|
|
80926aef0a | ||
|
|
4ad12a842f | ||
|
|
32d694a3e2 | ||
|
|
38169e60ae | ||
|
|
1e8ddbbf46 | ||
|
|
0e0cf3f30d | ||
|
|
715e27f728 | ||
|
|
a9449a816a | ||
|
|
db508d52b6 | ||
|
|
675d310067 | ||
|
|
094b5ee3eb | ||
|
|
573e87b8c3 | ||
|
|
adf9580431 | ||
|
|
ec7643eeb7 | ||
|
|
77e538f177 | ||
|
|
ee2ca4455c | ||
|
|
9b4d07e8fc | ||
|
|
ab0821956f | ||
|
|
b08cfb8271 | ||
|
|
abc4a8de8c | ||
|
|
9e5f0debe8 | ||
|
|
64867a5dc8 | ||
|
|
eb41616a98 | ||
|
|
f6c4d9f526 | ||
|
|
558343dacd | ||
|
|
8824201bb4 | ||
|
|
ab6cf63efe | ||
|
|
308f801f03 | ||
|
|
7c8174bb80 | ||
|
|
c659ac6972 | ||
|
|
fac80402bf | ||
|
|
dcf78f7f3d | ||
|
|
eb1ee57db9 | ||
|
|
102e92fd73 | ||
|
|
95f28baa52 | ||
|
|
b41ff0f424 | ||
|
|
b05deb8a5e | ||
|
|
0a04c7ac43 | ||
|
|
62bc7313da | ||
|
|
e7d4551b05 | ||
|
|
452d40dad7 | ||
|
|
0e758c687b |
@@ -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=81996a0479fa7c1aa7b40d96ba2bea14569d46b6
|
||||
WEB_COMMITID=9d5615635b05b177946649962d61df78c8d9fc07
|
||||
WEB_BRANCH=main
|
||||
|
||||
121
.woodpecker.star
121
.woodpecker.star
@@ -1,12 +1,6 @@
|
||||
"""OpenCloud CI definition
|
||||
"""
|
||||
|
||||
# Production release tags
|
||||
# NOTE: need to be updated if new production releases are determined
|
||||
# - follow semver
|
||||
# - omit 'v' prefix
|
||||
PRODUCTION_RELEASE_TAGS = ["2.0", "3.0"]
|
||||
|
||||
# Repository
|
||||
|
||||
repo_slug = "opencloud-eu/opencloud"
|
||||
@@ -132,6 +126,7 @@ config = {
|
||||
"suites": [
|
||||
"apiGraph",
|
||||
"apiServiceAvailability",
|
||||
"collaborativePosix",
|
||||
],
|
||||
"skip": False,
|
||||
"withRemotePhp": [True],
|
||||
@@ -343,6 +338,20 @@ config = {
|
||||
},
|
||||
"dockerReleases": {
|
||||
"architectures": ["arm64", "amd64"],
|
||||
"production": {
|
||||
# NOTE: need to be updated if new production releases are determined
|
||||
"tags": ["2.0"],
|
||||
"repo": docker_repo_slug,
|
||||
"build_type": "production",
|
||||
},
|
||||
"rolling": {
|
||||
"repo": docker_repo_slug + "-rolling",
|
||||
"build_type": "rolling",
|
||||
},
|
||||
"daily": {
|
||||
"repo": docker_repo_slug + "-rolling",
|
||||
"build_type": "daily",
|
||||
},
|
||||
},
|
||||
"litmus": True,
|
||||
"codestyle": True,
|
||||
@@ -433,12 +442,12 @@ def main(ctx):
|
||||
|
||||
test_pipelines = \
|
||||
codestyle(ctx) + \
|
||||
checkGherkinLint() + \
|
||||
checkTestSuitesInExpectedFailures() + \
|
||||
checkGherkinLint(ctx) + \
|
||||
checkTestSuitesInExpectedFailures(ctx) + \
|
||||
buildWebCache(ctx) + \
|
||||
getGoBinForTesting(ctx) + \
|
||||
buildOpencloudBinaryForTesting(ctx) + \
|
||||
checkStarlark() + \
|
||||
checkStarlark(ctx) + \
|
||||
build_release_helpers + \
|
||||
testOpencloudAndUploadResults(ctx) + \
|
||||
testPipelines(ctx)
|
||||
@@ -479,7 +488,7 @@ def main(ctx):
|
||||
pipelineSanityChecks(pipelines)
|
||||
return pipelines
|
||||
|
||||
def cachePipeline(name, steps):
|
||||
def cachePipeline(ctx, name, steps):
|
||||
return {
|
||||
"name": "build-%s-cache" % name,
|
||||
"skip_clone": True,
|
||||
@@ -489,14 +498,19 @@ def cachePipeline(name, steps):
|
||||
"event": ["push", "manual"],
|
||||
"branch": ["main", "stable-*"],
|
||||
},
|
||||
event["pull_request"],
|
||||
{
|
||||
"event": "pull_request",
|
||||
"path": {
|
||||
"exclude": skipIfUnchanged(ctx, "base"),
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
def buildWebCache(ctx):
|
||||
return [
|
||||
cachePipeline("web", generateWebCache(ctx)),
|
||||
cachePipeline("web-pnpm", generateWebPnpmCache(ctx)),
|
||||
cachePipeline(ctx, "web", generateWebCache(ctx)),
|
||||
cachePipeline(ctx, "web-pnpm", generateWebPnpmCache(ctx)),
|
||||
]
|
||||
|
||||
def testOpencloudAndUploadResults(ctx):
|
||||
@@ -730,7 +744,7 @@ def buildOpencloudBinaryForTesting(ctx):
|
||||
{
|
||||
"event": "pull_request",
|
||||
"path": {
|
||||
"exclude": skipIfUnchanged(ctx, "unit-tests"),
|
||||
"exclude": skipIfUnchanged(ctx, "base"),
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -761,7 +775,7 @@ def vendorbinCodesniffer(phpVersion):
|
||||
],
|
||||
}]
|
||||
|
||||
def checkTestSuitesInExpectedFailures():
|
||||
def checkTestSuitesInExpectedFailures(ctx):
|
||||
return [{
|
||||
"name": "check-suites-in-expected-failures",
|
||||
"steps": [
|
||||
@@ -773,10 +787,18 @@ def checkTestSuitesInExpectedFailures():
|
||||
],
|
||||
},
|
||||
],
|
||||
"when": [event["pull_request"]],
|
||||
"when": [
|
||||
event["base"],
|
||||
{
|
||||
"event": "pull_request",
|
||||
"path": {
|
||||
"exclude": skipIfUnchanged(ctx, "acceptance-tests"),
|
||||
},
|
||||
},
|
||||
],
|
||||
}]
|
||||
|
||||
def checkGherkinLint():
|
||||
def checkGherkinLint(ctx):
|
||||
return [{
|
||||
"name": "check-gherkin-standard",
|
||||
"steps": [
|
||||
@@ -789,7 +811,15 @@ def checkGherkinLint():
|
||||
],
|
||||
},
|
||||
],
|
||||
"when": [event["pull_request"]],
|
||||
"when": [
|
||||
event["base"],
|
||||
{
|
||||
"event": "pull_request",
|
||||
"path": {
|
||||
"exclude": skipIfUnchanged(ctx, "lint"),
|
||||
},
|
||||
},
|
||||
],
|
||||
}]
|
||||
|
||||
def codestyle(ctx):
|
||||
@@ -900,7 +930,7 @@ def localApiTestPipeline(ctx):
|
||||
for storage in params["storages"]:
|
||||
for run_with_remote_php in params["withRemotePhp"]:
|
||||
pipeline = {
|
||||
"name": "%s-%s%s-%s" % ("CLI" if name.startswith("cli") else "API", name, "-withoutRemotePhp" if not run_with_remote_php else "", storage),
|
||||
"name": "%s-%s%s-%s" % ("CLI" if name.startswith("cli") else "API", name, "-withoutRemotePhp" if not run_with_remote_php else "", "decomposed" if name.startswith("cli") else storage),
|
||||
"steps": restoreBuildArtifactCache(ctx, dirs["opencloudBinArtifact"], dirs["opencloudBinPath"]) +
|
||||
(tikaService() if params["tikaNeeded"] else []) +
|
||||
(waitForServices("online-offices", ["collabora:9980", "onlyoffice:443", "fakeoffice:8080"]) if params["collaborationServiceNeeded"] else []) +
|
||||
@@ -931,7 +961,7 @@ def localApiTestPipeline(ctx):
|
||||
|
||||
def localApiTests(name, suites, storage = "decomposed", extra_environment = {}, with_remote_php = False):
|
||||
test_dir = "%s/tests/acceptance" % dirs["base"]
|
||||
expected_failures_file = "%s/expected-failures-localAPI-on-decomposed-storage.md" % test_dir
|
||||
expected_failures_file = "%s/expected-failures-localAPI-on-%s-storage.md" % (test_dir, storage)
|
||||
|
||||
environment = {
|
||||
"TEST_SERVER_URL": OC_URL,
|
||||
@@ -939,12 +969,13 @@ def localApiTests(name, suites, storage = "decomposed", extra_environment = {},
|
||||
"SEND_SCENARIO_LINE_REFERENCES": True,
|
||||
"STORAGE_DRIVER": storage,
|
||||
"BEHAT_SUITES": ",".join(suites),
|
||||
"BEHAT_FILTER_TAGS": "~@skip&&~@skipOnGraph&&~@skipOnOpencloud-%s-Storage" % storage,
|
||||
"BEHAT_FILTER_TAGS": "~@skip&&~@skipOnOpencloud-%s-Storage" % storage,
|
||||
"EXPECTED_FAILURES_FILE": expected_failures_file,
|
||||
"UPLOAD_DELETE_WAIT_TIME": "1" if storage == "owncloud" else 0,
|
||||
"OC_WRAPPER_URL": "http://%s:5200" % OC_SERVER_NAME,
|
||||
"WITH_REMOTE_PHP": with_remote_php,
|
||||
"COLLABORATION_SERVICE_URL": "http://wopi-fakeoffice:9300",
|
||||
"OC_STORAGE_PATH": "$HOME/.opencloud/storage/users",
|
||||
}
|
||||
|
||||
for item in extra_environment:
|
||||
@@ -1107,7 +1138,7 @@ def coreApiTests(ctx, part_number = 1, number_of_parts = 1, with_remote_php = Fa
|
||||
storage = "posix"
|
||||
if "[decomposed]" in ctx.build.title.lower():
|
||||
storage = "decomposed"
|
||||
filterTags = "~@skipOnGraph&&~@skipOnOpencloud-%s-Storage" % storage
|
||||
filterTags = "~@skipOnOpencloud-%s-Storage" % storage
|
||||
test_dir = "%s/tests/acceptance" % dirs["base"]
|
||||
expected_failures_file = "%s/expected-failures-API-on-%s-storage.md" % (test_dir, storage)
|
||||
|
||||
@@ -1472,26 +1503,31 @@ def logTracingResults():
|
||||
def dockerReleases(ctx):
|
||||
pipelines = []
|
||||
docker_repos = []
|
||||
build_type = "daily"
|
||||
build_type = ""
|
||||
|
||||
# dockerhub repo
|
||||
# - "opencloudeu/opencloud-rolling"
|
||||
repo = docker_repo_slug + "-rolling"
|
||||
docker_repos.append(repo)
|
||||
|
||||
# production release repo
|
||||
if ctx.build.event == "tag":
|
||||
tag = ctx.build.ref.replace("refs/tags/v", "").lower()
|
||||
for prod_tag in PRODUCTION_RELEASE_TAGS:
|
||||
|
||||
is_production = False
|
||||
for prod_tag in config["dockerReleases"]["production"]["tags"]:
|
||||
if tag.startswith(prod_tag):
|
||||
docker_repos.append(docker_repo_slug)
|
||||
is_production = True
|
||||
break
|
||||
|
||||
if is_production:
|
||||
docker_repos.append(config["dockerReleases"]["production"]["repo"])
|
||||
build_type = config["dockerReleases"]["production"]["build_type"]
|
||||
|
||||
else:
|
||||
docker_repos.append(config["dockerReleases"]["rolling"]["repo"])
|
||||
build_type = config["dockerReleases"]["rolling"]["build_type"]
|
||||
|
||||
else:
|
||||
docker_repos.append(config["dockerReleases"]["daily"]["repo"])
|
||||
build_type = config["dockerReleases"]["daily"]["build_type"]
|
||||
|
||||
for repo in docker_repos:
|
||||
repo_pipelines = []
|
||||
if ctx.build.event == "tag":
|
||||
build_type = "rolling" if "rolling" in repo else "production"
|
||||
|
||||
repo_pipelines.append(dockerRelease(ctx, repo, build_type))
|
||||
|
||||
# manifest = releaseDockerManifest(ctx, repo, build_type)
|
||||
@@ -1884,6 +1920,7 @@ def opencloudServer(storage = "decomposed", accounts_hash_difficulty = 4, depend
|
||||
"OC_JWT_SECRET": "some-opencloud-jwt-secret",
|
||||
"EVENTHISTORY_STORE": "memory",
|
||||
"OC_TRANSLATION_PATH": "%s/tests/config/translations" % dirs["base"],
|
||||
"ACTIVITYLOG_WRITE_BUFFER_DURATION": "0", # Disable write buffer so that test expectations are met in time
|
||||
# debug addresses required for running services health tests
|
||||
"ACTIVITYLOG_DEBUG_ADDR": "0.0.0.0:9197",
|
||||
"APP_PROVIDER_DEBUG_ADDR": "0.0.0.0:9165",
|
||||
@@ -2001,6 +2038,8 @@ def opencloudServer(storage = "decomposed", accounts_hash_difficulty = 4, depend
|
||||
},
|
||||
},
|
||||
"commands": [
|
||||
"apt-get update",
|
||||
"apt-get install -y inotify-tools",
|
||||
"%s init --insecure true" % dirs["opencloudBin"],
|
||||
"cat $OC_CONFIG_DIR/opencloud.yaml",
|
||||
"cp tests/config/woodpecker/app-registry.yaml $OC_CONFIG_DIR/app-registry.yaml",
|
||||
@@ -2103,7 +2142,7 @@ def skipIfUnchanged(ctx, type):
|
||||
skip = base + acceptance
|
||||
elif type == "build-binary" or type == "build-docker" or type == "litmus":
|
||||
skip = base + unit + acceptance
|
||||
elif type == "cache":
|
||||
elif type == "cache" or type == "base":
|
||||
skip = base
|
||||
|
||||
return skip
|
||||
@@ -2183,7 +2222,7 @@ def deploy(config, rebuild):
|
||||
],
|
||||
}
|
||||
|
||||
def checkStarlark():
|
||||
def checkStarlark(ctx):
|
||||
return [{
|
||||
"name": "check-starlark",
|
||||
"steps": [
|
||||
@@ -2209,7 +2248,15 @@ def checkStarlark():
|
||||
},
|
||||
],
|
||||
"depends_on": [],
|
||||
"when": [event["pull_request"]],
|
||||
"when": [
|
||||
event["base"],
|
||||
{
|
||||
"event": "pull_request",
|
||||
"path": {
|
||||
"exclude": skipIfUnchanged(ctx, "base"),
|
||||
},
|
||||
},
|
||||
],
|
||||
}]
|
||||
|
||||
def genericCache(name, action, mounts, cache_path):
|
||||
|
||||
143
CHANGELOG.md
143
CHANGELOG.md
@@ -1,5 +1,148 @@
|
||||
# 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! ❤️
|
||||
|
||||
@AlexAndBear, @ScharfViktor, @aduffeck, @butonic, @micbar, @rhafer
|
||||
|
||||
### ✨ Features
|
||||
|
||||
- deployment: Adapt opencloud_full to include radicale [[#773](https://github.com/opencloud-eu/opencloud/pull/773)]
|
||||
- proxy(router): Allow to set some outgoing headers [[#756](https://github.com/opencloud-eu/opencloud/pull/756)]
|
||||
- feat: set idp logo defaul url [[#746](https://github.com/opencloud-eu/opencloud/pull/746)]
|
||||
|
||||
### 📈 Enhancement
|
||||
|
||||
- Reduce load caused by the activitylog service [[#842](https://github.com/opencloud-eu/opencloud/pull/842)]
|
||||
|
||||
### ✅ Tests
|
||||
|
||||
- PosixTest. Check that version, share and link still exist [[#837](https://github.com/opencloud-eu/opencloud/pull/837)]
|
||||
- [test-only] test for #452 [[#826](https://github.com/opencloud-eu/opencloud/pull/826)]
|
||||
- collaboration posix tests [[#780](https://github.com/opencloud-eu/opencloud/pull/780)]
|
||||
- collaborative posix test [[#672](https://github.com/opencloud-eu/opencloud/pull/672)]
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- nats: Don't enable debug and trace logging by default [[#825](https://github.com/opencloud-eu/opencloud/pull/825)]
|
||||
- fix: show special roles at the end of the list [[#806](https://github.com/opencloud-eu/opencloud/pull/806)]
|
||||
- fix: idp login logo url exceeds logo [[#742](https://github.com/opencloud-eu/opencloud/pull/742)]
|
||||
|
||||
### 📦️ Dependencies
|
||||
|
||||
- [full-ci] chore(web): bump web to v2.3.0 [[#885](https://github.com/opencloud-eu/opencloud/pull/885)]
|
||||
- chore:reva bump v.2.33 [[#884](https://github.com/opencloud-eu/opencloud/pull/884)]
|
||||
- build(deps): bump google.golang.org/grpc from 1.72.0 to 1.72.1 [[#862](https://github.com/opencloud-eu/opencloud/pull/862)]
|
||||
- build(deps): bump golang.org/x/net from 0.39.0 to 0.40.0 [[#855](https://github.com/opencloud-eu/opencloud/pull/855)]
|
||||
- build(deps-dev): bump dotenv-expand from 10.0.0 to 12.0.2 in /services/idp [[#831](https://github.com/opencloud-eu/opencloud/pull/831)]
|
||||
- build(deps): bump github.com/libregraph/lico from 0.65.2-0.20250428103211-356e98f98457 to 0.66.0 [[#839](https://github.com/opencloud-eu/opencloud/pull/839)]
|
||||
- build(deps): bump i18next from 23.16.8 to 25.1.2 in /services/idp [[#832](https://github.com/opencloud-eu/opencloud/pull/832)]
|
||||
- build(deps): bump dario.cat/mergo from 1.0.1 to 1.0.2 [[#829](https://github.com/opencloud-eu/opencloud/pull/829)]
|
||||
- build(deps): bump golang.org/x/image from 0.26.0 to 0.27.0 [[#817](https://github.com/opencloud-eu/opencloud/pull/817)]
|
||||
- build(deps): bump github.com/CiscoM31/godata from 1.0.10 to 1.0.11 [[#815](https://github.com/opencloud-eu/opencloud/pull/815)]
|
||||
- build(deps): bump github.com/KimMachineGun/automemlimit from 0.7.1 to 0.7.2 [[#803](https://github.com/opencloud-eu/opencloud/pull/803)]
|
||||
- build(deps): bump golang.org/x/crypto from 0.37.0 to 0.38.0 [[#802](https://github.com/opencloud-eu/opencloud/pull/802)]
|
||||
- build(deps): bump github.com/open-policy-agent/opa from 1.3.0 to 1.4.2 [[#784](https://github.com/opencloud-eu/opencloud/pull/784)]
|
||||
- build(deps): bump golang.org/x/sync from 0.13.0 to 0.14.0 [[#785](https://github.com/opencloud-eu/opencloud/pull/785)]
|
||||
- build(deps-dev): bump eslint-plugin-import from 2.30.0 to 2.31.0 in /services/idp [[#777](https://github.com/opencloud-eu/opencloud/pull/777)]
|
||||
- build(deps): bump github.com/nats-io/nats.go from 1.41.2 to 1.42.0 [[#776](https://github.com/opencloud-eu/opencloud/pull/776)]
|
||||
- build(deps): bump golang.org/x/oauth2 from 0.29.0 to 0.30.0 [[#775](https://github.com/opencloud-eu/opencloud/pull/775)]
|
||||
- build(deps): bump i18next-http-backend from 2.5.2 to 3.0.2 in /services/idp [[#774](https://github.com/opencloud-eu/opencloud/pull/774)]
|
||||
- build(deps): bump github.com/beevik/etree from 1.5.0 to 1.5.1 [[#759](https://github.com/opencloud-eu/opencloud/pull/759)]
|
||||
- build(deps): bump github.com/nats-io/nats-server/v2 from 2.11.2 to 2.11.3 [[#762](https://github.com/opencloud-eu/opencloud/pull/762)]
|
||||
- build(deps): bump github.com/nats-io/nats-server/v2 from 2.11.1 to 2.11.2 [[#754](https://github.com/opencloud-eu/opencloud/pull/754)]
|
||||
- build(deps): bump github.com/gookit/config/v2 from 2.2.5 to 2.2.6 [[#753](https://github.com/opencloud-eu/opencloud/pull/753)]
|
||||
- build(deps-dev): bump css-loader from 5.2.7 to 7.1.2 in /services/idp [[#740](https://github.com/opencloud-eu/opencloud/pull/740)]
|
||||
- build(deps): bump react-i18next from 15.1.1 to 15.5.1 in /services/idp [[#741](https://github.com/opencloud-eu/opencloud/pull/741)]
|
||||
- build(deps): bump github.com/blevesearch/bleve/v2 from 2.4.4 to 2.5.0 [[#743](https://github.com/opencloud-eu/opencloud/pull/743)]
|
||||
- build(deps): bump github.com/gabriel-vasile/mimetype from 1.4.8 to 1.4.9 [[#744](https://github.com/opencloud-eu/opencloud/pull/744)]
|
||||
|
||||
## [2.2.0](https://github.com/opencloud-eu/opencloud/releases/tag/v2.2.0) - 2025-04-28
|
||||
|
||||
### ❤️ Thanks to all contributors! ❤️
|
||||
|
||||
@@ -182,7 +182,7 @@ COLLABORA=:collabora.yml
|
||||
# Domain of Collabora, where you can find the frontend.
|
||||
# Defaults to "collabora.opencloud.test"
|
||||
COLLABORA_DOMAIN=
|
||||
# Domain of the wopiserver which handles OnlyOffice.
|
||||
# Domain of the wopiserver which handles Collabora.
|
||||
# Defaults to "wopiserver.opencloud.test"
|
||||
WOPISERVER_DOMAIN=
|
||||
# Admin user for Collabora.
|
||||
@@ -225,19 +225,10 @@ COLLABORA_SSL_VERIFICATION=false
|
||||
# Defaults to "partial"
|
||||
#ANTIVIRUS_MAX_SCAN_SIZE_MODE=
|
||||
# Image version of the ClamAV container.
|
||||
# Defaults to "latest"
|
||||
# Defaults to "latest"y
|
||||
CLAMAV_DOCKER_TAG=
|
||||
|
||||
|
||||
### OnlyOffice Settings ###
|
||||
# Note: the leading colon is required to enable the service.
|
||||
#ONLYOFFICE=:onlyoffice.yml
|
||||
# Domain for OnlyOffice. Defaults to "onlyoffice.opencloud.test".
|
||||
ONLYOFFICE_DOMAIN=
|
||||
# Domain for the wopiserver which handles OnlyOffice.
|
||||
WOPISERVER_ONLYOFFICE_DOMAIN=
|
||||
|
||||
|
||||
### Inbucket Settings ###
|
||||
# Inbucket is a mail catcher tool for testing purposes.
|
||||
# DO NOT use in Production.
|
||||
@@ -269,6 +260,11 @@ LDAP_ADMIN_PASSWORD=
|
||||
# LDAP manager domain. Defaults to "ldap.opencloud.test"
|
||||
LDAP_MANAGER_DOMAIN=
|
||||
|
||||
### LibreGraph Connect (lico) IDP ###
|
||||
# LibreGraph Connect (lico) implements an OpenID provider (OP) with integrated web login and consent forms.
|
||||
# Text hint that appears within the username input field on the sign-in page
|
||||
IDP_DEFAULT_SIGNIN_PAGE_TEXT=
|
||||
|
||||
### Keycloak Settings ###
|
||||
# Keycloak is an open-source identity and access management solution.
|
||||
# We are using Keycloak as the default identity provider on production installations.
|
||||
@@ -294,8 +290,23 @@ KEYCLOAK_ADMIN_PASSWORD=
|
||||
# Autoprovisioning mode. Defaults to "true"
|
||||
#KEYCLOAK_AUTOPROVISIONING=:keycloak-autoprovisioning.yml
|
||||
|
||||
### Radicale Setting ###
|
||||
# Radicale is a small open-source CalDAV (calendars, to-do lists) and CardDAV (contacts) server.
|
||||
# When enabled OpenCloud is configured as a reverse proxy for Radicale, providing all authenticated
|
||||
# OpenCloud users access to a Personal Calendar and Addressbook
|
||||
#RADICALE=:radicale.yml
|
||||
# Docker image to use for the Radicale Container
|
||||
#RADICALE_DOCKER_IMAGE=opencloudeu/radicale
|
||||
# Docker tag to pull for the Radicale Container
|
||||
#RADICALE_DOCKER_TAG=latest
|
||||
# Define the storage location for the Radicale data. Set the path to a local path.
|
||||
# Ensure that the configuration and data directories are owned by the user and group with ID 1000:1000.
|
||||
# This matches the default user inside the container and avoids permission issues when accessing files.
|
||||
# Leaving it default stores data in docker internal volumes.
|
||||
#RADICALE_DATA_DIR=/your/local/radicale/data
|
||||
|
||||
## IMPORTANT ##
|
||||
# This MUST be the last line as it assembles the supplemental compose files to be used.
|
||||
# ALL supplemental configs must be added here, whether commented or not.
|
||||
# Each var must either be empty or contain :path/file.yml
|
||||
COMPOSE_FILE=docker-compose.yml${OPENCLOUD:-}${TIKA:-}${DECOMPOSEDS3:-}${DECOMPOSEDS3_MINIO:-}${DECOMPOSED:-}${COLLABORA:-}${MONITORING:-}${IMPORTER:-}${CLAMAV:-}${ONLYOFFICE:-}${INBUCKET:-}${EXTENSIONS:-}${UNZIP:-}${DRAWIO:-}${JSONVIEWER:-}${PROGRESSBARS:-}${EXTERNALSITES:-}${KEYCLOAK:-}${LDAP:-}${KEYCLOAK_AUTOPROVISIONING:-}${LDAP_MANAGER:-}
|
||||
COMPOSE_FILE=docker-compose.yml${OPENCLOUD:-}${TIKA:-}${DECOMPOSEDS3:-}${DECOMPOSEDS3_MINIO:-}${DECOMPOSED:-}${COLLABORA:-}${MONITORING:-}${IMPORTER:-}${CLAMAV:-}${INBUCKET:-}${EXTENSIONS:-}${UNZIP:-}${DRAWIO:-}${JSONVIEWER:-}${PROGRESSBARS:-}${EXTERNALSITES:-}${KEYCLOAK:-}${LDAP:-}${KEYCLOAK_AUTOPROVISIONING:-}${LDAP_MANAGER:-}${RADICALE:-}
|
||||
|
||||
@@ -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:24.04.13.2.1
|
||||
image: collabora/code:25.04.2.1.1
|
||||
# release notes: https://www.collaboraonline.com/release-notes/
|
||||
networks:
|
||||
opencloud-net:
|
||||
@@ -83,4 +83,5 @@ services:
|
||||
entrypoint: ['/bin/bash', '-c']
|
||||
command: ['coolconfig generate-proof-key && /start-collabora-online.sh']
|
||||
healthcheck:
|
||||
test: [ "CMD", "curl", "-f", "http://localhost:9980/hosting/discovery" ]
|
||||
test: ["CMD", "bash", "-c", "exec 3<>/dev/tcp/127.0.0.1/9980 && echo -e 'GET /hosting/discovery HTTP/1.1\r\nHost: localhost:9980\r\n\r\n' >&3 && head -n 1 <&3 | grep '200 OK'"]
|
||||
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
# we can't mount it directly because the run-document-server.sh script wants to move it
|
||||
cp /etc/onlyoffice/documentserver/local.dist.json /etc/onlyoffice/documentserver/local.json
|
||||
|
||||
/app/ds/run-document-server.sh
|
||||
@@ -1,71 +0,0 @@
|
||||
{
|
||||
"services": {
|
||||
"CoAuthoring": {
|
||||
"sql": {
|
||||
"type": "postgres",
|
||||
"dbHost": "localhost",
|
||||
"dbPort": "5432",
|
||||
"dbName": "onlyoffice",
|
||||
"dbUser": "onlyoffice",
|
||||
"dbPass": "onlyoffice"
|
||||
},
|
||||
"token": {
|
||||
"enable": {
|
||||
"request": {
|
||||
"inbox": true,
|
||||
"outbox": true
|
||||
},
|
||||
"browser": true
|
||||
},
|
||||
"inbox": {
|
||||
"header": "Authorization"
|
||||
},
|
||||
"outbox": {
|
||||
"header": "Authorization"
|
||||
}
|
||||
},
|
||||
"secret": {
|
||||
"inbox": {
|
||||
"string": "B8LjkNqGxn6gf8bkuBUiMwyuCFwFddnu"
|
||||
},
|
||||
"outbox": {
|
||||
"string": "B8LjkNqGxn6gf8bkuBUiMwyuCFwFddnu"
|
||||
},
|
||||
"session": {
|
||||
"string": "B8LjkNqGxn6gf8bkuBUiMwyuCFwFddnu"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"rabbitmq": {
|
||||
"url": "amqp://guest:guest@localhost"
|
||||
},
|
||||
"FileConverter": {
|
||||
"converter": {
|
||||
"inputLimits": [
|
||||
{
|
||||
"type": "docx;dotx;docm;dotm",
|
||||
"zip": {
|
||||
"uncompressed": "1GB",
|
||||
"template": "*.xml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "xlsx;xltx;xlsm;xltm",
|
||||
"zip": {
|
||||
"uncompressed": "1GB",
|
||||
"template": "*.xml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "pptx;ppsx;potx;pptm;ppsm;potm",
|
||||
"zip": {
|
||||
"uncompressed": "1GB",
|
||||
"template": "*.xml"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,7 +19,6 @@ directives:
|
||||
- 'blob:'
|
||||
- 'https://embed.diagrams.net/'
|
||||
# In contrary to bash and docker the default is given after the | character
|
||||
- 'https://${ONLYOFFICE_DOMAIN|onlyoffice.opencloud.test}/'
|
||||
- 'https://${COLLABORA_DOMAIN|collabora.opencloud.test}/'
|
||||
# This is needed for the external-sites web extension when embedding sites
|
||||
- 'https://docs.opencloud.eu'
|
||||
@@ -29,7 +28,6 @@ directives:
|
||||
- 'blob:'
|
||||
- 'https://raw.githubusercontent.com/opencloud-eu/awesome-apps/'
|
||||
# In contrary to bash and docker the default is given after the | character
|
||||
- 'https://${ONLYOFFICE_DOMAIN|onlyoffice.opencloud.test}/'
|
||||
- 'https://${COLLABORA_DOMAIN|collabora.opencloud.test}/'
|
||||
manifest-src:
|
||||
- '''self'''
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
# This adds four additional routes to the proxy. Forwarding
|
||||
# request on '/carddav/', '/caldav/' and the respective '/.well-knwown'
|
||||
# endpoints to the radicale container and setting the required headers.
|
||||
additional_policies:
|
||||
- name: default
|
||||
routes:
|
||||
- endpoint: /caldav/
|
||||
backend: http://radicale:5232
|
||||
remote_user_header: X-Remote-User
|
||||
skip_x_access_token: true
|
||||
additional_headers:
|
||||
- X-Script-Name: /caldav
|
||||
- endpoint: /.well-known/caldav
|
||||
backend: http://radicale:5232
|
||||
remote_user_header: X-Remote-User
|
||||
skip_x_access_token: true
|
||||
additional_headers:
|
||||
- X-Script-Name: /caldav
|
||||
- endpoint: /carddav/
|
||||
backend: http://radicale:5232
|
||||
remote_user_header: X-Remote-User
|
||||
skip_x_access_token: true
|
||||
additional_headers:
|
||||
- X-Script-Name: /carddav
|
||||
- endpoint: /.well-known/carddav
|
||||
backend: http://radicale:5232
|
||||
remote_user_header: X-Remote-User
|
||||
skip_x_access_token: true
|
||||
additional_headers:
|
||||
- X-Script-Name: /carddav
|
||||
# To enable the radicale web UI add this rule.
|
||||
# "unprotected" is True because the Web UI itself ask for
|
||||
# the password.
|
||||
# Also set "type" to "internal" in the config/radicale/config
|
||||
# - endpoint: /caldav/.web/
|
||||
# backend: http://radicale:5232/
|
||||
# unprotected: true
|
||||
# skip_x_access_token: true
|
||||
# additional_headers:
|
||||
# - X-Script-Name: /caldav
|
||||
325
deployments/examples/opencloud_full/config/radicale/config
Normal file
325
deployments/examples/opencloud_full/config/radicale/config
Normal file
@@ -0,0 +1,325 @@
|
||||
# -*- mode: conf -*-
|
||||
# vim:ft=cfg
|
||||
|
||||
# Config file for Radicale - A simple calendar server
|
||||
#
|
||||
# Place it into /etc/radicale/config (global)
|
||||
# or ~/.config/radicale/config (user)
|
||||
#
|
||||
# The current values are the default ones
|
||||
|
||||
|
||||
[server]
|
||||
|
||||
# CalDAV server hostnames separated by a comma
|
||||
# IPv4 syntax: address:port
|
||||
# IPv6 syntax: [address]:port
|
||||
# Hostname syntax (using "getaddrinfo" to resolve to IPv4/IPv6 adress(es)): hostname:port
|
||||
# For example: 0.0.0.0:9999, [::]:9999, localhost:9999
|
||||
hosts = 0.0.0.0:5232
|
||||
|
||||
# Max parallel connections
|
||||
#max_connections = 8
|
||||
|
||||
# Max size of request body (bytes)
|
||||
#max_content_length = 100000000
|
||||
|
||||
# Socket timeout (seconds)
|
||||
#timeout = 30
|
||||
|
||||
# SSL flag, enable HTTPS protocol
|
||||
#ssl = False
|
||||
|
||||
# SSL certificate path
|
||||
#certificate = /etc/ssl/radicale.cert.pem
|
||||
|
||||
# SSL private key
|
||||
#key = /etc/ssl/radicale.key.pem
|
||||
|
||||
# CA certificate for validating clients. This can be used to secure
|
||||
# TCP traffic between Radicale and a reverse proxy
|
||||
#certificate_authority =
|
||||
|
||||
# SSL protocol, secure configuration: ALL -SSLv3 -TLSv1 -TLSv1.1
|
||||
#protocol = (default)
|
||||
|
||||
# SSL ciphersuite, secure configuration: DHE:ECDHE:-NULL:-SHA (see also "man openssl-ciphers")
|
||||
#ciphersuite = (default)
|
||||
|
||||
# script name to strip from URI if called by reverse proxy
|
||||
#script_name = (default taken from HTTP_X_SCRIPT_NAME or SCRIPT_NAME)
|
||||
|
||||
|
||||
[encoding]
|
||||
|
||||
# Encoding for responding requests
|
||||
#request = utf-8
|
||||
|
||||
# Encoding for storing local collections
|
||||
#stock = utf-8
|
||||
|
||||
|
||||
[auth]
|
||||
|
||||
# Authentication method
|
||||
# Value: none | htpasswd | remote_user | http_x_remote_user | dovecot | ldap | oauth2 | pam | denyall
|
||||
type = http_x_remote_user
|
||||
|
||||
# Cache logins for until expiration time
|
||||
#cache_logins = false
|
||||
|
||||
# Expiration time for caching successful logins in seconds
|
||||
#cache_successful_logins_expiry = 15
|
||||
|
||||
## Expiration time of caching failed logins in seconds
|
||||
#cache_failed_logins_expiry = 90
|
||||
|
||||
# Ignore modifyTimestamp and createTimestamp attributes. Required e.g. for Authentik LDAP server
|
||||
#ldap_ignore_attribute_create_modify_timestamp = false
|
||||
|
||||
# URI to the LDAP server
|
||||
#ldap_uri = ldap://localhost
|
||||
|
||||
# The base DN where the user accounts have to be searched
|
||||
#ldap_base = ##BASE_DN##
|
||||
|
||||
# The reader DN of the LDAP server
|
||||
#ldap_reader_dn = CN=ldapreader,CN=Users,##BASE_DN##
|
||||
|
||||
# Password of the reader DN
|
||||
#ldap_secret = ldapreader-secret
|
||||
|
||||
# Path of the file containing password of the reader DN
|
||||
#ldap_secret_file = /run/secrets/ldap_password
|
||||
|
||||
# the attribute to read the group memberships from in the user's LDAP entry (default: not set)
|
||||
#ldap_groups_attribute = memberOf
|
||||
|
||||
# The filter to find the DN of the user. This filter must contain a python-style placeholder for the login
|
||||
#ldap_filter = (&(objectClass=person)(uid={0}))
|
||||
|
||||
# the attribute holding the value to be used as username after authentication
|
||||
#ldap_user_attribute = cn
|
||||
|
||||
# Use ssl on the ldap connection
|
||||
# Soon to be deprecated, use ldap_security instead
|
||||
#ldap_use_ssl = False
|
||||
|
||||
# the encryption mode to be used: tls, starttls, default is none
|
||||
#ldap_security = none
|
||||
|
||||
# The certificate verification mode. Works for ssl and starttls. NONE, OPTIONAL, default is REQUIRED
|
||||
#ldap_ssl_verify_mode = REQUIRED
|
||||
|
||||
# The path to the CA file in pem format which is used to certificate the server certificate
|
||||
#ldap_ssl_ca_file =
|
||||
|
||||
# Connection type for dovecot authentication (AF_UNIX|AF_INET|AF_INET6)
|
||||
# Note: credentials are transmitted in cleartext
|
||||
#dovecot_connection_type = AF_UNIX
|
||||
|
||||
# The path to the Dovecot client authentication socket (eg. /run/dovecot/auth-client on Fedora). Radicale must have read / write access to the socket.
|
||||
#dovecot_socket = /var/run/dovecot/auth-client
|
||||
|
||||
# Host of via network exposed dovecot socket
|
||||
#dovecot_host = localhost
|
||||
|
||||
# Port of via network exposed dovecot socket
|
||||
#dovecot_port = 12345
|
||||
|
||||
# IMAP server hostname
|
||||
# Syntax: address | address:port | [address]:port | imap.server.tld
|
||||
#imap_host = localhost
|
||||
|
||||
# Secure the IMAP connection
|
||||
# Value: tls | starttls | none
|
||||
#imap_security = tls
|
||||
|
||||
# OAuth2 token endpoint URL
|
||||
#oauth2_token_endpoint = <URL>
|
||||
|
||||
# PAM service
|
||||
#pam_serivce = radicale
|
||||
|
||||
# PAM group user should be member of
|
||||
#pam_group_membership =
|
||||
|
||||
# Htpasswd filename
|
||||
#htpasswd_filename = /etc/radicale/users
|
||||
|
||||
# Htpasswd encryption method
|
||||
# Value: plain | bcrypt | md5 | sha256 | sha512 | autodetect
|
||||
# bcrypt requires the installation of 'bcrypt' module.
|
||||
#htpasswd_encryption = autodetect
|
||||
|
||||
# Enable caching of htpasswd file based on size and mtime_ns
|
||||
#htpasswd_cache = False
|
||||
|
||||
# Incorrect authentication delay (seconds)
|
||||
#delay = 1
|
||||
|
||||
# Message displayed in the client when a password is needed
|
||||
#realm = Radicale - Password Required
|
||||
|
||||
# Convert username to lowercase, must be true for case-insensitive auth providers
|
||||
#lc_username = False
|
||||
|
||||
# Strip domain name from username
|
||||
#strip_domain = False
|
||||
|
||||
|
||||
[rights]
|
||||
|
||||
# Rights backend
|
||||
# Value: authenticated | owner_only | owner_write | from_file
|
||||
#type = owner_only
|
||||
|
||||
# File for rights management from_file
|
||||
#file = /etc/radicale/rights
|
||||
|
||||
# Permit delete of a collection (global)
|
||||
#permit_delete_collection = True
|
||||
|
||||
# Permit overwrite of a collection (global)
|
||||
#permit_overwrite_collection = True
|
||||
|
||||
|
||||
[storage]
|
||||
|
||||
# Storage backend
|
||||
# Value: multifilesystem | multifilesystem_nolock
|
||||
#type = multifilesystem
|
||||
|
||||
# Folder for storing local collections, created if not present
|
||||
#filesystem_folder = /var/lib/radicale/collections
|
||||
|
||||
# Folder for storing cache of local collections, created if not present
|
||||
# Note: only used in case of use_cache_subfolder_* options are active
|
||||
# Note: can be used on multi-instance setup to cache files on local node (see below)
|
||||
#filesystem_cache_folder = (filesystem_folder)
|
||||
|
||||
# Use subfolder 'collection-cache' for 'item' cache file structure instead of inside collection folder
|
||||
# Note: can be used on multi-instance setup to cache 'item' on local node
|
||||
#use_cache_subfolder_for_item = False
|
||||
|
||||
# Use subfolder 'collection-cache' for 'history' cache file structure instead of inside collection folder
|
||||
# Note: use only on single-instance setup, will break consistency with client in multi-instance setup
|
||||
#use_cache_subfolder_for_history = False
|
||||
|
||||
# Use subfolder 'collection-cache' for 'sync-token' cache file structure instead of inside collection folder
|
||||
# Note: use only on single-instance setup, will break consistency with client in multi-instance setup
|
||||
#use_cache_subfolder_for_synctoken = False
|
||||
|
||||
# Use last modifiction time (nanoseconds) and size (bytes) for 'item' cache instead of SHA256 (improves speed)
|
||||
# Note: check used filesystem mtime precision before enabling
|
||||
# Note: conversion is done on access, bulk conversion can be done offline using storage verification option: radicale --verify-storage
|
||||
#use_mtime_and_size_for_item_cache = False
|
||||
|
||||
# Use configured umask for folder creation (not applicable for OS Windows)
|
||||
# Useful value: 0077 | 0027 | 0007 | 0022
|
||||
#folder_umask = (system default, usual 0022)
|
||||
|
||||
# Delete sync token that are older (seconds)
|
||||
#max_sync_token_age = 2592000
|
||||
|
||||
# Skip broken item instead of triggering an exception
|
||||
#skip_broken_item = True
|
||||
|
||||
# Command that is run after changes to storage, default is emtpy
|
||||
# Supported placeholders:
|
||||
# %(user)s: logged-in user
|
||||
# %(cwd)s : current working directory
|
||||
# %(path)s: full path of item
|
||||
# Command will be executed with base directory defined in filesystem_folder
|
||||
# For "git" check DOCUMENTATION.md for bootstrap instructions
|
||||
# Example(test): echo \"user=%(user)s path=%(path)s cwd=%(cwd)s\"
|
||||
# Example(git): git add -A && (git diff --cached --quiet || git commit -m "Changes by \"%(user)s\"")
|
||||
#hook =
|
||||
|
||||
# Create predefined user collections
|
||||
#
|
||||
# json format:
|
||||
#
|
||||
# {
|
||||
# "def-addressbook": {
|
||||
# "D:displayname": "Personal Address Book",
|
||||
# "tag": "VADDRESSBOOK"
|
||||
# },
|
||||
# "def-calendar": {
|
||||
# "C:supported-calendar-component-set": "VEVENT,VJOURNAL,VTODO",
|
||||
# "D:displayname": "Personal Calendar",
|
||||
# "tag": "VCALENDAR"
|
||||
# }
|
||||
# }
|
||||
#
|
||||
predefined_collections = {
|
||||
"def-addressbook": {
|
||||
"D:displayname": "Personal Address Book",
|
||||
"tag": "VADDRESSBOOK"
|
||||
},
|
||||
"def-calendar": {
|
||||
"C:supported-calendar-component-set": "VEVENT,VJOURNAL,VTODO",
|
||||
"D:displayname": "Personal Calendar",
|
||||
"tag": "VCALENDAR"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[web]
|
||||
|
||||
# Web interface backend
|
||||
# Value: none | internal
|
||||
type = none
|
||||
|
||||
|
||||
[logging]
|
||||
|
||||
# Threshold for the logger
|
||||
# Value: debug | info | warning | error | critical
|
||||
#level = info
|
||||
|
||||
# Don't include passwords in logs
|
||||
#mask_passwords = True
|
||||
|
||||
# Log bad PUT request content
|
||||
#bad_put_request_content = False
|
||||
|
||||
# Log backtrace on level=debug
|
||||
#backtrace_on_debug = False
|
||||
|
||||
# Log request header on level=debug
|
||||
#request_header_on_debug = False
|
||||
|
||||
# Log request content on level=debug
|
||||
#request_content_on_debug = False
|
||||
|
||||
# Log response content on level=debug
|
||||
#response_content_on_debug = False
|
||||
|
||||
# Log rights rule which doesn't match on level=debug
|
||||
#rights_rule_doesnt_match_on_debug = False
|
||||
|
||||
# Log storage cache actions on level=debug
|
||||
#storage_cache_actions_on_debug = False
|
||||
|
||||
[headers]
|
||||
|
||||
# Additional HTTP headers
|
||||
#Access-Control-Allow-Origin = *
|
||||
|
||||
|
||||
[hook]
|
||||
|
||||
# Hook types
|
||||
# Value: none | rabbitmq
|
||||
#type = none
|
||||
#rabbitmq_endpoint =
|
||||
#rabbitmq_topic =
|
||||
#rabbitmq_queue_type = classic
|
||||
|
||||
|
||||
[reporting]
|
||||
|
||||
# When returning a free-busy report, limit the number of returned
|
||||
# occurences per event to prevent DOS attacks.
|
||||
#max_freebusy_occurrence = 10000
|
||||
@@ -1,86 +0,0 @@
|
||||
---
|
||||
services:
|
||||
traefik:
|
||||
networks:
|
||||
opencloud-net:
|
||||
aliases:
|
||||
- ${ONLYOFFICE_DOMAIN:-onlyoffice.opencloud.test}
|
||||
- ${WOPISERVER_ONLYOFFICE_DOMAIN:-wopiserver-oo.opencloud.test}
|
||||
|
||||
collaboration-oo:
|
||||
image: ${OC_DOCKER_IMAGE:-opencloudeu/opencloud-rolling}:${OC_DOCKER_TAG:-latest}
|
||||
networks:
|
||||
opencloud-net:
|
||||
depends_on:
|
||||
opencloud:
|
||||
condition: service_started
|
||||
onlyoffice:
|
||||
condition: service_healthy
|
||||
entrypoint:
|
||||
- /bin/sh
|
||||
command: [ "-c", "opencloud collaboration server" ]
|
||||
environment:
|
||||
COLLABORATION_GRPC_ADDR: 0.0.0.0:9301
|
||||
COLLABORATION_HTTP_ADDR: 0.0.0.0:9300
|
||||
MICRO_REGISTRY: "nats-js-kv"
|
||||
MICRO_REGISTRY_ADDRESS: "opencloud:9233"
|
||||
COLLABORATION_WOPI_SRC: https://${WOPISERVER_ONLYOFFICE_DOMAIN:-wopiserver-oo.opencloud.test}
|
||||
COLLABORATION_APP_NAME: "OnlyOffice"
|
||||
COLLABORATION_APP_PRODUCT: "OnlyOffice"
|
||||
COLLABORATION_APP_ADDR: https://${ONLYOFFICE_DOMAIN:-onlyoffice.opencloud.test}
|
||||
COLLABORATION_APP_ICON: https://${ONLYOFFICE_DOMAIN:-onlyoffice.opencloud.test}/web-apps/apps/documenteditor/main/resources/img/favicon.ico
|
||||
COLLABORATION_APP_INSECURE: "${INSECURE:-true}"
|
||||
COLLABORATION_CS3API_DATAGATEWAY_INSECURE: "${INSECURE:-true}"
|
||||
COLLABORATION_LOG_LEVEL: ${LOG_LEVEL:-info}
|
||||
COLLABORATION_APP_PROOF_DISABLE: "true"
|
||||
OC_URL: https://${OC_DOMAIN:-cloud.opencloud.test}
|
||||
volumes:
|
||||
# configure the .env file to use own paths instead of docker internal volumes
|
||||
- ${OC_CONFIG_DIR:-opencloud-config}:/etc/opencloud
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.collaboration-oo.entrypoints=https"
|
||||
- "traefik.http.routers.collaboration-oo.rule=Host(`${WOPISERVER_ONLYOFFICE_DOMAIN:-wopiserver-oo.opencloud.test}`)"
|
||||
- "traefik.http.routers.collaboration-oo.tls.certresolver=http"
|
||||
- "traefik.http.routers.collaboration-oo.service=collaboration-oo"
|
||||
- "traefik.http.services.collaboration-oo.loadbalancer.server.port=9300"
|
||||
logging:
|
||||
driver: ${LOG_DRIVER:-local}
|
||||
restart: always
|
||||
|
||||
onlyoffice:
|
||||
# if you want to use oo enterprise edition, use: onlyoffice/documentserver-ee:<version>
|
||||
# note, you also need to add a volume, see below
|
||||
image: onlyoffice/documentserver:8.2.2
|
||||
# changelog https://github.com/ONLYOFFICE/DocumentServer/releases
|
||||
networks:
|
||||
opencloud-net:
|
||||
entrypoint:
|
||||
- /bin/sh
|
||||
- /entrypoint-override.sh
|
||||
environment:
|
||||
WOPI_ENABLED: "true"
|
||||
# self-signed certificates
|
||||
USE_UNAUTHORIZED_STORAGE: "${INSECURE:-false}"
|
||||
volumes:
|
||||
# paths are relative to the main compose file
|
||||
- ./config/onlyoffice/entrypoint-override.sh:/entrypoint-override.sh
|
||||
- ./config/onlyoffice/local.json:/etc/onlyoffice/documentserver/local.dist.json
|
||||
# if you want to use oo enterprise edition, you need to add a volume for the license file
|
||||
# for details see: Registering your Enterprise Edition version -->
|
||||
# https://helpcenter.onlyoffice.com/installation/docs-enterprise-install-docker.aspx
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.onlyoffice.entrypoints=https"
|
||||
- "traefik.http.routers.onlyoffice.rule=Host(`${ONLYOFFICE_DOMAIN:-onlyoffice.opencloud.test}`)"
|
||||
- "traefik.http.routers.onlyoffice.tls.certresolver=http"
|
||||
- "traefik.http.routers.onlyoffice.service=onlyoffice"
|
||||
- "traefik.http.services.onlyoffice.loadbalancer.server.port=80"
|
||||
# websockets can't be opened when this is omitted
|
||||
- "traefik.http.middlewares.onlyoffice.headers.customrequestheaders.X-Forwarded-Proto=https"
|
||||
- "traefik.http.routers.onlyoffice.middlewares=onlyoffice"
|
||||
logging:
|
||||
driver: ${LOG_DRIVER:-local}
|
||||
restart: always
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost/hosting/discovery"]
|
||||
@@ -36,6 +36,8 @@ services:
|
||||
IDM_ADMIN_PASSWORD: "${ADMIN_PASSWORD:-admin}" # this overrides the admin password from the configuration file
|
||||
# demo users
|
||||
IDM_CREATE_DEMO_USERS: "${DEMO_USERS:-false}"
|
||||
# idp login form settings
|
||||
IDP_DEFAULT_SIGNIN_PAGE_TEXT: "${IDP_DEFAULT_SIGNIN_PAGE_TEXT}"
|
||||
# email server (if configured)
|
||||
NOTIFICATIONS_SMTP_HOST: "${SMTP_HOST}"
|
||||
NOTIFICATIONS_SMTP_PORT: "${SMTP_PORT}"
|
||||
@@ -53,7 +55,6 @@ services:
|
||||
PROXY_CSP_CONFIG_FILE_LOCATION: /etc/opencloud/csp.yaml
|
||||
# these three vars are needed to the csp config file to include the web office apps and the importer
|
||||
COLLABORA_DOMAIN: ${COLLABORA_DOMAIN:-collabora.opencloud.test}
|
||||
ONLYOFFICE_DOMAIN: ${ONLYOFFICE_DOMAIN:-onlyoffice.opencloud.test}
|
||||
COMPANION_DOMAIN: ${COMPANION_DOMAIN:-companion.opencloud.test}
|
||||
# enable to allow using the banned passwords list
|
||||
OC_PASSWORD_POLICY_BANNED_PASSWORDS_LIST: banned-password-list.txt
|
||||
|
||||
18
deployments/examples/opencloud_full/radicale.yml
Normal file
18
deployments/examples/opencloud_full/radicale.yml
Normal file
@@ -0,0 +1,18 @@
|
||||
---
|
||||
services:
|
||||
opencloud:
|
||||
volumes:
|
||||
# external sites needs to have additional routes configured in the proxy
|
||||
- ./config/opencloud/proxy.yaml:/etc/opencloud/proxy.yaml
|
||||
radicale:
|
||||
image: ${RADICALE_DOCKER_IMAGE:-opencloudeu/radicale}:${RADICALE_DOCKER_TAG:-latest}
|
||||
networks:
|
||||
opencloud-net:
|
||||
logging:
|
||||
driver: ${LOG_DRIVER:-local}
|
||||
restart: always
|
||||
volumes:
|
||||
- ./config/radicale/config:/etc/radicale/config
|
||||
- ${RADICALE_DATA_DIR:-radicale-data}:/var/lib/radicale
|
||||
volumes:
|
||||
radicale-data:
|
||||
142
go.mod
142
go.mod
@@ -3,15 +3,15 @@ module github.com/opencloud-eu/opencloud
|
||||
go 1.24.1
|
||||
|
||||
require (
|
||||
dario.cat/mergo v1.0.1
|
||||
github.com/CiscoM31/godata v1.0.10
|
||||
github.com/KimMachineGun/automemlimit v0.7.1
|
||||
dario.cat/mergo v1.0.2
|
||||
github.com/CiscoM31/godata v1.0.11
|
||||
github.com/KimMachineGun/automemlimit v0.7.2
|
||||
github.com/Masterminds/semver v1.5.0
|
||||
github.com/MicahParks/keyfunc/v2 v2.1.0
|
||||
github.com/Nerzal/gocloak/v13 v13.9.0
|
||||
github.com/bbalet/stopwords v1.0.0
|
||||
github.com/beevik/etree v1.5.0
|
||||
github.com/blevesearch/bleve/v2 v2.5.0
|
||||
github.com/beevik/etree v1.5.1
|
||||
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
|
||||
@@ -40,7 +40,7 @@ require (
|
||||
github.com/google/go-cmp v0.7.0
|
||||
github.com/google/go-tika v0.3.1
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/gookit/config/v2 v2.2.5
|
||||
github.com/gookit/config/v2 v2.2.6
|
||||
github.com/gorilla/mux v1.8.1
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3
|
||||
github.com/invopop/validation v0.8.0
|
||||
@@ -49,32 +49,31 @@ 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.65.2-0.20250428103211-356e98f98457
|
||||
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.1
|
||||
github.com/nats-io/nats.go v1.41.2
|
||||
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.3.0
|
||||
github.com/opencloud-eu/reva/v2 v2.32.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/owncloud/libre-graph-api-go v1.0.5-0.20240829135935-80dc00d6f5ea
|
||||
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
|
||||
github.com/rogpeppe/go-internal v1.14.1
|
||||
github.com/rs/cors v1.11.1
|
||||
github.com/rs/zerolog v1.34.0
|
||||
github.com/shamaton/msgpack/v2 v2.2.3
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/spf13/afero v1.14.0
|
||||
github.com/spf13/cobra v1.9.1
|
||||
@@ -85,27 +84,28 @@ require (
|
||||
github.com/tus/tusd/v2 v2.8.0
|
||||
github.com/unrolled/secure v1.16.0
|
||||
github.com/urfave/cli/v2 v2.27.6
|
||||
github.com/vmihailenco/msgpack/v5 v5.4.1
|
||||
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.37.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.26.0
|
||||
golang.org/x/net v0.39.0
|
||||
golang.org/x/oauth2 v0.29.0
|
||||
golang.org/x/sync v0.13.0
|
||||
golang.org/x/term v0.31.0
|
||||
golang.org/x/text v0.24.0
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb
|
||||
google.golang.org/grpc v1.72.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.15.0
|
||||
golang.org/x/term v0.32.0
|
||||
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
|
||||
@@ -167,6 +167,7 @@ require (
|
||||
github.com/deckarep/golang-set v1.8.0 // indirect
|
||||
github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect
|
||||
github.com/dgraph-io/ristretto v0.2.0 // indirect
|
||||
github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/dlclark/regexp2 v1.4.0 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
@@ -176,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
|
||||
@@ -206,20 +207,19 @@ require (
|
||||
github.com/gobwas/pool v0.2.1 // indirect
|
||||
github.com/gobwas/ws v1.2.1 // indirect
|
||||
github.com/goccy/go-json v0.10.5 // indirect
|
||||
github.com/goccy/go-yaml v1.11.2 // indirect
|
||||
github.com/goccy/go-yaml v1.12.0 // indirect
|
||||
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
|
||||
github.com/gookit/goutil v0.6.15 // indirect
|
||||
github.com/gookit/goutil v0.6.18 // indirect
|
||||
github.com/gorilla/handlers v1.5.1 // indirect
|
||||
github.com/gorilla/schema v1.4.1 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
|
||||
@@ -246,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
|
||||
@@ -254,28 +254,31 @@ 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
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/mschoch/smat v0.2.0 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/nats-io/jwt/v2 v2.7.3 // indirect
|
||||
github.com/nats-io/jwt/v2 v2.7.4 // indirect
|
||||
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
|
||||
@@ -284,12 +287,13 @@ require (
|
||||
github.com/rs/xid v1.6.0 // indirect
|
||||
github.com/russellhaering/goxmldsig v1.5.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/segmentio/kafka-go v0.4.47 // indirect
|
||||
github.com/segmentio/kafka-go v0.4.48 // indirect
|
||||
github.com/segmentio/ksuid v1.0.4 // indirect
|
||||
github.com/sercand/kuberesolver/v5 v5.1.1 // indirect
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
|
||||
github.com/sethvargo/go-diceware v0.5.0 // indirect
|
||||
github.com/sethvargo/go-password v0.3.1 // indirect
|
||||
github.com/shamaton/msgpack/v2 v2.2.3 // indirect
|
||||
github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c // indirect
|
||||
github.com/shurcooL/vfsgen v0.0.0-20230704071429-0000e147ea92 // indirect
|
||||
github.com/skeema/knownhosts v1.3.0 // indirect
|
||||
@@ -300,8 +304,11 @@ 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
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
@@ -309,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
|
||||
golang.org/x/sys v0.32.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
|
||||
@@ -341,10 +347,10 @@ replace github.com/egirna/icap-client => github.com/fschade/icap-client v0.0.0-2
|
||||
|
||||
replace github.com/unrolled/secure => github.com/DeepDiver1975/secure v0.0.0-20240611112133-abc838fb797c
|
||||
|
||||
replace github.com/go-micro/plugins/v4/store/nats-js-kv => github.com/kobergj/plugins/v4/store/nats-js-kv v0.0.0-20240807130109-f62bb67e8c90
|
||||
|
||||
replace go-micro.dev/v4 => github.com/butonic/go-micro/v4 v4.11.1-0.20241115112658-b5d4de5ed9b3
|
||||
|
||||
// exclude the v2 line of go-sqlite3 which was released accidentally and prevents pulling in newer versions of go-sqlite3
|
||||
// see https://github.com/mattn/go-sqlite3/issues/965 for more details
|
||||
exclude github.com/mattn/go-sqlite3 v2.0.3+incompatible
|
||||
|
||||
replace github.com/go-micro/plugins/v4/store/nats-js-kv => github.com/opencloud-eu/go-micro-plugins/v4/store/nats-js-kv v0.0.0-20250512152754-23325793059a
|
||||
|
||||
289
go.sum
289
go.sum
@@ -36,8 +36,8 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
|
||||
contrib.go.opencensus.io/exporter/ocagent v0.4.12/go.mod h1:450APlNTSR6FrvC3CTRqYosuDstRB9un7SOx2k/9ckA=
|
||||
contrib.go.opencensus.io/exporter/prometheus v0.4.2 h1:sqfsYl5GIY/L570iT+l93ehxaWJs2/OwXtiWwew3oAg=
|
||||
contrib.go.opencensus.io/exporter/prometheus v0.4.2/go.mod h1:dvEHbiKmgvbr5pjaF9fpw1KeYcjrnC1J8B+JKjsZyRQ=
|
||||
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
|
||||
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||
dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
|
||||
dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||
@@ -64,12 +64,12 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
|
||||
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
|
||||
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/CiscoM31/godata v1.0.10 h1:DZdJ6M8QNh4HquvDDOqNLu6h77Wl86KGK7Qlbmb90sk=
|
||||
github.com/CiscoM31/godata v1.0.10/go.mod h1:ZMiT6JuD3Rm83HEtiTx4JEChsd25YCrxchKGag/sdTc=
|
||||
github.com/CiscoM31/godata v1.0.11 h1:w7y8twuW02LdH6mak3/GJ5i0GrCv2IoZUJVqa/g5Yeo=
|
||||
github.com/CiscoM31/godata v1.0.11/go.mod h1:ZMiT6JuD3Rm83HEtiTx4JEChsd25YCrxchKGag/sdTc=
|
||||
github.com/DeepDiver1975/secure v0.0.0-20240611112133-abc838fb797c h1:ocsNvQ2tNHme4v/lTs17HROamc7mFzZfzWcg4m+UXN0=
|
||||
github.com/DeepDiver1975/secure v0.0.0-20240611112133-abc838fb797c/go.mod h1:BmF5hyM6tXczk3MpQkFf1hpKSRqCyhqcbiQtiAF7+40=
|
||||
github.com/KimMachineGun/automemlimit v0.7.1 h1:QcG/0iCOLChjfUweIMC3YL5Xy9C3VBeNmCZHrZfJMBw=
|
||||
github.com/KimMachineGun/automemlimit v0.7.1/go.mod h1:QZxpHaGOQoYvFhv/r4u3U0JTC2ZcOwbSr11UZF46UBM=
|
||||
github.com/KimMachineGun/automemlimit v0.7.2 h1:DyfHI7zLWmZPn2Wqdy2AgTiUvrGPmnYWgwhHXtAegX4=
|
||||
github.com/KimMachineGun/automemlimit v0.7.2/go.mod h1:QZxpHaGOQoYvFhv/r4u3U0JTC2ZcOwbSr11UZF46UBM=
|
||||
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
|
||||
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
|
||||
@@ -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.0 h1:iaQZFSDS+3kYZiGoc9uKeOkUY3nYMXOKLl6KIJxiJWs=
|
||||
github.com/beevik/etree v1.5.0/go.mod h1:gPNJNaBGVZ9AwsidazFZyygnd+0pAU38N4D+WemwKNs=
|
||||
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||
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/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=
|
||||
@@ -257,15 +261,15 @@ github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS3
|
||||
github.com/deepmap/oapi-codegen v1.3.11/go.mod h1:suMvK7+rKlx3+tpa8ByptmvoXbAV70wERKTOGH3hLp0=
|
||||
github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f h1:U5y3Y5UE0w7amNe7Z5G/twsBW0KEalRQXZzf8ufSh9I=
|
||||
github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE=
|
||||
github.com/dgraph-io/badger/v4 v4.6.0 h1:acOwfOOZ4p1dPRnYzvkVm7rUk2Y21TgPVepCy5dJdFQ=
|
||||
github.com/dgraph-io/badger/v4 v4.6.0/go.mod h1:KSJ5VTuZNC3Sd+YhvVjk2nYua9UZnnTr/SkXvdtiPgI=
|
||||
github.com/dgraph-io/badger/v4 v4.7.0 h1:Q+J8HApYAY7UMpL8d9owqiB+odzEc0zn/aqOD9jhc6Y=
|
||||
github.com/dgraph-io/badger/v4 v4.7.0/go.mod h1:He7TzG3YBy3j4f5baj5B7Zl2XyfNe5bl4Udl0aPemVA=
|
||||
github.com/dgraph-io/ristretto v0.2.0 h1:XAfl+7cmoUDWW/2Lx8TGZQjjxIQ2Ley9DSf52dru4WE=
|
||||
github.com/dgraph-io/ristretto v0.2.0/go.mod h1:8uBHCU/PBV4Ag0CJrP47b9Ofby5dqWNh4FicAdoqFNU=
|
||||
github.com/dgraph-io/ristretto/v2 v2.1.0 h1:59LjpOJLNDULHh8MC4UaegN52lC4JnO2dITsie/Pa8I=
|
||||
github.com/dgraph-io/ristretto/v2 v2.1.0/go.mod h1:uejeqfYXpUomfse0+lO+13ATz4TypQYLJZzBSAemuB4=
|
||||
github.com/dgraph-io/ristretto/v2 v2.2.0 h1:bkY3XzJcXoMuELV8F+vS8kzNgicwQFAaGINAEJdWGOM=
|
||||
github.com/dgraph-io/ristretto/v2 v2.2.0/go.mod h1:RZrm63UmcBAaYWC1DotLYBmTvgkrs0+XhBd7Npn7/zI=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y=
|
||||
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
||||
github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da h1:aIftn67I1fkbMa512G+w+Pxci9hJPB8oMnkcP3iZF38=
|
||||
github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
@@ -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=
|
||||
@@ -438,8 +442,8 @@ github.com/gobwas/ws v1.2.1 h1:F2aeBZrm2NDsc7vbovKrWSogd4wvfAxg0FQ89/iqOTk=
|
||||
github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
|
||||
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
||||
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/goccy/go-yaml v1.11.2 h1:joq77SxuyIs9zzxEjgyLBugMQ9NEgTWxXfz2wVqwAaQ=
|
||||
github.com/goccy/go-yaml v1.11.2/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU=
|
||||
github.com/goccy/go-yaml v1.12.0 h1:/1WHjnMsI1dlIBQutrvSMGZRQufVO3asrHfTwfACoPM=
|
||||
github.com/goccy/go-yaml v1.12.0/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E=
|
||||
github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0=
|
||||
@@ -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=
|
||||
@@ -552,10 +554,10 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=
|
||||
github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w=
|
||||
github.com/gookit/config/v2 v2.2.5 h1:RECbYYbtherywmzn3LNeu9NA5ZqhD7MSKEMsJ7l+MpU=
|
||||
github.com/gookit/config/v2 v2.2.5/go.mod h1:NeX+yiNYn6Ei10eJvCQFXuHEPIE/IPS8bqaFIsszzaM=
|
||||
github.com/gookit/goutil v0.6.15 h1:mMQ0ElojNZoyPD0eVROk5QXJPh2uKR4g06slgPDF5Jo=
|
||||
github.com/gookit/goutil v0.6.15/go.mod h1:qdKdYEHQdEtyH+4fNdQNZfJHhI0jUZzHxQVAV3DaMDY=
|
||||
github.com/gookit/config/v2 v2.2.6 h1:8ZbkSr3gnFg1En8za9X3vldnZca3y3C7kaBLGsdLghE=
|
||||
github.com/gookit/config/v2 v2.2.6/go.mod h1:++APDf3Ebj6mjzW1ALkegvg1evQKyx4FpuQqQZ2s2WM=
|
||||
github.com/gookit/goutil v0.6.18 h1:MUVj0G16flubWT8zYVicIuisUiHdgirPAkmnfD2kKgw=
|
||||
github.com/gookit/goutil v0.6.18/go.mod h1:AY/5sAwKe7Xck+mEbuxj0n/bc3qwrGNe3Oeulln7zBA=
|
||||
github.com/gookit/ini/v2 v2.2.3 h1:nSbN+x9OfQPcMObTFP+XuHt8ev6ndv/fWWqxFhPMu2E=
|
||||
github.com/gookit/ini/v2 v2.2.3/go.mod h1:Vu6p7P7xcfmb8KYu3L0ek8bqu/Im63N81q208SCCZY4=
|
||||
github.com/gophercloud/gophercloud v0.15.1-0.20210202035223-633d73521055/go.mod h1:wRtmUelyIIv3CSSDI47aUwbs075O6i+LY+pXsKCBsb4=
|
||||
@@ -690,8 +692,6 @@ github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2
|
||||
github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||
github.com/kobergj/gowebdav v0.0.0-20250102091030-aa65266db202 h1:A1xJ2NKgiYFiaHiLl9B5yw/gUBACSs9crDykTS3GuQI=
|
||||
github.com/kobergj/gowebdav v0.0.0-20250102091030-aa65266db202/go.mod h1:bHA7t77X/QFExdeAnDzK6vKM34kEZAcE1OX4MfiwjkE=
|
||||
github.com/kobergj/plugins/v4/store/nats-js-kv v0.0.0-20240807130109-f62bb67e8c90 h1:pfI8Z5yavO6fU6vDGlWhZ4BgDlvj8c6xB7J57HfTPwA=
|
||||
github.com/kobergj/plugins/v4/store/nats-js-kv v0.0.0-20240807130109-f62bb67e8c90/go.mod h1:pjcozWijkNPbEtX5SIQaxEW/h8VAVZYTLx+70bmB3LY=
|
||||
github.com/kolo/xmlrpc v0.0.0-20200310150728-e0350524596b/go.mod h1:o03bZfuBwAXHetKXuInt4S7omeXUu62/A845kiycsSQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
@@ -716,12 +716,12 @@ 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.65.2-0.20250428103211-356e98f98457 h1:cwmUM+mSeqWYtZKAHn8QN7ns1nNf3Pc8nUfShka9+x0=
|
||||
github.com/libregraph/lico v0.65.2-0.20250428103211-356e98f98457/go.mod h1:2s2UkO0pY7/k1UlenXwio1qenfHZ217Npx22YyZJfSA=
|
||||
github.com/libregraph/lico v0.66.0 h1:7T6fD1YF0Ep9n0g4KN6dvWHTlDC3awrQpgsP5GdYCF4=
|
||||
github.com/libregraph/lico v0.66.0/go.mod h1:QI7NfmAkAWQ2y97iVfLv10S8tcvPQjc630uyfHGjIOw=
|
||||
github.com/libregraph/oidc-go v1.1.0 h1:RyudjL3UyQblqeBQI06W53PniWobqODeeyAy6v/HumA=
|
||||
github.com/libregraph/oidc-go v1.1.0/go.mod h1:qW9ubcXvZrfbbWZBaLMuk7bt5qAUMYyt9/NtXQt07Cw=
|
||||
github.com/linode/linodego v0.25.3/go.mod h1:GSBKPpjoQfxEfryoCRcgkuUOCuVtGHWhzI8OMdycNTE=
|
||||
@@ -763,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=
|
||||
@@ -784,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,12 +820,12 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04/go.mod h1:5sN+Lt1CaY4wsPvgQH/jsuJi4XO2ssZbdsIizr4CVC8=
|
||||
github.com/nats-io/jwt/v2 v2.7.3 h1:6bNPK+FXgBeAqdj4cYQ0F8ViHRbi7woQLq4W29nUAzE=
|
||||
github.com/nats-io/jwt/v2 v2.7.3/go.mod h1:GvkcbHhKquj3pkioy5put1wvPxs78UlZ7D/pY+BgZk4=
|
||||
github.com/nats-io/nats-server/v2 v2.11.1 h1:LwdauqMqMNhTxTN3+WFTX6wGDOKntHljgZ+7gL5HCnk=
|
||||
github.com/nats-io/nats-server/v2 v2.11.1/go.mod h1:leXySghbdtXSUmWem8K9McnJ6xbJOb0t9+NQ5HTRZjI=
|
||||
github.com/nats-io/nats.go v1.41.2 h1:5UkfLAtu/036s99AhFRlyNDI1Ieylb36qbGjJzHixos=
|
||||
github.com/nats-io/nats.go v1.41.2/go.mod h1:iRWIPokVIFbVijxuMQq4y9ttaBTMe0SFdlZfMDd+33g=
|
||||
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.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=
|
||||
@@ -844,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=
|
||||
@@ -858,10 +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.3.0 h1:zVvQvQg+9+FuSRBt4LgKNzJwsWl/c85kD5jPozJTydY=
|
||||
github.com/open-policy-agent/opa v1.3.0/go.mod h1:t9iPNhaplD2qpiBqeudzJtEX3fKHK8zdA29oFvofAHo=
|
||||
github.com/opencloud-eu/reva/v2 v2.32.0 h1:JRWPleHiEl0film95Gkh1iBEhc6eikEsx5FKLfVx6l8=
|
||||
github.com/opencloud-eu/reva/v2 v2.32.0/go.mod h1:FDhGVC+ZsRRWdC3am4EbuILBtviTbCDVrTUjFECOqvg=
|
||||
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.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=
|
||||
@@ -870,8 +879,6 @@ github.com/oracle/oci-go-sdk v24.3.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35uk
|
||||
github.com/orcaman/concurrent-map v1.0.0 h1:I/2A2XPCb4IuQWcQhBhSwGfiuybl/J0ev9HDbW65HOY=
|
||||
github.com/orcaman/concurrent-map v1.0.0/go.mod h1:Lu3tH6HLW3feq74c2GC+jIMS/K2CFcDWnWD9XkenwhI=
|
||||
github.com/ovh/go-ovh v1.1.0/go.mod h1:AxitLZ5HBRPyUd+Zl60Ajaag+rNTdVXWIkzfrVuTXWA=
|
||||
github.com/owncloud/libre-graph-api-go v1.0.5-0.20240829135935-80dc00d6f5ea h1:ClVthQOjKb7uI2DhHFzIPy+adc6plptGaryH20KOoxQ=
|
||||
github.com/owncloud/libre-graph-api-go v1.0.5-0.20240829135935-80dc00d6f5ea/go.mod h1:yXI+rmE8yYx+ZsGVrnCpprw/gZMcxjwntnX2y2+VKxY=
|
||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw=
|
||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
|
||||
github.com/pablodz/inotifywaitgo v0.0.9 h1:njquRbBU7fuwIe5rEvtaniVBjwWzcpdUVptSgzFqZsw=
|
||||
@@ -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=
|
||||
@@ -989,8 +998,8 @@ github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb
|
||||
github.com/sacloud/libsacloud v1.36.2/go.mod h1:P7YAOVmnIn3DKHqCZcUKYUXmSwGBm3yS7IBEjKVSrjg=
|
||||
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210127161313-bd30bebeac4f/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/segmentio/kafka-go v0.4.47 h1:IqziR4pA3vrZq7YdRxaT3w1/5fvIH5qpCwstUanQQB0=
|
||||
github.com/segmentio/kafka-go v0.4.47/go.mod h1:HjF6XbOKh0Pjlkr5GVZxt6CsjjwnmhVOfURM5KMd8qg=
|
||||
github.com/segmentio/kafka-go v0.4.48 h1:9jyu9CWK4W5W+SroCe8EffbrRZVqAOkuaLd/ApID4Vs=
|
||||
github.com/segmentio/kafka-go v0.4.48/go.mod h1:HjF6XbOKh0Pjlkr5GVZxt6CsjjwnmhVOfURM5KMd8qg=
|
||||
github.com/segmentio/ksuid v1.0.4 h1:sBo2BdShXjmcugAMwjugoGUdUV0pcxY5mW4xKRn3v4c=
|
||||
github.com/segmentio/ksuid v1.0.4/go.mod h1:/XUiZBD3kVx5SmUOl55voK5yeAbBNNIed+2O73XgrPE=
|
||||
github.com/sercand/kuberesolver/v5 v5.1.1 h1:CYH+d67G0sGBj7q5wLK61yzqJJ8gLLC8aeprPTHb6yY=
|
||||
@@ -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,7 +1113,13 @@ 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=
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
|
||||
github.com/vultr/govultr/v2 v2.0.0/go.mod h1:2PsEeg+gs3p/Fo5Pw8F9mv+DUBEOlrNZ8GmCTGmhOhs=
|
||||
github.com/wk8/go-ordered-map v1.0.0 h1:BV7z+2PaK8LTSd/mWgY12HyMAo5CEgkHqbkVq2thqr8=
|
||||
github.com/wk8/go-ordered-map v1.0.0/go.mod h1:9ZIbRunKbuvfPKyBP1SIKLcXNlv74YCOZ3t3VTS6gRk=
|
||||
@@ -1139,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=
|
||||
@@ -1157,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=
|
||||
@@ -1200,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=
|
||||
@@ -1223,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.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
|
||||
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
|
||||
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=
|
||||
@@ -1240,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.26.0 h1:4XjIFEZWQmCZi6Wv8BoxsDhRU3RVnLX04dToTDAEPlY=
|
||||
golang.org/x/image v0.26.0/go.mod h1:lcxbMFAovzpnJxzXS3nyL83K27tmqtKzIJpctK8YO5c=
|
||||
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=
|
||||
@@ -1266,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=
|
||||
@@ -1322,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=
|
||||
@@ -1331,8 +1346,8 @@ golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4Iltr
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||
golang.org/x/oauth2 v0.29.0 h1:WdYw2tdTK1S8olAzWHdgeqfy+Mtm9XNhv/xJsY65d98=
|
||||
golang.org/x/oauth2 v0.29.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
|
||||
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
|
||||
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -1350,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.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
|
||||
golang.org/x/sync v0.13.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=
|
||||
@@ -1432,8 +1447,8 @@ golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
@@ -1445,8 +1460,8 @@ golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
|
||||
golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
|
||||
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
|
||||
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -1462,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.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
|
||||
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
|
||||
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=
|
||||
@@ -1526,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=
|
||||
@@ -1589,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=
|
||||
@@ -1608,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.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM=
|
||||
google.golang.org/grpc v1.72.0/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=
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/node"
|
||||
"github.com/shamaton/msgpack/v2"
|
||||
"github.com/vmihailenco/msgpack/v5"
|
||||
)
|
||||
|
||||
// ListBlobstore required to check blob consistency
|
||||
|
||||
@@ -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})
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/node"
|
||||
"github.com/shamaton/msgpack/v2"
|
||||
"github.com/vmihailenco/msgpack/v5"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -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 {
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/conversions"
|
||||
)
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/Nerzal/gocloak/v13"
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
)
|
||||
|
||||
// Some attribute constants.
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/Nerzal/gocloak/v13"
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
)
|
||||
|
||||
// UserAction defines a type for user actions
|
||||
|
||||
@@ -42,7 +42,7 @@ func ExtractAccountUUID(opts ...account.Option) func(http.Handler) http.Handler
|
||||
}
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
token := r.Header.Get("x-access-token")
|
||||
token := r.Header.Get(revactx.TokenHeader)
|
||||
if len(token) == 0 {
|
||||
roleIDsJSON, _ := json.Marshal([]string{})
|
||||
ctx := metadata.Set(r.Context(), RoleIDs, string(roleIDsJSON))
|
||||
|
||||
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.2.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
|
||||
|
||||
@@ -32,6 +32,9 @@ type Config struct {
|
||||
ServiceAccount ServiceAccount `yaml:"service_account"`
|
||||
|
||||
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.
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package defaults
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/shared"
|
||||
"github.com/opencloud-eu/opencloud/pkg/structs"
|
||||
"github.com/opencloud-eu/opencloud/services/activitylog/pkg/config"
|
||||
@@ -50,6 +52,8 @@ func DefaultConfig() *config.Config {
|
||||
AllowCredentials: true,
|
||||
},
|
||||
},
|
||||
WriteBufferDuration: 10 * time.Second,
|
||||
MaxActivities: 6000,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/pkg/l10n"
|
||||
ehmsg "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/messages/eventhistory/v0"
|
||||
ehsvc "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/services/eventhistory/v0"
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -45,7 +45,7 @@ func (s *ActivitylogService) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
// HandleGetItemActivities handles the request to get the activities of an item.
|
||||
func (s *ActivitylogService) HandleGetItemActivities(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
ctx = metadata.AppendToOutgoingContext(ctx, revactx.TokenHeader, r.Header.Get("X-Access-Token"))
|
||||
ctx = metadata.AppendToOutgoingContext(ctx, revactx.TokenHeader, r.Header.Get(revactx.TokenHeader))
|
||||
|
||||
activeUser, ok := revactx.ContextGetUser(ctx)
|
||||
if !ok {
|
||||
|
||||
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
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
@@ -18,16 +20,18 @@ type Option func(*Options)
|
||||
|
||||
// Options for the activitylog service
|
||||
type Options struct {
|
||||
Logger log.Logger
|
||||
Config *config.Config
|
||||
TraceProvider trace.TracerProvider
|
||||
Stream events.Stream
|
||||
RegisteredEvents []events.Unmarshaller
|
||||
Store microstore.Store
|
||||
GatewaySelector pool.Selectable[gateway.GatewayAPIClient]
|
||||
Mux *chi.Mux
|
||||
HistoryClient ehsvc.EventHistoryService
|
||||
ValueClient settingssvc.ValueService
|
||||
Logger log.Logger
|
||||
Config *config.Config
|
||||
TraceProvider trace.TracerProvider
|
||||
Stream events.Stream
|
||||
RegisteredEvents []events.Unmarshaller
|
||||
Store microstore.Store
|
||||
GatewaySelector pool.Selectable[gateway.GatewayAPIClient]
|
||||
Mux *chi.Mux
|
||||
HistoryClient ehsvc.EventHistoryService
|
||||
ValueClient settingssvc.ValueService
|
||||
WriteBufferDuration time.Duration
|
||||
MaxActivities int
|
||||
}
|
||||
|
||||
// Logger configures a logger for the activitylog service
|
||||
|
||||
@@ -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/owncloud/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",
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,22 +1,30 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base32"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
|
||||
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"
|
||||
microstore "go-micro.dev/v4/store"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/vmihailenco/msgpack/v5"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
ehsvc "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/services/eventhistory/v0"
|
||||
@@ -25,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 {
|
||||
@@ -36,22 +44,105 @@ type RawActivity struct {
|
||||
|
||||
// ActivitylogService logs events per resource
|
||||
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
|
||||
valService settingssvc.ValueService
|
||||
lock sync.RWMutex
|
||||
cfg *config.Config
|
||||
log log.Logger
|
||||
events <-chan events.Event
|
||||
gws pool.Selectable[gateway.GatewayAPIClient]
|
||||
mux *chi.Mux
|
||||
evHistory ehsvc.EventHistoryService
|
||||
valService settingssvc.ValueService
|
||||
lock sync.RWMutex
|
||||
tp trace.TracerProvider
|
||||
tracer trace.Tracer
|
||||
debouncer *Debouncer
|
||||
parentIdCache *ttlcache.Cache
|
||||
natskv nats.KeyValue
|
||||
|
||||
maxActivities int
|
||||
|
||||
registeredEvents map[string]events.Unmarshaller
|
||||
}
|
||||
|
||||
type Debouncer struct {
|
||||
after time.Duration
|
||||
f func(id string, ra []RawActivity) error
|
||||
pending sync.Map
|
||||
inProgress sync.Map
|
||||
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
type queueItem struct {
|
||||
activities []RawActivity
|
||||
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{
|
||||
after: d,
|
||||
f: f,
|
||||
pending: sync.Map{},
|
||||
inProgress: sync.Map{},
|
||||
}
|
||||
}
|
||||
|
||||
// Debounce restarts the debounce timer for the given space
|
||||
func (d *Debouncer) Debounce(id string, ra RawActivity) {
|
||||
if d.after == 0 {
|
||||
d.f(id, []RawActivity{ra})
|
||||
return
|
||||
}
|
||||
|
||||
d.mutex.Lock()
|
||||
defer d.mutex.Unlock()
|
||||
|
||||
activities := []RawActivity{ra}
|
||||
item := &queueItem{
|
||||
activities: activities,
|
||||
}
|
||||
if i, ok := d.pending.Load(id); ok {
|
||||
// if the item is already in the queue, append the new activities
|
||||
item, ok = i.(*queueItem)
|
||||
if ok {
|
||||
item.activities = append(item.activities, ra)
|
||||
}
|
||||
}
|
||||
|
||||
if item.timer == nil {
|
||||
item.timer = time.AfterFunc(d.after, func() {
|
||||
if _, ok := d.inProgress.Load(id); ok {
|
||||
// Reschedule this run for when the previous run has finished
|
||||
d.mutex.Lock()
|
||||
if i, ok := d.pending.Load(id); ok {
|
||||
i.(*queueItem).timer.Reset(d.after)
|
||||
}
|
||||
|
||||
d.mutex.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
d.pending.Delete(id)
|
||||
d.inProgress.Store(id, true)
|
||||
defer d.inProgress.Delete(id)
|
||||
d.f(id, item.activities)
|
||||
})
|
||||
}
|
||||
|
||||
d.pending.Store(id, item)
|
||||
}
|
||||
|
||||
// New creates a new ActivitylogService
|
||||
func New(opts ...Option) (*ActivitylogService, error) {
|
||||
o := &Options{}
|
||||
o := &Options{
|
||||
MaxActivities: _maxActivitiesDefault,
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(o)
|
||||
}
|
||||
@@ -60,11 +151,44 @@ 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
|
||||
}
|
||||
|
||||
ch, err := events.Consume(o.Stream, o.Config.Service.Name, o.RegisteredEvents...)
|
||||
cache := ttlcache.NewCache()
|
||||
err = cache.SetTTL(30 * time.Second)
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
@@ -73,13 +197,24 @@ func New(opts ...Option) (*ActivitylogService, error) {
|
||||
log: o.Logger,
|
||||
cfg: o.Config,
|
||||
events: ch,
|
||||
store: o.Store,
|
||||
gws: o.GatewaySelector,
|
||||
mux: o.Mux,
|
||||
evHistory: o.HistoryClient,
|
||||
valService: o.ValueClient,
|
||||
lock: sync.RWMutex{},
|
||||
registeredEvents: make(map[string]events.Unmarshaller),
|
||||
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.mux.Get("/graph/v1beta1/extensions/org.libregraph/activities", s.HandleGetItemActivities)
|
||||
@@ -100,9 +235,9 @@ func (a *ActivitylogService) Run() {
|
||||
var err error
|
||||
switch ev := e.Event.(type) {
|
||||
case events.UploadReady:
|
||||
err = a.AddActivity(ev.FileRef, e.ID, utils.TSToTime(ev.Timestamp))
|
||||
err = a.AddActivity(ev.FileRef, ev.ParentID, e.ID, utils.TSToTime(ev.Timestamp))
|
||||
case events.FileTouched:
|
||||
err = a.AddActivity(ev.Ref, e.ID, utils.TSToTime(ev.Timestamp))
|
||||
err = a.AddActivity(ev.Ref, ev.ParentID, e.ID, utils.TSToTime(ev.Timestamp))
|
||||
// Disabled https://github.com/owncloud/ocis/issues/10293
|
||||
//case events.FileDownloaded:
|
||||
// we are only interested in public link downloads - so no need to store others.
|
||||
@@ -110,29 +245,32 @@ func (a *ActivitylogService) Run() {
|
||||
// err = a.AddActivity(ev.Ref, e.ID, utils.TSToTime(ev.Timestamp))
|
||||
//}
|
||||
case events.ContainerCreated:
|
||||
err = a.AddActivity(ev.Ref, e.ID, utils.TSToTime(ev.Timestamp))
|
||||
err = a.AddActivity(ev.Ref, ev.ParentID, e.ID, utils.TSToTime(ev.Timestamp))
|
||||
case events.ItemTrashed:
|
||||
err = a.AddActivityTrashed(ev.ID, ev.Ref, e.ID, utils.TSToTime(ev.Timestamp))
|
||||
err = a.AddActivityTrashed(ev.ID, ev.Ref, nil, e.ID, utils.TSToTime(ev.Timestamp))
|
||||
case events.ItemPurged:
|
||||
err = a.RemoveResource(ev.ID)
|
||||
case events.ItemMoved:
|
||||
err = a.AddActivity(ev.Ref, e.ID, utils.TSToTime(ev.Timestamp))
|
||||
// remove the cached parent id for this resource
|
||||
a.removeCachedParentID(ev.Ref)
|
||||
|
||||
err = a.AddActivity(ev.Ref, nil, e.ID, utils.TSToTime(ev.Timestamp))
|
||||
case events.ShareCreated:
|
||||
err = a.AddActivity(toRef(ev.ItemID), e.ID, utils.TSToTime(ev.CTime))
|
||||
err = a.AddActivity(toRef(ev.ItemID), nil, e.ID, utils.TSToTime(ev.CTime))
|
||||
case events.ShareUpdated:
|
||||
if ev.Sharer != nil && ev.ItemID != nil && ev.Sharer.GetOpaqueId() != ev.ItemID.GetSpaceId() {
|
||||
err = a.AddActivity(toRef(ev.ItemID), e.ID, utils.TSToTime(ev.MTime))
|
||||
err = a.AddActivity(toRef(ev.ItemID), nil, e.ID, utils.TSToTime(ev.MTime))
|
||||
}
|
||||
case events.ShareRemoved:
|
||||
err = a.AddActivity(toRef(ev.ItemID), e.ID, ev.Timestamp)
|
||||
err = a.AddActivity(toRef(ev.ItemID), nil, e.ID, ev.Timestamp)
|
||||
case events.LinkCreated:
|
||||
err = a.AddActivity(toRef(ev.ItemID), e.ID, utils.TSToTime(ev.CTime))
|
||||
err = a.AddActivity(toRef(ev.ItemID), nil, e.ID, utils.TSToTime(ev.CTime))
|
||||
case events.LinkUpdated:
|
||||
if ev.Sharer != nil && ev.ItemID != nil && ev.Sharer.GetOpaqueId() != ev.ItemID.GetSpaceId() {
|
||||
err = a.AddActivity(toRef(ev.ItemID), e.ID, utils.TSToTime(ev.MTime))
|
||||
err = a.AddActivity(toRef(ev.ItemID), nil, e.ID, utils.TSToTime(ev.MTime))
|
||||
}
|
||||
case events.LinkRemoved:
|
||||
err = a.AddActivity(toRef(ev.ItemID), e.ID, utils.TSToTime(ev.Timestamp))
|
||||
err = a.AddActivity(toRef(ev.ItemID), nil, e.ID, utils.TSToTime(ev.Timestamp))
|
||||
case events.SpaceShared:
|
||||
err = a.AddSpaceActivity(ev.ID, e.ID, ev.Timestamp)
|
||||
case events.SpaceUnshared:
|
||||
@@ -146,7 +284,7 @@ func (a *ActivitylogService) Run() {
|
||||
}
|
||||
|
||||
// AddActivity adds the activity to the given resource and all its parents
|
||||
func (a *ActivitylogService) AddActivity(initRef *provider.Reference, eventID string, timestamp time.Time) error {
|
||||
func (a *ActivitylogService) AddActivity(initRef *provider.Reference, parentId *provider.ResourceId, eventID string, timestamp time.Time) error {
|
||||
gwc, err := a.gws.Next()
|
||||
if err != nil {
|
||||
return fmt.Errorf("cant get gateway client: %w", err)
|
||||
@@ -156,14 +294,17 @@ func (a *ActivitylogService) AddActivity(initRef *provider.Reference, eventID st
|
||||
if err != nil {
|
||||
return fmt.Errorf("cant get service user context: %w", err)
|
||||
}
|
||||
var span trace.Span
|
||||
ctx, span = a.tracer.Start(ctx, "AddActivity")
|
||||
defer span.End()
|
||||
|
||||
return a.addActivity(initRef, 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)
|
||||
})
|
||||
}
|
||||
|
||||
// AddActivityTrashed adds the activity to given trashed resource and all its former parents
|
||||
func (a *ActivitylogService) AddActivityTrashed(resourceID *provider.ResourceId, reference *provider.Reference, eventID string, timestamp time.Time) error {
|
||||
func (a *ActivitylogService) AddActivityTrashed(resourceID *provider.ResourceId, reference *provider.Reference, parentId *provider.ResourceId, eventID string, timestamp time.Time) error {
|
||||
gwc, err := a.gws.Next()
|
||||
if err != nil {
|
||||
return fmt.Errorf("cant get gateway client: %w", err)
|
||||
@@ -175,7 +316,13 @@ func (a *ActivitylogService) AddActivityTrashed(resourceID *provider.ResourceId,
|
||||
}
|
||||
|
||||
// store activity on trashed item
|
||||
if err := a.storeActivity(storagespace.FormatResourceID(resourceID), eventID, 0, timestamp); err != nil {
|
||||
if err := a.storeActivity(storagespace.FormatResourceID(resourceID), []RawActivity{
|
||||
{
|
||||
EventID: eventID,
|
||||
Depth: 0,
|
||||
Timestamp: timestamp,
|
||||
},
|
||||
}); err != nil {
|
||||
return fmt.Errorf("could not store activity: %w", err)
|
||||
}
|
||||
|
||||
@@ -185,7 +332,11 @@ func (a *ActivitylogService) AddActivityTrashed(resourceID *provider.ResourceId,
|
||||
Path: filepath.Dir(reference.GetPath()),
|
||||
}
|
||||
|
||||
return a.addActivity(ref, eventID, timestamp, func(ref *provider.Reference) (*provider.ResourceInfo, error) {
|
||||
var span trace.Span
|
||||
ctx, span = a.tracer.Start(ctx, "AddActivityTrashed")
|
||||
defer span.End()
|
||||
|
||||
return a.addActivity(ctx, ref, parentId, eventID, timestamp, func(ctx context.Context, ref *provider.Reference) (*provider.ResourceInfo, error) {
|
||||
return utils.GetResource(ctx, ref, gwc)
|
||||
})
|
||||
}
|
||||
@@ -200,7 +351,13 @@ func (a *ActivitylogService) AddSpaceActivity(spaceID *provider.StorageSpaceId,
|
||||
return fmt.Errorf("could not parse space id: %w", err)
|
||||
}
|
||||
rid.OpaqueId = rid.GetSpaceId()
|
||||
return a.storeActivity(storagespace.FormatResourceID(&rid), eventID, 0, timestamp)
|
||||
return a.storeActivity(storagespace.FormatResourceID(&rid), []RawActivity{
|
||||
{
|
||||
EventID: eventID,
|
||||
Depth: 0,
|
||||
Timestamp: timestamp,
|
||||
},
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
@@ -234,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
|
||||
@@ -249,91 +404,214 @@ 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 := 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(initRef *provider.Reference, 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 (
|
||||
info *provider.ResourceInfo
|
||||
err error
|
||||
depth int
|
||||
ref = initRef
|
||||
)
|
||||
ctx, span := a.tracer.Start(ctx, "addActivity")
|
||||
defer span.End()
|
||||
for {
|
||||
info, err = getResource(ref)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not get resource info: %w", err)
|
||||
var info *provider.ResourceInfo
|
||||
id := ref.GetResourceId()
|
||||
if ref.Path != "" {
|
||||
// Path based reference, we need to resolve the resource id
|
||||
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)
|
||||
}
|
||||
id = info.GetId()
|
||||
}
|
||||
if id == nil {
|
||||
return fmt.Errorf("resource id is required")
|
||||
}
|
||||
|
||||
if err := a.storeActivity(storagespace.FormatResourceID(info.GetId()), eventID, depth, timestamp); err != nil {
|
||||
return fmt.Errorf("could not store activity: %w", err)
|
||||
key := storagespace.FormatResourceID(id)
|
||||
a.debouncer.Debounce(key, RawActivity{
|
||||
EventID: eventID,
|
||||
Depth: depth,
|
||||
Timestamp: timestamp,
|
||||
})
|
||||
|
||||
if id.OpaqueId == id.SpaceId {
|
||||
// we are at the root of the space, no need to go further
|
||||
break
|
||||
}
|
||||
|
||||
if info != nil && utils.IsSpaceRoot(info) {
|
||||
return nil
|
||||
// check if parent id is cached
|
||||
// parent id is cached in the format <storageid>$<spaceid>!<resourceid>
|
||||
// if it is not cached, get the resource info and cache it
|
||||
if parentId == nil {
|
||||
if v, err := a.parentIdCache.Get(key); err != nil {
|
||||
if info == nil {
|
||||
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)
|
||||
}
|
||||
}
|
||||
parentId = info.GetParentId()
|
||||
a.parentIdCache.Set(key, parentId)
|
||||
} else {
|
||||
parentId = v.(*provider.ResourceId)
|
||||
}
|
||||
} else {
|
||||
a.log.Debug().Msg("parent id is cached")
|
||||
}
|
||||
|
||||
depth++
|
||||
ref = &provider.Reference{ResourceId: info.GetParentId()}
|
||||
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, eventID string, depth int, timestamp time.Time) error {
|
||||
func (a *ActivitylogService) storeActivity(resourceID string, activities []RawActivity) error {
|
||||
a.lock.Lock()
|
||||
defer a.lock.Unlock()
|
||||
|
||||
records, err := a.store.Read(resourceID)
|
||||
if err != nil && err != microstore.ErrNotFound {
|
||||
return err
|
||||
}
|
||||
ctx, span := a.tracer.Start(context.Background(), "storeActivity")
|
||||
defer span.End()
|
||||
|
||||
var activities []RawActivity
|
||||
if len(records) > 0 {
|
||||
if err := json.Unmarshal(records[0].Value, &activities); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if l := len(activities); l >= _maxActivities {
|
||||
activities = activities[l-_maxActivities+1:]
|
||||
}
|
||||
|
||||
activities = append(activities, RawActivity{
|
||||
EventID: eventID,
|
||||
Depth: depth,
|
||||
Timestamp: timestamp,
|
||||
})
|
||||
|
||||
b, err := json.Marshal(activities)
|
||||
_, 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 {
|
||||
@@ -347,3 +625,37 @@ func toSpace(r *provider.Reference) *provider.StorageSpaceId {
|
||||
OpaqueId: storagespace.FormatStorageID(r.GetResourceId().GetStorageId(), r.GetResourceId().GetSpaceId()),
|
||||
}
|
||||
}
|
||||
|
||||
func (a *ActivitylogService) removeCachedParentID(ref *provider.Reference) {
|
||||
purgeId := ref.GetResourceId()
|
||||
if ref.GetPath() != "" {
|
||||
gwc, err := a.gws.Next()
|
||||
if err != nil {
|
||||
a.log.Error().Err(err).Msg("could not get gateway client")
|
||||
return
|
||||
}
|
||||
|
||||
ctx, err := utils.GetServiceUserContext(a.cfg.ServiceAccount.ServiceAccountID, gwc, a.cfg.ServiceAccount.ServiceAccountSecret)
|
||||
if err != nil {
|
||||
a.log.Error().Err(err).Msg("could not get service user context")
|
||||
return
|
||||
}
|
||||
|
||||
info, err := utils.GetResource(ctx, ref, gwc)
|
||||
if err != nil {
|
||||
a.log.Error().Err(err).Msg("could not get resource info")
|
||||
return
|
||||
}
|
||||
purgeId = info.GetId()
|
||||
}
|
||||
if err := a.parentIdCache.Remove(storagespace.FormatResourceID(purgeId)); err != nil {
|
||||
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())
|
||||
}
|
||||
|
||||
13
services/activitylog/pkg/service/service_suite_test.go
Normal file
13
services/activitylog/pkg/service/service_suite_test.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package service_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
func TestService(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "Service Suite")
|
||||
}
|
||||
@@ -1,148 +1,273 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"context"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/store"
|
||||
"github.com/stretchr/testify/require"
|
||||
"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/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"
|
||||
)
|
||||
|
||||
func TestAddActivity(t *testing.T) {
|
||||
testCases := []struct {
|
||||
Name string
|
||||
Tree map[string]*provider.ResourceInfo
|
||||
Activities map[string]string
|
||||
Expected map[string][]RawActivity
|
||||
}{
|
||||
{
|
||||
Name: "simple",
|
||||
Tree: map[string]*provider.ResourceInfo{
|
||||
"base": resourceInfo("base", "parent"),
|
||||
"parent": resourceInfo("parent", "spaceid"),
|
||||
"spaceid": resourceInfo("spaceid", "spaceid"),
|
||||
},
|
||||
Activities: map[string]string{
|
||||
"activity": "base",
|
||||
},
|
||||
Expected: map[string][]RawActivity{
|
||||
"base": activitites("activity", 0),
|
||||
"parent": activitites("activity", 1),
|
||||
"spaceid": activitites("activity", 2),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "two activities on same resource",
|
||||
Tree: map[string]*provider.ResourceInfo{
|
||||
"base": resourceInfo("base", "parent"),
|
||||
"parent": resourceInfo("parent", "spaceid"),
|
||||
"spaceid": resourceInfo("spaceid", "spaceid"),
|
||||
},
|
||||
Activities: map[string]string{
|
||||
"activity1": "base",
|
||||
"activity2": "base",
|
||||
},
|
||||
Expected: map[string][]RawActivity{
|
||||
"base": activitites("activity1", 0, "activity2", 0),
|
||||
"parent": activitites("activity1", 1, "activity2", 1),
|
||||
"spaceid": activitites("activity1", 2, "activity2", 2),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "two activities on different resources",
|
||||
Tree: map[string]*provider.ResourceInfo{
|
||||
"base1": resourceInfo("base1", "parent"),
|
||||
"base2": resourceInfo("base2", "parent"),
|
||||
"parent": resourceInfo("parent", "spaceid"),
|
||||
"spaceid": resourceInfo("spaceid", "spaceid"),
|
||||
},
|
||||
Activities: map[string]string{
|
||||
"activity1": "base1",
|
||||
"activity2": "base2",
|
||||
},
|
||||
Expected: map[string][]RawActivity{
|
||||
"base1": activitites("activity1", 0),
|
||||
"base2": activitites("activity2", 0),
|
||||
"parent": activitites("activity1", 1, "activity2", 1),
|
||||
"spaceid": activitites("activity1", 2, "activity2", 2),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "more elaborate resource tree",
|
||||
Tree: map[string]*provider.ResourceInfo{
|
||||
"base1": resourceInfo("base1", "parent1"),
|
||||
"base2": resourceInfo("base2", "parent1"),
|
||||
"parent1": resourceInfo("parent1", "spaceid"),
|
||||
"base3": resourceInfo("base3", "parent2"),
|
||||
"parent2": resourceInfo("parent2", "spaceid"),
|
||||
"spaceid": resourceInfo("spaceid", "spaceid"),
|
||||
},
|
||||
Activities: map[string]string{
|
||||
"activity1": "base1",
|
||||
"activity2": "base2",
|
||||
"activity3": "base3",
|
||||
},
|
||||
Expected: map[string][]RawActivity{
|
||||
"base1": activitites("activity1", 0),
|
||||
"base2": activitites("activity2", 0),
|
||||
"base3": activitites("activity3", 0),
|
||||
"parent1": activitites("activity1", 1, "activity2", 1),
|
||||
"parent2": activitites("activity3", 1),
|
||||
"spaceid": activitites("activity1", 2, "activity2", 2, "activity3", 2),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "different depths within one resource",
|
||||
Tree: map[string]*provider.ResourceInfo{
|
||||
"base1": resourceInfo("base1", "parent1"),
|
||||
"parent1": resourceInfo("parent1", "parent2"),
|
||||
"base2": resourceInfo("base2", "parent2"),
|
||||
"parent2": resourceInfo("parent2", "parent3"),
|
||||
"base3": resourceInfo("base3", "parent3"),
|
||||
"parent3": resourceInfo("parent3", "spaceid"),
|
||||
"spaceid": resourceInfo("spaceid", "spaceid"),
|
||||
},
|
||||
Activities: map[string]string{
|
||||
"activity1": "base1",
|
||||
"activity2": "base2",
|
||||
"activity3": "base3",
|
||||
"activity4": "parent2",
|
||||
},
|
||||
Expected: map[string][]RawActivity{
|
||||
"base1": activitites("activity1", 0),
|
||||
"base2": activitites("activity2", 0),
|
||||
"base3": activitites("activity3", 0),
|
||||
"parent1": activitites("activity1", 1),
|
||||
"parent2": activitites("activity1", 2, "activity2", 1, "activity4", 0),
|
||||
"parent3": activitites("activity1", 3, "activity2", 2, "activity3", 1, "activity4", 1),
|
||||
"spaceid": activitites("activity1", 4, "activity2", 3, "activity3", 2, "activity4", 2),
|
||||
},
|
||||
},
|
||||
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
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
alog := &ActivitylogService{
|
||||
store: store.Create(),
|
||||
}
|
||||
|
||||
getResource := func(ref *provider.Reference) (*provider.ResourceInfo, error) {
|
||||
return tc.Tree[ref.GetResourceId().GetOpaqueId()], nil
|
||||
}
|
||||
|
||||
for k, v := range tc.Activities {
|
||||
err := alog.addActivity(reference(v), k, time.Time{}, getResource)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
for id, acts := range tc.Expected {
|
||||
activities, err := alog.Activities(resourceID(id))
|
||||
require.NoError(t, err, tc.Name+":"+id)
|
||||
require.ElementsMatch(t, acts, activities, tc.Name+":"+id)
|
||||
}
|
||||
}
|
||||
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(_ 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() {
|
||||
writebufferduration = 0
|
||||
})
|
||||
|
||||
Describe("AddActivity", func() {
|
||||
type testCase struct {
|
||||
Name string
|
||||
Tree map[string]*provider.ResourceInfo
|
||||
Activities map[string]string
|
||||
Expected map[string][]RawActivity
|
||||
}
|
||||
|
||||
testCases := []testCase{
|
||||
{
|
||||
Name: "simple",
|
||||
Tree: map[string]*provider.ResourceInfo{
|
||||
"base": resourceInfo("base", "parent"),
|
||||
"parent": resourceInfo("parent", "spaceid"),
|
||||
"spaceid": resourceInfo("spaceid", "spaceid"),
|
||||
},
|
||||
Activities: map[string]string{
|
||||
"activity": "base",
|
||||
},
|
||||
Expected: map[string][]RawActivity{
|
||||
"base": activitites("activity", 0),
|
||||
"parent": activitites("activity", 1),
|
||||
"spaceid": activitites("activity", 2),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "two activities on same resource",
|
||||
Tree: map[string]*provider.ResourceInfo{
|
||||
"base": resourceInfo("base", "parent"),
|
||||
"parent": resourceInfo("parent", "spaceid"),
|
||||
"spaceid": resourceInfo("spaceid", "spaceid"),
|
||||
},
|
||||
Activities: map[string]string{
|
||||
"activity1": "base",
|
||||
"activity2": "base",
|
||||
},
|
||||
Expected: map[string][]RawActivity{
|
||||
"base": activitites("activity1", 0, "activity2", 0),
|
||||
"parent": activitites("activity1", 1, "activity2", 1),
|
||||
"spaceid": activitites("activity1", 2, "activity2", 2),
|
||||
},
|
||||
},
|
||||
// Add other test cases here...
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tc := tc // capture range variable
|
||||
Context(tc.Name, func() {
|
||||
JustBeforeEach(func() {
|
||||
getResource = func(_ context.Context, ref *provider.Reference) (*provider.ResourceInfo, error) {
|
||||
return tc.Tree[ref.GetResourceId().GetOpaqueId()], nil
|
||||
}
|
||||
|
||||
for k, v := range tc.Activities {
|
||||
err := alog.addActivity(context.Background(), reference(v), nil, k, time.Time{}, getResource)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
}
|
||||
})
|
||||
|
||||
It("should match the expected activities", func() {
|
||||
for id, acts := range tc.Expected {
|
||||
activities, err := alog.Activities(resourceID(id))
|
||||
Expect(err).NotTo(HaveOccurred(), tc.Name+":"+id)
|
||||
Expect(activities).To(ConsistOf(acts), tc.Name+":"+id)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
Context("with a debouncing debouncer", func() {
|
||||
var (
|
||||
tree = map[string]*provider.ResourceInfo{
|
||||
"base": resourceInfo("base", "parent"),
|
||||
"parent": resourceInfo("parent", "spaceid"),
|
||||
"spaceid": resourceInfo("spaceid", "spaceid"),
|
||||
}
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
writebufferduration = 100 * time.Millisecond
|
||||
})
|
||||
|
||||
Describe("addActivity", func() {
|
||||
var (
|
||||
getResource = func(_ context.Context, ref *provider.Reference) (*provider.ResourceInfo, error) {
|
||||
return tree[ref.GetResourceId().GetOpaqueId()], nil
|
||||
}
|
||||
)
|
||||
|
||||
It("debounces activities", func() {
|
||||
|
||||
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())
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
func activitites(acts ...interface{}) []RawActivity {
|
||||
var activities []RawActivity
|
||||
act := RawActivity{}
|
||||
|
||||
@@ -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})
|
||||
|
||||
@@ -278,7 +278,7 @@ func (a *AuthAppService) authenticateUser(userID, userName string, gwc gateway.G
|
||||
|
||||
func getContext(r *http.Request) context.Context {
|
||||
ctx := r.Context()
|
||||
return metadata.AppendToOutgoingContext(ctx, ctxpkg.TokenHeader, r.Header.Get("X-Access-Token"))
|
||||
return metadata.AppendToOutgoingContext(ctx, ctxpkg.TokenHeader, r.Header.Get(ctxpkg.TokenHeader))
|
||||
}
|
||||
|
||||
func buildClientID(userID, userName string) string {
|
||||
|
||||
@@ -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:
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
collaborationv1beta1 "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1"
|
||||
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
|
||||
@@ -5,10 +5,12 @@ package mocks
|
||||
import (
|
||||
context "context"
|
||||
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
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
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
|
||||
"github.com/go-chi/chi/v5/middleware"
|
||||
"github.com/go-chi/render"
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
)
|
||||
|
||||
// Error defines a custom error struct, containing and MS Graph error code and a textual error message
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"github.com/CiscoM31/godata"
|
||||
cs3group "github.com/cs3org/go-cs3apis/cs3/identity/group/v1beta1"
|
||||
cs3user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/errorcode"
|
||||
)
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/errorcode"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
|
||||
revautils "github.com/opencloud-eu/reva/v2/pkg/utils"
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
)
|
||||
|
||||
// IdentityCache implements a simple ttl based cache for looking up users and groups by ID
|
||||
|
||||
@@ -13,8 +13,9 @@ 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/owncloud/libre-graph-api-go"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package identity
|
||||
import (
|
||||
"context"
|
||||
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
)
|
||||
|
||||
// ErrEducationBackend is a dummy EducationBackend, doing nothing
|
||||
|
||||
@@ -14,11 +14,12 @@ import (
|
||||
"github.com/go-ldap/ldap/v3"
|
||||
"github.com/google/uuid"
|
||||
"github.com/libregraph/idm/pkg/ldapdn"
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
|
||||
"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"))
|
||||
}
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"github.com/go-ldap/ldap/v3"
|
||||
"github.com/libregraph/idm/pkg/ldapdn"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/errorcode"
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
)
|
||||
|
||||
type educationClassAttributeMap struct {
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
"github.com/go-ldap/ldap/v3"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/identity/mocks"
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
@@ -11,7 +11,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"
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
)
|
||||
|
||||
type educationConfig struct {
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"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/identity/mocks"
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/go-ldap/ldap/v3"
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/errorcode"
|
||||
)
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
"github.com/go-ldap/ldap/v3"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/identity/mocks"
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
@@ -12,9 +12,10 @@ import (
|
||||
"github.com/go-ldap/ldap/v3"
|
||||
"github.com/gofrs/uuid"
|
||||
"github.com/libregraph/idm/pkg/ldapdn"
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
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
|
||||
}
|
||||
|
||||
@@ -12,7 +12,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/identity/mocks"
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
godata "github.com/CiscoM31/godata"
|
||||
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ package mocks
|
||||
import (
|
||||
context "context"
|
||||
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
linkv1beta1 "github.com/cs3org/go-cs3apis/cs3/sharing/link/v1beta1"
|
||||
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/utils/grants"
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/unifiedrole"
|
||||
)
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/linktype"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/utils/grants"
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
)
|
||||
|
||||
var _ = Describe("LinktypeFromPermission", func() {
|
||||
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
opkgm "github.com/opencloud-eu/opencloud/pkg/middleware"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/errorcode"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/auth/scope"
|
||||
ctxpkg "github.com/opencloud-eu/reva/v2/pkg/ctx"
|
||||
revactx "github.com/opencloud-eu/reva/v2/pkg/ctx"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/token/manager/jwt"
|
||||
)
|
||||
@@ -43,7 +42,7 @@ func Auth(opts ...account.Option) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
t := r.Header.Get("x-access-token")
|
||||
t := r.Header.Get(revactx.TokenHeader)
|
||||
if t == "" {
|
||||
errorcode.InvalidAuthenticationToken.Render(w, r, http.StatusUnauthorized, "Access token is empty.")
|
||||
/* msgraph error for GET https://graph.microsoft.com/v1.0/me
|
||||
@@ -84,10 +83,10 @@ func Auth(opts ...account.Option) func(http.Handler) http.Handler {
|
||||
}
|
||||
ctx = metadata.AppendToOutgoingContext(ctx, revactx.TokenHeader, t)
|
||||
|
||||
initiatorID := r.Header.Get(ctxpkg.InitiatorHeader)
|
||||
initiatorID := r.Header.Get(revactx.InitiatorHeader)
|
||||
if initiatorID != "" {
|
||||
ctx = ctxpkg.ContextSetInitiator(ctx, initiatorID)
|
||||
ctx = metadata.AppendToOutgoingContext(ctx, ctxpkg.InitiatorHeader, initiatorID)
|
||||
ctx = revactx.ContextSetInitiator(ctx, initiatorID)
|
||||
ctx = metadata.AppendToOutgoingContext(ctx, revactx.InitiatorHeader, initiatorID)
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
|
||||
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"
|
||||
@@ -18,7 +20,7 @@ import (
|
||||
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-chi/render"
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
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/publicshare"
|
||||
@@ -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)
|
||||
|
||||
@@ -17,7 +17,7 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/linktype"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storagespace"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/utils"
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
)
|
||||
|
||||
func (s DriveItemPermissionsService) CreateLink(ctx context.Context, driveItemID *storageprovider.ResourceId, createLink libregraph.DriveItemCreateLink) (libregraph.Permission, error) {
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/status"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/utils"
|
||||
cs3mocks "github.com/opencloud-eu/reva/v2/tests/cs3mocks/mocks"
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
"github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@ 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/opencloud/services/graph/pkg/config"
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
"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()
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
|
||||
storageprovider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
"github.com/go-chi/render"
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
"google.golang.org/protobuf/types/known/fieldmaskpb"
|
||||
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
"github.com/go-chi/chi/v5"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/tidwall/gjson"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
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)
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"github.com/go-chi/render"
|
||||
settingssvc "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/services/settings/v0"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/errorcode"
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
)
|
||||
|
||||
// ListApplications implements the Service interface.
|
||||
|
||||
@@ -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/owncloud/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() {
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
revactx "github.com/opencloud-eu/reva/v2/pkg/ctx"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/events"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/utils"
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
merrors "go-micro.dev/v4/errors"
|
||||
)
|
||||
|
||||
|
||||
@@ -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/owncloud/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() {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user