Skip to content

Commit

Permalink
[full-ci] enhancement: allow ocis to provide custom web applications (#…
Browse files Browse the repository at this point in the history
…8523)

* enhancement: allow ocis to provide custom web applications

* enhancement: add an option to disable web apps

* test: add default logger tests

* test: add app loading tests

* test: add asset server tests

* enhancement: make use of dedicated app conf file and app asset paths

* enhancement: adjust asset locations and deprecate WEB_ASSET_PATH

* enhancement: get rid of default logger and use the service level logger instead

* Apply suggestions from code review

Co-authored-by: Benedikt Kulmann <[email protected]>
Co-authored-by: kobergj <[email protected]>

* enhancement: use basename as app id

* Apply suggestions from code review

Co-authored-by: Martin <[email protected]>

* enhancement: use afero as fs abstraction

* enhancement: simplify logo upload

* enhancement: make use of introductionVersion field annotations

---------

Co-authored-by: Benedikt Kulmann <[email protected]>
Co-authored-by: kobergj <[email protected]>
Co-authored-by: Martin <[email protected]>
  • Loading branch information
4 people committed Mar 5, 2024
1 parent 6ba9e4a commit 6814c61
Show file tree
Hide file tree
Showing 63 changed files with 5,834 additions and 129 deletions.
11 changes: 11 additions & 0 deletions changelog/unreleased/enhancement-web-app-loading.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Enhancement: Custom WEB App Loading

We've added a new feature which allows the administrator of the environment to provide custom web applications to the
users. This feature is useful for organizations that have specific web applications that they want to provide to their
users.

The users will then be able to access these custom web applications from the web ui.
For a detailed description of the feature, please read the WEB service README.md file.

https://github.com/owncloud/ocis/pull/8523
https://github.com/owncloud/ocis/issues/8392
5 changes: 3 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/owncloud/ocis/v2
go 1.21

