This commit is contained in:
drosoCode 2021-09-23 14:13:30 -07:00 committed by GitHub
commit d560b877f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 306 additions and 18 deletions

View File

@ -39,6 +39,7 @@ override the options.`,
DisableExternal: mustGetBool(flags, "branding.disableExternal"),
Files: mustGetString(flags, "branding.files"),
},
OnlyOffice: "",
}
ser := &settings.Server{

View File

@ -57,6 +57,8 @@ you want to change. Other options will remain unchanged.`,
set.Branding.DisableExternal = mustGetBool(flags, flag.Name)
case "branding.files":
set.Branding.Files = mustGetString(flags, flag.Name)
case "onlyoffice":
set.OnlyOffice = mustGetString(flags, flag.Name)
}
})

View File

@ -236,6 +236,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"
}

View File

@ -190,6 +190,8 @@
"newPassword": "كلمة المرور الجديدة",
"newPasswordConfirm": "تأكيد كلمة المرور",
"newUser": "مستخدم جديد",
"onlyOffice": "Only Office Integration",
"onlyOfficeUrl": "Only Office URL (leave blank to disable)",
"password": "كلمة المرور",
"passwordUpdated": "تم تغيير كلمة المرور",
"path": "",
@ -253,4 +255,4 @@
"seconds": "ثواني",
"unit": "وحدة الوقت"
}
}
}

View File

@ -190,6 +190,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": "",
@ -253,4 +255,4 @@
"seconds": "Sekunden",
"unit": "Zeiteinheit"
}
}
}

View File

@ -198,6 +198,8 @@
"newPassword": "Your new password",
"newPasswordConfirm": "Confirm your new password",
"newUser": "New User",
"onlyOffice": "Only Office Integration",
"onlyOfficeUrl": "Only Office URL (leave blank to disable)",
"password": "Password",
"passwordUpdated": "Password updated!",
"path": "Path",
@ -263,4 +265,4 @@
"seconds": "Seconds",
"unit": "Time Unit"
}
}
}

View File

@ -190,6 +190,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": "",
@ -253,4 +255,4 @@
"seconds": "Segundos",
"unit": "Unidad"
}
}
}

View File

@ -190,6 +190,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": "",
@ -253,4 +255,4 @@
"seconds": "Secondes",
"unit": "Unité de temps"
}
}
}

View File

@ -190,6 +190,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": "",
@ -253,4 +255,4 @@
"seconds": "Sekúndur",
"unit": "Tímastilling"
}
}
}

View File

@ -190,6 +190,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": "",
@ -253,4 +255,4 @@
"seconds": "Secondi",
"unit": "Unità di tempo"
}
}
}

View File

@ -190,6 +190,8 @@
"newPassword": "新しいパスワード",
"newPasswordConfirm": "新しいパスワードを確認します",
"newUser": "新しいユーザー",
"onlyOffice": "Only Office Integration",
"onlyOfficeUrl": "Only Office URL (leave blank to disable)",
"password": "パスワード",
"passwordUpdated": "パスワードは更新されました!",
"path": "",
@ -253,4 +255,4 @@
"seconds": "秒",
"unit": "時間単位"
}
}
}

View File

@ -190,6 +190,8 @@
"newPassword": "새로운 비밀번호",
"newPasswordConfirm": "새로운 비밀번호 확인",
"newUser": "새로운 사용자",
"onlyOffice": "Only Office Integration",
"onlyOfficeUrl": "Only Office URL (leave blank to disable)",
"password": "비밀번호",
"passwordUpdated": "비밀번호 수정 완료!",
"path": "",
@ -253,4 +255,4 @@
"seconds": "초",
"unit": "Time Unit"
}
}
}

View File

@ -190,6 +190,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": "",
@ -253,4 +255,4 @@
"seconds": "Seconden",
"unit": "Tijdseenheid"
}
}
}

View File

@ -190,6 +190,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": "",
@ -253,4 +255,4 @@
"seconds": "Sekundy",
"unit": "Jednostka czasu"
}
}
}

View File

@ -190,6 +190,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": "",
@ -253,4 +255,4 @@
"seconds": "Segundos",
"unit": "Unidades de Tempo"
}
}
}

View File

@ -190,6 +190,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": "",
@ -253,4 +255,4 @@
"seconds": "Segundos",
"unit": "Unidades de tempo"
}
}
}

View File

@ -190,6 +190,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": "",
@ -253,4 +255,4 @@
"seconds": "Secunde",
"unit": "Unitate de timp"
}
}
}

