feat(wopi): change doc preview config based on WOPI discovery results

This commit is contained in:
HFO4
2023-01-09 19:36:41 +08:00
parent c39daeb0d0
commit 4541400755
7 changed files with 107 additions and 22 deletions

View File

@@ -7,22 +7,23 @@ import (
// SiteConfig 站点全局设置序列
type SiteConfig struct {
SiteName string `json:"title"`
LoginCaptcha bool `json:"loginCaptcha"`
RegCaptcha bool `json:"regCaptcha"`
ForgetCaptcha bool `json:"forgetCaptcha"`
EmailActive bool `json:"emailActive"`
Themes string `json:"themes"`
DefaultTheme string `json:"defaultTheme"`
HomepageViewMethod string `json:"home_view_method"`
ShareViewMethod string `json:"share_view_method"`
Authn bool `json:"authn"`
User User `json:"user"`
ReCaptchaKey string `json:"captcha_ReCaptchaKey"`
CaptchaType string `json:"captcha_type"`
TCaptchaCaptchaAppId string `json:"tcaptcha_captcha_app_id"`
RegisterEnabled bool `json:"registerEnabled"`
AppPromotion bool `json:"app_promotion"`
SiteName string `json:"title"`
LoginCaptcha bool `json:"loginCaptcha"`
RegCaptcha bool `json:"regCaptcha"`
ForgetCaptcha bool `json:"forgetCaptcha"`
EmailActive bool `json:"emailActive"`
Themes string `json:"themes"`
DefaultTheme string `json:"defaultTheme"`
HomepageViewMethod string `json:"home_view_method"`
ShareViewMethod string `json:"share_view_method"`
Authn bool `json:"authn"`
User User `json:"user"`
ReCaptchaKey string `json:"captcha_ReCaptchaKey"`
CaptchaType string `json:"captcha_type"`
TCaptchaCaptchaAppId string `json:"tcaptcha_captcha_app_id"`
RegisterEnabled bool `json:"registerEnabled"`
AppPromotion bool `json:"app_promotion"`
WopiExts []string `json:"wopi_exts"`
}
type task struct {
@@ -60,7 +61,7 @@ func checkSettingValue(setting map[string]string, key string) string {
}
// BuildSiteConfig 站点全局设置
func BuildSiteConfig(settings map[string]string, user *model.User) Response {
func BuildSiteConfig(settings map[string]string, user *model.User, wopiExts []string) Response {
var userRes User
if user != nil {
userRes = BuildUser(*user)
@@ -85,6 +86,7 @@ func BuildSiteConfig(settings map[string]string, user *model.User) Response {
TCaptchaCaptchaAppId: checkSettingValue(settings, "captcha_TCaptcha_CaptchaAppId"),
RegisterEnabled: model.IsTrueVal(checkSettingValue(settings, "register_enabled")),
AppPromotion: model.IsTrueVal(checkSettingValue(settings, "show_app_promotion")),
WopiExts: wopiExts,
}}
return res
}

View File

@@ -18,10 +18,10 @@ func TestCheckSettingValue(t *testing.T) {
func TestBuildSiteConfig(t *testing.T) {
asserts := assert.New(t)
res := BuildSiteConfig(map[string]string{"not exist": ""}, &model.User{})
res := BuildSiteConfig(map[string]string{"not exist": ""}, &model.User{}, nil)
asserts.Equal("", res.Data.(SiteConfig).SiteName)
res = BuildSiteConfig(map[string]string{"siteName": "123"}, &model.User{})
res = BuildSiteConfig(map[string]string{"siteName": "123"}, &model.User{}, nil)
asserts.Equal("123", res.Data.(SiteConfig).SiteName)
// 非空用户
@@ -29,7 +29,7 @@ func TestBuildSiteConfig(t *testing.T) {
Model: gorm.Model{
ID: 5,
},
})
}, nil)
asserts.Len(res.Data.(SiteConfig).User.ID, 4)
}

View File

@@ -4,7 +4,9 @@ import (
"encoding/xml"
"fmt"
"github.com/cloudreve/Cloudreve/v3/pkg/cache"
"github.com/cloudreve/Cloudreve/v3/pkg/util"
"net/http"
"strings"
)
type ActonType string
@@ -19,6 +21,27 @@ const (
DiscoverRefreshDuration = 24 * 3600 // 24 hrs
)
func (c *client) AvailableExts() []string {
if err := c.checkDiscovery(); err != nil {
util.Log().Error("Failed to check WOPI discovery: %s", err)
return nil
}
c.mu.RUnlock()
defer c.mu.RUnlock()
exts := make([]string, 0, len(c.actions))
for ext, actions := range c.actions {
_, previewable := actions[string(ActionPreview)]
_, editable := actions[string(ActionEdit)]
if previewable || editable {
exts = append(exts, strings.TrimPrefix(ext, "."))
}
}
return exts
}
// checkDiscovery checks if discovery content is needed to be refreshed.
// If so, it will refresh discovery content.
func (c *client) checkDiscovery() error {

View File

@@ -6,6 +6,7 @@ import (
model "github.com/cloudreve/Cloudreve/v3/models"
"github.com/cloudreve/Cloudreve/v3/pkg/cache"
"github.com/cloudreve/Cloudreve/v3/pkg/request"
"github.com/cloudreve/Cloudreve/v3/pkg/util"
"net/url"
"path"
"strings"
@@ -13,11 +14,18 @@ import (
)
type Client interface {
// NewSession creates a new document session with access token.
NewSession(user *model.User, file *model.File, action ActonType) (*Session, error)
// AvailableExts returns a list of file extensions that are supported by WOPI.
AvailableExts() []string
}
var (
ErrActionNotSupported = errors.New("action not supported by current wopi endpoint")
Default Client
DefaultMu sync.Mutex
queryPlaceholders = map[string]string{
"BUSINESS_USER": "",
"DC_LLCC": "lng",
@@ -38,6 +46,24 @@ const (
wopiSrcPlaceholder = "WOPI_SOURCE"
)
// Init initializes a new global WOPI client.
func Init() {
settings := model.GetSettingByNames("wopi_endpoint", "wopi_enabled")
if !model.IsTrueVal(settings["wopi_enabled"]) {
return
}
wopiClient, err := NewClient(settings["wopi_endpoint"], cache.Store, request.NewClient())
if err != nil {
util.Log().Error("Failed to initialize WOPI client: %s", err)
return
}
DefaultMu.Lock()
Default = wopiClient
DefaultMu.Unlock()
}
type client struct {
cache cache.Driver
http request.Client
@@ -53,6 +79,21 @@ type config struct {
discoveryEndpoint *url.URL
}
func NewClient(endpoint string, cache cache.Driver, http request.Client) (Client, error) {
endpointUrl, err := url.Parse(endpoint)
if err != nil {
return nil, fmt.Errorf("failed to parse WOPI endpoint: %s", err)
}
return &client{
cache: cache,
http: http,
config: config{
discoveryEndpoint: endpointUrl,
},
}, nil
}
func (c *client) NewSession(user *model.User, file *model.File, action ActonType) (*Session, error) {
if err := c.checkDiscovery(); err != nil {
return nil, err
@@ -79,6 +120,8 @@ func (c *client) NewSession(user *model.User, file *model.File, action ActonType
return nil, nil
}
// Replace query parameters in action URL template. Some placeholders need to be replaced
// at the frontend, e.g. `THEME_ID`.
func generateActionUrl(src string, fileSrc string) (*url.URL, error) {
src = strings.ReplaceAll(src, "<", "")
src = strings.ReplaceAll(src, ">", "")