Merge branch 'master' into no-additional-init

This commit is contained in:
A.Unger
2021-07-02 13:25:30 +02:00
662 changed files with 43301 additions and 29594 deletions
+21 -210
View File
@@ -1,177 +1,39 @@
SHELL := bash
NAME := settings
IMPORT := github.com/owncloud/ocis/$(NAME)
BIN := bin
DIST := dist
PROTO_VERSION := v0
PROTO_SRC := pkg/proto/$(PROTO_VERSION)
ifeq ($(OS), Windows_NT)
EXECUTABLE := $(NAME).exe
UNAME := Windows
else
EXECUTABLE := $(NAME)
UNAME := $(shell uname -s)
endif
ifeq ($(UNAME), Darwin)
GOBUILD ?= go build -i
else
GOBUILD ?= go build
endif
PACKAGES ?= $(shell go list ./...)
SOURCES ?= $(shell find . -name "*.go" -type f -not -path "./node_modules/*")
GENERATE ?= $(PACKAGES)
FEATURE_PATH ?= "ui/tests/acceptance/features"
TAGS ?=
ifndef GOPATH
export GOPATH := $(shell go env GOPATH)
endif
export PATH := $(PATH):$(GOPATH)/bin
ifndef OUTPUT
ifneq ($(DRONE_TAG),)
OUTPUT ?= $(subst v,,$(DRONE_TAG))
else
OUTPUT ?= testing
endif
endif
ifndef VERSION
ifneq ($(DRONE_TAG),)
VERSION ?= $(subst v,,$(DRONE_TAG))
else
VERSION ?= $(shell git rev-parse --short HEAD)
endif
endif
ifndef DATE
DATE := $(shell date -u '+%Y%m%d')
endif
LDFLAGS += -s -w -X "$(IMPORT)/pkg/version.String=$(VERSION)" -X "$(IMPORT)/pkg/version.Date=$(DATE)"
DEBUG_LDFLAGS += -X "$(IMPORT)/pkg/version.String=$(VERSION)" -X "$(IMPORT)/pkg/version.Date=$(DATE)"
GCFLAGS += all=-N -l
.PHONY: all
all: build
.PHONY: sync
sync:
go mod download
.PHONY: clean
clean:
go clean -i ./...
rm -rf $(BIN) $(DIST)
.PHONY: go-mod-tidy
go-mod-tidy:
@go mod tidy
.PHONY: fmt
fmt:
gofmt -s -w $(SOURCES)
.PHONY: vet
vet:
go vet $(PACKAGES)
.PHONY: staticcheck
staticcheck:
go run honnef.co/go/tools/cmd/staticcheck -tags '$(TAGS)' $(PACKAGES)
.PHONY: lint
lint:
for PKG in $(PACKAGES); do go run golang.org/x/lint/golint -set_exit_status $$PKG || exit 1; done;
.PHONY: changelog
changelog:
go run github.com/restic/calens >| CHANGELOG.md
.PHONY: test
test:
go run github.com/haya14busa/goverage -v -coverprofile coverage.out $(PACKAGES)
.PHONY: go-coverage
go-coverage:
@if [ ! -f coverage.out ]; then $(MAKE) test &>/dev/null; fi;
@go tool cover -func coverage.out | tail -1 | grep -Eo "[0-9]+\.[0-9]+"
.PHONY: install
install: $(SOURCES)
go install -v -tags '$(TAGS)' -ldflags '$(LDFLAGS)' ./cmd/$(NAME)
.PHONY: build
build: $(BIN)/$(EXECUTABLE) $(BIN)/$(EXECUTABLE)-debug
$(BIN)/$(EXECUTABLE): $(SOURCES)
$(GOBUILD) -v -tags '$(TAGS)' -ldflags '$(LDFLAGS)' -o $@ ./cmd/$(NAME)
$(BIN)/$(EXECUTABLE)-debug: $(SOURCES)
$(GOBUILD) -v -tags '$(TAGS)' -ldflags '$(DEBUG_LDFLAGS)' -gcflags '$(GCFLAGS)' -o $@ ./cmd/$(NAME)
.PHONY: release
release: release-dirs release-linux release-windows release-darwin release-copy release-check
.PHONY: release-dirs
release-dirs:
mkdir -p $(DIST)/binaries $(DIST)/release
.PHONY: release-linux
release-linux: release-dirs
go run github.com/mitchellh/gox -tags 'netgo $(TAGS)' -ldflags '-extldflags "-static" $(LDFLAGS)' -os 'linux' -arch 'amd64 386 arm64 arm' -output '$(DIST)/binaries/$(EXECUTABLE)-$(OUTPUT)-{{.OS}}-{{.Arch}}' ./cmd/$(NAME)
.PHONY: release-windows
release-windows: release-dirs
go run github.com/mitchellh/gox -tags 'netgo $(TAGS)' -ldflags '-extldflags "-static" $(LDFLAGS)' -os 'windows' -arch 'amd64' -output '$(DIST)/binaries/$(EXECUTABLE)-$(OUTPUT)-{{.OS}}-{{.Arch}}' ./cmd/$(NAME)
.PHONY: release-darwin
release-darwin: release-dirs
go run github.com/mitchellh/gox -tags 'netgo $(TAGS)' -ldflags '$(LDFLAGS)' -os 'darwin' -arch 'amd64' -output '$(DIST)/binaries/$(EXECUTABLE)-$(OUTPUT)-{{.OS}}-{{.Arch}}' ./cmd/$(NAME)
.PHONY: release-copy
release-copy:
$(foreach file,$(wildcard $(DIST)/binaries/$(EXECUTABLE)-*),cp $(file) $(DIST)/release/$(notdir $(file));)
.PHONY: release-check
release-check:
cd $(DIST)/release; $(foreach file,$(wildcard $(DIST)/release/$(EXECUTABLE)-*),sha256sum $(notdir $(file)) > $(notdir $(file)).sha256;)
.PHONY: release-finish
release-finish: release-copy release-check
.PHONY: test-acceptance-webui
test-acceptance-webui:
./ui/tests/run-acceptance-test.sh $(FEATURE_PATH)
.PHONY: watch
watch:
go run github.com/cespare/reflex -c reflex.conf
############ tooling ############
ifneq (, $(shell which go 2> /dev/null)) # supress `command not found warnings` for non go targets in CI
include ../.bingo/Variables.mk
endif
############ go tooling ############
include ../.make/go.mk
############ release ############
include ../.make/release.mk
############ docs generate ############
include ../.make/docs.mk
############ l10n ############
include ../.make/l10n.mk
.PHONY: docs-generate
docs-generate: config-docs-generate \
grpc-docs-generate
.PHONY: config-docs-generate
config-docs-generate:
go run github.com/owncloud/flaex >| ../docs/extensions/$(NAME)/configuration.md
.PHONY: grpc-docs-generate
grpc-docs-generate: ../docs/extensions/${NAME}/grpc.md
############ generate ############
.PHONY: generate
generate: ci-node-generate ci-go-generate
include ../.make/generate.mk
.PHONY: ci-go-generate
ci-go-generate: protobuf # CI runs ci-node-generate automatically before this target
go generate $(GENERATE)
@go generate $(GENERATE)
.PHONY: ci-node-generate
ci-node-generate: yarn-build
@@ -187,61 +49,10 @@ node_modules:
yarn install --frozen-lockfile
############ protobuf ############
$(GOPATH)/bin/protoc-gen-go:
go get -v google.golang.org/protobuf/cmd/protoc-gen-go@v1.25.0
PROTO_VERSION := v0
PROTO_SRC := pkg/proto/$(PROTO_VERSION)
$(GOPATH)/bin/protoc-gen-micro:
GO111MODULE=on go get -v github.com/asim/go-micro/cmd/protoc-gen-micro/v3
$(GOPATH)/bin/protoc-gen-microweb:
GO111MODULE=off go get -v github.com/owncloud/protoc-gen-microweb
$(GOPATH)/bin/protoc-gen-openapiv2:
GO111MODULE=off go get -v github.com/grpc-ecosystem/grpc-gateway/protoc-gen-openapiv2
$(GOPATH)/bin/protoc-gen-doc:
GO111MODULE=off go get -v github.com/pseudomuto/protoc-gen-doc/cmd/protoc-gen-doc
.PHONY: $(PROTO_SRC)/${NAME}.pb.go
$(PROTO_SRC)/${NAME}.pb.go: $(GOPATH)/bin/protoc-gen-openapiv2 $(GOPATH)/bin/protoc-gen-go
protoc \
-I=../third_party/ \
-I=$(PROTO_SRC)/ \
-I=$(GOPATH)/src/github.com/grpc-ecosystem/grpc-gateway/ \
--go_out=. ${NAME}.proto
.PHONY: $(PROTO_SRC)/${NAME}.pb.micro.go
$(PROTO_SRC)/${NAME}.pb.micro.go: $(GOPATH)/bin/protoc-gen-openapiv2 $(GOPATH)/bin/protoc-gen-micro
protoc \
-I=../third_party/ \
-I=$(PROTO_SRC)/ \
-I=$(GOPATH)/src/github.com/grpc-ecosystem/grpc-gateway/ \
--micro_out=. ${NAME}.proto
.PHONY: $(PROTO_SRC)/${NAME}.pb.web.go
$(PROTO_SRC)/${NAME}.pb.web.go: $(GOPATH)/bin/protoc-gen-openapiv2 $(GOPATH)/bin/protoc-gen-microweb
protoc \
-I=../third_party/ \
-I=$(PROTO_SRC)/ \
-I=$(GOPATH)/src/github.com/grpc-ecosystem/grpc-gateway/ \
--microweb_out=. ${NAME}.proto
.PHONY: $(PROTO_SRC)/${NAME}.swagger.json
$(PROTO_SRC)/${NAME}.swagger.json: $(GOPATH)/bin/protoc-gen-openapiv2
protoc \
-I=../third_party/ \
-I=$(PROTO_SRC)/ \
-I=$(GOPATH)/src/github.com/grpc-ecosystem/grpc-gateway/ \
--openapiv2_out=$(PROTO_SRC)/ ${NAME}.proto
.PHONY: ../docs/extensions/${NAME}/grpc.md
../docs/extensions/${NAME}/grpc.md: $(GOPATH)/bin/protoc-gen-openapiv2 $(GOPATH)/bin/protoc-gen-doc
protoc \
-I=../third_party/ \
-I=$(PROTO_SRC)/ \
-I=$(GOPATH)/src/github.com/grpc-ecosystem/grpc-gateway/ \
--doc_opt=./templates/GRPC.tmpl,grpc.md \
--doc_out=../docs/extensions/${NAME} $(PROTO_SRC)/${NAME}.proto
include ../.make/protobuf.mk
.PHONY: protobuf
protobuf: $(PROTO_SRC)/${NAME}.pb.go \
+2 -1
View File
@@ -4,10 +4,11 @@ import (
"os"
"github.com/owncloud/ocis/settings/pkg/command"
"github.com/owncloud/ocis/settings/pkg/config"
)
func main() {
if err := command.Execute(); err != nil {
if err := command.Execute(config.New()); err != nil {
os.Exit(1)
}
}
+13 -23
View File
@@ -1,48 +1,38 @@
module github.com/owncloud/ocis/settings
go 1.15
go 1.16
require (
contrib.go.opencensus.io/exporter/jaeger v0.2.1
contrib.go.opencensus.io/exporter/ocagent v0.6.0
contrib.go.opencensus.io/exporter/zipkin v0.1.1
github.com/Masterminds/sprig/v3 v3.2.2 // indirect
github.com/UnnoTed/fileb0x v1.1.4
contrib.go.opencensus.io/exporter/ocagent v0.7.0
contrib.go.opencensus.io/exporter/zipkin v0.1.2
github.com/asim/go-micro/v3 v3.5.1-0.20210217182006-0f0ace1a44a9
github.com/go-chi/chi v4.1.2+incompatible
github.com/go-chi/render v1.0.1
github.com/go-ozzo/ozzo-validation/v4 v4.2.1
github.com/gofrs/uuid v3.3.0+incompatible
github.com/golang/protobuf v1.4.3
github.com/golang/protobuf v1.5.2
github.com/grpc-ecosystem/grpc-gateway/v2 v2.2.0
github.com/huandu/xstrings v1.3.2 // indirect
github.com/micro/cli/v2 v2.1.2
github.com/mitchellh/copystructure v1.1.1 // indirect
github.com/mitchellh/gox v1.0.1
github.com/oklog/run v1.1.0
github.com/olekukonko/tablewriter v0.0.4
github.com/openzipkin/zipkin-go v0.2.2
github.com/olekukonko/tablewriter v0.0.5
github.com/openzipkin/zipkin-go v0.2.5
github.com/owncloud/ocis/ocis-pkg v0.0.0-20210216094451-dc73176dc62d
github.com/prometheus/client_golang v1.7.1
github.com/restic/calens v0.2.0
github.com/spf13/viper v1.7.0
github.com/prometheus/client_golang v1.10.0
github.com/spf13/viper v1.7.1
github.com/stretchr/testify v1.7.0
go.opencensus.io v0.22.6
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad // indirect
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5
golang.org/x/mod v0.4.1 // indirect
golang.org/x/net v0.0.0-20201224014010-6772e930b67b
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c // indirect
github.com/thejerf/suture/v4 v4.0.0
go.opencensus.io v0.23.0
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781
google.golang.org/genproto v0.0.0-20210207032614-bba0dbe2a9ea
google.golang.org/protobuf v1.25.0
google.golang.org/protobuf v1.27.0
gotest.tools v2.2.0+incompatible
)
replace (
github.com/owncloud/ocis/ocis-pkg => ../ocis-pkg
github.com/owncloud/ocis/store => ../store
// taken from https://github.com/asim/go-micro/blob/master/plugins/registry/etcd/go.mod#L14-L16
go.etcd.io/etcd/api/v3 => go.etcd.io/etcd/api/v3 v3.0.0-20210204162551-dae29bb719dd
go.etcd.io/etcd/pkg/v3 => go.etcd.io/etcd/pkg/v3 v3.0.0-20210204162551-dae29bb719dd
// latest version compatible with etcd
google.golang.org/grpc => google.golang.org/grpc v1.29.1
)
+551 -188
View File
File diff suppressed because it is too large Load Diff
+9
View File
@@ -0,0 +1,9 @@
[main]
host = https://www.transifex.com
[owncloud.ocis-settings]
file_filter = locale/<lang>/LC_MESSAGES/app.po
minimum_perc = 0
source_file = template.pot
source_lang = en
type = PO
+1
View File
@@ -0,0 +1 @@
{"de":{"{{ bundle.displayName }}":"{{ bundle.displayName }}","Account":"Konto","Cancel":"Abbrechen","Hello":"Hallo","Language":"Sprache","Loading personal settings":"Lade persönliche Einstellungen","Loading personal settings...":"Lade persönliche Einstellungen...","msg":"msg","No settings available":"Keine Einstellungen verfügbar","Save":"Speichern","Settings":"Einstellungen","Settings type not implemented: %{type}":"Einstellungs-Typ nicht verfügbar: %{type}"},"de_DE":{"{{ bundle.displayName }}":"{{ bundle.displayName }}","Account":"Benutzerkonto","Cancel":"Abbrechen","Hello":"Hallo","Language":"Sprache","Loading personal settings":"Lade persönliche Einstellungen","Loading personal settings...":"Lade persönliche Einstellungen...","msg":"msg","No settings available":"Keine Einstellungen verfügbar","Save":"Speichern","Settings":"Einstellungen","Settings type not implemented: %{type}":"Einstellungs-Typ nicht verfügbar: %{type}"},"es":{"{{ bundle.displayName }}":"{{bundle.displayName}}","Account":"Cuenta","Cancel":"Cancelar","Hello":"Hola","Language":"Idioma","Loading personal settings":"Cargando configuraciones personales","Loading personal settings...":"Cargando configuración personal ...","msg":"msg","No settings available":"No hay configuraciones disponibles","Save":"Guardar","Settings":"Configuración","Settings type not implemented: %{type}":"Tipo de configuración no implementado: %{type}"},"pl":{"{{ bundle.displayName }}":"{{ bundle.displayName }}","Account":"Konto","Cancel":"Anuluj","Hello":"Witaj","Language":"Język","Loading personal settings":"Ładowanie ustawień osobistych","Loading personal settings...":"Ładowanie ustawień osobistych...","msg":"wiad","No settings available":"Brak dostępnych ustawień","Save":"Zapisz","Settings":"Ustawienia","Settings type not implemented: %{type}":"Typ ustawień nie jest wdrożony: %{type}"},"pt_BR":{"{{ bundle.displayName }}":"{{ bundle.displayName }}","Account":"Conta","Cancel":"Cancelar","Hello":"Olá","Language":"Idioma","Loading personal settings":"Carregando configurações pessoais ","Loading personal settings...":"Carregando configurações pessoais... ","msg":"msg","No settings available":"Nenhuma configuração disponível ","Save":"Salvar","Settings":"Configurações","Settings type not implemented: %{type}":"Tipo de configuração não implementado: %{type}"},"ru":{"{{ bundle.displayName }}":"{{ bundle.displayName }}","Account":"Уч.запись","Cancel":"Отмена","Hello":"Здравствуйте","Language":"Язык","Loading personal settings":"Загрузка личных настроек","Loading personal settings...":"Загрузка личных настроек…","msg":"сообщ","No settings available":"Нет доступных настроек","Save":"Сохранить","Settings":"Настройки","Settings type not implemented: %{type}":"Тип настроек не реализован: %{type}"},"sq":{"{{ bundle.displayName }}":"{{ bundle.displayName }}","Account":"Llogari","Cancel":"Anuloje","Hello":"Tungjatjeta","Language":"Gjuhë","Loading personal settings":"Ngarkim rregullimesh personale","Loading personal settings...":"Po ngarkohen rregullime personale…","msg":"msz","No settings available":"Ska rregullime","Save":"Ruaje","Settings":"Rregullime","Settings type not implemented: %{type}":"Lloj rregullimi i pasendërtuar: %{type}"},"th_TH":{"{{ bundle.displayName }}":"{{ bundle.displayName }}","Account":"บัญชี","Cancel":"ยกเลิก","Hello":"สวัสดี","Language":"ภาษา","Loading personal settings":"กำลังโหลดการตั้งค่าส่วนบุคคล","Loading personal settings...":"กำลังโหลดการตั้งค่าส่วนบุคคล...","msg":"msg","No settings available":"ไม่มีการตั้งค่า","Save":"บันทึก","Settings":"ตั้งค่า","Settings type not implemented: %{type}":"ประเภทการตั้งค่าที่ยังไม่ถูกดำเนินการ: %{type}"}}
+1 -6
View File
@@ -1,15 +1,10 @@
const path = require('path')
const WEB_PATH = process.env.WEB_PATH
const TEST_INFRA_DIRECTORY = process.env.TEST_INFRA_DIRECTORY
const OCIS_SETTINGS_STORE = process.env.OCIS_SETTINGS_STORE || './ocis-settings-store'
const config = require(path.join(WEB_PATH, 'nightwatch.conf.js'))
config.page_objects_path = [TEST_INFRA_DIRECTORY + '/acceptance/pageObjects', 'ui/tests/acceptance/pageobjects']
config.custom_commands_path = TEST_INFRA_DIRECTORY + '/acceptance/customCommands'
config.test_settings.default.globals = { ...config.test_settings.default.globals, settings_store: OCIS_SETTINGS_STORE }
module.exports = {
...config
}
module.exports = config
+18 -16
View File
@@ -8,7 +8,7 @@
"author": "ownCloud GmbH <devops@owncloud.com>",
"repository": "https://github.com/owncloud/ocis-settings.git",
"bugs": {
"url": "https://github.com/owncloud/ocis/settings/issues",
"url": "https://github.com/owncloud/ocis/issues",
"email": "support@owncloud.com"
},
"scripts": {
@@ -17,46 +17,46 @@
"watch": "rollup -c -w",
"test": "echo 'Not implemented'",
"generate-api": "node node_modules/swagger-vue-generator/bin/generate-api.js --package-version v0 --source pkg/proto/v0/settings.swagger.json --moduleName settings --destination ui/client/settings/index.js",
"acceptance-tests": "cucumber-js --require-module @babel/register --require-module @babel/polyfill --require ${TEST_INFRA_DIRECTORY}/acceptance/setup.js --require ui/tests/acceptance/stepDefinitions --require ${TEST_INFRA_DIRECTORY}/acceptance/stepDefinitions --format node_modules/cucumber-pretty -t \"${TEST_TAGS:-not @skip and not @skipOnOC10}\""
"acceptance-tests": "cucumber-js --retry 1 --require-module @babel/register --require-module @babel/polyfill --require ${TEST_INFRA_DIRECTORY}/acceptance/setup.js --require ui/tests/acceptance/stepDefinitions --require ${TEST_INFRA_DIRECTORY}/acceptance/stepDefinitions --format node_modules/cucumber-pretty -t \"${TEST_TAGS:-not @skip and not @skipOnOC10}\""
},
"devDependencies": {
"@babel/core": "^7.7.7",
"@babel/core": "^7.13.10",
"@babel/plugin-proposal-class-properties": "^7.7.4",
"@babel/plugin-proposal-export-default-from": "^7.7.4",
"@babel/plugin-proposal-object-rest-spread": "^7.7.7",
"@babel/plugin-syntax-dynamic-import": "^7.7.4",
"@babel/plugin-transform-runtime": "^7.8.0",
"@babel/plugin-transform-runtime": "^7.13.10",
"@babel/polyfill": "^7.10.1",
"@babel/preset-env": "^7.7.7",
"@babel/preset-env": "^7.13.12",
"@babel/register": "^7.10.1",
"@erquhart/rollup-plugin-node-builtins": "^2.1.5",
"@rollup/plugin-commonjs": "^17.1.0",
"@rollup/plugin-json": "^4.0.1",
"@rollup/plugin-replace": "^2.3.0",
"archiver": "^5.2.0",
"@rollup/plugin-replace": "^2.4.2",
"archiver": "^5.3.0",
"axios": "^0.21.1",
"core-js": "3",
"core-js": "3.9.1",
"cross-env": "^7.0.3",
"cucumber": "^6.0.5",
"cucumber-pretty": ">=6.0.0",
"debounce": "^1.2.0",
"debounce": "^1.2.1",
"easygettext": "^2.7.0",
"eslint": "7.20.0",
"eslint": "7.22.0",
"eslint-config-standard": "^16.0.2",
"eslint-plugin-import": "^2.17.3",
"eslint-plugin-node": "11.1.0",
"eslint-plugin-promise": "^4.1.1",
"eslint-plugin-standard": "^5.0.0",
"eslint-plugin-vue": "^7.6.0",
"eslint-plugin-vue": "^7.8.0",
"fs-extra": "^9.0.1",
"join-path": "^1.1.1",
"ldap": "^0.7.1",
"nightwatch": "^1.3.6",
"nightwatch": "^1.6.0",
"nightwatch-api": "^3.0.1",
"node-fetch": "^2.6.1",
"qs": "^6.9.1",
"qs": "^6.10.1",
"rimraf": "^3.0.0",
"rollup": "^2.39.0",
"rollup": "^2.42.2",
"rollup-plugin-babel": "^4.3.3",
"rollup-plugin-eslint": "^7.0.0",
"rollup-plugin-filesize": "^9.1.0",
@@ -65,7 +65,7 @@
"rollup-plugin-terser": "^7.0.2",
"rollup-plugin-vue": "^5.1.9",
"swagger-vue-generator": "^1.0.6",
"url-search-params-polyfill": "^8.1.0",
"url-search-params-polyfill": "^8.1.1",
"vue-template-compiler": "^2.6.11",
"xml-js": "^1.6.11"
},
@@ -74,10 +74,12 @@
"not dead"
],
"peerDependencies": {
"owncloud-design-system": "^1.7.0"
"owncloud-design-system": "^7.4.2"
},
"dependencies": {
"ldapjs": "^2.2.4",
"lodash": "^4.17.15",
"nightwatch-vrt": "^0.2.10",
"vuex": "^3.2.0"
}
}
+1 -1
View File
@@ -15,7 +15,7 @@ import (
_ "golang.org/x/net/webdav"
)
//go:generate go run github.com/UnnoTed/fileb0x embed.yml
//go:generate make -C ../.. embed.yml
// assets gets initialized by New and provides the handler.
type assets struct {
File diff suppressed because one or more lines are too long
+34 -3
View File
@@ -1,21 +1,24 @@
package command
import (
"context"
"os"
"strings"
"github.com/owncloud/ocis/ocis-pkg/sync"
"github.com/micro/cli/v2"
ociscfg "github.com/owncloud/ocis/ocis-pkg/config"
"github.com/owncloud/ocis/ocis-pkg/log"
"github.com/owncloud/ocis/settings/pkg/config"
"github.com/owncloud/ocis/settings/pkg/flagset"
"github.com/owncloud/ocis/settings/pkg/version"
"github.com/spf13/viper"
"github.com/thejerf/suture/v4"
)
// Execute is the entry point for the ocis-settings command.
func Execute() error {
cfg := config.New()
func Execute(cfg *config.Config) error {
app := &cli.App{
Name: "ocis-settings",
Version: version.String,
@@ -63,11 +66,14 @@ func NewLogger(cfg *config.Config) log.Logger {
log.Level(cfg.Log.Level),
log.Pretty(cfg.Log.Pretty),
log.Color(cfg.Log.Color),
log.File(cfg.Log.File),
)
}
// ParseConfig loads settings configuration from Viper known paths.
func ParseConfig(c *cli.Context, cfg *config.Config) error {
sync.ParsingViperConfig.Lock()
defer sync.ParsingViperConfig.Unlock()
logger := NewLogger(cfg)
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
@@ -108,3 +114,28 @@ func ParseConfig(c *cli.Context, cfg *config.Config) error {
return nil
}
// SutureService allows for the settings command to be embedded and supervised by a suture supervisor tree.
type SutureService struct {
cfg *config.Config
}
// NewSutureService creates a new settings.SutureService
func NewSutureService(cfg *ociscfg.Config) suture.Service {
if cfg.Mode == 0 {
cfg.Settings.Supervised = true
}
cfg.Settings.Log.File = cfg.Log.File
return SutureService{
cfg: cfg.Settings,
}
}
func (s SutureService) Serve(ctx context.Context) error {
s.cfg.Context = ctx
if err := Execute(s.cfg); err != nil {
return err
}
return nil
}
+50 -185
View File
@@ -2,27 +2,18 @@ package command
import (
"context"
"os"
"os/signal"
"strings"
"time"
"github.com/owncloud/ocis/settings/pkg/metrics"
"contrib.go.opencensus.io/exporter/jaeger"
"contrib.go.opencensus.io/exporter/ocagent"
"contrib.go.opencensus.io/exporter/zipkin"
"github.com/micro/cli/v2"
"github.com/oklog/run"
openzipkin "github.com/openzipkin/zipkin-go"
zipkinhttp "github.com/openzipkin/zipkin-go/reporter/http"
"github.com/owncloud/ocis/ocis-pkg/sync"
"github.com/owncloud/ocis/settings/pkg/config"
"github.com/owncloud/ocis/settings/pkg/flagset"
"github.com/owncloud/ocis/settings/pkg/metrics"
"github.com/owncloud/ocis/settings/pkg/server/debug"
"github.com/owncloud/ocis/settings/pkg/server/grpc"
"github.com/owncloud/ocis/settings/pkg/server/http"
"go.opencensus.io/stats/view"
"go.opencensus.io/trace"
"github.com/owncloud/ocis/settings/pkg/tracing"
)
// Server is the entrypoint for the server command.
@@ -32,202 +23,76 @@ func Server(cfg *config.Config) *cli.Command {
Usage: "Start integrated server",
Flags: flagset.ServerWithConfig(cfg),
Before: func(ctx *cli.Context) error {
logger := NewLogger(cfg)
if cfg.HTTP.Root != "/" {
cfg.HTTP.Root = strings.TrimSuffix(cfg.HTTP.Root, "/")
}
// When running on single binary mode the before hook from the root command won't get called. We manually
// call this before hook from ocis command, so the configuration can be loaded.
return ParseConfig(ctx, cfg)
if !cfg.Supervised {
return ParseConfig(ctx, cfg)
}
logger.Debug().Str("service", "settings").Msg("ignoring config file parsing when running supervised")
return nil
},
Action: func(c *cli.Context) error {
logger := NewLogger(cfg)
if cfg.Tracing.Enabled {
switch t := cfg.Tracing.Type; t {
case "agent":
exporter, err := ocagent.NewExporter(
ocagent.WithReconnectionPeriod(5*time.Second),
ocagent.WithAddress(cfg.Tracing.Endpoint),
ocagent.WithServiceName(cfg.Tracing.Service),
)
if err != nil {
logger.Error().
Err(err).
Str("endpoint", cfg.Tracing.Endpoint).
Str("collector", cfg.Tracing.Collector).
Msg("Failed to create agent tracing")
return err
}
trace.RegisterExporter(exporter)
view.RegisterExporter(exporter)
case "jaeger":
exporter, err := jaeger.NewExporter(
jaeger.Options{
AgentEndpoint: cfg.Tracing.Endpoint,
CollectorEndpoint: cfg.Tracing.Collector,
Process: jaeger.Process{
ServiceName: cfg.Tracing.Service,
},
},
)
if err != nil {
logger.Error().
Err(err).
Str("endpoint", cfg.Tracing.Endpoint).
Str("collector", cfg.Tracing.Collector).
Msg("Failed to create jaeger tracing")
return err
}
trace.RegisterExporter(exporter)
case "zipkin":
endpoint, err := openzipkin.NewEndpoint(
cfg.Tracing.Service,
cfg.Tracing.Endpoint,
)
if err != nil {
logger.Error().
Err(err).
Str("endpoint", cfg.Tracing.Endpoint).
Str("collector", cfg.Tracing.Collector).
Msg("Failed to create zipkin tracing")
return err
}
exporter := zipkin.NewExporter(
zipkinhttp.NewReporter(
cfg.Tracing.Collector,
),
endpoint,
)
trace.RegisterExporter(exporter)
default:
logger.Warn().
Str("type", t).
Msg("Unknown tracing backend")
}
trace.ApplyConfig(
trace.Config{
DefaultSampler: trace.AlwaysSample(),
},
)
} else {
logger.Debug().
Msg("Tracing is not enabled")
err := tracing.Configure(cfg, logger)
if err != nil {
return err
}
var (
gr = run.Group{}
ctx, cancel = context.WithCancel(context.Background())
mtrcs = metrics.New()
)
servers := run.Group{}
ctx, cancel := func() (context.Context, context.CancelFunc) {
if cfg.Context == nil {
return context.WithCancel(context.Background())
}
return context.WithCancel(cfg.Context)
}()
defer cancel()
mtrcs := metrics.New()
mtrcs.BuildInfo.WithLabelValues(cfg.Service.Version).Set(1)
{
server := http.Server(
http.Name(cfg.Service.Name),
http.Logger(logger),
http.Context(ctx),
http.Config(cfg),
http.Metrics(mtrcs),
http.Flags(flagset.RootWithConfig(config.New())),
http.Flags(flagset.ServerWithConfig(config.New())),
)
// prepare an HTTP server and add it to the group run.
httpServer := http.Server(
http.Name(cfg.Service.Name),
http.Logger(logger),
http.Context(ctx),
http.Config(cfg),
http.Metrics(mtrcs),
)
servers.Add(httpServer.Run, func(_ error) {
logger.Info().Str("server", "http").Msg("Shutting down server")
cancel()
})
gr.Add(server.Run, func(_ error) {
logger.Info().
Str("server", "http").
Msg("Shutting down server")
// prepare a gRPC server and add it to the group run.
grpcServer := grpc.Server(grpc.Name(cfg.Service.Name), grpc.Logger(logger), grpc.Context(ctx), grpc.Config(cfg), grpc.Metrics(mtrcs))
servers.Add(grpcServer.Run, func(_ error) {
logger.Info().Str("server", "grpc").Msg("Shutting down server")
cancel()
})
cancel()
})
// prepare a debug server and add it to the group run.
debugServer, err := debug.Server(debug.Logger(logger), debug.Context(ctx), debug.Config(cfg))
if err != nil {
logger.Error().Err(err).Str("server", "debug").Msg("Failed to initialize server")
return err
}
{
server := grpc.Server(
grpc.Name(cfg.Service.Name),
grpc.Logger(logger),
grpc.Context(ctx),
grpc.Config(cfg),
grpc.Metrics(mtrcs),
)
servers.Add(debugServer.ListenAndServe, func(_ error) {
_ = debugServer.Shutdown(ctx)
cancel()
})
gr.Add(server.Run, func(_ error) {
logger.Info().
Str("server", "grpc").
Msg("Shutting down server")
cancel()
})
if !cfg.Supervised {
sync.Trap(&servers, cancel)
}
{
server, err := debug.Server(
debug.Logger(logger),
debug.Context(ctx),
debug.Config(cfg),
)
if err != nil {
logger.Error().
Err(err).
Str("server", "debug").
Msg("Failed to initialize server")
return err
}
gr.Add(server.ListenAndServe, func(_ error) {
ctx, timeout := context.WithTimeout(ctx, 5*time.Second)
defer timeout()
defer cancel()
if err := server.Shutdown(ctx); err != nil {
logger.Error().
Err(err).
Str("server", "debug").
Msg("Failed to shutdown server")
} else {
logger.Info().
Str("server", "debug").
Msg("Shutting down server")
}
})
}
{
stop := make(chan os.Signal, 1)
gr.Add(func() error {
signal.Notify(stop, os.Interrupt)
<-stop
return nil
}, func(err error) {
close(stop)
cancel()
})
}
return gr.Run()
return servers.Run()
},
}
}
+6
View File
@@ -1,10 +1,13 @@
package config
import "context"
// Log defines the available logging configuration.
type Log struct {
Level string
Pretty bool
Color bool
File string
}
// Debug defines the available debug configuration.
@@ -66,6 +69,9 @@ type Config struct {
Tracing Tracing
Asset Asset
TokenManager TokenManager
Context context.Context
Supervised bool
}
// New initializes a new configuration with or without defaults.
+27 -25
View File
@@ -2,6 +2,7 @@ package flagset
import (
"github.com/micro/cli/v2"
"github.com/owncloud/ocis/ocis-pkg/flags"
"github.com/owncloud/ocis/settings/pkg/config"
)
@@ -10,23 +11,20 @@ func RootWithConfig(cfg *config.Config) []cli.Flag {
return []cli.Flag{
&cli.StringFlag{
Name: "log-level",
Value: "info",
Usage: "Set logging level",
EnvVars: []string{"SETTINGS_LOG_LEVEL"},
EnvVars: []string{"SETTINGS_LOG_LEVEL", "OCIS_LOG_LEVEL"},
Destination: &cfg.Log.Level,
},
&cli.BoolFlag{
Name: "log-pretty",
Value: true,
Usage: "Enable pretty logging",
EnvVars: []string{"SETTINGS_LOG_PRETTY"},
EnvVars: []string{"SETTINGS_LOG_PRETTY", "OCIS_LOG_PRETTY"},
Destination: &cfg.Log.Pretty,
},
&cli.BoolFlag{
Name: "log-color",
Value: true,
Usage: "Enable colored logging",
EnvVars: []string{"SETTINGS_LOG_COLOR"},
EnvVars: []string{"SETTINGS_LOG_COLOR", "OCIS_LOG_COLOR"},
Destination: &cfg.Log.Color,
},
}
@@ -37,7 +35,7 @@ func HealthWithConfig(cfg *config.Config) []cli.Flag {
return []cli.Flag{
&cli.StringFlag{
Name: "debug-addr",
Value: "0.0.0.0:9194",
Value: flags.OverrideDefaultString(cfg.Debug.Addr, "0.0.0.0:9194"),
Usage: "Address to debug endpoint",
EnvVars: []string{"SETTINGS_DEBUG_ADDR"},
Destination: &cfg.Debug.Addr,
@@ -63,42 +61,42 @@ func ServerWithConfig(cfg *config.Config) []cli.Flag {
},
&cli.StringFlag{
Name: "tracing-type",
Value: "jaeger",
Value: flags.OverrideDefaultString(cfg.Tracing.Type, "jaeger"),
Usage: "Tracing backend type",
EnvVars: []string{"SETTINGS_TRACING_TYPE"},
Destination: &cfg.Tracing.Type,
},
&cli.StringFlag{
Name: "tracing-endpoint",
Value: "",
Value: flags.OverrideDefaultString(cfg.Tracing.Endpoint, ""),
Usage: "Endpoint for the agent",
EnvVars: []string{"SETTINGS_TRACING_ENDPOINT"},
Destination: &cfg.Tracing.Endpoint,
},
&cli.StringFlag{
Name: "tracing-collector",
Value: "",
Value: flags.OverrideDefaultString(cfg.Tracing.Collector, ""),
Usage: "Endpoint for the collector",
EnvVars: []string{"SETTINGS_TRACING_COLLECTOR"},
Destination: &cfg.Tracing.Collector,
},
&cli.StringFlag{
Name: "tracing-service",
Value: "settings",
Value: flags.OverrideDefaultString(cfg.Tracing.Service, "settings"),
Usage: "Service name for tracing",
EnvVars: []string{"SETTINGS_TRACING_SERVICE"},
Destination: &cfg.Tracing.Service,
},
&cli.StringFlag{
Name: "debug-addr",
Value: "0.0.0.0:9194",
Value: flags.OverrideDefaultString(cfg.Debug.Addr, "0.0.0.0:9194"),
Usage: "Address to bind debug server",
EnvVars: []string{"SETTINGS_DEBUG_ADDR"},
Destination: &cfg.Debug.Addr,
},
&cli.StringFlag{
Name: "debug-token",
Value: "",
Value: flags.OverrideDefaultString(cfg.Debug.Token, ""),
Usage: "Token to grant metrics access",
EnvVars: []string{"SETTINGS_DEBUG_TOKEN"},
Destination: &cfg.Debug.Token,
@@ -117,74 +115,78 @@ func ServerWithConfig(cfg *config.Config) []cli.Flag {
},
&cli.StringFlag{
Name: "http-addr",
Value: "0.0.0.0:9190",
Value: flags.OverrideDefaultString(cfg.HTTP.Addr, "0.0.0.0:9190"),
Usage: "Address to bind http server",
EnvVars: []string{"SETTINGS_HTTP_ADDR"},
Destination: &cfg.HTTP.Addr,
},
&cli.StringFlag{
Name: "http-namespace",
Value: "com.owncloud.web",
Value: flags.OverrideDefaultString(cfg.HTTP.Namespace, "com.owncloud.web"),
Usage: "Set the base namespace for the http namespace",
EnvVars: []string{"SETTINGS_HTTP_NAMESPACE"},
Destination: &cfg.HTTP.Namespace,
},
&cli.StringFlag{
Name: "http-root",
Value: "/",
Value: flags.OverrideDefaultString(cfg.HTTP.Root, "/"),
Usage: "Root path of http server",
EnvVars: []string{"SETTINGS_HTTP_ROOT"},
Destination: &cfg.HTTP.Root,
},
&cli.IntFlag{
Name: "http-cache-ttl",
Value: 604800, // 7 days
Value: flags.OverrideDefaultInt(cfg.HTTP.CacheTTL, 604800), // 10 days
Usage: "Set the static assets caching duration in seconds",
EnvVars: []string{"SETTINGS_CACHE_TTL"},
Destination: &cfg.HTTP.CacheTTL,
},
&cli.StringFlag{
Name: "grpc-addr",
Value: "0.0.0.0:9191",
Value: flags.OverrideDefaultString(cfg.GRPC.Addr, "0.0.0.0:9191"),
Usage: "Address to bind grpc server",
EnvVars: []string{"SETTINGS_GRPC_ADDR"},
Destination: &cfg.GRPC.Addr,
},
&cli.StringFlag{
Name: "asset-path",
Value: "",
Value: flags.OverrideDefaultString(cfg.Asset.Path, ""),
Usage: "Path to custom assets",
EnvVars: []string{"SETTINGS_ASSET_PATH"},
Destination: &cfg.Asset.Path,
},
&cli.StringFlag{
Name: "grpc-namespace",
Value: "com.owncloud.api",
Value: flags.OverrideDefaultString(cfg.GRPC.Namespace, "com.owncloud.api"),
Usage: "Set the base namespace for the grpc namespace",
EnvVars: []string{"SETTINGS_GRPC_NAMESPACE"},
Destination: &cfg.GRPC.Namespace,
},
&cli.StringFlag{
Name: "name",
Value: "settings",
Value: flags.OverrideDefaultString(cfg.Service.Name, "settings"),
Usage: "service name",
EnvVars: []string{"SETTINGS_NAME"},
Destination: &cfg.Service.Name,
},
&cli.StringFlag{
Name: "data-path",
Value: "/var/tmp/ocis/settings",
Value: flags.OverrideDefaultString(cfg.Service.DataPath, "/var/tmp/ocis/settings"),
Usage: "Mount path for the storage",
EnvVars: []string{"SETTINGS_DATA_PATH"},
Destination: &cfg.Service.DataPath,
},
&cli.StringFlag{
Name: "jwt-secret",
Value: "Pive-Fumkiu4",
Value: flags.OverrideDefaultString(cfg.TokenManager.JWTSecret, "Pive-Fumkiu4"),
Usage: "Used to create JWT to talk to reva, should equal reva's jwt-secret",
EnvVars: []string{"SETTINGS_JWT_SECRET", "OCIS_JWT_SECRET"},
Destination: &cfg.TokenManager.JWTSecret,
},
&cli.StringFlag{
Name: "extensions",
Usage: "Run specific extensions during supervised mode. This flag is set by the runtime",
},
}
}
@@ -193,14 +195,14 @@ func ListSettingsWithConfig(cfg *config.Config) []cli.Flag {
return []cli.Flag{
&cli.StringFlag{
Name: "grpc-namespace",
Value: "com.owncloud.api",
Value: flags.OverrideDefaultString(cfg.GRPC.Namespace, "com.owncloud.api"),
Usage: "Set the base namespace for the grpc namespace",
EnvVars: []string{"SETTINGS_GRPC_NAMESPACE"},
Destination: &cfg.GRPC.Namespace,
},
&cli.StringFlag{
Name: "name",
Value: "settings",
Value: flags.OverrideDefaultString(cfg.Service.Name, "settings"),
Usage: "service name",
EnvVars: []string{"SETTINGS_NAME"},
Destination: &cfg.Service.Name,
File diff suppressed because it is too large Load Diff
+23 -65
View File
@@ -1005,7 +1005,6 @@ func TestListRolesAfterSavingBundle(t *testing.T) {
name: bundle.Name,
})
}
assert.Equal(t, len(tt.expectedBundles), len(rolesRes.Bundles))
})
}
}
@@ -1267,13 +1266,19 @@ func TestListFilteredBundle(t *testing.T) {
listRes, err := bundleService.ListBundles(ctx, &proto.ListBundlesRequest{})
assert.NoError(t, err)
for _, bundle := range listRes.Bundles {
assert.Contains(t, tt.expectedBundles, expectedBundle{
displayName: bundle.DisplayName,
name: bundle.Name,
// we don't want to deep-assert the values returned only add checks on name and displayName
// this will suffice.
listResAsExpectedBundle := make([]expectedBundle, 0)
for i := range listRes.Bundles {
listResAsExpectedBundle = append(listResAsExpectedBundle, expectedBundle{
displayName: listRes.Bundles[i].DisplayName,
name: listRes.Bundles[i].Name,
})
}
assert.Equal(t, len(tt.expectedBundles), len(listRes.Bundles))
for _, bundle := range tt.expectedBundles {
assert.Contains(t, listResAsExpectedBundle, bundle)
}
})
}
}
@@ -1568,13 +1573,19 @@ func TestListGetBundleSettingMixedPermission(t *testing.T) {
listRes, err := bundleService.ListBundles(ctx, &proto.ListBundlesRequest{})
assert.NoError(t, err)
for _, setting := range listRes.Bundles[0].Settings {
assert.Contains(t, tt.expectedSettings, expectedSetting{
displayName: setting.DisplayName,
name: setting.Name,
})
listedSettings := make([]expectedSetting, 0)
for i := range listRes.Bundles {
for _, setting := range listRes.Bundles[i].Settings {
listedSettings = append(listedSettings, expectedSetting{
displayName: setting.DisplayName,
name: setting.Name,
})
}
}
for i := range tt.expectedSettings {
assert.Contains(t, listedSettings, tt.expectedSettings[i])
}
assert.Equal(t, len(tt.expectedSettings), len(listRes.Bundles[0].Settings))
getRes, err := bundleService.GetBundle(ctx, &proto.GetBundleRequest{BundleId: bundle.Id})
assert.NoError(t, err)
@@ -1585,59 +1596,6 @@ func TestListGetBundleSettingMixedPermission(t *testing.T) {
name: setting.Name,
})
}
assert.Equal(t, len(tt.expectedSettings), len(getRes.Bundle.Settings))
})
}
}
func TestListFilteredBundle_SetPermissionsOnSettingAndBundle(t *testing.T) {
tests := []struct {
name string
settingPermission proto.Permission_Operation
bundlePermission proto.Permission_Operation
expectedAmountOfSettings int
}{
{
"setting has read permission bundle not",
proto.Permission_OPERATION_READ,
proto.Permission_OPERATION_UNKNOWN,
1,
},
{
"bundle has read permission setting not",
proto.Permission_OPERATION_UNKNOWN,
proto.Permission_OPERATION_READ,
5,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
teardown := setup()
defer teardown()
ctx := metadata.Set(context.Background(), middleware.AccountID, testAccountID)
ctx = metadata.Set(ctx, middleware.RoleIDs, getRoleIDAsJSON(svc.BundleUUIDRoleAdmin))
_, err := bundleService.SaveBundle(ctx, &proto.SaveBundleRequest{
Bundle: &bundleStub,
})
assert.NoError(t, err)
setPermissionOnBundleOrSetting(
ctx, t, bundleStub.Id, proto.Resource_TYPE_BUNDLE, tt.bundlePermission, svc.BundleUUIDRoleAdmin,
)
setPermissionOnBundleOrSetting(
ctx, t, bundleStub.Settings[0].Id, proto.Resource_TYPE_SETTING,
tt.settingPermission, svc.BundleUUIDRoleAdmin,
)
listRes, err := bundleService.ListBundles(ctx, &proto.ListBundlesRequest{})
assert.NoError(t, err)
assert.Equal(t, 1, len(listRes.Bundles))
assert.Equal(t, tt.expectedAmountOfSettings, len(listRes.Bundles[0].Settings))
assert.Equal(t, bundleStub.Id, listRes.Bundles[0].Id)
assert.Equal(t, bundleStub.Settings[0].Id, listRes.Bundles[0].Settings[0].Id)
})
}
}
+25 -24
View File
@@ -1,7 +1,8 @@
syntax = "proto3";
package proto;
option go_package = "pkg/proto/v0;proto";
package com.owncloud.ocis.settings.v0;
option go_package = "github.com/owncloud/ocis/settings/pkg/proto/v0;proto";
import "google/api/annotations.proto";
import "google/protobuf/empty.proto";
@@ -9,28 +10,28 @@ import "google/protobuf/empty.proto";
import "protoc-gen-openapiv2/options/annotations.proto";
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
info: {
title: "ownCloud Infinite Scale settings";
version: "1.0.0";
contact: {
name: "ownCloud GmbH";
url: "https://github.com/owncloud/ocis";
email: "support@owncloud.com";
};
license: {
name: "Apache-2.0";
url: "https://github.com/owncloud/ocis/blob/master/LICENSE";
};
};
schemes: HTTP;
schemes: HTTPS;
consumes: "application/json";
produces: "application/json";
external_docs: {
description: "Developer Manual";
url: "https://owncloud.github.io/extensions/settings/";
};
};
info: {
title: "ownCloud Infinite Scale settings";
version: "1.0.0";
contact: {
name: "ownCloud GmbH";
url: "https://github.com/owncloud/ocis";
email: "support@owncloud.com";
};
license: {
name: "Apache-2.0";
url: "https://github.com/owncloud/ocis/blob/master/LICENSE";
};
};
schemes: HTTP;
schemes: HTTPS;
consumes: "application/json";
produces: "application/json";
external_docs: {
description: "Developer Manual";
url: "https://owncloud.dev/extensions/settings/";
};
};
service BundleService {
rpc SaveBundle(SaveBundleRequest) returns (SaveBundleResponse) {
File diff suppressed because it is too large Load Diff
+6
View File
@@ -65,6 +65,12 @@ func (g Service) RegisterDefaultRoles() {
Msg("failed to register permission")
}
}
for _, req := range defaultRoleAssignments() {
if _, err := g.manager.WriteRoleAssignment(req.AccountUuid, req.RoleId); err != nil {
g.logger.Error().Err(err).Msg("failed to register role assignment")
}
}
}
// TODO: check permissions on every request
+248 -1
View File
@@ -1,6 +1,8 @@
package svc
import settings "github.com/owncloud/ocis/settings/pkg/proto/v0"
import (
settings "github.com/owncloud/ocis/settings/pkg/proto/v0"
)
const (
// BundleUUIDRoleAdmin represents the admin role
@@ -21,6 +23,21 @@ const (
SettingsManagementPermissionID string = "79e13b30-3e22-11eb-bc51-0b9f0bad9a58"
// SettingsManagementPermissionName is the hardcoded setting name for the settings management permission
SettingsManagementPermissionName string = "settings-management"
settingUUIDProfileLanguage = "aa8cfbe5-95d4-4f7e-a032-c3c01f5f062f"
// AccountManagementPermissionID is the hardcoded setting UUID for the account management permission
AccountManagementPermissionID string = "8e587774-d929-4215-910b-a317b1e80f73"
// AccountManagementPermissionName is the hardcoded setting name for the account management permission
AccountManagementPermissionName string = "account-management"
// GroupManagementPermissionID is the hardcoded setting UUID for the group management permission
GroupManagementPermissionID string = "522adfbe-5908-45b4-b135-41979de73245"
// GroupManagementPermissionName is the hardcoded setting name for the group management permission
GroupManagementPermissionName string = "group-management"
// SelfManagementPermissionID is the hardcoded setting UUID for the self management permission
SelfManagementPermissionID string = "e03070e9-4362-4cc6-a872-1c7cb2eb2b8e"
// SelfManagementPermissionName is the hardcoded setting name for the self management permission
SelfManagementPermissionName string = "self-management"
)
// generateBundlesDefaultRoles bootstraps the default roles.
@@ -29,6 +46,7 @@ func generateBundlesDefaultRoles() []*settings.Bundle {
generateBundleAdminRole(),
generateBundleUserRole(),
generateBundleGuestRole(),
generateBundleProfileRequest(),
}
}
@@ -74,6 +92,94 @@ func generateBundleGuestRole() *settings.Bundle {
}
}
var languageSetting = settings.Setting_SingleChoiceValue{
SingleChoiceValue: &settings.SingleChoiceList{
Options: []*settings.ListOption{
{
Value: &settings.ListOptionValue{
Option: &settings.ListOptionValue_StringValue{
StringValue: "cs",
},
},
DisplayValue: "Czech",
},
{
Value: &settings.ListOptionValue{
Option: &settings.ListOptionValue_StringValue{
StringValue: "de",
},
},
DisplayValue: "Deutsch",
},
{
Value: &settings.ListOptionValue{
Option: &settings.ListOptionValue_StringValue{
StringValue: "en",
},
},
DisplayValue: "English",
},
{
Value: &settings.ListOptionValue{
Option: &settings.ListOptionValue_StringValue{
StringValue: "es",
},
},
DisplayValue: "Español",
},
{
Value: &settings.ListOptionValue{
Option: &settings.ListOptionValue_StringValue{
StringValue: "fr",
},
},
DisplayValue: "Français",
},
{
Value: &settings.ListOptionValue{
Option: &settings.ListOptionValue_StringValue{
StringValue: "gl",
},
},
DisplayValue: "Galego",
},
{
Value: &settings.ListOptionValue{
Option: &settings.ListOptionValue_StringValue{
StringValue: "it",
},
},
DisplayValue: "Italiano",
},
},
},
}
func generateBundleProfileRequest() *settings.Bundle {
return &settings.Bundle{
Id: "2a506de7-99bd-4f0d-994e-c38e72c28fd9",
Name: "profile",
Extension: "ocis-accounts",
Type: settings.Bundle_TYPE_DEFAULT,
Resource: &settings.Resource{
Type: settings.Resource_TYPE_SYSTEM,
},
DisplayName: "Profile",
Settings: []*settings.Setting{
{
Id: settingUUIDProfileLanguage,
Name: "language",
DisplayName: "Language",
Description: "User language",
Resource: &settings.Resource{
Type: settings.Resource_TYPE_USER,
},
Value: &languageSetting,
},
},
}
}
func generatePermissionRequests() []*settings.AddSettingToBundleRequest {
return []*settings.AddSettingToBundleRequest{
{
@@ -114,5 +220,146 @@ func generatePermissionRequests() []*settings.AddSettingToBundleRequest {
},
},
},
{
BundleId: BundleUUIDRoleAdmin,
Setting: &settings.Setting{
Id: "7d81f103-0488-4853-bce5-98dcce36d649",
Name: "language-readwrite",
DisplayName: "Permission to read and set the language (anyone)",
Resource: &settings.Resource{
Type: settings.Resource_TYPE_SETTING,
Id: settingUUIDProfileLanguage,
},
Value: &settings.Setting_PermissionValue{
PermissionValue: &settings.Permission{
Operation: settings.Permission_OPERATION_READWRITE,
Constraint: settings.Permission_CONSTRAINT_ALL,
},
},
},
},
{
BundleId: BundleUUIDRoleUser,
Setting: &settings.Setting{
Id: "640e00d2-4df8-41bd-b1c2-9f30a01e0e99",
Name: "language-readwrite",
DisplayName: "Permission to read and set the language (self)",
Resource: &settings.Resource{
Type: settings.Resource_TYPE_SETTING,
Id: settingUUIDProfileLanguage,
},
Value: &settings.Setting_PermissionValue{
PermissionValue: &settings.Permission{
Operation: settings.Permission_OPERATION_READWRITE,
Constraint: settings.Permission_CONSTRAINT_OWN,
},
},
},
},
{
BundleId: BundleUUIDRoleGuest,
Setting: &settings.Setting{
Id: "ca878636-8b1a-4fae-8282-8617a4c13597",
Name: "language-readwrite",
DisplayName: "Permission to read and set the language (self)",
Resource: &settings.Resource{
Type: settings.Resource_TYPE_SETTING,
Id: settingUUIDProfileLanguage,
},
Value: &settings.Setting_PermissionValue{
PermissionValue: &settings.Permission{
Operation: settings.Permission_OPERATION_READWRITE,
Constraint: settings.Permission_CONSTRAINT_OWN,
},
},
},
},
{
BundleId: BundleUUIDRoleAdmin,
Setting: &settings.Setting{
Id: AccountManagementPermissionID,
Name: AccountManagementPermissionName,
DisplayName: "Account Management",
Description: "This permission gives full access to everything that is related to account management.",
Resource: &settings.Resource{
Type: settings.Resource_TYPE_USER,
Id: "all",
},
Value: &settings.Setting_PermissionValue{
PermissionValue: &settings.Permission{
Operation: settings.Permission_OPERATION_READWRITE,
Constraint: settings.Permission_CONSTRAINT_ALL,
},
},
},
},
{
BundleId: BundleUUIDRoleAdmin,
Setting: &settings.Setting{
Id: GroupManagementPermissionID,
Name: GroupManagementPermissionName,
DisplayName: "Group Management",
Description: "This permission gives full access to everything that is related to group management.",
Resource: &settings.Resource{
Type: settings.Resource_TYPE_GROUP,
Id: "all",
},
Value: &settings.Setting_PermissionValue{
PermissionValue: &settings.Permission{
Operation: settings.Permission_OPERATION_READWRITE,
Constraint: settings.Permission_CONSTRAINT_ALL,
},
},
},
},
{
BundleId: BundleUUIDRoleUser,
Setting: &settings.Setting{
Id: SelfManagementPermissionID,
Name: SelfManagementPermissionName,
DisplayName: "Self Management",
Description: "This permission gives access to self management.",
Resource: &settings.Resource{
Type: settings.Resource_TYPE_USER,
Id: "me",
},
Value: &settings.Setting_PermissionValue{
PermissionValue: &settings.Permission{
Operation: settings.Permission_OPERATION_READWRITE,
Constraint: settings.Permission_CONSTRAINT_OWN,
},
},
},
},
}
}
func defaultRoleAssignments() []*settings.UserRoleAssignment {
return []*settings.UserRoleAssignment{
// default admin users
{
AccountUuid: "058bff95-6708-4fe5-91e4-9ea3d377588b",
RoleId: BundleUUIDRoleAdmin,
}, {
AccountUuid: "ddc2004c-0977-11eb-9d3f-a793888cd0f8",
RoleId: BundleUUIDRoleAdmin,
}, {
AccountUuid: "820ba2a1-3f54-4538-80a4-2d73007e30bf",
RoleId: BundleUUIDRoleAdmin,
}, {
AccountUuid: "bc596f3c-c955-4328-80a0-60d018b4ad57",
RoleId: BundleUUIDRoleAdmin,
},
// default users with role "user"
{
AccountUuid: "4c510ada-c86b-4815-8820-42cdf82c3d51",
RoleId: BundleUUIDRoleUser,
}, {
AccountUuid: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
RoleId: BundleUUIDRoleUser,
}, {
AccountUuid: "932b4540-8d16-481e-8ef4-588e4b6b151c",
RoleId: BundleUUIDRoleUser,
},
}
}
+1
View File
@@ -28,6 +28,7 @@ func New(cfg *config.Config) settings.Manager {
olog.Color(cfg.Log.Color),
olog.Pretty(cfg.Log.Pretty),
olog.Level(cfg.Log.Level),
olog.File(cfg.Log.File),
),
}
+105
View File
@@ -0,0 +1,105 @@
package tracing
import (
"time"
"contrib.go.opencensus.io/exporter/jaeger"
"contrib.go.opencensus.io/exporter/ocagent"
"contrib.go.opencensus.io/exporter/zipkin"
openzipkin "github.com/openzipkin/zipkin-go"
zipkinhttp "github.com/openzipkin/zipkin-go/reporter/http"
"github.com/owncloud/ocis/ocis-pkg/log"
"github.com/owncloud/ocis/settings/pkg/config"
"go.opencensus.io/stats/view"
"go.opencensus.io/trace"
)
// Configure tracing from config
func Configure(cfg *config.Config, logger log.Logger) error {
if cfg.Tracing.Enabled {
switch t := cfg.Tracing.Type; t {
case "agent":
exporter, err := ocagent.NewExporter(
ocagent.WithReconnectionPeriod(5*time.Second),
ocagent.WithAddress(cfg.Tracing.Endpoint),
ocagent.WithServiceName(cfg.Tracing.Service),
)
if err != nil {
logger.Error().
Err(err).
Str("endpoint", cfg.Tracing.Endpoint).
Str("collector", cfg.Tracing.Collector).
Msg("Failed to create agent tracing")
return err
}
trace.RegisterExporter(exporter)
view.RegisterExporter(exporter)
case "jaeger":
exporter, err := jaeger.NewExporter(
jaeger.Options{
AgentEndpoint: cfg.Tracing.Endpoint,
CollectorEndpoint: cfg.Tracing.Collector,
Process: jaeger.Process{
ServiceName: cfg.Tracing.Service,
},
},
)
if err != nil {
logger.Error().
Err(err).
Str("endpoint", cfg.Tracing.Endpoint).
Str("collector", cfg.Tracing.Collector).
Msg("Failed to create jaeger tracing")
return err
}
trace.RegisterExporter(exporter)
case "zipkin":
endpoint, err := openzipkin.NewEndpoint(
cfg.Tracing.Service,
cfg.Tracing.Endpoint,
)
if err != nil {
logger.Error().
Err(err).
Str("endpoint", cfg.Tracing.Endpoint).
Str("collector", cfg.Tracing.Collector).
Msg("Failed to create zipkin tracing")
return err
}
exporter := zipkin.NewExporter(
zipkinhttp.NewReporter(
cfg.Tracing.Collector,
),
endpoint,
)
trace.RegisterExporter(exporter)
default:
logger.Warn().
Str("type", t).
Msg("Unknown tracing backend")
}
trace.ApplyConfig(
trace.Config{
DefaultSampler: trace.AlwaysSample(),
},
)
} else {
logger.Debug().
Msg("Tracing is not enabled")
}
return nil
}
+5 -3
View File
@@ -7,8 +7,9 @@ geekdocEditPath: edit/master/settings/templates
geekdocFilePath: CONFIGURATION.tmpl
---
{{- define "options"}}
{{ $fnName := (last . ).Flags -}}
{{ range $opt := first . }}{{ with list $fnName $opt -}}
{{ $fnNames := (last . ).Flags -}}
{{ range $opt := first . }}
{{ range $fnName := $fnNames }}{{ with list $fnName $opt -}}
{{ $o := last . -}}
{{ if eq $o.FnName $fnName -}}
-{{ $o.Name }} | {{ range $i, $e := $o.Env }} {{ if $i }}, {{ end }}${{ $e }}{{ end }}
@@ -17,6 +18,7 @@ geekdocFilePath: CONFIGURATION.tmpl
{{ end -}}
{{ end -}}
{{ end -}}
{{ end -}}
{{ end }}
{{`{{< toc >}}`}}
@@ -35,7 +37,7 @@ $HOME/.ocis
For this configuration to be picked up, have a look at your extension `root` command and look for which default config name it has assigned. *i.e: ocis-proxy reads `proxy.json | yaml | toml ...`*.
So far we support the file formats `JSON` and `YAML`, if you want to get a full example configuration just take a look at [our repository](https://github.com/owncloud/ocis/tree/master/config), there you can always see the latest configuration format. These example configurations include all available options and the default values. The configuration file will be automatically loaded if it's placed at `/etc/ocis/ocis.yml`, `${HOME}/.ocis/ocis.yml` or `$(pwd)/config/ocis.yml`.
So far we support the file formats `JSON` and `YAML`, if you want to get a full example configuration just take a look at [our repository](https://github.com/owncloud/ocis/tree/master/settings/config), there you can always see the latest configuration format. These example configurations include all available options and the default values. The configuration file will be automatically loaded if it's placed at `/etc/ocis/ocis.yml`, `${HOME}/.ocis/ocis.yml` or `$(pwd)/config/ocis.yml`.
### Environment variables
-11
View File
@@ -1,11 +0,0 @@
// +build tools
package main
import (
_ "github.com/UnnoTed/fileb0x"
_ "github.com/mitchellh/gox"
_ "github.com/restic/calens"
_ "golang.org/x/lint/golint"
// _ "honnef.co/go/tools/cmd/staticcheck"
)
+3 -1
View File
@@ -1,6 +1,7 @@
import 'regenerator-runtime/runtime'
import SettingsApp from './components/SettingsApp.vue'
import store from './store'
import translations from './../l10n/translations.json'
// just a dummy function to trick gettext tools
function $gettext (msg) {
@@ -41,5 +42,6 @@ export default {
appInfo,
store,
routes,
navItems
navItems,
translations
}
+2 -2
View File
@@ -1,6 +1,6 @@
<template>
<div class="oc-p">
<div class="uk-flex uk-flex-column" id="settings-app">
<main class="uk-flex uk-flex-column" id="settings-app">
<template v-if="initialized">
<oc-alert v-if="extensions.length === 0" variation="primary" no-close>
<p class="uk-flex uk-flex-middle">
@@ -34,7 +34,7 @@
</template>
</template>
<oc-loader v-else />
</div>
</main>
</div>
</template>
+2 -2
View File
@@ -1,8 +1,8 @@
<template>
<div class="uk-width-1-1 uk-width-2-3@m uk-width-1-2@l uk-width-1-3@xl">
<div class="oc-text-bold oc-mb-s">
<h2 class="oc-mb-s">
<translate>{{ bundle.displayName }}</translate>
</div>
</h2>
<oc-grid gutter="small">
<template>
<div class="uk-width-1-1" v-for="setting in bundle.settings" :key="setting.id">
@@ -1,36 +1,11 @@
<template>
<div>
<oc-button :id="buttonElementId" class="uk-width-expand" justify-content="space-between">
<span v-if="selectedOptions !== null && selectedOptions.length > 0">
{{ selectedOptionsDisplayValues }}
</span>
<span v-else>
{{ setting.placeholder || $gettext('Please select') }}
</span>
<oc-icon name="expand_more" />
</oc-button>
<oc-drop
:drop-id="dropElementId"
:toggle="`#${buttonElementId}`"
mode="click"
position="bottom-justify"
:options="{ offset: 0, delayHide: 200, flip: false }"
>
<ul class="uk-list">
<li
v-for="(option, index) in setting.multiChoiceValue.options"
:key="getOptionElementId(index)"
>
<oc-checkbox
v-model="selectedOptions"
:option="option"
@input="onSelectedOption"
:label="option.displayValue"
/>
</li>
</ul>
</oc-drop>
</div>
<oc-select
v-model="selectedOptions"
:clearable="false"
:options="displayOptions"
@input="onSelectedOption"
multiple
/>
</template>
<script>
@@ -53,28 +28,21 @@ export default {
},
data () {
return {
selectedOptions: null
selectedOptions: []
}
},
computed: {
selectedOptionsDisplayValues () {
return Array.from(this.selectedOptions).map(option => option.displayValue).join(', ')
},
dropElementId () {
return `multi-choice-drop-${this.setting.id}`
},
buttonElementId () {
return `multi-choice-toggle-${this.setting.id}`
displayOptions () {
return this.setting.multiChoiceValue.options.map(val => val.displayValue)
}
},
methods: {
getOptionElementId (index) {
return `${this.setting.id}-${index}`
},
async onSelectedOption () {
const values = []
if (!isNil(this.selectedOptions)) {
this.selectedOptions.forEach(option => {
this.selectedOptions.forEach(displayValue => {
const option = this.setting.multiChoiceValue.options.find(val => val.displayValue === displayValue)
if (option.value.intValue) {
values.push({ intValue: option.value.intValue })
}
@@ -123,13 +91,15 @@ export default {
return selectedValues.includes(option.value.stringValue)
}
return false
})
}).map(val => val.displayValue)
}
}
// TODO: load the settings value of the authenticated user and set it in `selectedOptions`
// if not set, yet, apply defaults from settings bundle definition
if (this.selectedOptions === null) {
this.selectedOptions = this.setting.multiChoiceValue.options.filter(option => option.default)
this.selectedOptions = this.setting.multiChoiceValue.options
.filter(option => option.default)
.map(val => val.displayValue)
}
}
}
@@ -1,36 +1,11 @@
<template>
<div>
<oc-button :id="buttonElementId" class="uk-width-expand" justify-content="space-between">
<span v-if="selectedOption">
{{ selectedOption.displayValue }}
</span>
<span v-else>
{{ setting.placeholder || $gettext('Please select') }}
</span>
<oc-icon name="expand_more" />
</oc-button>
<oc-drop
:drop-id="dropElementId"
:toggle="`#${buttonElementId}`"
mode="click"
close-on-click
position="bottom-justify"
:options="{ offset: 0, delayHide: 200, flip: false }"
>
<ul class="uk-list">
<li
v-for="(option, index) in setting.singleChoiceValue.options"
:key="getOptionElementId(index)"
>
<oc-radio
v-model="selectedOption"
:option="option"
@input="onSelectedOption"
:label="option.displayValue"
/>
</li>
</ul>
</oc-drop>
<oc-select
v-model="selectedOption"
:clearable="false"
:options="displayOptions"
@input="onSelectedOption"
/>
</div>
</template>
@@ -58,25 +33,21 @@ export default {
}
},
computed: {
dropElementId () {
return `single-choice-drop-${this.setting.id}`
},
buttonElementId () {
return `single-choice-toggle-${this.setting.id}`
displayOptions () {
return this.setting.singleChoiceValue.options.map(val => val.displayValue)
}
},
methods: {
getOptionElementId (index) {
return `${this.setting.id}-${index}`
},
async onSelectedOption () {
const values = []
if (!isNil(this.selectedOption)) {
if (this.selectedOption.value.intValue) {
values.push({ intValue: this.selectedOption.value.intValue })
const option = this.setting.singleChoiceValue.options.find(val => val.displayValue === this.selectedOption)
if (option.value.intValue) {
values.push({ intValue: option.value.intValue })
}
if (this.selectedOption.value.stringValue) {
values.push({ stringValue: this.selectedOption.value.stringValue })
if (option.value.stringValue) {
values.push({ stringValue: option.value.stringValue })
}
}
const payload = {
@@ -106,14 +77,14 @@ export default {
}
})
if (filtered.length > 0) {
this.selectedOption = filtered[0]
this.selectedOption = filtered[0].displayValue
}
}
// if not set, yet, apply default from settings bundle definition
if (isNil(this.selectedOption)) {
const defaults = this.setting.singleChoiceValue.options.filter(option => option.default)
if (defaults.length === 1) {
this.selectedOption = defaults[0]
this.selectedOption = defaults[0].displayValue
}
}
}
+14
View File
@@ -0,0 +1,14 @@
/**
* This file contains strings that should be synced to transifex but not exist in the UI directly,
* moreover, they get loaded for example by API requests
*/
// just a dummy function to trick gettext tools
function $gettext (msg) {
return msg
}
// eslint-disable-next-line no-unused-vars
const dictionary = [
$gettext('Language')
]
@@ -4,26 +4,36 @@ Feature: Set user specific settings
So that I can customize my OCIS experience to my liking
Background:
Given these users have been created with default attributes:
Given these users have been created with default attributes and without skeleton files:
| username |
| user1 |
| user2 |
And user "user1" has created folder "simple-folder"
Scenario: Check the default settings
Given user "user1" has logged in using the webUI
And the user browses to the settings page
Then the setting "Language" should have value "Please select"
Then the setting "Language" should not have any value
When the user browses to the files page
Then the files menu should be listed in language "English"
Scenario: changing the language
Scenario: changing the language (reactive and with page reload)
Given user "user1" has logged in using the webUI
And the user browses to the settings page
When the user changes the language to "Deutsch"
Then the setting "Language" should have value "Deutsch"
When the user browses to the files page
And the user reloads the current page of the webUI
Then the files menu should be listed in language "Deutsch"
And the account menu should be listed in language "Deutsch"
And the files header should be displayed in language "Deutsch"
When the user reloads the current page of the webUI
Then the files menu should be listed in language "Deutsch"
And the account menu should be listed in language "Deutsch"
And the files header should be displayed in language "Deutsch"
When the user browses to the settings page
And the user changes the language to "English"
And the user browses to the files page
Then the files menu should be listed in language "English"
Scenario: changing the language only affects one user
Given user "user2" has logged in using the webUI
@@ -31,27 +41,6 @@ Feature: Set user specific settings
When the user changes the language to "Español"
Then the setting "Language" should have value "Español"
When the user browses to the files page
And the user reloads the current page of the webUI
Then the files menu should be listed in language "Español"
When the user re-logs in as "user1" using the webUI
And the user reloads the current page of the webUI
Then the files menu should be listed in language "English"
Scenario: Check the accounts menu when the language is changed
Given user "user2" has logged in using the webUI
And the user browses to the settings page
When the user changes the language to "Deutsch"
And the user reloads the current page of the webUI
Then the setting "Language" should have value "Deutsch"
And the account menu should be listed in language "Deutsch"
When the user changes the language to "Français"
Then the account menu should be listed in language "Français"
Scenario: Check the files table header menu when the language is changed
Given user "user2" has logged in using the webUI
And the user browses to the settings page
When the user changes the language to "Deutsch"
Then the setting "Language" should have value "Deutsch"
When the user browses to the files page
And the user reloads the current page of the webUI
Then the files header should be displayed in language "Deutsch"
@@ -3,43 +3,51 @@ const filesMenu = {
'All files',
'Shared with me',
'Shared with others',
'Trash bin'
'Shared via link',
'Deleted files'
],
Deutsch: [
'Alle Dateien',
'Mit mir geteilt',
'Mit anderen geteilt',
'Papierkorb'
'Per Link geteilt',
'Gelöschte Dateien'
],
Español: [
'Todos los archivos',
'Compartido conmigo',
'Compartido con otros',
'Papelera de reciclaje'
'Shared via link',
'Archivos borrados'
],
Français: [
'Tous les fichiers',
'Partagé avec moi',
'Partagé avec autres',
'Corbeille'
'Shared via link',
'Fichiers supprimés'
]
}
const accountMenu = {
English: [
'Manage your account',
'Profile',
'Settings',
'Log out'
],
Deutsch: [
'Verwalten Sie Ihr Benutzerkonto',
'Profil',
'Einstellungen',
'Abmelden'
],
Español: [
'Administra tu cuenta',
'Profile',
'Configuración',
'Salir'
],
Français: [
'Modifier votre compte',
'Profil',
'Settings',
'Se déconnecter'
]
}
@@ -48,19 +56,19 @@ const filesListHeaderMenu = {
English: [
'Name',
'Size',
'Updated',
'Modified',
'Actions'
],
Deutsch: [
'Name',
'Größe',
'Erneuert',
'Geändert',
'Aktionen'
],
Español: [
'Nombre',
'Tamaño',
'Actualizado',
'Modificado',
'Acciones'
],
Français: [
@@ -33,9 +33,8 @@ module.exports = {
})
})
await this
.waitForElementVisible('@userMenuBtn')
.click('@userMenuBtn')
.waitForElementNotVisible('@userMenuContainer')
.waitForElementNotPresent('@userMenuContainer')
return menu
},
getFileHeaderItems: async function () {
@@ -57,10 +56,6 @@ module.exports = {
pageHeader: {
selector: '.oc-page-title'
},
languageValue: {
selector: "//button[@id='single-choice-toggle-profile-language']",
locateStrategy: 'xpath'
},
fileSidebarNavItem: {
selector: '.oc-sidebar-nav-item'
},
@@ -78,7 +73,7 @@ module.exports = {
selector: '#account-info-container'
},
fileTableHeaderItems: {
selector: '//*[@id="files-table-header"]//span[not(*) and not(ancestor::label)]',
selector: '//*[@id="files-personal-table"]//th[not(.//div)]',
locateStrategy: 'xpath'
}
}
@@ -31,6 +31,19 @@ module.exports = {
let output
switch (key) {
case 'Language':
let elemfound = true
// Language value is set to empty at beginning
// In that case jsut return false
await this.api.element('@languageValue', result => {
if (result.status < 0) {
elemfound = false
}
})
if (!elemfound) {
output = false
break
}
await this.waitForElementVisible('@languageValue')
.getText('@languageValue', (result) => {
output = result.value
@@ -42,16 +55,11 @@ module.exports = {
return output
},
changeSettings: async function (key, value) {
const selectXpath = util.format(this.elements.languageSelect.selector, value)
switch (key) {
case 'Language':
await this.waitForElementVisible('@languageValue')
.click('@languageValue')
.useXpath()
.waitForElementVisible(this.elements.languageDropdown.selector)
.click(selectXpath)
.waitForElementNotVisible(this.elements.languageDropdown.selector)
.useCss()
await this
.waitForElementVisible('@languageInput')
.setValue('@languageInput', value + '\n')
break
default:
throw new Error('failed to find the setting')
@@ -64,16 +72,12 @@ module.exports = {
selector: '.oc-page-title'
},
languageValue: {
selector: "//label[.='Language']/..//button[starts-with(@id, 'single-choice-toggle')]",
selector: "//label[.='Language']/..//span[@class='vs__selected']",
locateStrategy: 'xpath'
},
languageDropdown: {
selector: "//label[.='Language']/..//div[starts-with(@id, 'single-choice-drop')]",
languageInput: {
selector: "//label[.='Language']/..//input",
locateStrategy: 'xpath'
},
languageSelect: {
selector: "//label[.='Language']/..//div[starts-with(@id, 'single-choice-drop')]//label[normalize-space()='%s']",
locateStrategy: 'xpath'
}
}
}
@@ -2,9 +2,11 @@ const assert = require('assert')
const path = require('path')
const fs = require('fs-extra')
const { client } = require('nightwatch-api')
const { Given, When, Then, After } = require('cucumber')
const { Given, When, Then, After, Before } = require('cucumber')
const languageHelper = require('../helpers/language')
const initialLanguageAssignments = []
Given('the user browses to the settings page', function () {
return client.page.settingsPage().navigateAndWaitTillLoaded()
})
@@ -14,6 +16,11 @@ Then('the setting {string} should have value {string}', async function (setting,
assert.strictEqual(actual, result, 'The setting value doesnt matches to ' + result)
})
Then('the setting {string} should not have any value', async function (setting) {
const actual = await client.page.settingsPage().getSettingsValue(setting)
assert.strictEqual(actual, false, 'The setting value was expected not to be present but was')
})
When('the user changes the language to {string}', async function (value) {
await client.page.settingsPage().changeSettings('Language', value)
})
@@ -21,35 +28,17 @@ When('the user changes the language to {string}', async function (value) {
Then('the files menu should be listed in language {string}', async function (language) {
const menu = await client.page.filesPageSettingsContext().getMenuList()
const expected = languageHelper.getFilesMenuForLanguage(language)
assert.deepEqual(menu, expected, 'the menu list were not same')
assert.deepStrictEqual(menu, expected, 'the menu list were not same')
})
Then('the account menu should be listed in language {string}', async function (language) {
const menu = await client.page.filesPageSettingsContext().getUserMenu()
const expected = languageHelper.getUserMenuForLanguage(language)
assert.deepEqual(menu, expected, 'the menu list were not same')
assert.deepStrictEqual(menu, expected, 'the menu list were not same')
})
Then('the files header should be displayed in language {string}', async function (language) {
const items = await client.page.filesPageSettingsContext().getFileHeaderItems()
const expected = languageHelper.getFilesHeaderMenuForLanguage(language)
assert.deepEqual(items, expected, 'the menu list were not same')
})
After(async function () {
const directory = path.join(client.globals.settings_store, 'values')
try {
console.log('Elements')
fs.readdirSync(directory).map(element => {
console.log(element)
})
} catch (err) {
console.log('Error while reading the settings values from file system... ')
}
try {
fs.emptyDirSync(directory)
} catch (err) {
console.log('Error while clearing settings values from file system')
console.log('No settings may have been changed by the tests')
}
assert.deepStrictEqual(items, expected, 'the menu list were not same')
})
@@ -1,16 +0,0 @@
---
# OpenID Connect client registry.
clients:
- id: web
name: OCIS
application_type: web
insecure: yes
trusted: yes
redirect_uris:
- https://ocis-server:9200/oidc-callback.html
- https://ocis-server:9200/
origins:
- https://ocis-server:9200
authorities:
@@ -1,27 +0,0 @@
{
"server": "https://ocis-server:9200",
"theme": "owncloud",
"version": "0.1.0",
"openIdConnect": {
"metadata_url": "https://ocis-server:9200/.well-known/openid-configuration",
"authority": "https://ocis-server:9200",
"client_id": "web",
"response_type": "code",
"scope": "openid profile email"
},
"apps": [
"files",
"draw-io",
"markdown-editor",
"media-viewer"
],
"external_apps": [
{
"id": "settings",
"path": "https://ocis-server:9200/settings.js",
"config": {
"url": "https://ocis-server:9200"
}
}
]
}
@@ -1,82 +0,0 @@
{
"HTTP": {
"Namespace": "com.owncloud"
},
"policy_selector": {
"static": {
"policy": "reva"
}
},
"policies": [
{
"name": "reva",
"routes": [
{
"endpoint": "/",
"backend": "http://localhost:9100"
},
{
"endpoint": "/.well-known/",
"backend": "http://localhost:9130"
},
{
"endpoint": "/konnect/",
"backend": "http://localhost:9130"
},
{
"endpoint": "/signin/",
"backend": "http://localhost:9130"
},
{
"endpoint": "/ocs/",
"backend": "http://localhost:9140"
},
{
"type": "regex",
"endpoint": "/ocs/v[12].php/cloud/user",
"backend": "http://localhost:9110"
},
{
"endpoint": "/remote.php/",
"backend": "http://localhost:9140"
},
{
"endpoint": "/dav/",
"backend": "http://localhost:9140"
},
{
"endpoint": "/webdav/",
"backend": "http://localhost:9140"
},
{
"endpoint": "/status.php",
"backend": "http://localhost:9140"
},
{
"endpoint": "/index.php/",
"backend": "http://localhost:9140"
},
{
"endpoint": "/data",
"backend": "http://localhost:9140"
},
{
"endpoint": "/api/v0/accounts",
"backend": "http://localhost:9181"
},
{
"endpoint": "/accounts.js",
"backend": "http://localhost:9181"
},
{
"endpoint": "/api/v0/settings",
"backend": "http://localhost:9190"
},
{
"endpoint": "/settings.js",
"backend": "http://localhost:9190"
}
]
}
]
}
+4 -13
View File
@@ -6,15 +6,9 @@ then
exit 1
fi
if [ -z "$OCIS_SKELETON_DIR" ]
then
echo "OCIS_SKELETON_DIR env variable is not set, cannot find skeleton directory"
exit 1
fi
if [ -z "$WEB_UI_CONFIG" ]
then
echo "WEB_UI_CONFIG env variable is not set, cannot find ownCloud Web config file"
echo "WEB_UI_CONFIG env variable is not set, cannot find web config file"
exit 1
fi
@@ -29,9 +23,9 @@ trap clean_up SIGHUP SIGINT SIGTERM
if [ -z "$TEST_INFRA_DIRECTORY" ]
then
cleanup=true
testFolder=$(cat < /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1)
testFolder=$(mktemp -d -p .)
printf "creating folder $testFolder for Test infrastructure setup\n\n"
export TEST_INFRA_DIRECTORY=$testFolder
export TEST_INFRA_DIRECTORY=$testFolder/tests
fi
clean_up() {
@@ -46,13 +40,10 @@ clean_up() {
trap clean_up SIGHUP SIGINT SIGTERM EXIT
cp -r "$WEB_PATH/tests" "./$testFolder"
cp -r "$WEB_PATH"/tests "$testFolder"
export NODE_TLS_REJECT_UNAUTHORIZED='0'
export SERVER_HOST=${SERVER_HOST:-https://localhost:9200}
export BACKEND_HOST=${BACKEND_HOST:-https://localhost:9200}
export OCIS_SETTINGS_STORE=${OCIS_SETTINGS_STORE:-"/var/tmp/ocis/settings"}
export RUN_ON_OCIS=true
export TEST_TAGS=${TEST_TAGS:-"not @skip"}
yarn run acceptance-tests "$1"
+1286 -839
View File
File diff suppressed because it is too large Load Diff