diff --git a/changelog/unreleased/fix-wopi-app-open-with-web-due-to-app-registry-ordering.md b/changelog/unreleased/fix-wopi-app-open-with-web-due-to-app-registry-ordering.md new file mode 100644 index 00000000000..481f39185c5 --- /dev/null +++ b/changelog/unreleased/fix-wopi-app-open-with-web-due-to-app-registry-ordering.md @@ -0,0 +1,5 @@ +Bugfix: Fix WOPI open-with-web due to app registry ordering + +Made app selection deterministic when no app is specified: the system now uses the configured default app for the file type, or picks the first provider sorted by priority then name, ensuring users get consistent results instead of random app selection based on registration timing. + +https://github.com/owncloud/reva/pull/540 diff --git a/internal/http/services/appprovider/appprovider.go b/internal/http/services/appprovider/appprovider.go index 682b85abe07..b6a2ce255c0 100644 --- a/internal/http/services/appprovider/appprovider.go +++ b/internal/http/services/appprovider/appprovider.go @@ -27,6 +27,7 @@ import ( "strings" appregistry "github.com/cs3org/go-cs3apis/cs3/app/registry/v1beta1" + "github.com/owncloud/reva/v2/pkg/app/registry/micro" providerv1beta1 "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1" gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1" rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" @@ -403,23 +404,30 @@ func (s *svc) handleOpen(openMode int) http.HandlerFunc { appName := r.Form.Get("app_name") if appName == "" { - apps, err := client.GetAppProviders(ctx, &appregistry.GetAppProvidersRequest{ - ResourceInfo: statRes.Info, + defRes, err := client.GetDefaultAppProviderForMimeType(ctx, &appregistry.GetDefaultAppProviderForMimeTypeRequest{ + MimeType: statRes.Info.MimeType, }) - if err != nil { - writeError(w, r, appErrorServerError, "error getting app providers", err) - return - } - if apps.Status.Code != rpc.Code_CODE_OK { - writeError(w, r, appErrorServerError, "error getting app providers", nil) - return - } - if len(apps.Providers) == 0 { - writeError(w, r, appErrorProviderNotFound, "no app providers found", nil) - return + if err == nil && defRes.Status.Code == rpc.Code_CODE_OK && defRes.Provider != nil { + appName = defRes.Provider.Name + } else { + apps, err := client.GetAppProviders(ctx, &appregistry.GetAppProvidersRequest{ + ResourceInfo: statRes.Info, + }) + if err != nil { + writeError(w, r, appErrorServerError, "error getting app providers", err) + return + } + if apps.Status.Code != rpc.Code_CODE_OK { + writeError(w, r, appErrorServerError, "error getting app providers", nil) + return + } + if len(apps.Providers) == 0 { + writeError(w, r, appErrorProviderNotFound, "no app providers found", nil) + return + } + micro.SortByPriorityThenName(apps.Providers) + appName = apps.Providers[0].Name } - - appName = apps.Providers[0].Name } openReq := gateway.OpenInAppRequest{ diff --git a/pkg/app/registry/micro/manager.go b/pkg/app/registry/micro/manager.go index b63aa2343c9..3b64dcb65b9 100644 --- a/pkg/app/registry/micro/manager.go +++ b/pkg/app/registry/micro/manager.go @@ -20,11 +20,13 @@ package micro import ( "context" - "sort" - "strconv" "sync" "time" + "sort" + "strconv" + "strings" + registrypb "github.com/cs3org/go-cs3apis/cs3/app/registry/v1beta1" typesv1beta1 "github.com/cs3org/go-cs3apis/cs3/types/v1beta1" "github.com/owncloud/reva/v2/pkg/app" @@ -222,7 +224,7 @@ func (m *manager) updateProvidersFromMicroRegistry() error { if err != nil { return err } - sortByPriority(lst) + SortByPriorityThenName(lst) for _, outer := range lst { for _, inner := range outer.MimeTypes { ma[inner] = append(ma[inner], outer) @@ -245,7 +247,8 @@ func equalsProviderInfo(p1, p2 *registrypb.ProviderInfo) bool { return false } -func getPriority(p *registrypb.ProviderInfo) string { +// GetPriority extracts priority from ProviderInfo.Opaque, returns defaultPriority ("0") if not set. +func GetPriority(p *registrypb.ProviderInfo) string { if p.Opaque != nil && len(p.Opaque.Map) != 0 { if priority, ok := p.Opaque.Map["priority"]; ok { return string(priority.GetValue()) @@ -254,12 +257,14 @@ func getPriority(p *registrypb.ProviderInfo) string { return defaultPriority } -func sortByPriority(providers []*registrypb.ProviderInfo) { - less := func(i, j int) bool { - prioI, _ := strconv.ParseInt(getPriority(providers[i]), 10, 64) - prioJ, _ := strconv.ParseInt(getPriority(providers[j]), 10, 64) - return prioI < prioJ - } - - sort.Slice(providers, less) +// SortByPriorityThenName sorts providers by priority (lower first), then by Name. Used by micro registry and HTTP appprovider. +func SortByPriorityThenName(providers []*registrypb.ProviderInfo) { + sort.Slice(providers, func(i, j int) bool { + pi, _ := strconv.ParseInt(GetPriority(providers[i]), 10, 64) + pj, _ := strconv.ParseInt(GetPriority(providers[j]), 10, 64) + if pi != pj { + return pi < pj + } + return strings.ToLower(providers[i].Name) < strings.ToLower(providers[j].Name) + }) } diff --git a/pkg/app/registry/micro/micro_test.go b/pkg/app/registry/micro/micro_test.go index 3213a1954ed..e4d2fb4b32d 100644 --- a/pkg/app/registry/micro/micro_test.go +++ b/pkg/app/registry/micro/micro_test.go @@ -997,7 +997,7 @@ func registerWithMicroReg(ns string, p *registrypb.ProviderInfo) error { node.Metadata[ns+".app-provider.icon"] = p.Icon node.Metadata[ns+".app-provider.allow_creation"] = registrypb.ProviderInfo_Capability_name[int32(p.Capability)] - node.Metadata[ns+".app-provider.priority"] = getPriority(p) + node.Metadata[ns+".app-provider.priority"] = GetPriority(p) if p.DesktopOnly { node.Metadata[ns+".app-provider.desktop_only"] = "true" }