diff --git a/cmd/config_init.go b/cmd/config_init.go index 60a0f37b..a8426e7c 100644 --- a/cmd/config_init.go +++ b/cmd/config_init.go @@ -42,6 +42,10 @@ override the options.`, Theme: mustGetString(flags, "branding.theme"), Files: mustGetString(flags, "branding.files"), }, + OnlyOffice: settings.OnlyOffice{ + URL: mustGetString(flags, "onlyoffice.url"), + JWTSecret: mustGetString(flags, "onlyoffice.jwtSecret"), + }, } ser := &settings.Server{ diff --git a/cmd/config_set.go b/cmd/config_set.go index 23ff7e1b..11a40040 100644 --- a/cmd/config_set.go +++ b/cmd/config_set.go @@ -63,6 +63,10 @@ you want to change. Other options will remain unchanged.`, set.Branding.DisableUsedPercentage = mustGetBool(flags, flag.Name) case "branding.files": set.Branding.Files = mustGetString(flags, flag.Name) + case "onlyoffice.url": + set.OnlyOffice.URL = mustGetString(flags, flag.Name) + case "onlyoffice.jwtSecret": + set.OnlyOffice.JWTSecret = mustGetString(flags, flag.Name) } }) diff --git a/files/file.go b/files/file.go index 03b3a6f9..7d3a695b 100644 --- a/files/file.go +++ b/files/file.go @@ -276,6 +276,9 @@ func (i *FileInfo) detectType(modify, saveContent, readHeader bool) error { i.Content = string(content) } return nil + case strings.HasPrefix(mimetype, "application/vnd.openxmlformats-officedocument"): + i.Type = "officedocument" + return nil default: i.Type = "blob" } diff --git a/frontend/src/i18n/ar.json b/frontend/src/i18n/ar.json index 0236a9f3..ede9b9c3 100644 --- a/frontend/src/i18n/ar.json +++ b/frontend/src/i18n/ar.json @@ -195,6 +195,8 @@ "newPassword": "كلمة المرور الجديدة", "newPasswordConfirm": "تأكيد كلمة المرور", "newUser": "مستخدم جديد", + "onlyOffice": "Only Office Integration", + "onlyOfficeUrl": "Only Office URL (leave blank to disable)", "password": "كلمة المرور", "passwordUpdated": "تم تغيير كلمة المرور!", "path": "المسار", diff --git a/frontend/src/i18n/de.json b/frontend/src/i18n/de.json index 2609a5f3..0c45a09d 100644 --- a/frontend/src/i18n/de.json +++ b/frontend/src/i18n/de.json @@ -182,6 +182,8 @@ "newPassword": "Ihr neues Passwort.", "newPasswordConfirm": "Bestätigen Sie Ihr neues Passwort", "newUser": "Neuer Benutzer", + "onlyOffice": "Only Office Integration", + "onlyOfficeUrl": "Only Office URL (leave blank to disable)", "password": "Passwort", "passwordUpdated": "Passwort aktualisiert!", "path": "Pfad", @@ -247,4 +249,4 @@ "seconds": "Sekunden", "unit": "Zeiteinheit" } -} +} \ No newline at end of file diff --git a/frontend/src/i18n/en.json b/frontend/src/i18n/en.json index 00d43b9d..9127ee72 100644 --- a/frontend/src/i18n/en.json +++ b/frontend/src/i18n/en.json @@ -195,6 +195,9 @@ "newPassword": "Your new password", "newPasswordConfirm": "Confirm your new password", "newUser": "New User", + "onlyOffice": "Only Office Integration", + "onlyOfficeUrl": "Only Office URL (leave blank to disable)", + "onlyOfficeJwtSecret": "Only Office JWT Secret (works only with https, leave blank to disable)", "password": "Password", "passwordUpdated": "Password updated!", "path": "Path", @@ -261,4 +264,4 @@ "seconds": "Seconds", "unit": "Time Unit" } -} +} \ No newline at end of file diff --git a/frontend/src/i18n/es.json b/frontend/src/i18n/es.json index 06197a79..43d4dc92 100644 --- a/frontend/src/i18n/es.json +++ b/frontend/src/i18n/es.json @@ -182,6 +182,8 @@ "newPassword": "Tu nueva contraseña", "newPasswordConfirm": "Confirma tu contraseña", "newUser": "Nuevo usuario", + "onlyOffice": "Only Office Integration", + "onlyOfficeUrl": "Only Office URL (leave blank to disable)", "password": "Contraseña", "passwordUpdated": "¡Contraseña actualizada!", "path": "Ruta", @@ -247,4 +249,4 @@ "seconds": "Segundos", "unit": "Unidad" } -} +} \ No newline at end of file diff --git a/frontend/src/i18n/fr.json b/frontend/src/i18n/fr.json index 30725641..d03d26b2 100644 --- a/frontend/src/i18n/fr.json +++ b/frontend/src/i18n/fr.json @@ -181,6 +181,8 @@ "newPassword": "Votre nouveau mot de passe", "newPasswordConfirm": "Confirmation du nouveau mot de passe", "newUser": "Nouvel Utilisateur", + "onlyOffice": "Intégration Only Office", + "onlyOfficeUrl": "URL vers OnlyOffice (laisser vide pour désactiver)", "password": "Mot de passe", "passwordUpdated": "Mot de passe mis à jour !", "path": "", @@ -246,4 +248,4 @@ "seconds": "Secondes", "unit": "Unité de temps" } -} +} \ No newline at end of file diff --git a/frontend/src/i18n/is.json b/frontend/src/i18n/is.json index d53874c8..603aa7b9 100644 --- a/frontend/src/i18n/is.json +++ b/frontend/src/i18n/is.json @@ -169,6 +169,8 @@ "newPassword": "Nýja lykilorðið þitt", "newPasswordConfirm": "Staðfestu nýja lykilorðið", "newUser": "Nýr notandi", + "onlyOffice": "Only Office Integration", + "onlyOfficeUrl": "Only Office URL (leave blank to disable)", "password": "Lykilorð", "passwordUpdated": "Lykilorð vistað!", "path": "", @@ -232,4 +234,4 @@ "seconds": "Sekúndur", "unit": "Tímastilling" } -} +} \ No newline at end of file diff --git a/frontend/src/i18n/it.json b/frontend/src/i18n/it.json index a03c7f42..64451c56 100644 --- a/frontend/src/i18n/it.json +++ b/frontend/src/i18n/it.json @@ -170,6 +170,8 @@ "newPassword": "La tua nuova password", "newPasswordConfirm": "Conferma la password", "newUser": "Nuovo utente", + "onlyOffice": "Only Office Integration", + "onlyOfficeUrl": "Only Office URL (leave blank to disable)", "password": "Password", "passwordUpdated": "Password aggiornata!", "path": "Percorso", @@ -233,4 +235,4 @@ "seconds": "Secondi", "unit": "Unità di tempo" } -} +} \ No newline at end of file diff --git a/frontend/src/i18n/ja.json b/frontend/src/i18n/ja.json index f16a9d16..81634557 100644 --- a/frontend/src/i18n/ja.json +++ b/frontend/src/i18n/ja.json @@ -191,6 +191,8 @@ "newPassword": "新しいパスワード", "newPasswordConfirm": "新しいパスワード(再入力)", "newUser": "新規ユーザー作成", + "onlyOffice": "Only Office Integration", + "onlyOfficeUrl": "Only Office URL (leave blank to disable)", "password": "パスワード", "passwordUpdated": "パスワードを更新しました!", "path": "パス", @@ -256,4 +258,4 @@ "seconds": "秒", "unit": "時間の単位" } -} +} \ No newline at end of file diff --git a/frontend/src/i18n/ko.json b/frontend/src/i18n/ko.json index 046a712b..7ae3de8c 100644 --- a/frontend/src/i18n/ko.json +++ b/frontend/src/i18n/ko.json @@ -169,6 +169,8 @@ "newPassword": "새로운 비밀번호", "newPasswordConfirm": "새로운 비밀번호 확인", "newUser": "새로운 사용자", + "onlyOffice": "Only Office Integration", + "onlyOfficeUrl": "Only Office URL (leave blank to disable)", "password": "비밀번호", "passwordUpdated": "비밀번호 수정 완료!", "path": "", @@ -232,4 +234,4 @@ "seconds": "초", "unit": "Time Unit" } -} +} \ No newline at end of file diff --git a/frontend/src/i18n/nl-be.json b/frontend/src/i18n/nl-be.json index 913e48f0..2e94a45a 100644 --- a/frontend/src/i18n/nl-be.json +++ b/frontend/src/i18n/nl-be.json @@ -169,6 +169,8 @@ "newPassword": "Uw nieuw wachtwoord", "newPasswordConfirm": "Bevestig uw nieuw wachtwoord", "newUser": "Nieuwe gebruiker", + "onlyOffice": "Only Office Integration", + "onlyOfficeUrl": "Only Office URL (leave blank to disable)", "password": "Wachtwoord", "passwordUpdated": "Wachtwoord bijgewerkt!", "path": "", @@ -232,4 +234,4 @@ "seconds": "Seconden", "unit": "Tijdseenheid" } -} +} \ No newline at end of file diff --git a/frontend/src/i18n/pl.json b/frontend/src/i18n/pl.json index 9fcd4afa..95ad5fc3 100644 --- a/frontend/src/i18n/pl.json +++ b/frontend/src/i18n/pl.json @@ -169,6 +169,8 @@ "newPassword": "Twoje nowe hasło", "newPasswordConfirm": "Potwierdź swoje hasło", "newUser": "Nowy Użytkownik", + "onlyOffice": "Only Office Integration", + "onlyOfficeUrl": "Only Office URL (leave blank to disable)", "password": "Hasło", "passwordUpdated": "Hasło zostało zapisane!", "path": "Ścieżka", @@ -232,4 +234,4 @@ "seconds": "Sekundy", "unit": "Jednostka czasu" } -} +} \ No newline at end of file diff --git a/frontend/src/i18n/pt-br.json b/frontend/src/i18n/pt-br.json index 53d855d1..f78c3b2b 100644 --- a/frontend/src/i18n/pt-br.json +++ b/frontend/src/i18n/pt-br.json @@ -182,6 +182,8 @@ "newPassword": "Nova senha", "newPasswordConfirm": "Confirme a nova senha", "newUser": "Novo usuário", + "onlyOffice": "Only Office Integration", + "onlyOfficeUrl": "Only Office URL (leave blank to disable)", "password": "Senha", "passwordUpdated": "Senha atualizada!", "path": "", @@ -247,4 +249,4 @@ "seconds": "Segundos", "unit": "Unidades de Tempo" } -} +} \ No newline at end of file diff --git a/frontend/src/i18n/pt.json b/frontend/src/i18n/pt.json index e7cd9efa..47740180 100644 --- a/frontend/src/i18n/pt.json +++ b/frontend/src/i18n/pt.json @@ -170,6 +170,8 @@ "newPassword": "Nova palavra-passe", "newPasswordConfirm": "Confirme a nova palavra-passe", "newUser": "Novo utilizador", + "onlyOffice": "Only Office Integration", + "onlyOfficeUrl": "Only Office URL (leave blank to disable)", "password": "Palavra-passe", "passwordUpdated": "Palavra-passe atualizada!", "path": "", @@ -233,4 +235,4 @@ "seconds": "Segundos", "unit": "Unidades de tempo" } -} +} \ No newline at end of file diff --git a/frontend/src/i18n/ro.json b/frontend/src/i18n/ro.json index 6d564461..068c3c4f 100644 --- a/frontend/src/i18n/ro.json +++ b/frontend/src/i18n/ro.json @@ -169,6 +169,8 @@ "newPassword": "Noua ta parolă", "newPasswordConfirm": "Confirmă noua parolă", "newUser": "Utilizator nou", + "onlyOffice": "Only Office Integration", + "onlyOfficeUrl": "Only Office URL (leave blank to disable)", "password": "Parola", "passwordUpdated": "Parola actualizată!", "path": "", @@ -232,4 +234,4 @@ "seconds": "Secunde", "unit": "Unitate de timp" } -} +} \ No newline at end of file diff --git a/frontend/src/i18n/ru.json b/frontend/src/i18n/ru.json index bb6e8c92..8d261ae9 100644 --- a/frontend/src/i18n/ru.json +++ b/frontend/src/i18n/ru.json @@ -177,6 +177,8 @@ "newPassword": "Новый пароль", "newPasswordConfirm": "Повтор нового пароля", "newUser": "Новый пользователь", + "onlyOffice": "Only Office Integration", + "onlyOfficeUrl": "Only Office URL (leave blank to disable)", "password": "Пароль", "passwordUpdated": "Пароль обновлен!", "path": "Путь", @@ -242,4 +244,4 @@ "seconds": "Секунды", "unit": "Единица времени" } -} +} \ No newline at end of file diff --git a/frontend/src/i18n/sv-se.json b/frontend/src/i18n/sv-se.json index d6bb1676..b53257c6 100644 --- a/frontend/src/i18n/sv-se.json +++ b/frontend/src/i18n/sv-se.json @@ -169,6 +169,8 @@ "newPassword": "Ditt nya lösenord", "newPasswordConfirm": "Bekräfta ditt nya lösenord", "newUser": "Ny användare", + "onlyOffice": "Only Office Integration", + "onlyOfficeUrl": "Only Office URL (leave blank to disable)", "password": "Lösenord", "passwordUpdated": "Lösenord uppdaterat", "path": "", @@ -232,4 +234,4 @@ "seconds": "Sekunder", "unit": "Tidsenhet" } -} +} \ No newline at end of file diff --git a/frontend/src/i18n/zh-cn.json b/frontend/src/i18n/zh-cn.json index 51801a59..a0ab108c 100644 --- a/frontend/src/i18n/zh-cn.json +++ b/frontend/src/i18n/zh-cn.json @@ -191,6 +191,8 @@ "newPassword": "你的新密码", "newPasswordConfirm": "再次输入以确认你的新密码", "newUser": "新建用户", + "onlyOffice": "Only Office Integration", + "onlyOfficeUrl": "Only Office URL (leave blank to disable)", "password": "密码", "passwordUpdated": "密码已更新!", "path": "路径", @@ -256,4 +258,4 @@ "seconds": "秒", "unit": "时间单位" } -} +} \ No newline at end of file diff --git a/frontend/src/i18n/zh-tw.json b/frontend/src/i18n/zh-tw.json index 26da1978..2f176dae 100644 --- a/frontend/src/i18n/zh-tw.json +++ b/frontend/src/i18n/zh-tw.json @@ -169,6 +169,8 @@ "newPassword": "您的新密碼", "newPasswordConfirm": "重輸一遍新密碼", "newUser": "建立使用者", + "onlyOffice": "Only Office Integration", + "onlyOfficeUrl": "Only Office URL (leave blank to disable)", "password": "密碼", "passwordUpdated": "密碼已更新!", "path": "", @@ -232,4 +234,4 @@ "seconds": "秒", "unit": "時間單位" } -} +} \ No newline at end of file diff --git a/frontend/src/utils/constants.ts b/frontend/src/utils/constants.ts index 3f131b1a..c437b0d2 100644 --- a/frontend/src/utils/constants.ts +++ b/frontend/src/utils/constants.ts @@ -18,6 +18,7 @@ const enableExec: boolean = window.FileBrowser.EnableExec; const tusSettings = window.FileBrowser.TusSettings; const origin = window.location.origin; const tusEndpoint = `/api/tus`; +const onlyOffice = window.FileBrowser.OnlyOffice; export { name, @@ -39,4 +40,5 @@ export { tusSettings, origin, tusEndpoint, + onlyOffice, }; diff --git a/frontend/src/views/Files.vue b/frontend/src/views/Files.vue index 2e82fc6b..ea6196d2 100644 --- a/frontend/src/views/Files.vue +++ b/frontend/src/views/Files.vue @@ -37,6 +37,7 @@ import { storeToRefs } from "pinia"; import { useFileStore } from "@/stores/file"; import { useLayoutStore } from "@/stores/layout"; import { useUploadStore } from "@/stores/upload"; +import { onlyOffice } from "@/utils/constants"; import HeaderBar from "@/components/header/HeaderBar.vue"; import Breadcrumbs from "@/components/Breadcrumbs.vue"; @@ -47,6 +48,7 @@ import FileListing from "@/views/files/FileListing.vue"; import { StatusError } from "@/api/utils"; const Editor = defineAsyncComponent(() => import("@/views/files/Editor.vue")); const Preview = defineAsyncComponent(() => import("@/views/files/Preview.vue")); +const OnlyOfficeEditor = defineAsyncComponent(() => import("@/views/files/OnlyOfficeEditor.vue")); const layoutStore = useLayoutStore(); const fileStore = useFileStore(); @@ -77,6 +79,8 @@ const currentView = computed(() => { fileStore.req.type === "textImmutable" ) { return Editor; + } else if (fileStore.req.type === "officedocument" && onlyOffice !== "") { + return OnlyOfficeEditor; } else { return Preview; } diff --git a/frontend/src/views/files/OnlyOfficeEditor.vue b/frontend/src/views/files/OnlyOfficeEditor.vue new file mode 100644 index 00000000..bb76dce8 --- /dev/null +++ b/frontend/src/views/files/OnlyOfficeEditor.vue @@ -0,0 +1,170 @@ + + + + + diff --git a/frontend/src/views/settings/Global.vue b/frontend/src/views/settings/Global.vue index 40a3ec04..1b77e9e5 100644 --- a/frontend/src/views/settings/Global.vue +++ b/frontend/src/views/settings/Global.vue @@ -136,6 +136,31 @@ />

+ +

{{ $t("settings.onlyOffice") }}

+ +

+ + +

+

+ + +

diff --git a/http/http.go b/http/http.go index 620c43fd..1da832bd 100644 --- a/http/http.go +++ b/http/http.go @@ -60,6 +60,8 @@ func NewHandler( users.Handle("/{id:[0-9]+}", monkey(userGetHandler, "")).Methods("GET") users.Handle("/{id:[0-9]+}", monkey(userDeleteHandler, "")).Methods("DELETE") + api.PathPrefix("/onlyoffice").Handler(monkey(onlyofficeCallbackHandler, "/api/onlyoffice/callback")).Methods("POST") + api.PathPrefix("/resources").Handler(monkey(resourceGetHandler, "/api/resources")).Methods("GET") api.PathPrefix("/resources").Handler(monkey(resourceDeleteHandler(fileCache), "/api/resources")).Methods("DELETE") api.PathPrefix("/resources").Handler(monkey(resourcePostHandler(fileCache), "/api/resources")).Methods("POST") diff --git a/http/onlyoffice.go b/http/onlyoffice.go new file mode 100644 index 00000000..55d6416e --- /dev/null +++ b/http/onlyoffice.go @@ -0,0 +1,64 @@ +package http + +import ( + "encoding/json" + "errors" + "io" + "net/http" +) + +type OnlyOfficeCallback struct { + ChangesURL string `json:"changesurl,omitempty"` + Key string `json:"key"` + Status int `json:"status"` + URL string `json:"url,omitempty"` + Users []string `json:"users,omitempty"` + UserData string `json:"userdata,omitempty"` +} + +var onlyofficeCallbackHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) { + body, err := io.ReadAll(r.Body) + if err != nil { + return http.StatusInternalServerError, err + } + + var data OnlyOfficeCallback + err = json.Unmarshal(body, &data) + if err != nil { + return http.StatusInternalServerError, err + } + + if data.Status == 2 || data.Status == 6 { + docPath := r.URL.Query().Get("save") + if docPath == "" { + return http.StatusInternalServerError, errors.New("unable to get file save path") + } + + if !d.user.Perm.Modify || !d.Check(docPath) { + return http.StatusForbidden, nil + } + + doc, err := http.Get(data.URL) + if err != nil { + return http.StatusInternalServerError, err + } + defer doc.Body.Close() + + err = d.RunHook(func() error { + _, writeErr := writeFile(d.user.Fs, docPath, doc.Body) + if writeErr != nil { + return writeErr + } + return nil + }, "save", docPath, "", d.user) + + if err != nil { + return http.StatusInternalServerError, err + } + } + + resp := map[string]int{ + "error": 0, + } + return renderJSON(w, r, resp) +}) diff --git a/http/settings.go b/http/settings.go index de3f22ad..4c294148 100644 --- a/http/settings.go +++ b/http/settings.go @@ -18,6 +18,7 @@ type settingsData struct { Tus settings.Tus `json:"tus"` Shell []string `json:"shell"` Commands map[string][]string `json:"commands"` + OnlyOffice settings.OnlyOffice `json:"onlyoffice"` } var settingsGetHandler = withAdmin(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) { @@ -31,6 +32,7 @@ var settingsGetHandler = withAdmin(func(w http.ResponseWriter, r *http.Request, Tus: d.settings.Tus, Shell: d.settings.Shell, Commands: d.settings.Commands, + OnlyOffice: d.settings.OnlyOffice, } return renderJSON(w, r, data) @@ -52,6 +54,7 @@ var settingsPutHandler = withAdmin(func(_ http.ResponseWriter, r *http.Request, d.settings.Tus = req.Tus d.settings.Shell = req.Shell d.settings.Commands = req.Commands + d.settings.OnlyOffice = req.OnlyOffice err = d.store.Settings.Save(d.settings) return errToStatus(err), err diff --git a/http/static.go b/http/static.go index 47d828c6..d8f19c4c 100644 --- a/http/static.go +++ b/http/static.go @@ -46,6 +46,7 @@ func handleWithStaticData(w http.ResponseWriter, _ *http.Request, d *data, fSys "ResizePreview": d.server.ResizePreview, "EnableExec": d.server.EnableExec, "TusSettings": d.settings.Tus, + "OnlyOffice": d.settings.OnlyOffice, } if d.settings.Branding.Files != "" { diff --git a/settings/onlyoffice.go b/settings/onlyoffice.go new file mode 100644 index 00000000..1b6cb185 --- /dev/null +++ b/settings/onlyoffice.go @@ -0,0 +1,7 @@ +package settings + +// OnlyOffice contains the onlyoffice server connection settings of the app. +type OnlyOffice struct { + URL string `json:"url"` + JWTSecret string `json:"jwtSecret"` +} diff --git a/settings/settings.go b/settings/settings.go index 22908396..1ee0b1c1 100644 --- a/settings/settings.go +++ b/settings/settings.go @@ -27,6 +27,7 @@ type Settings struct { Commands map[string][]string `json:"commands"` Shell []string `json:"shell"` Rules []rules.Rule `json:"rules"` + OnlyOffice OnlyOffice `json:"onlyoffice"` } // GetRules implements rules.Provider. diff --git a/test.docx b/test.docx new file mode 100644 index 00000000..adf9a8c0 Binary files /dev/null and b/test.docx differ