require (
dario.cat/mergo v1.0.0
github.com/CiscoM31/godata v1.0.10
github.com/KimMachineGun/automemlimit v0.5.0
github.com/Masterminds/semver v1.5.0
Expand Down Expand Up @@ -79,6 +80,7 @@ require (
github.com/rs/zerolog v1.32.0
github.com/shamaton/msgpack/v2 v2.1.1
github.com/sirupsen/logrus v1.9.3
github.com/spf13/afero v1.11.0
github.com/spf13/cobra v1.8.0
github.com/stretchr/testify v1.8.4
github.com/thejerf/suture/v4 v4.0.2
Expand All @@ -96,6 +98,7 @@ require (
go.opentelemetry.io/otel/sdk v1.24.0
go.opentelemetry.io/otel/trace v1.24.0
golang.org/x/crypto v0.19.0
golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3
golang.org/x/image v0.15.0
golang.org/x/net v0.21.0
golang.org/x/oauth2 v0.17.0
Expand All @@ -114,7 +117,6 @@ require (

require (
contrib.go.opencensus.io/exporter/prometheus v0.4.2 // indirect
dario.cat/mergo v1.0.0 // indirect
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
github.com/BurntSushi/toml v1.3.2 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
Expand Down Expand Up @@ -333,7 +335,6 @@ require (
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.8.0 // indirect
go.uber.org/zap v1.23.0 // indirect
golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3 // indirect
golang.org/x/mod v0.14.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/time v0.5.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1968,6 +1968,8 @@ github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY52
github.com/spf13/afero v1.4.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
Expand Down
34 changes: 34 additions & 0 deletions internal/testenv/test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package testenv

import (
"fmt"
"os"
"os/exec"
)

// CMDTest spawns a new independent test environment
type CMDTest struct {
n string
f func()
}

// NewCMDTest creates a new CMDTest instance
func NewCMDTest(name string) CMDTest {
return CMDTest{
n: name,
}
}

// Run runs the cmd subtest
func (t CMDTest) Run(envs ...string) ([]byte, error) {
cmd := exec.Command(os.Args[0], fmt.Sprintf("-test.run=%s", t.n))
cmd.Env = append(os.Environ(), "RUN_CMD_TEST=1")
cmd.Env = append(cmd.Env, envs...)

return cmd.CombinedOutput()
}

// ShouldRun checks if the cmd subtest should run
func (CMDTest) ShouldRun() bool {
return os.Getenv("RUN_CMD_TEST") == "1"
}
23 changes: 23 additions & 0 deletions internal/testenv/test_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package testenv

import (
"fmt"
"testing"

"github.com/onsi/gomega"
)

func TestNewSubTest(t *testing.T) {
testString := "this is a sub-test"
cmdTest := NewCMDTest(t.Name())
if cmdTest.ShouldRun() {
fmt.Println(testString)
return
}

out, err := cmdTest.Run()

g := gomega.NewWithT(t)
g.Expect(err).ToNot(gomega.HaveOccurred())
g.Expect(string(out)).To(gomega.ContainSubstring(testString))
}
63 changes: 0 additions & 63 deletions ocis-pkg/assetsfs/assetsfs.go

This file was deleted.

4 changes: 2 additions & 2 deletions ocis-pkg/config/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

gofig "github.com/gookit/config/v2"
gooyaml "github.com/gookit/config/v2/yaml"

"github.com/owncloud/ocis/v2/ocis-pkg/config/defaults"
)

Expand All @@ -25,8 +26,7 @@ func BindSourcesToStructs(service string, dst interface{}) (*gofig.Config, error
})
cnf.AddDriver(gooyaml.Driver)

cfgFile := path.Join(defaults.BaseConfigPath(), service+".yaml")
_ = cnf.LoadFiles([]string{cfgFile}...)
_ = cnf.LoadFiles(path.Join(defaults.BaseConfigPath(), service+".yaml"))

err := cnf.BindStruct("", &dst)
if err != nil {
Expand Down
10 changes: 9 additions & 1 deletion ocis-pkg/log/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ import (

chimiddleware "github.com/go-chi/chi/v5/middleware"
mzlog "github.com/go-micro/plugins/v4/logger/zerolog"
"github.com/owncloud/ocis/v2/ocis-pkg/shared"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"go-micro.dev/v4/logger"

"github.com/owncloud/ocis/v2/ocis-pkg/shared"
)

var (
Expand Down Expand Up @@ -148,3 +149,10 @@ func (l Logger) SubloggerWithRequestID(c context.Context) Logger {
l.With().Str(RequestIDString, chimiddleware.GetReqID(c)).Logger(),
}
}

// Deprecation logs a deprecation message,
// it is used to inform the user that a certain feature is deprecated and will be removed in the future.
// Do not use a logger here because the message MUST be visible independent of the log level.
func Deprecation(a ...any) {
fmt.Printf("\033[1;31mDEPRECATION: %s\033[0m\n", a...)
}
24 changes: 24 additions & 0 deletions ocis-pkg/log/log_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package log_test

import (
"testing"

"github.com/onsi/gomega"

"github.com/owncloud/ocis/v2/internal/testenv"
"github.com/owncloud/ocis/v2/ocis-pkg/log"
)

func TestDeprecation(t *testing.T) {
cmdTest := testenv.NewCMDTest(t.Name())
if cmdTest.ShouldRun() {
log.Deprecation("this is a deprecation")
return
}

out, err := cmdTest.Run()

g := gomega.NewWithT(t)
g.Expect(err).ToNot(gomega.HaveOccurred())
g.Expect(string(out)).To(gomega.HavePrefix("\033[1;31mDEPRECATION: this is a deprecation"))
}
37 changes: 37 additions & 0 deletions ocis-pkg/x/io/fsx/fallback.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package fsx

import (
"github.com/spf13/afero"
)

var (
// assert interfaces implemented
_ afero.Fs = (*FallbackFS)(nil)
_ FS = (*FallbackFS)(nil)
)

// FallbackFS is a filesystem that layers a primary filesystem on top of a secondary filesystem.
type FallbackFS struct {
FS
primary *BaseFS
secondary *BaseFS
}

// Primary returns the primary filesystem.
func (d *FallbackFS) Primary() *BaseFS {
return d.primary
}

// Secondary returns the secondary filesystem.
func (d *FallbackFS) Secondary() *BaseFS {
return d.secondary
}

// NewFallbackFS returns a new FallbackFS instance.
func NewFallbackFS(primary, secondary FS) *FallbackFS {
return &FallbackFS{
FS: FromAfero(afero.NewCopyOnWriteFs(secondary, primary)),
primary: &BaseFS{Fs: primary},
secondary: &BaseFS{Fs: secondary},
}
}
83 changes: 83 additions & 0 deletions ocis-pkg/x/io/fsx/fallback_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package fsx_test

import (
"io"
"testing"

"github.com/onsi/gomega"
"github.com/spf13/afero"

"github.com/owncloud/ocis/v2/ocis-pkg/x/io/fsx"
)

func TestLayeredFS(t *testing.T) {
g := gomega.NewWithT(t)

read := func(fs fsx.FS, name string) (string, error) {
f, err := fs.Open(name)
if err != nil {
return "", err
}

b, err := io.ReadAll(f)
if err != nil {
return "", err
}

return string(b), nil
}

mustRead := func(fs fsx.FS, name string) string {
s, err := read(fs, name)
g.Expect(err).ToNot(gomega.HaveOccurred())

return s
}

create := func(fs fsx.FS, name, content string) {
err := afero.WriteFile(fs, name, []byte(content), 0644)
g.Expect(err).ToNot(gomega.HaveOccurred())
}

primary := fsx.NewMemMapFs()
create(primary, "both.txt", "primary")
g.Expect(mustRead(primary, "both.txt")).To(gomega.Equal("primary"))
create(primary, "primary.txt", "primary")
g.Expect(mustRead(primary, "primary.txt")).To(gomega.Equal("primary"))

secondary := fsx.NewMemMapFs()
create(secondary, "both.txt", "secondary")
g.Expect(mustRead(secondary, "both.txt")).To(gomega.Equal("secondary"))
create(secondary, "secondary.txt", "secondary")
g.Expect(mustRead(secondary, "secondary.txt")).To(gomega.Equal("secondary"))

fs := fsx.NewFallbackFS(primary, fsx.NewReadOnlyFs(secondary))
g.Expect(mustRead(fs, "both.txt")).To(gomega.Equal("primary"))
g.Expect(mustRead(fs, "primary.txt")).To(gomega.Equal("primary"))
g.Expect(mustRead(fs, "secondary.txt")).To(gomega.Equal("secondary"))

create(fs, "fallback-fs.txt", "fallback-fs")
g.Expect(mustRead(fs, "fallback-fs.txt")).To(gomega.Equal("fallback-fs"))
g.Expect(mustRead(primary, "fallback-fs.txt")).To(gomega.Equal("fallback-fs"))
g.Expect(mustRead(fs.Primary(), "fallback-fs.txt")).To(gomega.Equal("fallback-fs"))
_, err := read(secondary, "fallback-fs.txt")
g.Expect(err).To(gomega.HaveOccurred())
_, err = read(fs.Secondary(), "fallback-fs.txt")
g.Expect(err).To(gomega.HaveOccurred())
}

func TestLayeredFS_Primary(t *testing.T) {
g := gomega.NewWithT(t)
primary := fsx.NewMemMapFs()
fs := fsx.NewFallbackFS(primary, fsx.NewMemMapFs())

g.Expect(primary).To(gomega.BeIdenticalTo(fs.Primary().Fs))
}

func TestLayeredFS_Secondary(t *testing.T) {
g := gomega.NewWithT(t)
secondary := fsx.NewMemMapFs()
fs := fsx.NewFallbackFS(fsx.NewMemMapFs(), secondary)

g.Expect(secondary).To(gomega.BeIdenticalTo(fs.Secondary().Fs))
}
Loading

0 comments on commit 6814c61

Please sign in to comment.