View File

@ -189,6 +189,8 @@
"newPassword": "Новый пароль",
"newPasswordConfirm": "Повтор нового пароля",
"newUser": "Новый пользователь",
"onlyOffice": "Only Office Integration",
"onlyOfficeUrl": "Only Office URL (leave blank to disable)",
"password": "Пароль",
"passwordUpdated": "Пароль обновлен!",
"path": "Путь",
@ -252,4 +254,4 @@
"seconds": "Секунды",
"unit": "Единица времени"
}
}
}

View File

@ -190,6 +190,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": "",
@ -253,4 +255,4 @@
"seconds": "Sekunder",
"unit": "Tidsenhet"
}
}
}

View File

@ -193,6 +193,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": "时间单位"
}
}
}

View File

@ -190,6 +190,8 @@
"newPassword": "您的新密碼",
"newPasswordConfirm": "重輸一遍新密碼",
"newUser": "建立使用者",
"onlyOffice": "Only Office Integration",
"onlyOfficeUrl": "Only Office URL (leave blank to disable)",
"password": "密碼",
"passwordUpdated": "密碼已更新!",
"path": "",
@ -253,4 +255,4 @@
"seconds": "秒",
"unit": "時間單位"
}
}
}

View File

@ -14,6 +14,7 @@ const theme = window.FileBrowser.Theme;
const enableThumbs = window.FileBrowser.EnableThumbs;
const resizePreview = window.FileBrowser.ResizePreview;
const enableExec = window.FileBrowser.EnableExec;
const onlyOffice = window.FileBrowser.OnlyOffice;
export {
name,
@ -31,4 +32,5 @@ export {
enableThumbs,
resizePreview,
enableExec,
onlyOffice,
};

View File

@ -22,6 +22,7 @@
<script>
import { files as api } from "@/api";
import { mapState, mapMutations } from "vuex";
import { onlyOffice } from "@/utils/constants";
import HeaderBar from "@/components/header/HeaderBar";
import Breadcrumbs from "@/components/Breadcrumbs";
@ -42,6 +43,7 @@ export default {
Preview,
Listing,
Editor: () => import("@/views/files/Editor"),
OnlyOfficeEditor: () => import("@/views/files/OnlyOfficeEditor"),
},
data: function () {
return {
@ -63,6 +65,8 @@ export default {
this.req.type === "textImmutable"
) {
return "editor";
} else if (this.req.type === "officedocument" && onlyOffice !== "") {
return "OnlyOfficeEditor";
} else {
return "preview";
}

View File

@ -0,0 +1,154 @@
<template>
<div id="editor-container">
<header-bar>
<action icon="close" :label="$t('buttons.close')" @action="close()" />
<title>{{ req.name }}</title>
</header-bar>
<breadcrumbs base="/files" noLink />
<div id="editor"></div>
</div>
</template>
<style scoped>
#editor-container {
height: 100vh;
width: 100vw;
}
</style>
<script>
import { mapState } from "vuex";
import url from "@/utils/url";
import { baseURL, onlyOffice } from "@/utils/constants";
import HeaderBar from "@/components/header/HeaderBar";
import Action from "@/components/header/Action";
import Breadcrumbs from "@/components/Breadcrumbs";
export default {
name: "onlyofficeeditor",
components: {
HeaderBar,
Action,
Breadcrumbs,
},
data: function () {
return {};
},
computed: {
...mapState(["req", "user", "jwt"]),
breadcrumbs() {
let parts = this.$route.path.split("/");
if (parts[0] === "") {
parts.shift();
}
if (parts[parts.length - 1] === "") {
parts.pop();
}
let breadcrumbs = [];
for (let i = 0; i < parts.length; i++) {
breadcrumbs.push({ name: decodeURIComponent(parts[i]) });
}
breadcrumbs.shift();
if (breadcrumbs.length > 3) {
while (breadcrumbs.length !== 4) {
breadcrumbs.shift();
}
breadcrumbs[0].name = "...";
}
return breadcrumbs;
},
},
created() {
window.addEventListener("keydown", this.keyEvent);
},
beforeDestroy() {
window.removeEventListener("keydown", this.keyEvent);
this.editor.destroyEditor();
},
mounted: function () {
let onlyofficeScript = document.createElement("script");
onlyofficeScript.setAttribute(
"src",
`${onlyOffice}/web-apps/apps/api/documents/api.js`
);
document.head.appendChild(onlyofficeScript);
onlyofficeScript.onload = () => {
let fileUrl = `${window.location.protocol}//${window.location.host}${baseURL}/api/raw${url.encodePath(
this.req.path
)}?auth=${this.jwt}`;
let key = Date.parse(this.req.modified).toString() + url.encodePath(this.req.path);
key = key.replaceAll(/[-_.!~[\]*'()/,;:\-%+.]/g, "");
if (key.length > 127) {
key = key.substring(0, 127);
}
/*eslint-disable */
let config = {
document: {
fileType: this.req.extension.substring(1),
key: key,
title: this.req.name,
url: fileUrl,
permissions: {
edit: this.user.perm.modify,
download: this.user.perm.download,
print: this.user.perm.download
}
},
editorConfig: {
callbackUrl: `${window.location.protocol}//${window.location.host}${baseURL}/api/onlyoffice/callback?auth=${this.jwt}&save=${encodeURIComponent(this.req.path)}`,
user: {
id: this.user.id,
name: `User ${this.user.id}`
},
customization: {
autosave: true,
forcesave: true
},
lang: this.user.locale,
mode: this.user.perm.modify ? "edit" : "view"
}
};
this.editor = new DocsAPI.DocEditor("editor", config);
/*eslint-enable */
};
},
methods: {
back() {
let uri = url.removeLastDir(this.$route.path) + "/";
this.$router.push({ path: uri });
},
keyEvent(event) {
if (!event.ctrlKey && !event.metaKey) {
return;
}
if (String.fromCharCode(event.which).toLowerCase() !== "s") {
return;
}
event.preventDefault();
this.save();
},
close() {
this.$store.commit("updateRequest", {});
let uri = url.removeLastDir(this.$route.path) + "/";
this.$router.push({ path: uri });
},
},
};
</script>

View File

@ -83,6 +83,20 @@
id="branding-files"
/>
</p>
<h3>{{ $t("settings.onlyOffice") }}</h3>
<p>
<label for="onlyoffice-url">{{
$t("settings.onlyOfficeUrl")
}}</label>
<input
class="input input--block"
type="text"
v-model="settings.onlyoffice"
id="onlyoffice-url"
/>
</p>
</div>
<div class="card-action">

View File

@ -59,6 +59,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")

65
http/onlyoffice.go Normal file
View File

@ -0,0 +1,65 @@
package http
import (
"encoding/json"
"errors"
"io/ioutil"
"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, e1 := ioutil.ReadAll(r.Body)
if e1 != nil {
return http.StatusInternalServerError, e1
}
var data OnlyOfficeCallback
err1 := json.Unmarshal(body, &data)
if err1 != nil {
return http.StatusInternalServerError, err1
}
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, err2 := http.Get(data.URL)
if err2 != nil {
return http.StatusInternalServerError, err2
}
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 {
_ = d.user.Fs.RemoveAll(docPath)
return http.StatusInternalServerError, err
}
}
resp := map[string]int{
"error": 0,
}
return renderJSON(w, r, resp)
})

View File

@ -16,6 +16,7 @@ type settingsData struct {
Branding settings.Branding `json:"branding"`
Shell []string `json:"shell"`
Commands map[string][]string `json:"commands"`
OnlyOffice string `json:"onlyoffice"`
}
var settingsGetHandler = withAdmin(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
@ -27,6 +28,7 @@ var settingsGetHandler = withAdmin(func(w http.ResponseWriter, r *http.Request,
Branding: d.settings.Branding,
Shell: d.settings.Shell,
Commands: d.settings.Commands,
OnlyOffice: d.settings.OnlyOffice,
}
return renderJSON(w, r, data)
@ -46,6 +48,7 @@ var settingsPutHandler = withAdmin(func(w http.ResponseWriter, r *http.Request,
d.settings.Branding = req.Branding
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

View File

@ -43,6 +43,7 @@ func handleWithStaticData(w http.ResponseWriter, _ *http.Request, d *data, fSys
"EnableThumbs": d.server.EnableThumbnails,
"ResizePreview": d.server.ResizePreview,
"EnableExec": d.server.EnableExec,
"OnlyOffice": d.settings.OnlyOffice,
}
if d.settings.Branding.Files != "" {

View File

@ -21,6 +21,7 @@ type Settings struct {
Commands map[string][]string `json:"commands"`
Shell []string `json:"shell"`
Rules []rules.Rule `json:"rules"`
OnlyOffice string `json:"onlyoffice"`
}
// GetRules implements rules.Provider.