From 12b09d6c364599b26d96b2199afd47c178811e17 Mon Sep 17 00:00:00 2001 From: Sergey Linnik Date: Thu, 12 Oct 2023 17:42:32 +0300 Subject: [PATCH 001/114] oC Web: compatibility owncloud-web v7.0 https://github.com/ONLYOFFICE/onlyoffice-owncloud-web/commit/88fc85d103fcd957adae6253497c1e9edea7208f --- CHANGELOG.md | 3 + js/web/onlyoffice.js | 8132 ++++++++++++++++++++++++++++++------------ 2 files changed, 5805 insertions(+), 2330 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1fcace2e..98da63be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Change Log +### Changed +- compatible with ownCloud Web 7.0 + ## 8.2.3 ## Added - Ukrainian translation diff --git a/js/web/onlyoffice.js b/js/web/onlyoffice.js index c8927c7a..f745fa04 100644 --- a/js/web/onlyoffice.js +++ b/js/web/onlyoffice.js @@ -1,298 +1,183 @@ -define((function () { 'use strict'; +define(['vue'], (function (vue) { 'use strict'; var global$1 = (typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}); - // shim for using process in browser - // based off https://github.com/defunctzombie/node-process/blob/master/browser.js - - function defaultSetTimout() { - throw new Error('setTimeout has not been defined'); - } - function defaultClearTimeout () { - throw new Error('clearTimeout has not been defined'); + function getDevtoolsGlobalHook() { + return getTarget().__VUE_DEVTOOLS_GLOBAL_HOOK__; } - var cachedSetTimeout = defaultSetTimout; - var cachedClearTimeout = defaultClearTimeout; - if (typeof global$1.setTimeout === 'function') { - cachedSetTimeout = setTimeout; + function getTarget() { + // @ts-ignore + return (typeof navigator !== 'undefined' && typeof window !== 'undefined') + ? window + : typeof global$1 !== 'undefined' + ? global$1 + : {}; } - if (typeof global$1.clearTimeout === 'function') { - cachedClearTimeout = clearTimeout; - } - - function runTimeout(fun) { - if (cachedSetTimeout === setTimeout) { - //normal enviroments in sane situations - return setTimeout(fun, 0); - } - // if setTimeout wasn't available but was latter defined - if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { - cachedSetTimeout = setTimeout; - return setTimeout(fun, 0); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedSetTimeout(fun, 0); - } catch(e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedSetTimeout.call(null, fun, 0); - } catch(e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error - return cachedSetTimeout.call(this, fun, 0); - } - } + const isProxyAvailable = typeof Proxy === 'function'; + const HOOK_SETUP = 'devtools-plugin:setup'; + const HOOK_PLUGIN_SETTINGS_SET = 'plugin:settings:set'; - } - function runClearTimeout(marker) { - if (cachedClearTimeout === clearTimeout) { - //normal enviroments in sane situations - return clearTimeout(marker); + let supported; + let perf; + function isPerformanceSupported() { + var _a; + if (supported !== undefined) { + return supported; } - // if clearTimeout wasn't available but was latter defined - if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { - cachedClearTimeout = clearTimeout; - return clearTimeout(marker); + if (typeof window !== 'undefined' && window.performance) { + supported = true; + perf = window.performance; } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedClearTimeout(marker); - } catch (e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedClearTimeout.call(null, marker); - } catch (e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. - // Some versions of I.E. have different rules for clearTimeout vs setTimeout - return cachedClearTimeout.call(this, marker); - } + else if (typeof global$1 !== 'undefined' && ((_a = global$1.perf_hooks) === null || _a === void 0 ? void 0 : _a.performance)) { + supported = true; + perf = global$1.perf_hooks.performance; } - - - + else { + supported = false; + } + return supported; + } + function now() { + return isPerformanceSupported() ? perf.now() : Date.now(); } - var queue = []; - var draining = false; - var currentQueue; - var queueIndex = -1; - function cleanUpNextTick() { - if (!draining || !currentQueue) { - return; - } - draining = false; - if (currentQueue.length) { - queue = currentQueue.concat(queue); - } else { - queueIndex = -1; + class ApiProxy { + constructor(plugin, hook) { + this.target = null; + this.targetQueue = []; + this.onQueue = []; + this.plugin = plugin; + this.hook = hook; + const defaultSettings = {}; + if (plugin.settings) { + for (const id in plugin.settings) { + const item = plugin.settings[id]; + defaultSettings[id] = item.defaultValue; + } + } + const localSettingsSaveId = `__vue-devtools-plugin-settings__${plugin.id}`; + let currentSettings = Object.assign({}, defaultSettings); + try { + const raw = localStorage.getItem(localSettingsSaveId); + const data = JSON.parse(raw); + Object.assign(currentSettings, data); + } + catch (e) { + // noop + } + this.fallbacks = { + getSettings() { + return currentSettings; + }, + setSettings(value) { + try { + localStorage.setItem(localSettingsSaveId, JSON.stringify(value)); + } + catch (e) { + // noop + } + currentSettings = value; + }, + now() { + return now(); + }, + }; + if (hook) { + hook.on(HOOK_PLUGIN_SETTINGS_SET, (pluginId, value) => { + if (pluginId === this.plugin.id) { + this.fallbacks.setSettings(value); + } + }); + } + this.proxiedOn = new Proxy({}, { + get: (_target, prop) => { + if (this.target) { + return this.target.on[prop]; + } + else { + return (...args) => { + this.onQueue.push({ + method: prop, + args, + }); + }; + } + }, + }); + this.proxiedTarget = new Proxy({}, { + get: (_target, prop) => { + if (this.target) { + return this.target[prop]; + } + else if (prop === 'on') { + return this.proxiedOn; + } + else if (Object.keys(this.fallbacks).includes(prop)) { + return (...args) => { + this.targetQueue.push({ + method: prop, + args, + resolve: () => { }, + }); + return this.fallbacks[prop](...args); + }; + } + else { + return (...args) => { + return new Promise(resolve => { + this.targetQueue.push({ + method: prop, + args, + resolve, + }); + }); + }; + } + }, + }); } - if (queue.length) { - drainQueue(); + async setRealTarget(target) { + this.target = target; + for (const item of this.onQueue) { + this.target.on[item.method](...item.args); + } + for (const item of this.targetQueue) { + item.resolve(await this.target[item.method](...item.args)); + } } } - function drainQueue() { - if (draining) { - return; + function setupDevtoolsPlugin(pluginDescriptor, setupFn) { + const descriptor = pluginDescriptor; + const target = getTarget(); + const hook = getDevtoolsGlobalHook(); + const enableProxy = isProxyAvailable && descriptor.enableEarlyProxy; + if (hook && (target.__VUE_DEVTOOLS_PLUGIN_API_AVAILABLE__ || !enableProxy)) { + hook.emit(HOOK_SETUP, pluginDescriptor, setupFn); } - var timeout = runTimeout(cleanUpNextTick); - draining = true; - - var len = queue.length; - while(len) { - currentQueue = queue; - queue = []; - while (++queueIndex < len) { - if (currentQueue) { - currentQueue[queueIndex].run(); - } - } - queueIndex = -1; - len = queue.length; - } - currentQueue = null; - draining = false; - runClearTimeout(timeout); - } - function nextTick(fun) { - var args = new Array(arguments.length - 1); - if (arguments.length > 1) { - for (var i = 1; i < arguments.length; i++) { - args[i - 1] = arguments[i]; - } + else { + const proxy = enableProxy ? new ApiProxy(descriptor, hook) : null; + const list = target.__VUE_DEVTOOLS_PLUGINS__ = target.__VUE_DEVTOOLS_PLUGINS__ || []; + list.push({ + pluginDescriptor: descriptor, + setupFn, + proxy, + }); + if (proxy) + setupFn(proxy.proxiedTarget); } - queue.push(new Item(fun, args)); - if (queue.length === 1 && !draining) { - runTimeout(drainQueue); - } - } - // v8 likes predictible objects - function Item(fun, array) { - this.fun = fun; - this.array = array; - } - Item.prototype.run = function () { - this.fun.apply(null, this.array); - }; - var title = 'browser'; - var platform = 'browser'; - var browser$1 = true; - var env = {}; - var argv = []; - var version$1 = ''; // empty string to avoid regexp issues - var versions = {}; - var release = {}; - var config = {}; - - function noop() {} - - var on = noop; - var addListener = noop; - var once = noop; - var off = noop; - var removeListener = noop; - var removeAllListeners = noop; - var emit = noop; - - function binding(name) { - throw new Error('process.binding is not supported'); - } - - function cwd () { return '/' } - function chdir (dir) { - throw new Error('process.chdir is not supported'); - }function umask() { return 0; } - - // from https://github.com/kumavis/browser-process-hrtime/blob/master/index.js - var performance = global$1.performance || {}; - var performanceNow = - performance.now || - performance.mozNow || - performance.msNow || - performance.oNow || - performance.webkitNow || - function(){ return (new Date()).getTime() }; - - // generate timestamp or delta - // see http://nodejs.org/api/process.html#process_process_hrtime - function hrtime(previousTimestamp){ - var clocktime = performanceNow.call(performance)*1e-3; - var seconds = Math.floor(clocktime); - var nanoseconds = Math.floor((clocktime%1)*1e9); - if (previousTimestamp) { - seconds = seconds - previousTimestamp[0]; - nanoseconds = nanoseconds - previousTimestamp[1]; - if (nanoseconds<0) { - seconds--; - nanoseconds += 1e9; - } - } - return [seconds,nanoseconds] - } - - var startTime = new Date(); - function uptime() { - var currentTime = new Date(); - var dif = currentTime - startTime; - return dif / 1000; - } - - var process = { - nextTick: nextTick, - title: title, - browser: browser$1, - env: env, - argv: argv, - version: version$1, - versions: versions, - on: on, - addListener: addListener, - once: once, - off: off, - removeListener: removeListener, - removeAllListeners: removeAllListeners, - emit: emit, - binding: binding, - cwd: cwd, - chdir: chdir, - umask: umask, - hrtime: hrtime, - platform: platform, - release: release, - config: config, - uptime: uptime - }; + } /*! - * vuex v3.6.2 - * (c) 2021 Evan You + * vuex v4.1.0 + * (c) 2022 Evan You * @license MIT */ - function applyMixin (Vue) { - var version = Number(Vue.version.split('.')[0]); - - if (version >= 2) { - Vue.mixin({ beforeCreate: vuexInit }); - } else { - // override init and inject vuex init procedure - // for 1.x backwards compatibility. - var _init = Vue.prototype._init; - Vue.prototype._init = function (options) { - if ( options === void 0 ) options = {}; - - options.init = options.init - ? [vuexInit].concat(options.init) - : vuexInit; - _init.call(this, options); - }; - } - - /** - * Vuex init hook, injected into each instances init hooks list. - */ - function vuexInit () { - var options = this.$options; - // store injection - if (options.store) { - this.$store = typeof options.store === 'function' - ? options.store() - : options.store; - } else if (options.parent && options.parent.$store) { - this.$store = options.parent.$store; - } - } - } - - var target = typeof window !== 'undefined' - ? window - : typeof global$1 !== 'undefined' - ? global$1 - : {}; - var devtoolHook = target.__VUE_DEVTOOLS_GLOBAL_HOOK__; - - function devtoolPlugin (store) { - if (!devtoolHook) { return } - - store._devtoolHook = devtoolHook; - - devtoolHook.emit('vuex:init', store); - - devtoolHook.on('vuex:travel-to-state', function (targetState) { - store.replaceState(targetState); - }); - - store.subscribe(function (mutation, state) { - devtoolHook.emit('vuex:mutation', mutation, state); - }, { prepend: true }); - - store.subscribeAction(function (action, state) { - devtoolHook.emit('vuex:action', action, state); - }, { prepend: true }); - } + var storeKey = 'store'; /** * forEach for object @@ -319,1455 +204,5101 @@ define((function () { 'use strict'; } } - // Base data struct for store's module, package with some attribute and method - var Module = function Module (rawModule, runtime) { - this.runtime = runtime; - // Store some children item - this._children = Object.create(null); - // Store the origin module object which passed by programmer - this._rawModule = rawModule; - var rawState = rawModule.state; - - // Store the origin module's state - this.state = (typeof rawState === 'function' ? rawState() : rawState) || {}; - }; - - var prototypeAccessors = { namespaced: { configurable: true } }; + function genericSubscribe (fn, subs, options) { + if (subs.indexOf(fn) < 0) { + options && options.prepend + ? subs.unshift(fn) + : subs.push(fn); + } + return function () { + var i = subs.indexOf(fn); + if (i > -1) { + subs.splice(i, 1); + } + } + } - prototypeAccessors.namespaced.get = function () { - return !!this._rawModule.namespaced - }; + function resetStore (store, hot) { + store._actions = Object.create(null); + store._mutations = Object.create(null); + store._wrappedGetters = Object.create(null); + store._modulesNamespaceMap = Object.create(null); + var state = store.state; + // init all modules + installModule(store, state, [], store._modules.root, true); + // reset state + resetStoreState(store, state, hot); + } - Module.prototype.addChild = function addChild (key, module) { - this._children[key] = module; - }; + function resetStoreState (store, state, hot) { + var oldState = store._state; + var oldScope = store._scope; - Module.prototype.removeChild = function removeChild (key) { - delete this._children[key]; - }; + // bind store public getters + store.getters = {}; + // reset local getters cache + store._makeLocalGettersCache = Object.create(null); + var wrappedGetters = store._wrappedGetters; + var computedObj = {}; + var computedCache = {}; + + // create a new effect scope and create computed object inside it to avoid + // getters (computed) getting destroyed on component unmount. + var scope = vue.effectScope(true); + + scope.run(function () { + forEachValue(wrappedGetters, function (fn, key) { + // use computed to leverage its lazy-caching mechanism + // direct inline function use will lead to closure preserving oldState. + // using partial to return function with only arguments preserved in closure environment. + computedObj[key] = partial(fn, store); + computedCache[key] = vue.computed(function () { return computedObj[key](); }); + Object.defineProperty(store.getters, key, { + get: function () { return computedCache[key].value; }, + enumerable: true // for local getters + }); + }); + }); - Module.prototype.getChild = function getChild (key) { - return this._children[key] - }; + store._state = vue.reactive({ + data: state + }); - Module.prototype.hasChild = function hasChild (key) { - return key in this._children - }; + // register the newly created effect scope to the store so that we can + // dispose the effects when this method runs again in the future. + store._scope = scope; - Module.prototype.update = function update (rawModule) { - this._rawModule.namespaced = rawModule.namespaced; - if (rawModule.actions) { - this._rawModule.actions = rawModule.actions; + // enable strict mode for new state + if (store.strict) { + enableStrictMode(store); } - if (rawModule.mutations) { - this._rawModule.mutations = rawModule.mutations; + + if (oldState) { + if (hot) { + // dispatch changes in all subscribed watchers + // to force getter re-evaluation for hot reloading. + store._withCommit(function () { + oldState.data = null; + }); + } } - if (rawModule.getters) { - this._rawModule.getters = rawModule.getters; + + // dispose previously registered effect scope if there is one. + if (oldScope) { + oldScope.stop(); } - }; + } - Module.prototype.forEachChild = function forEachChild (fn) { - forEachValue(this._children, fn); - }; + function installModule (store, rootState, path, module, hot) { + var isRoot = !path.length; + var namespace = store._modules.getNamespace(path); - Module.prototype.forEachGetter = function forEachGetter (fn) { - if (this._rawModule.getters) { - forEachValue(this._rawModule.getters, fn); + // register in namespace map + if (module.namespaced) { + if (store._modulesNamespaceMap[namespace] && true) { + console.error(("[vuex] duplicate namespace " + namespace + " for the namespaced module " + (path.join('/')))); + } + store._modulesNamespaceMap[namespace] = module; } - }; - Module.prototype.forEachAction = function forEachAction (fn) { - if (this._rawModule.actions) { - forEachValue(this._rawModule.actions, fn); + // set state + if (!isRoot && !hot) { + var parentState = getNestedState(rootState, path.slice(0, -1)); + var moduleName = path[path.length - 1]; + store._withCommit(function () { + { + if (moduleName in parentState) { + console.warn( + ("[vuex] state field \"" + moduleName + "\" was overridden by a module with the same name at \"" + (path.join('.')) + "\"") + ); + } + } + parentState[moduleName] = module.state; + }); } - }; - Module.prototype.forEachMutation = function forEachMutation (fn) { - if (this._rawModule.mutations) { - forEachValue(this._rawModule.mutations, fn); - } - }; + var local = module.context = makeLocalContext(store, namespace, path); - Object.defineProperties( Module.prototype, prototypeAccessors ); + module.forEachMutation(function (mutation, key) { + var namespacedType = namespace + key; + registerMutation(store, namespacedType, mutation, local); + }); - var ModuleCollection = function ModuleCollection (rawRootModule) { - // register root module (Vuex.Store options) - this.register([], rawRootModule, false); - }; + module.forEachAction(function (action, key) { + var type = action.root ? key : namespace + key; + var handler = action.handler || action; + registerAction(store, type, handler, local); + }); - ModuleCollection.prototype.get = function get (path) { - return path.reduce(function (module, key) { - return module.getChild(key) - }, this.root) - }; + module.forEachGetter(function (getter, key) { + var namespacedType = namespace + key; + registerGetter(store, namespacedType, getter, local); + }); - ModuleCollection.prototype.getNamespace = function getNamespace (path) { - var module = this.root; - return path.reduce(function (namespace, key) { - module = module.getChild(key); - return namespace + (module.namespaced ? key + '/' : '') - }, '') - }; + module.forEachChild(function (child, key) { + installModule(store, rootState, path.concat(key), child, hot); + }); + } - ModuleCollection.prototype.update = function update$1 (rawRootModule) { - update([], this.root, rawRootModule); - }; + /** + * make localized dispatch, commit, getters and state + * if there is no namespace, just use root ones + */ + function makeLocalContext (store, namespace, path) { + var noNamespace = namespace === ''; - ModuleCollection.prototype.register = function register (path, rawModule, runtime) { - var this$1$1 = this; - if ( runtime === void 0 ) runtime = true; + var local = { + dispatch: noNamespace ? store.dispatch : function (_type, _payload, _options) { + var args = unifyObjectStyle(_type, _payload, _options); + var payload = args.payload; + var options = args.options; + var type = args.type; - if ((process.env.NODE_ENV !== 'production')) { - assertRawModule(path, rawModule); - } + if (!options || !options.root) { + type = namespace + type; + if (!store._actions[type]) { + console.error(("[vuex] unknown local action type: " + (args.type) + ", global type: " + type)); + return + } + } - var newModule = new Module(rawModule, runtime); - if (path.length === 0) { - this.root = newModule; - } else { - var parent = this.get(path.slice(0, -1)); - parent.addChild(path[path.length - 1], newModule); - } + return store.dispatch(type, payload) + }, - // register nested modules - if (rawModule.modules) { - forEachValue(rawModule.modules, function (rawChildModule, key) { - this$1$1.register(path.concat(key), rawChildModule, runtime); - }); - } - }; + commit: noNamespace ? store.commit : function (_type, _payload, _options) { + var args = unifyObjectStyle(_type, _payload, _options); + var payload = args.payload; + var options = args.options; + var type = args.type; - ModuleCollection.prototype.unregister = function unregister (path) { - var parent = this.get(path.slice(0, -1)); - var key = path[path.length - 1]; - var child = parent.getChild(key); + if (!options || !options.root) { + type = namespace + type; + if (!store._mutations[type]) { + console.error(("[vuex] unknown local mutation type: " + (args.type) + ", global type: " + type)); + return + } + } - if (!child) { - if ((process.env.NODE_ENV !== 'production')) { - console.warn( - "[vuex] trying to unregister module '" + key + "', which is " + - "not registered" - ); + store.commit(type, payload, options); + } + }; + + // getters and state object must be gotten lazily + // because they will be changed by state update + Object.defineProperties(local, { + getters: { + get: noNamespace + ? function () { return store.getters; } + : function () { return makeLocalGetters(store, namespace); } + }, + state: { + get: function () { return getNestedState(store.state, path); } + } + }); + + return local + } + + function makeLocalGetters (store, namespace) { + if (!store._makeLocalGettersCache[namespace]) { + var gettersProxy = {}; + var splitPos = namespace.length; + Object.keys(store.getters).forEach(function (type) { + // skip if the target getter is not match this namespace + if (type.slice(0, splitPos) !== namespace) { return } + + // extract local getter type + var localType = type.slice(splitPos); + + // Add a port to the getters proxy. + // Define as getter property because + // we do not want to evaluate the getters in this time. + Object.defineProperty(gettersProxy, localType, { + get: function () { return store.getters[type]; }, + enumerable: true + }); + }); + store._makeLocalGettersCache[namespace] = gettersProxy; + } + + return store._makeLocalGettersCache[namespace] + } + + function registerMutation (store, type, handler, local) { + var entry = store._mutations[type] || (store._mutations[type] = []); + entry.push(function wrappedMutationHandler (payload) { + handler.call(store, local.state, payload); + }); + } + + function registerAction (store, type, handler, local) { + var entry = store._actions[type] || (store._actions[type] = []); + entry.push(function wrappedActionHandler (payload) { + var res = handler.call(store, { + dispatch: local.dispatch, + commit: local.commit, + getters: local.getters, + state: local.state, + rootGetters: store.getters, + rootState: store.state + }, payload); + if (!isPromise(res)) { + res = Promise.resolve(res); + } + if (store._devtoolHook) { + return res.catch(function (err) { + store._devtoolHook.emit('vuex:error', err); + throw err + }) + } else { + return res + } + }); + } + + function registerGetter (store, type, rawGetter, local) { + if (store._wrappedGetters[type]) { + { + console.error(("[vuex] duplicate getter key: " + type)); } return } + store._wrappedGetters[type] = function wrappedGetter (store) { + return rawGetter( + local.state, // local state + local.getters, // local getters + store.state, // root state + store.getters // root getters + ) + }; + } + + function enableStrictMode (store) { + vue.watch(function () { return store._state.data; }, function () { + { + assert(store._committing, "do not mutate vuex store state outside mutation handlers."); + } + }, { deep: true, flush: 'sync' }); + } + + function getNestedState (state, path) { + return path.reduce(function (state, key) { return state[key]; }, state) + } + + function unifyObjectStyle (type, payload, options) { + if (isObject$1(type) && type.type) { + options = payload; + payload = type; + type = type.type; + } + + { + assert(typeof type === 'string', ("expects string as the type, but found " + (typeof type) + ".")); + } + + return { type: type, payload: payload, options: options } + } + + var LABEL_VUEX_BINDINGS = 'vuex bindings'; + var MUTATIONS_LAYER_ID = 'vuex:mutations'; + var ACTIONS_LAYER_ID = 'vuex:actions'; + var INSPECTOR_ID = 'vuex'; + + var actionId = 0; + + function addDevtools (app, store) { + setupDevtoolsPlugin( + { + id: 'org.vuejs.vuex', + app: app, + label: 'Vuex', + homepage: 'https://next.vuex.vuejs.org/', + logo: 'https://vuejs.org/images/icons/favicon-96x96.png', + packageName: 'vuex', + componentStateTypes: [LABEL_VUEX_BINDINGS] + }, + function (api) { + api.addTimelineLayer({ + id: MUTATIONS_LAYER_ID, + label: 'Vuex Mutations', + color: COLOR_LIME_500 + }); + + api.addTimelineLayer({ + id: ACTIONS_LAYER_ID, + label: 'Vuex Actions', + color: COLOR_LIME_500 + }); + + api.addInspector({ + id: INSPECTOR_ID, + label: 'Vuex', + icon: 'storage', + treeFilterPlaceholder: 'Filter stores...' + }); + + api.on.getInspectorTree(function (payload) { + if (payload.app === app && payload.inspectorId === INSPECTOR_ID) { + if (payload.filter) { + var nodes = []; + flattenStoreForInspectorTree(nodes, store._modules.root, payload.filter, ''); + payload.rootNodes = nodes; + } else { + payload.rootNodes = [ + formatStoreForInspectorTree(store._modules.root, '') + ]; + } + } + }); + + api.on.getInspectorState(function (payload) { + if (payload.app === app && payload.inspectorId === INSPECTOR_ID) { + var modulePath = payload.nodeId; + makeLocalGetters(store, modulePath); + payload.state = formatStoreForInspectorState( + getStoreModule(store._modules, modulePath), + modulePath === 'root' ? store.getters : store._makeLocalGettersCache, + modulePath + ); + } + }); + + api.on.editInspectorState(function (payload) { + if (payload.app === app && payload.inspectorId === INSPECTOR_ID) { + var modulePath = payload.nodeId; + var path = payload.path; + if (modulePath !== 'root') { + path = modulePath.split('/').filter(Boolean).concat( path); + } + store._withCommit(function () { + payload.set(store._state.data, path, payload.state.value); + }); + } + }); + + store.subscribe(function (mutation, state) { + var data = {}; + + if (mutation.payload) { + data.payload = mutation.payload; + } + + data.state = state; + + api.notifyComponentUpdate(); + api.sendInspectorTree(INSPECTOR_ID); + api.sendInspectorState(INSPECTOR_ID); + + api.addTimelineEvent({ + layerId: MUTATIONS_LAYER_ID, + event: { + time: Date.now(), + title: mutation.type, + data: data + } + }); + }); + + store.subscribeAction({ + before: function (action, state) { + var data = {}; + if (action.payload) { + data.payload = action.payload; + } + action._id = actionId++; + action._time = Date.now(); + data.state = state; + + api.addTimelineEvent({ + layerId: ACTIONS_LAYER_ID, + event: { + time: action._time, + title: action.type, + groupId: action._id, + subtitle: 'start', + data: data + } + }); + }, + after: function (action, state) { + var data = {}; + var duration = Date.now() - action._time; + data.duration = { + _custom: { + type: 'duration', + display: (duration + "ms"), + tooltip: 'Action duration', + value: duration + } + }; + if (action.payload) { + data.payload = action.payload; + } + data.state = state; + + api.addTimelineEvent({ + layerId: ACTIONS_LAYER_ID, + event: { + time: Date.now(), + title: action.type, + groupId: action._id, + subtitle: 'end', + data: data + } + }); + } + }); + } + ); + } + + // extracted from tailwind palette + var COLOR_LIME_500 = 0x84cc16; + var COLOR_DARK = 0x666666; + var COLOR_WHITE = 0xffffff; + + var TAG_NAMESPACED = { + label: 'namespaced', + textColor: COLOR_WHITE, + backgroundColor: COLOR_DARK + }; + + /** + * @param {string} path + */ + function extractNameFromPath (path) { + return path && path !== 'root' ? path.split('/').slice(-2, -1)[0] : 'Root' + } + + /** + * @param {*} module + * @return {import('@vue/devtools-api').CustomInspectorNode} + */ + function formatStoreForInspectorTree (module, path) { + return { + id: path || 'root', + // all modules end with a `/`, we want the last segment only + // cart/ -> cart + // nested/cart/ -> cart + label: extractNameFromPath(path), + tags: module.namespaced ? [TAG_NAMESPACED] : [], + children: Object.keys(module._children).map(function (moduleName) { return formatStoreForInspectorTree( + module._children[moduleName], + path + moduleName + '/' + ); } + ) + } + } + + /** + * @param {import('@vue/devtools-api').CustomInspectorNode[]} result + * @param {*} module + * @param {string} filter + * @param {string} path + */ + function flattenStoreForInspectorTree (result, module, filter, path) { + if (path.includes(filter)) { + result.push({ + id: path || 'root', + label: path.endsWith('/') ? path.slice(0, path.length - 1) : path || 'Root', + tags: module.namespaced ? [TAG_NAMESPACED] : [] + }); + } + Object.keys(module._children).forEach(function (moduleName) { + flattenStoreForInspectorTree(result, module._children[moduleName], filter, path + moduleName + '/'); + }); + } + + /** + * @param {*} module + * @return {import('@vue/devtools-api').CustomInspectorState} + */ + function formatStoreForInspectorState (module, getters, path) { + getters = path === 'root' ? getters : getters[path]; + var gettersKeys = Object.keys(getters); + var storeState = { + state: Object.keys(module.state).map(function (key) { return ({ + key: key, + editable: true, + value: module.state[key] + }); }) + }; + + if (gettersKeys.length) { + var tree = transformPathsToObjectTree(getters); + storeState.getters = Object.keys(tree).map(function (key) { return ({ + key: key.endsWith('/') ? extractNameFromPath(key) : key, + editable: false, + value: canThrow(function () { return tree[key]; }) + }); }); + } + + return storeState + } + + function transformPathsToObjectTree (getters) { + var result = {}; + Object.keys(getters).forEach(function (key) { + var path = key.split('/'); + if (path.length > 1) { + var target = result; + var leafKey = path.pop(); + path.forEach(function (p) { + if (!target[p]) { + target[p] = { + _custom: { + value: {}, + display: p, + tooltip: 'Module', + abstract: true + } + }; + } + target = target[p]._custom.value; + }); + target[leafKey] = canThrow(function () { return getters[key]; }); + } else { + result[key] = canThrow(function () { return getters[key]; }); + } + }); + return result + } + + function getStoreModule (moduleMap, path) { + var names = path.split('/').filter(function (n) { return n; }); + return names.reduce( + function (module, moduleName, i) { + var child = module[moduleName]; + if (!child) { + throw new Error(("Missing module \"" + moduleName + "\" for path \"" + path + "\".")) + } + return i === names.length - 1 ? child : child._children + }, + path === 'root' ? moduleMap : moduleMap.root._children + ) + } + + function canThrow (cb) { + try { + return cb() + } catch (e) { + return e + } + } + + // Base data struct for store's module, package with some attribute and method + var Module = function Module (rawModule, runtime) { + this.runtime = runtime; + // Store some children item + this._children = Object.create(null); + // Store the origin module object which passed by programmer + this._rawModule = rawModule; + var rawState = rawModule.state; + + // Store the origin module's state + this.state = (typeof rawState === 'function' ? rawState() : rawState) || {}; + }; + + var prototypeAccessors$1 = { namespaced: { configurable: true } }; + + prototypeAccessors$1.namespaced.get = function () { + return !!this._rawModule.namespaced + }; + + Module.prototype.addChild = function addChild (key, module) { + this._children[key] = module; + }; + + Module.prototype.removeChild = function removeChild (key) { + delete this._children[key]; + }; + + Module.prototype.getChild = function getChild (key) { + return this._children[key] + }; + + Module.prototype.hasChild = function hasChild (key) { + return key in this._children + }; + + Module.prototype.update = function update (rawModule) { + this._rawModule.namespaced = rawModule.namespaced; + if (rawModule.actions) { + this._rawModule.actions = rawModule.actions; + } + if (rawModule.mutations) { + this._rawModule.mutations = rawModule.mutations; + } + if (rawModule.getters) { + this._rawModule.getters = rawModule.getters; + } + }; + + Module.prototype.forEachChild = function forEachChild (fn) { + forEachValue(this._children, fn); + }; + + Module.prototype.forEachGetter = function forEachGetter (fn) { + if (this._rawModule.getters) { + forEachValue(this._rawModule.getters, fn); + } + }; + + Module.prototype.forEachAction = function forEachAction (fn) { + if (this._rawModule.actions) { + forEachValue(this._rawModule.actions, fn); + } + }; + + Module.prototype.forEachMutation = function forEachMutation (fn) { + if (this._rawModule.mutations) { + forEachValue(this._rawModule.mutations, fn); + } + }; + + Object.defineProperties( Module.prototype, prototypeAccessors$1 ); + + var ModuleCollection = function ModuleCollection (rawRootModule) { + // register root module (Vuex.Store options) + this.register([], rawRootModule, false); + }; + + ModuleCollection.prototype.get = function get (path) { + return path.reduce(function (module, key) { + return module.getChild(key) + }, this.root) + }; + + ModuleCollection.prototype.getNamespace = function getNamespace (path) { + var module = this.root; + return path.reduce(function (namespace, key) { + module = module.getChild(key); + return namespace + (module.namespaced ? key + '/' : '') + }, '') + }; + + ModuleCollection.prototype.update = function update$1 (rawRootModule) { + update([], this.root, rawRootModule); + }; + + ModuleCollection.prototype.register = function register (path, rawModule, runtime) { + var this$1$1 = this; + if ( runtime === void 0 ) runtime = true; + + { + assertRawModule(path, rawModule); + } + + var newModule = new Module(rawModule, runtime); + if (path.length === 0) { + this.root = newModule; + } else { + var parent = this.get(path.slice(0, -1)); + parent.addChild(path[path.length - 1], newModule); + } + + // register nested modules + if (rawModule.modules) { + forEachValue(rawModule.modules, function (rawChildModule, key) { + this$1$1.register(path.concat(key), rawChildModule, runtime); + }); + } + }; + + ModuleCollection.prototype.unregister = function unregister (path) { + var parent = this.get(path.slice(0, -1)); + var key = path[path.length - 1]; + var child = parent.getChild(key); + + if (!child) { + { + console.warn( + "[vuex] trying to unregister module '" + key + "', which is " + + "not registered" + ); + } + return + } + + if (!child.runtime) { + return + } + + parent.removeChild(key); + }; + + ModuleCollection.prototype.isRegistered = function isRegistered (path) { + var parent = this.get(path.slice(0, -1)); + var key = path[path.length - 1]; + + if (parent) { + return parent.hasChild(key) + } + + return false + }; + + function update (path, targetModule, newModule) { + { + assertRawModule(path, newModule); + } + + // update target module + targetModule.update(newModule); + + // update nested modules + if (newModule.modules) { + for (var key in newModule.modules) { + if (!targetModule.getChild(key)) { + { + console.warn( + "[vuex] trying to add a new module '" + key + "' on hot reloading, " + + 'manual reload is needed' + ); + } + return + } + update( + path.concat(key), + targetModule.getChild(key), + newModule.modules[key] + ); + } + } + } + + var functionAssert = { + assert: function (value) { return typeof value === 'function'; }, + expected: 'function' + }; + + var objectAssert = { + assert: function (value) { return typeof value === 'function' || + (typeof value === 'object' && typeof value.handler === 'function'); }, + expected: 'function or object with "handler" function' + }; + + var assertTypes = { + getters: functionAssert, + mutations: functionAssert, + actions: objectAssert + }; + + function assertRawModule (path, rawModule) { + Object.keys(assertTypes).forEach(function (key) { + if (!rawModule[key]) { return } + + var assertOptions = assertTypes[key]; + + forEachValue(rawModule[key], function (value, type) { + assert( + assertOptions.assert(value), + makeAssertionMessage(path, key, type, value, assertOptions.expected) + ); + }); + }); + } + + function makeAssertionMessage (path, key, type, value, expected) { + var buf = key + " should be " + expected + " but \"" + key + "." + type + "\""; + if (path.length > 0) { + buf += " in module \"" + (path.join('.')) + "\""; + } + buf += " is " + (JSON.stringify(value)) + "."; + return buf + } + + var Store = function Store (options) { + var this$1$1 = this; + if ( options === void 0 ) options = {}; + + { + assert(typeof Promise !== 'undefined', "vuex requires a Promise polyfill in this browser."); + assert(this instanceof Store, "store must be called with the new operator."); + } + + var plugins = options.plugins; if ( plugins === void 0 ) plugins = []; + var strict = options.strict; if ( strict === void 0 ) strict = false; + var devtools = options.devtools; + + // store internal state + this._committing = false; + this._actions = Object.create(null); + this._actionSubscribers = []; + this._mutations = Object.create(null); + this._wrappedGetters = Object.create(null); + this._modules = new ModuleCollection(options); + this._modulesNamespaceMap = Object.create(null); + this._subscribers = []; + this._makeLocalGettersCache = Object.create(null); + + // EffectScope instance. when registering new getters, we wrap them inside + // EffectScope so that getters (computed) would not be destroyed on + // component unmount. + this._scope = null; + + this._devtools = devtools; + + // bind commit and dispatch to self + var store = this; + var ref = this; + var dispatch = ref.dispatch; + var commit = ref.commit; + this.dispatch = function boundDispatch (type, payload) { + return dispatch.call(store, type, payload) + }; + this.commit = function boundCommit (type, payload, options) { + return commit.call(store, type, payload, options) + }; + + // strict mode + this.strict = strict; + + var state = this._modules.root.state; + + // init root module. + // this also recursively registers all sub-modules + // and collects all module getters inside this._wrappedGetters + installModule(this, state, [], this._modules.root); + + // initialize the store state, which is responsible for the reactivity + // (also registers _wrappedGetters as computed properties) + resetStoreState(this, state); + + // apply plugins + plugins.forEach(function (plugin) { return plugin(this$1$1); }); + }; + + var prototypeAccessors = { state: { configurable: true } }; + + Store.prototype.install = function install (app, injectKey) { + app.provide(injectKey || storeKey, this); + app.config.globalProperties.$store = this; + + var useDevtools = this._devtools !== undefined + ? this._devtools + : true ; + + if (useDevtools) { + addDevtools(app, this); + } + }; + + prototypeAccessors.state.get = function () { + return this._state.data + }; + + prototypeAccessors.state.set = function (v) { + { + assert(false, "use store.replaceState() to explicit replace store state."); + } + }; + + Store.prototype.commit = function commit (_type, _payload, _options) { + var this$1$1 = this; + + // check object-style commit + var ref = unifyObjectStyle(_type, _payload, _options); + var type = ref.type; + var payload = ref.payload; + var options = ref.options; + + var mutation = { type: type, payload: payload }; + var entry = this._mutations[type]; + if (!entry) { + { + console.error(("[vuex] unknown mutation type: " + type)); + } + return + } + this._withCommit(function () { + entry.forEach(function commitIterator (handler) { + handler(payload); + }); + }); + + this._subscribers + .slice() // shallow copy to prevent iterator invalidation if subscriber synchronously calls unsubscribe + .forEach(function (sub) { return sub(mutation, this$1$1.state); }); + + if ( + options && options.silent + ) { + console.warn( + "[vuex] mutation type: " + type + ". Silent option has been removed. " + + 'Use the filter functionality in the vue-devtools' + ); + } + }; + + Store.prototype.dispatch = function dispatch (_type, _payload) { + var this$1$1 = this; + + // check object-style dispatch + var ref = unifyObjectStyle(_type, _payload); + var type = ref.type; + var payload = ref.payload; + + var action = { type: type, payload: payload }; + var entry = this._actions[type]; + if (!entry) { + { + console.error(("[vuex] unknown action type: " + type)); + } + return + } + + try { + this._actionSubscribers + .slice() // shallow copy to prevent iterator invalidation if subscriber synchronously calls unsubscribe + .filter(function (sub) { return sub.before; }) + .forEach(function (sub) { return sub.before(action, this$1$1.state); }); + } catch (e) { + { + console.warn("[vuex] error in before action subscribers: "); + console.error(e); + } + } + + var result = entry.length > 1 + ? Promise.all(entry.map(function (handler) { return handler(payload); })) + : entry[0](payload); + + return new Promise(function (resolve, reject) { + result.then(function (res) { + try { + this$1$1._actionSubscribers + .filter(function (sub) { return sub.after; }) + .forEach(function (sub) { return sub.after(action, this$1$1.state); }); + } catch (e) { + { + console.warn("[vuex] error in after action subscribers: "); + console.error(e); + } + } + resolve(res); + }, function (error) { + try { + this$1$1._actionSubscribers + .filter(function (sub) { return sub.error; }) + .forEach(function (sub) { return sub.error(action, this$1$1.state, error); }); + } catch (e) { + { + console.warn("[vuex] error in error action subscribers: "); + console.error(e); + } + } + reject(error); + }); + }) + }; + + Store.prototype.subscribe = function subscribe (fn, options) { + return genericSubscribe(fn, this._subscribers, options) + }; + + Store.prototype.subscribeAction = function subscribeAction (fn, options) { + var subs = typeof fn === 'function' ? { before: fn } : fn; + return genericSubscribe(subs, this._actionSubscribers, options) + }; + + Store.prototype.watch = function watch$1 (getter, cb, options) { + var this$1$1 = this; + + { + assert(typeof getter === 'function', "store.watch only accepts a function."); + } + return vue.watch(function () { return getter(this$1$1.state, this$1$1.getters); }, cb, Object.assign({}, options)) + }; + + Store.prototype.replaceState = function replaceState (state) { + var this$1$1 = this; + + this._withCommit(function () { + this$1$1._state.data = state; + }); + }; + + Store.prototype.registerModule = function registerModule (path, rawModule, options) { + if ( options === void 0 ) options = {}; + + if (typeof path === 'string') { path = [path]; } + + { + assert(Array.isArray(path), "module path must be a string or an Array."); + assert(path.length > 0, 'cannot register the root module by using registerModule.'); + } + + this._modules.register(path, rawModule); + installModule(this, this.state, path, this._modules.get(path), options.preserveState); + // reset store to update getters... + resetStoreState(this, this.state); + }; + + Store.prototype.unregisterModule = function unregisterModule (path) { + var this$1$1 = this; + + if (typeof path === 'string') { path = [path]; } + + { + assert(Array.isArray(path), "module path must be a string or an Array."); + } + + this._modules.unregister(path); + this._withCommit(function () { + var parentState = getNestedState(this$1$1.state, path.slice(0, -1)); + delete parentState[path[path.length - 1]]; + }); + resetStore(this); + }; + + Store.prototype.hasModule = function hasModule (path) { + if (typeof path === 'string') { path = [path]; } + + { + assert(Array.isArray(path), "module path must be a string or an Array."); + } + + return this._modules.isRegistered(path) + }; + + Store.prototype.hotUpdate = function hotUpdate (newOptions) { + this._modules.update(newOptions); + resetStore(this, true); + }; + + Store.prototype._withCommit = function _withCommit (fn) { + var committing = this._committing; + this._committing = true; + fn(); + this._committing = committing; + }; + + Object.defineProperties( Store.prototype, prototypeAccessors ); + + /** + * Reduce the code which written in Vue.js for getting the getters + * @param {String} [namespace] - Module's namespace + * @param {Object|Array} getters + * @return {Object} + */ + var mapGetters = normalizeNamespace(function (namespace, getters) { + var res = {}; + if (!isValidMap(getters)) { + console.error('[vuex] mapGetters: mapper parameter must be either an Array or an Object'); + } + normalizeMap(getters).forEach(function (ref) { + var key = ref.key; + var val = ref.val; + + // The namespace has been mutated by normalizeNamespace + val = namespace + val; + res[key] = function mappedGetter () { + if (namespace && !getModuleByNamespace(this.$store, 'mapGetters', namespace)) { + return + } + if (!(val in this.$store.getters)) { + console.error(("[vuex] unknown getter: " + val)); + return + } + return this.$store.getters[val] + }; + // mark vuex getter for devtools + res[key].vuex = true; + }); + return res + }); + + /** + * Reduce the code which written in Vue.js for dispatch the action + * @param {String} [namespace] - Module's namespace + * @param {Object|Array} actions # Object's item can be a function which accept `dispatch` function as the first param, it can accept anthor params. You can dispatch action and do any other things in this function. specially, You need to pass anthor params from the mapped function. + * @return {Object} + */ + var mapActions = normalizeNamespace(function (namespace, actions) { + var res = {}; + if (!isValidMap(actions)) { + console.error('[vuex] mapActions: mapper parameter must be either an Array or an Object'); + } + normalizeMap(actions).forEach(function (ref) { + var key = ref.key; + var val = ref.val; + + res[key] = function mappedAction () { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + // get dispatch function from store + var dispatch = this.$store.dispatch; + if (namespace) { + var module = getModuleByNamespace(this.$store, 'mapActions', namespace); + if (!module) { + return + } + dispatch = module.context.dispatch; + } + return typeof val === 'function' + ? val.apply(this, [dispatch].concat(args)) + : dispatch.apply(this.$store, [val].concat(args)) + }; + }); + return res + }); + + /** + * Normalize the map + * normalizeMap([1, 2, 3]) => [ { key: 1, val: 1 }, { key: 2, val: 2 }, { key: 3, val: 3 } ] + * normalizeMap({a: 1, b: 2, c: 3}) => [ { key: 'a', val: 1 }, { key: 'b', val: 2 }, { key: 'c', val: 3 } ] + * @param {Array|Object} map + * @return {Object} + */ + function normalizeMap (map) { + if (!isValidMap(map)) { + return [] + } + return Array.isArray(map) + ? map.map(function (key) { return ({ key: key, val: key }); }) + : Object.keys(map).map(function (key) { return ({ key: key, val: map[key] }); }) + } + + /** + * Validate whether given map is valid or not + * @param {*} map + * @return {Boolean} + */ + function isValidMap (map) { + return Array.isArray(map) || isObject$1(map) + } + + /** + * Return a function expect two param contains namespace and map. it will normalize the namespace and then the param's function will handle the new namespace and the map. + * @param {Function} fn + * @return {Function} + */ + function normalizeNamespace (fn) { + return function (namespace, map) { + if (typeof namespace !== 'string') { + map = namespace; + namespace = ''; + } else if (namespace.charAt(namespace.length - 1) !== '/') { + namespace += '/'; + } + return fn(namespace, map) + } + } + + /** + * Search a special module from store by namespace. if module not exist, print error message. + * @param {Object} store + * @param {String} helper + * @param {String} namespace + * @return {Object} + */ + function getModuleByNamespace (store, helper, namespace) { + var module = store._modulesNamespaceMap[namespace]; + if (!module) { + console.error(("[vuex] module namespace not found in " + helper + "(): " + namespace)); + } + return module + } + + function bind(fn, thisArg) { + return function wrap() { + return fn.apply(thisArg, arguments); + }; + } + + // utils is a library of generic helper functions non-specific to axios + + const {toString: toString$1} = Object.prototype; + const {getPrototypeOf} = Object; + + const kindOf = (cache => thing => { + const str = toString$1.call(thing); + return cache[str] || (cache[str] = str.slice(8, -1).toLowerCase()); + })(Object.create(null)); + + const kindOfTest = (type) => { + type = type.toLowerCase(); + return (thing) => kindOf(thing) === type + }; + + const typeOfTest = type => thing => typeof thing === type; + + /** + * Determine if a value is an Array + * + * @param {Object} val The value to test + * + * @returns {boolean} True if value is an Array, otherwise false + */ + const {isArray: isArray$1} = Array; + + /** + * Determine if a value is undefined + * + * @param {*} val The value to test + * + * @returns {boolean} True if the value is undefined, otherwise false + */ + const isUndefined = typeOfTest('undefined'); + + /** + * Determine if a value is a Buffer + * + * @param {*} val The value to test + * + * @returns {boolean} True if value is a Buffer, otherwise false + */ + function isBuffer$1(val) { + return val !== null && !isUndefined(val) && val.constructor !== null && !isUndefined(val.constructor) + && isFunction(val.constructor.isBuffer) && val.constructor.isBuffer(val); + } + + /** + * Determine if a value is an ArrayBuffer + * + * @param {*} val The value to test + * + * @returns {boolean} True if value is an ArrayBuffer, otherwise false + */ + const isArrayBuffer = kindOfTest('ArrayBuffer'); + + + /** + * Determine if a value is a view on an ArrayBuffer + * + * @param {*} val The value to test + * + * @returns {boolean} True if value is a view on an ArrayBuffer, otherwise false + */ + function isArrayBufferView(val) { + let result; + if ((typeof ArrayBuffer !== 'undefined') && (ArrayBuffer.isView)) { + result = ArrayBuffer.isView(val); + } else { + result = (val) && (val.buffer) && (isArrayBuffer(val.buffer)); + } + return result; + } + + /** + * Determine if a value is a String + * + * @param {*} val The value to test + * + * @returns {boolean} True if value is a String, otherwise false + */ + const isString = typeOfTest('string'); + + /** + * Determine if a value is a Function + * + * @param {*} val The value to test + * @returns {boolean} True if value is a Function, otherwise false + */ + const isFunction = typeOfTest('function'); + + /** + * Determine if a value is a Number + * + * @param {*} val The value to test + * + * @returns {boolean} True if value is a Number, otherwise false + */ + const isNumber = typeOfTest('number'); + + /** + * Determine if a value is an Object + * + * @param {*} thing The value to test + * + * @returns {boolean} True if value is an Object, otherwise false + */ + const isObject = (thing) => thing !== null && typeof thing === 'object'; + + /** + * Determine if a value is a Boolean + * + * @param {*} thing The value to test + * @returns {boolean} True if value is a Boolean, otherwise false + */ + const isBoolean = thing => thing === true || thing === false; + + /** + * Determine if a value is a plain Object + * + * @param {*} val The value to test + * + * @returns {boolean} True if value is a plain Object, otherwise false + */ + const isPlainObject = (val) => { + if (kindOf(val) !== 'object') { + return false; + } + + const prototype = getPrototypeOf(val); + return (prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null) && !(Symbol.toStringTag in val) && !(Symbol.iterator in val); + }; + + /** + * Determine if a value is a Date + * + * @param {*} val The value to test + * + * @returns {boolean} True if value is a Date, otherwise false + */ + const isDate = kindOfTest('Date'); + + /** + * Determine if a value is a File + * + * @param {*} val The value to test + * + * @returns {boolean} True if value is a File, otherwise false + */ + const isFile = kindOfTest('File'); + + /** + * Determine if a value is a Blob + * + * @param {*} val The value to test + * + * @returns {boolean} True if value is a Blob, otherwise false + */ + const isBlob = kindOfTest('Blob'); + + /** + * Determine if a value is a FileList + * + * @param {*} val The value to test + * + * @returns {boolean} True if value is a File, otherwise false + */ + const isFileList = kindOfTest('FileList'); + + /** + * Determine if a value is a Stream + * + * @param {*} val The value to test + * + * @returns {boolean} True if value is a Stream, otherwise false + */ + const isStream = (val) => isObject(val) && isFunction(val.pipe); + + /** + * Determine if a value is a FormData + * + * @param {*} thing The value to test + * + * @returns {boolean} True if value is an FormData, otherwise false + */ + const isFormData = (thing) => { + let kind; + return thing && ( + (typeof FormData === 'function' && thing instanceof FormData) || ( + isFunction(thing.append) && ( + (kind = kindOf(thing)) === 'formdata' || + // detect form-data instance + (kind === 'object' && isFunction(thing.toString) && thing.toString() === '[object FormData]') + ) + ) + ) + }; + + /** + * Determine if a value is a URLSearchParams object + * + * @param {*} val The value to test + * + * @returns {boolean} True if value is a URLSearchParams object, otherwise false + */ + const isURLSearchParams = kindOfTest('URLSearchParams'); + + /** + * Trim excess whitespace off the beginning and end of a string + * + * @param {String} str The String to trim + * + * @returns {String} The String freed of excess whitespace + */ + const trim = (str) => str.trim ? + str.trim() : str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ''); + + /** + * Iterate over an Array or an Object invoking a function for each item. + * + * If `obj` is an Array callback will be called passing + * the value, index, and complete array for each item. + * + * If 'obj' is an Object callback will be called passing + * the value, key, and complete object for each property. + * + * @param {Object|Array} obj The object to iterate + * @param {Function} fn The callback to invoke for each item + * + * @param {Boolean} [allOwnKeys = false] + * @returns {any} + */ + function forEach(obj, fn, {allOwnKeys = false} = {}) { + // Don't bother if no value provided + if (obj === null || typeof obj === 'undefined') { + return; + } + + let i; + let l; + + // Force an array if not already something iterable + if (typeof obj !== 'object') { + /*eslint no-param-reassign:0*/ + obj = [obj]; + } + + if (isArray$1(obj)) { + // Iterate over array values + for (i = 0, l = obj.length; i < l; i++) { + fn.call(null, obj[i], i, obj); + } + } else { + // Iterate over object keys + const keys = allOwnKeys ? Object.getOwnPropertyNames(obj) : Object.keys(obj); + const len = keys.length; + let key; + + for (i = 0; i < len; i++) { + key = keys[i]; + fn.call(null, obj[key], key, obj); + } + } + } + + function findKey(obj, key) { + key = key.toLowerCase(); + const keys = Object.keys(obj); + let i = keys.length; + let _key; + while (i-- > 0) { + _key = keys[i]; + if (key === _key.toLowerCase()) { + return _key; + } + } + return null; + } + + const _global = (() => { + /*eslint no-undef:0*/ + if (typeof globalThis !== "undefined") return globalThis; + return typeof self !== "undefined" ? self : (typeof window !== 'undefined' ? window : global$1) + })(); + + const isContextDefined = (context) => !isUndefined(context) && context !== _global; + + /** + * Accepts varargs expecting each argument to be an object, then + * immutably merges the properties of each object and returns result. + * + * When multiple objects contain the same key the later object in + * the arguments list will take precedence. + * + * Example: + * + * ```js + * var result = merge({foo: 123}, {foo: 456}); + * console.log(result.foo); // outputs 456 + * ``` + * + * @param {Object} obj1 Object to merge + * + * @returns {Object} Result of all merge properties + */ + function merge(/* obj1, obj2, obj3, ... */) { + const {caseless} = isContextDefined(this) && this || {}; + const result = {}; + const assignValue = (val, key) => { + const targetKey = caseless && findKey(result, key) || key; + if (isPlainObject(result[targetKey]) && isPlainObject(val)) { + result[targetKey] = merge(result[targetKey], val); + } else if (isPlainObject(val)) { + result[targetKey] = merge({}, val); + } else if (isArray$1(val)) { + result[targetKey] = val.slice(); + } else { + result[targetKey] = val; + } + }; + + for (let i = 0, l = arguments.length; i < l; i++) { + arguments[i] && forEach(arguments[i], assignValue); + } + return result; + } + + /** + * Extends object a by mutably adding to it the properties of object b. + * + * @param {Object} a The object to be extended + * @param {Object} b The object to copy properties from + * @param {Object} thisArg The object to bind function to + * + * @param {Boolean} [allOwnKeys] + * @returns {Object} The resulting value of object a + */ + const extend = (a, b, thisArg, {allOwnKeys}= {}) => { + forEach(b, (val, key) => { + if (thisArg && isFunction(val)) { + a[key] = bind(val, thisArg); + } else { + a[key] = val; + } + }, {allOwnKeys}); + return a; + }; + + /** + * Remove byte order marker. This catches EF BB BF (the UTF-8 BOM) + * + * @param {string} content with BOM + * + * @returns {string} content value without BOM + */ + const stripBOM = (content) => { + if (content.charCodeAt(0) === 0xFEFF) { + content = content.slice(1); + } + return content; + }; + + /** + * Inherit the prototype methods from one constructor into another + * @param {function} constructor + * @param {function} superConstructor + * @param {object} [props] + * @param {object} [descriptors] + * + * @returns {void} + */ + const inherits = (constructor, superConstructor, props, descriptors) => { + constructor.prototype = Object.create(superConstructor.prototype, descriptors); + constructor.prototype.constructor = constructor; + Object.defineProperty(constructor, 'super', { + value: superConstructor.prototype + }); + props && Object.assign(constructor.prototype, props); + }; + + /** + * Resolve object with deep prototype chain to a flat object + * @param {Object} sourceObj source object + * @param {Object} [destObj] + * @param {Function|Boolean} [filter] + * @param {Function} [propFilter] + * + * @returns {Object} + */ + const toFlatObject = (sourceObj, destObj, filter, propFilter) => { + let props; + let i; + let prop; + const merged = {}; + + destObj = destObj || {}; + // eslint-disable-next-line no-eq-null,eqeqeq + if (sourceObj == null) return destObj; + + do { + props = Object.getOwnPropertyNames(sourceObj); + i = props.length; + while (i-- > 0) { + prop = props[i]; + if ((!propFilter || propFilter(prop, sourceObj, destObj)) && !merged[prop]) { + destObj[prop] = sourceObj[prop]; + merged[prop] = true; + } + } + sourceObj = filter !== false && getPrototypeOf(sourceObj); + } while (sourceObj && (!filter || filter(sourceObj, destObj)) && sourceObj !== Object.prototype); + + return destObj; + }; + + /** + * Determines whether a string ends with the characters of a specified string + * + * @param {String} str + * @param {String} searchString + * @param {Number} [position= 0] + * + * @returns {boolean} + */ + const endsWith = (str, searchString, position) => { + str = String(str); + if (position === undefined || position > str.length) { + position = str.length; + } + position -= searchString.length; + const lastIndex = str.indexOf(searchString, position); + return lastIndex !== -1 && lastIndex === position; + }; + + + /** + * Returns new array from array like object or null if failed + * + * @param {*} [thing] + * + * @returns {?Array} + */ + const toArray = (thing) => { + if (!thing) return null; + if (isArray$1(thing)) return thing; + let i = thing.length; + if (!isNumber(i)) return null; + const arr = new Array(i); + while (i-- > 0) { + arr[i] = thing[i]; + } + return arr; + }; + + /** + * Checking if the Uint8Array exists and if it does, it returns a function that checks if the + * thing passed in is an instance of Uint8Array + * + * @param {TypedArray} + * + * @returns {Array} + */ + // eslint-disable-next-line func-names + const isTypedArray = (TypedArray => { + // eslint-disable-next-line func-names + return thing => { + return TypedArray && thing instanceof TypedArray; + }; + })(typeof Uint8Array !== 'undefined' && getPrototypeOf(Uint8Array)); + + /** + * For each entry in the object, call the function with the key and value. + * + * @param {Object} obj - The object to iterate over. + * @param {Function} fn - The function to call for each entry. + * + * @returns {void} + */ + const forEachEntry = (obj, fn) => { + const generator = obj && obj[Symbol.iterator]; + + const iterator = generator.call(obj); + + let result; + + while ((result = iterator.next()) && !result.done) { + const pair = result.value; + fn.call(obj, pair[0], pair[1]); + } + }; + + /** + * It takes a regular expression and a string, and returns an array of all the matches + * + * @param {string} regExp - The regular expression to match against. + * @param {string} str - The string to search. + * + * @returns {Array} + */ + const matchAll = (regExp, str) => { + let matches; + const arr = []; + + while ((matches = regExp.exec(str)) !== null) { + arr.push(matches); + } + + return arr; + }; + + /* Checking if the kindOfTest function returns true when passed an HTMLFormElement. */ + const isHTMLForm = kindOfTest('HTMLFormElement'); + + const toCamelCase = str => { + return str.toLowerCase().replace(/[-_\s]([a-z\d])(\w*)/g, + function replacer(m, p1, p2) { + return p1.toUpperCase() + p2; + } + ); + }; + + /* Creating a function that will check if an object has a property. */ + const hasOwnProperty = (({hasOwnProperty}) => (obj, prop) => hasOwnProperty.call(obj, prop))(Object.prototype); + + /** + * Determine if a value is a RegExp object + * + * @param {*} val The value to test + * + * @returns {boolean} True if value is a RegExp object, otherwise false + */ + const isRegExp = kindOfTest('RegExp'); + + const reduceDescriptors = (obj, reducer) => { + const descriptors = Object.getOwnPropertyDescriptors(obj); + const reducedDescriptors = {}; + + forEach(descriptors, (descriptor, name) => { + let ret; + if ((ret = reducer(descriptor, name, obj)) !== false) { + reducedDescriptors[name] = ret || descriptor; + } + }); + + Object.defineProperties(obj, reducedDescriptors); + }; + + /** + * Makes all methods read-only + * @param {Object} obj + */ + + const freezeMethods = (obj) => { + reduceDescriptors(obj, (descriptor, name) => { + // skip restricted props in strict mode + if (isFunction(obj) && ['arguments', 'caller', 'callee'].indexOf(name) !== -1) { + return false; + } + + const value = obj[name]; + + if (!isFunction(value)) return; + + descriptor.enumerable = false; + + if ('writable' in descriptor) { + descriptor.writable = false; + return; + } + + if (!descriptor.set) { + descriptor.set = () => { + throw Error('Can not rewrite read-only method \'' + name + '\''); + }; + } + }); + }; + + const toObjectSet = (arrayOrString, delimiter) => { + const obj = {}; + + const define = (arr) => { + arr.forEach(value => { + obj[value] = true; + }); + }; + + isArray$1(arrayOrString) ? define(arrayOrString) : define(String(arrayOrString).split(delimiter)); + + return obj; + }; + + const noop = () => {}; + + const toFiniteNumber = (value, defaultValue) => { + value = +value; + return Number.isFinite(value) ? value : defaultValue; + }; + + const ALPHA = 'abcdefghijklmnopqrstuvwxyz'; + + const DIGIT = '0123456789'; + + const ALPHABET = { + DIGIT, + ALPHA, + ALPHA_DIGIT: ALPHA + ALPHA.toUpperCase() + DIGIT + }; + + const generateString = (size = 16, alphabet = ALPHABET.ALPHA_DIGIT) => { + let str = ''; + const {length} = alphabet; + while (size--) { + str += alphabet[Math.random() * length|0]; + } + + return str; + }; + + /** + * If the thing is a FormData object, return true, otherwise return false. + * + * @param {unknown} thing - The thing to check. + * + * @returns {boolean} + */ + function isSpecCompliantForm(thing) { + return !!(thing && isFunction(thing.append) && thing[Symbol.toStringTag] === 'FormData' && thing[Symbol.iterator]); + } + + const toJSONObject = (obj) => { + const stack = new Array(10); + + const visit = (source, i) => { + + if (isObject(source)) { + if (stack.indexOf(source) >= 0) { + return; + } + + if(!('toJSON' in source)) { + stack[i] = source; + const target = isArray$1(source) ? [] : {}; + + forEach(source, (value, key) => { + const reducedValue = visit(value, i + 1); + !isUndefined(reducedValue) && (target[key] = reducedValue); + }); + + stack[i] = undefined; + + return target; + } + } + + return source; + }; + + return visit(obj, 0); + }; + + const isAsyncFn = kindOfTest('AsyncFunction'); + + const isThenable = (thing) => + thing && (isObject(thing) || isFunction(thing)) && isFunction(thing.then) && isFunction(thing.catch); + + var utils = { + isArray: isArray$1, + isArrayBuffer, + isBuffer: isBuffer$1, + isFormData, + isArrayBufferView, + isString, + isNumber, + isBoolean, + isObject, + isPlainObject, + isUndefined, + isDate, + isFile, + isBlob, + isRegExp, + isFunction, + isStream, + isURLSearchParams, + isTypedArray, + isFileList, + forEach, + merge, + extend, + trim, + stripBOM, + inherits, + toFlatObject, + kindOf, + kindOfTest, + endsWith, + toArray, + forEachEntry, + matchAll, + isHTMLForm, + hasOwnProperty, + hasOwnProp: hasOwnProperty, // an alias to avoid ESLint no-prototype-builtins detection + reduceDescriptors, + freezeMethods, + toObjectSet, + toCamelCase, + noop, + toFiniteNumber, + findKey, + global: _global, + isContextDefined, + ALPHABET, + generateString, + isSpecCompliantForm, + toJSONObject, + isAsyncFn, + isThenable + }; + + var lookup = []; + var revLookup = []; + var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array; + var inited = false; + function init () { + inited = true; + var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; + for (var i = 0, len = code.length; i < len; ++i) { + lookup[i] = code[i]; + revLookup[code.charCodeAt(i)] = i; + } + + revLookup['-'.charCodeAt(0)] = 62; + revLookup['_'.charCodeAt(0)] = 63; + } + + function toByteArray (b64) { + if (!inited) { + init(); + } + var i, j, l, tmp, placeHolders, arr; + var len = b64.length; + + if (len % 4 > 0) { + throw new Error('Invalid string. Length must be a multiple of 4') + } + + // the number of equal signs (place holders) + // if there are two placeholders, than the two characters before it + // represent one byte + // if there is only one, then the three characters before it represent 2 bytes + // this is just a cheap hack to not do indexOf twice + placeHolders = b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0; + + // base64 is 4/3 + up to two characters of the original data + arr = new Arr(len * 3 / 4 - placeHolders); + + // if there are placeholders, only get up to the last complete 4 chars + l = placeHolders > 0 ? len - 4 : len; + + var L = 0; + + for (i = 0, j = 0; i < l; i += 4, j += 3) { + tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | revLookup[b64.charCodeAt(i + 3)]; + arr[L++] = (tmp >> 16) & 0xFF; + arr[L++] = (tmp >> 8) & 0xFF; + arr[L++] = tmp & 0xFF; + } + + if (placeHolders === 2) { + tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4); + arr[L++] = tmp & 0xFF; + } else if (placeHolders === 1) { + tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | (revLookup[b64.charCodeAt(i + 2)] >> 2); + arr[L++] = (tmp >> 8) & 0xFF; + arr[L++] = tmp & 0xFF; + } + + return arr + } + + function tripletToBase64 (num) { + return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F] + } + + function encodeChunk (uint8, start, end) { + var tmp; + var output = []; + for (var i = start; i < end; i += 3) { + tmp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]); + output.push(tripletToBase64(tmp)); + } + return output.join('') + } + + function fromByteArray (uint8) { + if (!inited) { + init(); + } + var tmp; + var len = uint8.length; + var extraBytes = len % 3; // if we have 1 byte left, pad 2 bytes + var output = ''; + var parts = []; + var maxChunkLength = 16383; // must be multiple of 3 + + // go through the array every three bytes, we'll deal with trailing stuff later + for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) { + parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength))); + } + + // pad the end with zeros, but make sure to not forget the extra bytes + if (extraBytes === 1) { + tmp = uint8[len - 1]; + output += lookup[tmp >> 2]; + output += lookup[(tmp << 4) & 0x3F]; + output += '=='; + } else if (extraBytes === 2) { + tmp = (uint8[len - 2] << 8) + (uint8[len - 1]); + output += lookup[tmp >> 10]; + output += lookup[(tmp >> 4) & 0x3F]; + output += lookup[(tmp << 2) & 0x3F]; + output += '='; + } + + parts.push(output); + + return parts.join('') + } + + function read (buffer, offset, isLE, mLen, nBytes) { + var e, m; + var eLen = nBytes * 8 - mLen - 1; + var eMax = (1 << eLen) - 1; + var eBias = eMax >> 1; + var nBits = -7; + var i = isLE ? (nBytes - 1) : 0; + var d = isLE ? -1 : 1; + var s = buffer[offset + i]; + + i += d; + + e = s & ((1 << (-nBits)) - 1); + s >>= (-nBits); + nBits += eLen; + for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {} + + m = e & ((1 << (-nBits)) - 1); + e >>= (-nBits); + nBits += mLen; + for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {} + + if (e === 0) { + e = 1 - eBias; + } else if (e === eMax) { + return m ? NaN : ((s ? -1 : 1) * Infinity) + } else { + m = m + Math.pow(2, mLen); + e = e - eBias; + } + return (s ? -1 : 1) * m * Math.pow(2, e - mLen) + } + + function write (buffer, value, offset, isLE, mLen, nBytes) { + var e, m, c; + var eLen = nBytes * 8 - mLen - 1; + var eMax = (1 << eLen) - 1; + var eBias = eMax >> 1; + var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0); + var i = isLE ? 0 : (nBytes - 1); + var d = isLE ? 1 : -1; + var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0; + + value = Math.abs(value); + + if (isNaN(value) || value === Infinity) { + m = isNaN(value) ? 1 : 0; + e = eMax; + } else { + e = Math.floor(Math.log(value) / Math.LN2); + if (value * (c = Math.pow(2, -e)) < 1) { + e--; + c *= 2; + } + if (e + eBias >= 1) { + value += rt / c; + } else { + value += rt * Math.pow(2, 1 - eBias); + } + if (value * c >= 2) { + e++; + c /= 2; + } + + if (e + eBias >= eMax) { + m = 0; + e = eMax; + } else if (e + eBias >= 1) { + m = (value * c - 1) * Math.pow(2, mLen); + e = e + eBias; + } else { + m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen); + e = 0; + } + } + + for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} + + e = (e << mLen) | m; + eLen += mLen; + for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} + + buffer[offset + i - d] |= s * 128; + } + + var toString = {}.toString; + + var isArray = Array.isArray || function (arr) { + return toString.call(arr) == '[object Array]'; + }; + + var INSPECT_MAX_BYTES = 50; + + /** + * If `Buffer.TYPED_ARRAY_SUPPORT`: + * === true Use Uint8Array implementation (fastest) + * === false Use Object implementation (most compatible, even IE6) + * + * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+, + * Opera 11.6+, iOS 4.2+. + * + * Due to various browser bugs, sometimes the Object implementation will be used even + * when the browser supports typed arrays. + * + * Note: + * + * - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances, + * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438. + * + * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function. + * + * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of + * incorrect length in some situations. + + * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they + * get the Object implementation, which is slower but behaves correctly. + */ + Buffer.TYPED_ARRAY_SUPPORT = global$1.TYPED_ARRAY_SUPPORT !== undefined + ? global$1.TYPED_ARRAY_SUPPORT + : true; + + /* + * Export kMaxLength after typed array support is determined. + */ + kMaxLength(); + + function kMaxLength () { + return Buffer.TYPED_ARRAY_SUPPORT + ? 0x7fffffff + : 0x3fffffff + } + + function createBuffer (that, length) { + if (kMaxLength() < length) { + throw new RangeError('Invalid typed array length') + } + if (Buffer.TYPED_ARRAY_SUPPORT) { + // Return an augmented `Uint8Array` instance, for best performance + that = new Uint8Array(length); + that.__proto__ = Buffer.prototype; + } else { + // Fallback: Return an object instance of the Buffer class + if (that === null) { + that = new Buffer(length); + } + that.length = length; + } + + return that + } + + /** + * The Buffer constructor returns instances of `Uint8Array` that have their + * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of + * `Uint8Array`, so the returned instances will have all the node `Buffer` methods + * and the `Uint8Array` methods. Square bracket notation works as expected -- it + * returns a single octet. + * + * The `Uint8Array` prototype remains unmodified. + */ + + function Buffer (arg, encodingOrOffset, length) { + if (!Buffer.TYPED_ARRAY_SUPPORT && !(this instanceof Buffer)) { + return new Buffer(arg, encodingOrOffset, length) + } + + // Common case. + if (typeof arg === 'number') { + if (typeof encodingOrOffset === 'string') { + throw new Error( + 'If encoding is specified then the first argument must be a string' + ) + } + return allocUnsafe(this, arg) + } + return from(this, arg, encodingOrOffset, length) + } + + Buffer.poolSize = 8192; // not used by this implementation + + // TODO: Legacy, not needed anymore. Remove in next major version. + Buffer._augment = function (arr) { + arr.__proto__ = Buffer.prototype; + return arr + }; + + function from (that, value, encodingOrOffset, length) { + if (typeof value === 'number') { + throw new TypeError('"value" argument must not be a number') + } + + if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) { + return fromArrayBuffer(that, value, encodingOrOffset, length) + } + + if (typeof value === 'string') { + return fromString(that, value, encodingOrOffset) + } + + return fromObject(that, value) + } + + /** + * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError + * if value is a number. + * Buffer.from(str[, encoding]) + * Buffer.from(array) + * Buffer.from(buffer) + * Buffer.from(arrayBuffer[, byteOffset[, length]]) + **/ + Buffer.from = function (value, encodingOrOffset, length) { + return from(null, value, encodingOrOffset, length) + }; + + if (Buffer.TYPED_ARRAY_SUPPORT) { + Buffer.prototype.__proto__ = Uint8Array.prototype; + Buffer.__proto__ = Uint8Array; + if (typeof Symbol !== 'undefined' && Symbol.species && + Buffer[Symbol.species] === Buffer) ; + } + + function assertSize (size) { + if (typeof size !== 'number') { + throw new TypeError('"size" argument must be a number') + } else if (size < 0) { + throw new RangeError('"size" argument must not be negative') + } + } + + function alloc (that, size, fill, encoding) { + assertSize(size); + if (size <= 0) { + return createBuffer(that, size) + } + if (fill !== undefined) { + // Only pay attention to encoding if it's a string. This + // prevents accidentally sending in a number that would + // be interpretted as a start offset. + return typeof encoding === 'string' + ? createBuffer(that, size).fill(fill, encoding) + : createBuffer(that, size).fill(fill) + } + return createBuffer(that, size) + } + + /** + * Creates a new filled Buffer instance. + * alloc(size[, fill[, encoding]]) + **/ + Buffer.alloc = function (size, fill, encoding) { + return alloc(null, size, fill, encoding) + }; + + function allocUnsafe (that, size) { + assertSize(size); + that = createBuffer(that, size < 0 ? 0 : checked(size) | 0); + if (!Buffer.TYPED_ARRAY_SUPPORT) { + for (var i = 0; i < size; ++i) { + that[i] = 0; + } + } + return that + } + + /** + * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance. + * */ + Buffer.allocUnsafe = function (size) { + return allocUnsafe(null, size) + }; + /** + * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance. + */ + Buffer.allocUnsafeSlow = function (size) { + return allocUnsafe(null, size) + }; + + function fromString (that, string, encoding) { + if (typeof encoding !== 'string' || encoding === '') { + encoding = 'utf8'; + } + + if (!Buffer.isEncoding(encoding)) { + throw new TypeError('"encoding" must be a valid string encoding') + } + + var length = byteLength(string, encoding) | 0; + that = createBuffer(that, length); + + var actual = that.write(string, encoding); + + if (actual !== length) { + // Writing a hex string, for example, that contains invalid characters will + // cause everything after the first invalid character to be ignored. (e.g. + // 'abxxcd' will be treated as 'ab') + that = that.slice(0, actual); + } + + return that + } + + function fromArrayLike (that, array) { + var length = array.length < 0 ? 0 : checked(array.length) | 0; + that = createBuffer(that, length); + for (var i = 0; i < length; i += 1) { + that[i] = array[i] & 255; + } + return that + } + + function fromArrayBuffer (that, array, byteOffset, length) { + array.byteLength; // this throws if `array` is not a valid ArrayBuffer + + if (byteOffset < 0 || array.byteLength < byteOffset) { + throw new RangeError('\'offset\' is out of bounds') + } + + if (array.byteLength < byteOffset + (length || 0)) { + throw new RangeError('\'length\' is out of bounds') + } + + if (byteOffset === undefined && length === undefined) { + array = new Uint8Array(array); + } else if (length === undefined) { + array = new Uint8Array(array, byteOffset); + } else { + array = new Uint8Array(array, byteOffset, length); + } + + if (Buffer.TYPED_ARRAY_SUPPORT) { + // Return an augmented `Uint8Array` instance, for best performance + that = array; + that.__proto__ = Buffer.prototype; + } else { + // Fallback: Return an object instance of the Buffer class + that = fromArrayLike(that, array); + } + return that + } + + function fromObject (that, obj) { + if (internalIsBuffer(obj)) { + var len = checked(obj.length) | 0; + that = createBuffer(that, len); + + if (that.length === 0) { + return that + } + + obj.copy(that, 0, 0, len); + return that + } + + if (obj) { + if ((typeof ArrayBuffer !== 'undefined' && + obj.buffer instanceof ArrayBuffer) || 'length' in obj) { + if (typeof obj.length !== 'number' || isnan(obj.length)) { + return createBuffer(that, 0) + } + return fromArrayLike(that, obj) + } + + if (obj.type === 'Buffer' && isArray(obj.data)) { + return fromArrayLike(that, obj.data) + } + } + + throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.') + } + + function checked (length) { + // Note: cannot use `length < kMaxLength()` here because that fails when + // length is NaN (which is otherwise coerced to zero.) + if (length >= kMaxLength()) { + throw new RangeError('Attempt to allocate Buffer larger than maximum ' + + 'size: 0x' + kMaxLength().toString(16) + ' bytes') + } + return length | 0 + } + Buffer.isBuffer = isBuffer; + function internalIsBuffer (b) { + return !!(b != null && b._isBuffer) + } + + Buffer.compare = function compare (a, b) { + if (!internalIsBuffer(a) || !internalIsBuffer(b)) { + throw new TypeError('Arguments must be Buffers') + } + + if (a === b) return 0 + + var x = a.length; + var y = b.length; + + for (var i = 0, len = Math.min(x, y); i < len; ++i) { + if (a[i] !== b[i]) { + x = a[i]; + y = b[i]; + break + } + } + + if (x < y) return -1 + if (y < x) return 1 + return 0 + }; + + Buffer.isEncoding = function isEncoding (encoding) { + switch (String(encoding).toLowerCase()) { + case 'hex': + case 'utf8': + case 'utf-8': + case 'ascii': + case 'latin1': + case 'binary': + case 'base64': + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return true + default: + return false + } + }; + + Buffer.concat = function concat (list, length) { + if (!isArray(list)) { + throw new TypeError('"list" argument must be an Array of Buffers') + } + + if (list.length === 0) { + return Buffer.alloc(0) + } + + var i; + if (length === undefined) { + length = 0; + for (i = 0; i < list.length; ++i) { + length += list[i].length; + } + } + + var buffer = Buffer.allocUnsafe(length); + var pos = 0; + for (i = 0; i < list.length; ++i) { + var buf = list[i]; + if (!internalIsBuffer(buf)) { + throw new TypeError('"list" argument must be an Array of Buffers') + } + buf.copy(buffer, pos); + pos += buf.length; + } + return buffer + }; + + function byteLength (string, encoding) { + if (internalIsBuffer(string)) { + return string.length + } + if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' && + (ArrayBuffer.isView(string) || string instanceof ArrayBuffer)) { + return string.byteLength + } + if (typeof string !== 'string') { + string = '' + string; + } + + var len = string.length; + if (len === 0) return 0 + + // Use a for loop to avoid recursion + var loweredCase = false; + for (;;) { + switch (encoding) { + case 'ascii': + case 'latin1': + case 'binary': + return len + case 'utf8': + case 'utf-8': + case undefined: + return utf8ToBytes(string).length + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return len * 2 + case 'hex': + return len >>> 1 + case 'base64': + return base64ToBytes(string).length + default: + if (loweredCase) return utf8ToBytes(string).length // assume utf8 + encoding = ('' + encoding).toLowerCase(); + loweredCase = true; + } + } + } + Buffer.byteLength = byteLength; + + function slowToString (encoding, start, end) { + var loweredCase = false; + + // No need to verify that "this.length <= MAX_UINT32" since it's a read-only + // property of a typed array. + + // This behaves neither like String nor Uint8Array in that we set start/end + // to their upper/lower bounds if the value passed is out of range. + // undefined is handled specially as per ECMA-262 6th Edition, + // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization. + if (start === undefined || start < 0) { + start = 0; + } + // Return early if start > this.length. Done here to prevent potential uint32 + // coercion fail below. + if (start > this.length) { + return '' + } + + if (end === undefined || end > this.length) { + end = this.length; + } + + if (end <= 0) { + return '' + } + + // Force coersion to uint32. This will also coerce falsey/NaN values to 0. + end >>>= 0; + start >>>= 0; + + if (end <= start) { + return '' + } + + if (!encoding) encoding = 'utf8'; + + while (true) { + switch (encoding) { + case 'hex': + return hexSlice(this, start, end) + + case 'utf8': + case 'utf-8': + return utf8Slice(this, start, end) + + case 'ascii': + return asciiSlice(this, start, end) + + case 'latin1': + case 'binary': + return latin1Slice(this, start, end) + + case 'base64': + return base64Slice(this, start, end) + + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return utf16leSlice(this, start, end) + + default: + if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) + encoding = (encoding + '').toLowerCase(); + loweredCase = true; + } + } + } + + // The property is used by `Buffer.isBuffer` and `is-buffer` (in Safari 5-7) to detect + // Buffer instances. + Buffer.prototype._isBuffer = true; + + function swap (b, n, m) { + var i = b[n]; + b[n] = b[m]; + b[m] = i; + } + + Buffer.prototype.swap16 = function swap16 () { + var len = this.length; + if (len % 2 !== 0) { + throw new RangeError('Buffer size must be a multiple of 16-bits') + } + for (var i = 0; i < len; i += 2) { + swap(this, i, i + 1); + } + return this + }; + + Buffer.prototype.swap32 = function swap32 () { + var len = this.length; + if (len % 4 !== 0) { + throw new RangeError('Buffer size must be a multiple of 32-bits') + } + for (var i = 0; i < len; i += 4) { + swap(this, i, i + 3); + swap(this, i + 1, i + 2); + } + return this + }; + + Buffer.prototype.swap64 = function swap64 () { + var len = this.length; + if (len % 8 !== 0) { + throw new RangeError('Buffer size must be a multiple of 64-bits') + } + for (var i = 0; i < len; i += 8) { + swap(this, i, i + 7); + swap(this, i + 1, i + 6); + swap(this, i + 2, i + 5); + swap(this, i + 3, i + 4); + } + return this + }; + + Buffer.prototype.toString = function toString () { + var length = this.length | 0; + if (length === 0) return '' + if (arguments.length === 0) return utf8Slice(this, 0, length) + return slowToString.apply(this, arguments) + }; + + Buffer.prototype.equals = function equals (b) { + if (!internalIsBuffer(b)) throw new TypeError('Argument must be a Buffer') + if (this === b) return true + return Buffer.compare(this, b) === 0 + }; + + Buffer.prototype.inspect = function inspect () { + var str = ''; + var max = INSPECT_MAX_BYTES; + if (this.length > 0) { + str = this.toString('hex', 0, max).match(/.{2}/g).join(' '); + if (this.length > max) str += ' ... '; + } + return '' + }; + + Buffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) { + if (!internalIsBuffer(target)) { + throw new TypeError('Argument must be a Buffer') + } + + if (start === undefined) { + start = 0; + } + if (end === undefined) { + end = target ? target.length : 0; + } + if (thisStart === undefined) { + thisStart = 0; + } + if (thisEnd === undefined) { + thisEnd = this.length; + } + + if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) { + throw new RangeError('out of range index') + } + + if (thisStart >= thisEnd && start >= end) { + return 0 + } + if (thisStart >= thisEnd) { + return -1 + } + if (start >= end) { + return 1 + } + + start >>>= 0; + end >>>= 0; + thisStart >>>= 0; + thisEnd >>>= 0; + + if (this === target) return 0 + + var x = thisEnd - thisStart; + var y = end - start; + var len = Math.min(x, y); + + var thisCopy = this.slice(thisStart, thisEnd); + var targetCopy = target.slice(start, end); + + for (var i = 0; i < len; ++i) { + if (thisCopy[i] !== targetCopy[i]) { + x = thisCopy[i]; + y = targetCopy[i]; + break + } + } + + if (x < y) return -1 + if (y < x) return 1 + return 0 + }; + + // Finds either the first index of `val` in `buffer` at offset >= `byteOffset`, + // OR the last index of `val` in `buffer` at offset <= `byteOffset`. + // + // Arguments: + // - buffer - a Buffer to search + // - val - a string, Buffer, or number + // - byteOffset - an index into `buffer`; will be clamped to an int32 + // - encoding - an optional encoding, relevant is val is a string + // - dir - true for indexOf, false for lastIndexOf + function bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) { + // Empty buffer means no match + if (buffer.length === 0) return -1 + + // Normalize byteOffset + if (typeof byteOffset === 'string') { + encoding = byteOffset; + byteOffset = 0; + } else if (byteOffset > 0x7fffffff) { + byteOffset = 0x7fffffff; + } else if (byteOffset < -0x80000000) { + byteOffset = -0x80000000; + } + byteOffset = +byteOffset; // Coerce to Number. + if (isNaN(byteOffset)) { + // byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer + byteOffset = dir ? 0 : (buffer.length - 1); + } + + // Normalize byteOffset: negative offsets start from the end of the buffer + if (byteOffset < 0) byteOffset = buffer.length + byteOffset; + if (byteOffset >= buffer.length) { + if (dir) return -1 + else byteOffset = buffer.length - 1; + } else if (byteOffset < 0) { + if (dir) byteOffset = 0; + else return -1 + } + + // Normalize val + if (typeof val === 'string') { + val = Buffer.from(val, encoding); + } + + // Finally, search either indexOf (if dir is true) or lastIndexOf + if (internalIsBuffer(val)) { + // Special case: looking for empty string/buffer always fails + if (val.length === 0) { + return -1 + } + return arrayIndexOf(buffer, val, byteOffset, encoding, dir) + } else if (typeof val === 'number') { + val = val & 0xFF; // Search for a byte value [0-255] + if (Buffer.TYPED_ARRAY_SUPPORT && + typeof Uint8Array.prototype.indexOf === 'function') { + if (dir) { + return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset) + } else { + return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset) + } + } + return arrayIndexOf(buffer, [ val ], byteOffset, encoding, dir) + } + + throw new TypeError('val must be string, number or Buffer') + } + + function arrayIndexOf (arr, val, byteOffset, encoding, dir) { + var indexSize = 1; + var arrLength = arr.length; + var valLength = val.length; + + if (encoding !== undefined) { + encoding = String(encoding).toLowerCase(); + if (encoding === 'ucs2' || encoding === 'ucs-2' || + encoding === 'utf16le' || encoding === 'utf-16le') { + if (arr.length < 2 || val.length < 2) { + return -1 + } + indexSize = 2; + arrLength /= 2; + valLength /= 2; + byteOffset /= 2; + } + } + + function read (buf, i) { + if (indexSize === 1) { + return buf[i] + } else { + return buf.readUInt16BE(i * indexSize) + } + } + + var i; + if (dir) { + var foundIndex = -1; + for (i = byteOffset; i < arrLength; i++) { + if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) { + if (foundIndex === -1) foundIndex = i; + if (i - foundIndex + 1 === valLength) return foundIndex * indexSize + } else { + if (foundIndex !== -1) i -= i - foundIndex; + foundIndex = -1; + } + } + } else { + if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength; + for (i = byteOffset; i >= 0; i--) { + var found = true; + for (var j = 0; j < valLength; j++) { + if (read(arr, i + j) !== read(val, j)) { + found = false; + break + } + } + if (found) return i + } + } + + return -1 + } + + Buffer.prototype.includes = function includes (val, byteOffset, encoding) { + return this.indexOf(val, byteOffset, encoding) !== -1 + }; + + Buffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) { + return bidirectionalIndexOf(this, val, byteOffset, encoding, true) + }; + + Buffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) { + return bidirectionalIndexOf(this, val, byteOffset, encoding, false) + }; + + function hexWrite (buf, string, offset, length) { + offset = Number(offset) || 0; + var remaining = buf.length - offset; + if (!length) { + length = remaining; + } else { + length = Number(length); + if (length > remaining) { + length = remaining; + } + } + + // must be an even number of digits + var strLen = string.length; + if (strLen % 2 !== 0) throw new TypeError('Invalid hex string') + + if (length > strLen / 2) { + length = strLen / 2; + } + for (var i = 0; i < length; ++i) { + var parsed = parseInt(string.substr(i * 2, 2), 16); + if (isNaN(parsed)) return i + buf[offset + i] = parsed; + } + return i + } + + function utf8Write (buf, string, offset, length) { + return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length) + } + + function asciiWrite (buf, string, offset, length) { + return blitBuffer(asciiToBytes(string), buf, offset, length) + } + + function latin1Write (buf, string, offset, length) { + return asciiWrite(buf, string, offset, length) + } + + function base64Write (buf, string, offset, length) { + return blitBuffer(base64ToBytes(string), buf, offset, length) + } + + function ucs2Write (buf, string, offset, length) { + return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length) + } + + Buffer.prototype.write = function write (string, offset, length, encoding) { + // Buffer#write(string) + if (offset === undefined) { + encoding = 'utf8'; + length = this.length; + offset = 0; + // Buffer#write(string, encoding) + } else if (length === undefined && typeof offset === 'string') { + encoding = offset; + length = this.length; + offset = 0; + // Buffer#write(string, offset[, length][, encoding]) + } else if (isFinite(offset)) { + offset = offset | 0; + if (isFinite(length)) { + length = length | 0; + if (encoding === undefined) encoding = 'utf8'; + } else { + encoding = length; + length = undefined; + } + // legacy write(string, encoding, offset, length) - remove in v0.13 + } else { + throw new Error( + 'Buffer.write(string, encoding, offset[, length]) is no longer supported' + ) + } + + var remaining = this.length - offset; + if (length === undefined || length > remaining) length = remaining; + + if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) { + throw new RangeError('Attempt to write outside buffer bounds') + } + + if (!encoding) encoding = 'utf8'; + + var loweredCase = false; + for (;;) { + switch (encoding) { + case 'hex': + return hexWrite(this, string, offset, length) + + case 'utf8': + case 'utf-8': + return utf8Write(this, string, offset, length) + + case 'ascii': + return asciiWrite(this, string, offset, length) + + case 'latin1': + case 'binary': + return latin1Write(this, string, offset, length) + + case 'base64': + // Warning: maxLength not taken into account in base64Write + return base64Write(this, string, offset, length) + + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return ucs2Write(this, string, offset, length) + + default: + if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) + encoding = ('' + encoding).toLowerCase(); + loweredCase = true; + } + } + }; + + Buffer.prototype.toJSON = function toJSON () { + return { + type: 'Buffer', + data: Array.prototype.slice.call(this._arr || this, 0) + } + }; + + function base64Slice (buf, start, end) { + if (start === 0 && end === buf.length) { + return fromByteArray(buf) + } else { + return fromByteArray(buf.slice(start, end)) + } + } + + function utf8Slice (buf, start, end) { + end = Math.min(buf.length, end); + var res = []; + + var i = start; + while (i < end) { + var firstByte = buf[i]; + var codePoint = null; + var bytesPerSequence = (firstByte > 0xEF) ? 4 + : (firstByte > 0xDF) ? 3 + : (firstByte > 0xBF) ? 2 + : 1; + + if (i + bytesPerSequence <= end) { + var secondByte, thirdByte, fourthByte, tempCodePoint; + + switch (bytesPerSequence) { + case 1: + if (firstByte < 0x80) { + codePoint = firstByte; + } + break + case 2: + secondByte = buf[i + 1]; + if ((secondByte & 0xC0) === 0x80) { + tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F); + if (tempCodePoint > 0x7F) { + codePoint = tempCodePoint; + } + } + break + case 3: + secondByte = buf[i + 1]; + thirdByte = buf[i + 2]; + if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) { + tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F); + if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) { + codePoint = tempCodePoint; + } + } + break + case 4: + secondByte = buf[i + 1]; + thirdByte = buf[i + 2]; + fourthByte = buf[i + 3]; + if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) { + tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F); + if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) { + codePoint = tempCodePoint; + } + } + } + } + + if (codePoint === null) { + // we did not generate a valid codePoint so insert a + // replacement char (U+FFFD) and advance only 1 byte + codePoint = 0xFFFD; + bytesPerSequence = 1; + } else if (codePoint > 0xFFFF) { + // encode to utf16 (surrogate pair dance) + codePoint -= 0x10000; + res.push(codePoint >>> 10 & 0x3FF | 0xD800); + codePoint = 0xDC00 | codePoint & 0x3FF; + } + + res.push(codePoint); + i += bytesPerSequence; + } + + return decodeCodePointsArray(res) + } + + // Based on http://stackoverflow.com/a/22747272/680742, the browser with + // the lowest limit is Chrome, with 0x10000 args. + // We go 1 magnitude less, for safety + var MAX_ARGUMENTS_LENGTH = 0x1000; + + function decodeCodePointsArray (codePoints) { + var len = codePoints.length; + if (len <= MAX_ARGUMENTS_LENGTH) { + return String.fromCharCode.apply(String, codePoints) // avoid extra slice() + } + + // Decode in chunks to avoid "call stack size exceeded". + var res = ''; + var i = 0; + while (i < len) { + res += String.fromCharCode.apply( + String, + codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH) + ); + } + return res + } + + function asciiSlice (buf, start, end) { + var ret = ''; + end = Math.min(buf.length, end); + + for (var i = start; i < end; ++i) { + ret += String.fromCharCode(buf[i] & 0x7F); + } + return ret + } + + function latin1Slice (buf, start, end) { + var ret = ''; + end = Math.min(buf.length, end); + + for (var i = start; i < end; ++i) { + ret += String.fromCharCode(buf[i]); + } + return ret + } + + function hexSlice (buf, start, end) { + var len = buf.length; + + if (!start || start < 0) start = 0; + if (!end || end < 0 || end > len) end = len; + + var out = ''; + for (var i = start; i < end; ++i) { + out += toHex(buf[i]); + } + return out + } + + function utf16leSlice (buf, start, end) { + var bytes = buf.slice(start, end); + var res = ''; + for (var i = 0; i < bytes.length; i += 2) { + res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256); + } + return res + } + + Buffer.prototype.slice = function slice (start, end) { + var len = this.length; + start = ~~start; + end = end === undefined ? len : ~~end; + + if (start < 0) { + start += len; + if (start < 0) start = 0; + } else if (start > len) { + start = len; + } + + if (end < 0) { + end += len; + if (end < 0) end = 0; + } else if (end > len) { + end = len; + } + + if (end < start) end = start; + + var newBuf; + if (Buffer.TYPED_ARRAY_SUPPORT) { + newBuf = this.subarray(start, end); + newBuf.__proto__ = Buffer.prototype; + } else { + var sliceLen = end - start; + newBuf = new Buffer(sliceLen, undefined); + for (var i = 0; i < sliceLen; ++i) { + newBuf[i] = this[i + start]; + } + } + + return newBuf + }; + + /* + * Need to make sure that buffer isn't trying to write out of bounds. + */ + function checkOffset (offset, ext, length) { + if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint') + if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length') + } + + Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) { + offset = offset | 0; + byteLength = byteLength | 0; + if (!noAssert) checkOffset(offset, byteLength, this.length); + + var val = this[offset]; + var mul = 1; + var i = 0; + while (++i < byteLength && (mul *= 0x100)) { + val += this[offset + i] * mul; + } + + return val + }; + + Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) { + offset = offset | 0; + byteLength = byteLength | 0; + if (!noAssert) { + checkOffset(offset, byteLength, this.length); + } + + var val = this[offset + --byteLength]; + var mul = 1; + while (byteLength > 0 && (mul *= 0x100)) { + val += this[offset + --byteLength] * mul; + } + + return val + }; + + Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) { + if (!noAssert) checkOffset(offset, 1, this.length); + return this[offset] + }; + + Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 2, this.length); + return this[offset] | (this[offset + 1] << 8) + }; + + Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 2, this.length); + return (this[offset] << 8) | this[offset + 1] + }; + + Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 4, this.length); + + return ((this[offset]) | + (this[offset + 1] << 8) | + (this[offset + 2] << 16)) + + (this[offset + 3] * 0x1000000) + }; + + Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 4, this.length); + + return (this[offset] * 0x1000000) + + ((this[offset + 1] << 16) | + (this[offset + 2] << 8) | + this[offset + 3]) + }; + + Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) { + offset = offset | 0; + byteLength = byteLength | 0; + if (!noAssert) checkOffset(offset, byteLength, this.length); - if (!child.runtime) { - return + var val = this[offset]; + var mul = 1; + var i = 0; + while (++i < byteLength && (mul *= 0x100)) { + val += this[offset + i] * mul; } + mul *= 0x80; - parent.removeChild(key); + if (val >= mul) val -= Math.pow(2, 8 * byteLength); + + return val }; - ModuleCollection.prototype.isRegistered = function isRegistered (path) { - var parent = this.get(path.slice(0, -1)); - var key = path[path.length - 1]; + Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) { + offset = offset | 0; + byteLength = byteLength | 0; + if (!noAssert) checkOffset(offset, byteLength, this.length); - if (parent) { - return parent.hasChild(key) + var i = byteLength; + var mul = 1; + var val = this[offset + --i]; + while (i > 0 && (mul *= 0x100)) { + val += this[offset + --i] * mul; } + mul *= 0x80; - return false + if (val >= mul) val -= Math.pow(2, 8 * byteLength); + + return val }; - function update (path, targetModule, newModule) { - if ((process.env.NODE_ENV !== 'production')) { - assertRawModule(path, newModule); - } + Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) { + if (!noAssert) checkOffset(offset, 1, this.length); + if (!(this[offset] & 0x80)) return (this[offset]) + return ((0xff - this[offset] + 1) * -1) + }; - // update target module - targetModule.update(newModule); + Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 2, this.length); + var val = this[offset] | (this[offset + 1] << 8); + return (val & 0x8000) ? val | 0xFFFF0000 : val + }; - // update nested modules - if (newModule.modules) { - for (var key in newModule.modules) { - if (!targetModule.getChild(key)) { - if ((process.env.NODE_ENV !== 'production')) { - console.warn( - "[vuex] trying to add a new module '" + key + "' on hot reloading, " + - 'manual reload is needed' - ); - } - return - } - update( - path.concat(key), - targetModule.getChild(key), - newModule.modules[key] - ); - } - } - } + Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 2, this.length); + var val = this[offset + 1] | (this[offset] << 8); + return (val & 0x8000) ? val | 0xFFFF0000 : val + }; - var functionAssert = { - assert: function (value) { return typeof value === 'function'; }, - expected: 'function' + Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 4, this.length); + + return (this[offset]) | + (this[offset + 1] << 8) | + (this[offset + 2] << 16) | + (this[offset + 3] << 24) }; - var objectAssert = { - assert: function (value) { return typeof value === 'function' || - (typeof value === 'object' && typeof value.handler === 'function'); }, - expected: 'function or object with "handler" function' + Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 4, this.length); + + return (this[offset] << 24) | + (this[offset + 1] << 16) | + (this[offset + 2] << 8) | + (this[offset + 3]) }; - var assertTypes = { - getters: functionAssert, - mutations: functionAssert, - actions: objectAssert + Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 4, this.length); + return read(this, offset, true, 23, 4) }; - function assertRawModule (path, rawModule) { - Object.keys(assertTypes).forEach(function (key) { - if (!rawModule[key]) { return } + Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 4, this.length); + return read(this, offset, false, 23, 4) + }; - var assertOptions = assertTypes[key]; + Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 8, this.length); + return read(this, offset, true, 52, 8) + }; - forEachValue(rawModule[key], function (value, type) { - assert( - assertOptions.assert(value), - makeAssertionMessage(path, key, type, value, assertOptions.expected) - ); - }); - }); + Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 8, this.length); + return read(this, offset, false, 52, 8) + }; + + function checkInt (buf, value, offset, ext, max, min) { + if (!internalIsBuffer(buf)) throw new TypeError('"buffer" argument must be a Buffer instance') + if (value > max || value < min) throw new RangeError('"value" argument is out of bounds') + if (offset + ext > buf.length) throw new RangeError('Index out of range') } - function makeAssertionMessage (path, key, type, value, expected) { - var buf = key + " should be " + expected + " but \"" + key + "." + type + "\""; - if (path.length > 0) { - buf += " in module \"" + (path.join('.')) + "\""; + Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) { + value = +value; + offset = offset | 0; + byteLength = byteLength | 0; + if (!noAssert) { + var maxBytes = Math.pow(2, 8 * byteLength) - 1; + checkInt(this, value, offset, byteLength, maxBytes, 0); } - buf += " is " + (JSON.stringify(value)) + "."; - return buf - } - var Vue; // bind on install + var mul = 1; + var i = 0; + this[offset] = value & 0xFF; + while (++i < byteLength && (mul *= 0x100)) { + this[offset + i] = (value / mul) & 0xFF; + } - var Store = function Store (options) { - var this$1$1 = this; - if ( options === void 0 ) options = {}; + return offset + byteLength + }; - // Auto install if it is not done yet and `window` has `Vue`. - // To allow users to avoid auto-installation in some cases, - // this code should be placed here. See #731 - if (!Vue && typeof window !== 'undefined' && window.Vue) { - install(window.Vue); + Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) { + value = +value; + offset = offset | 0; + byteLength = byteLength | 0; + if (!noAssert) { + var maxBytes = Math.pow(2, 8 * byteLength) - 1; + checkInt(this, value, offset, byteLength, maxBytes, 0); } - if ((process.env.NODE_ENV !== 'production')) { - assert(Vue, "must call Vue.use(Vuex) before creating a store instance."); - assert(typeof Promise !== 'undefined', "vuex requires a Promise polyfill in this browser."); - assert(this instanceof Store, "store must be called with the new operator."); + var i = byteLength - 1; + var mul = 1; + this[offset + i] = value & 0xFF; + while (--i >= 0 && (mul *= 0x100)) { + this[offset + i] = (value / mul) & 0xFF; } - var plugins = options.plugins; if ( plugins === void 0 ) plugins = []; - var strict = options.strict; if ( strict === void 0 ) strict = false; - - // store internal state - this._committing = false; - this._actions = Object.create(null); - this._actionSubscribers = []; - this._mutations = Object.create(null); - this._wrappedGetters = Object.create(null); - this._modules = new ModuleCollection(options); - this._modulesNamespaceMap = Object.create(null); - this._subscribers = []; - this._watcherVM = new Vue(); - this._makeLocalGettersCache = Object.create(null); + return offset + byteLength + }; - // bind commit and dispatch to self - var store = this; - var ref = this; - var dispatch = ref.dispatch; - var commit = ref.commit; - this.dispatch = function boundDispatch (type, payload) { - return dispatch.call(store, type, payload) - }; - this.commit = function boundCommit (type, payload, options) { - return commit.call(store, type, payload, options) - }; + Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) { + value = +value; + offset = offset | 0; + if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0); + if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value); + this[offset] = (value & 0xff); + return offset + 1 + }; - // strict mode - this.strict = strict; + function objectWriteUInt16 (buf, value, offset, littleEndian) { + if (value < 0) value = 0xffff + value + 1; + for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; ++i) { + buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>> + (littleEndian ? i : 1 - i) * 8; + } + } - var state = this._modules.root.state; + Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) { + value = +value; + offset = offset | 0; + if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0); + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = (value & 0xff); + this[offset + 1] = (value >>> 8); + } else { + objectWriteUInt16(this, value, offset, true); + } + return offset + 2 + }; - // init root module. - // this also recursively registers all sub-modules - // and collects all module getters inside this._wrappedGetters - installModule(this, state, [], this._modules.root); + Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) { + value = +value; + offset = offset | 0; + if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0); + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = (value >>> 8); + this[offset + 1] = (value & 0xff); + } else { + objectWriteUInt16(this, value, offset, false); + } + return offset + 2 + }; - // initialize the store vm, which is responsible for the reactivity - // (also registers _wrappedGetters as computed properties) - resetStoreVM(this, state); + function objectWriteUInt32 (buf, value, offset, littleEndian) { + if (value < 0) value = 0xffffffff + value + 1; + for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; ++i) { + buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff; + } + } - // apply plugins - plugins.forEach(function (plugin) { return plugin(this$1$1); }); + Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) { + value = +value; + offset = offset | 0; + if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0); + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset + 3] = (value >>> 24); + this[offset + 2] = (value >>> 16); + this[offset + 1] = (value >>> 8); + this[offset] = (value & 0xff); + } else { + objectWriteUInt32(this, value, offset, true); + } + return offset + 4 + }; - var useDevtools = options.devtools !== undefined ? options.devtools : Vue.config.devtools; - if (useDevtools) { - devtoolPlugin(this); + Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) { + value = +value; + offset = offset | 0; + if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0); + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = (value >>> 24); + this[offset + 1] = (value >>> 16); + this[offset + 2] = (value >>> 8); + this[offset + 3] = (value & 0xff); + } else { + objectWriteUInt32(this, value, offset, false); } + return offset + 4 }; - var prototypeAccessors$1 = { state: { configurable: true } }; + Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) { + value = +value; + offset = offset | 0; + if (!noAssert) { + var limit = Math.pow(2, 8 * byteLength - 1); - prototypeAccessors$1.state.get = function () { - return this._vm._data.$$state - }; + checkInt(this, value, offset, byteLength, limit - 1, -limit); + } - prototypeAccessors$1.state.set = function (v) { - if ((process.env.NODE_ENV !== 'production')) { - assert(false, "use store.replaceState() to explicit replace store state."); + var i = 0; + var mul = 1; + var sub = 0; + this[offset] = value & 0xFF; + while (++i < byteLength && (mul *= 0x100)) { + if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) { + sub = 1; + } + this[offset + i] = ((value / mul) >> 0) - sub & 0xFF; } + + return offset + byteLength }; - Store.prototype.commit = function commit (_type, _payload, _options) { - var this$1$1 = this; + Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) { + value = +value; + offset = offset | 0; + if (!noAssert) { + var limit = Math.pow(2, 8 * byteLength - 1); - // check object-style commit - var ref = unifyObjectStyle(_type, _payload, _options); - var type = ref.type; - var payload = ref.payload; - var options = ref.options; + checkInt(this, value, offset, byteLength, limit - 1, -limit); + } - var mutation = { type: type, payload: payload }; - var entry = this._mutations[type]; - if (!entry) { - if ((process.env.NODE_ENV !== 'production')) { - console.error(("[vuex] unknown mutation type: " + type)); + var i = byteLength - 1; + var mul = 1; + var sub = 0; + this[offset + i] = value & 0xFF; + while (--i >= 0 && (mul *= 0x100)) { + if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) { + sub = 1; } - return + this[offset + i] = ((value / mul) >> 0) - sub & 0xFF; } - this._withCommit(function () { - entry.forEach(function commitIterator (handler) { - handler(payload); - }); - }); - this._subscribers - .slice() // shallow copy to prevent iterator invalidation if subscriber synchronously calls unsubscribe - .forEach(function (sub) { return sub(mutation, this$1$1.state); }); + return offset + byteLength + }; - if ( - (process.env.NODE_ENV !== 'production') && - options && options.silent - ) { - console.warn( - "[vuex] mutation type: " + type + ". Silent option has been removed. " + - 'Use the filter functionality in the vue-devtools' - ); + Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) { + value = +value; + offset = offset | 0; + if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80); + if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value); + if (value < 0) value = 0xff + value + 1; + this[offset] = (value & 0xff); + return offset + 1 + }; + + Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) { + value = +value; + offset = offset | 0; + if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000); + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = (value & 0xff); + this[offset + 1] = (value >>> 8); + } else { + objectWriteUInt16(this, value, offset, true); } + return offset + 2 }; - Store.prototype.dispatch = function dispatch (_type, _payload) { - var this$1$1 = this; + Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) { + value = +value; + offset = offset | 0; + if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000); + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = (value >>> 8); + this[offset + 1] = (value & 0xff); + } else { + objectWriteUInt16(this, value, offset, false); + } + return offset + 2 + }; - // check object-style dispatch - var ref = unifyObjectStyle(_type, _payload); - var type = ref.type; - var payload = ref.payload; + Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) { + value = +value; + offset = offset | 0; + if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000); + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = (value & 0xff); + this[offset + 1] = (value >>> 8); + this[offset + 2] = (value >>> 16); + this[offset + 3] = (value >>> 24); + } else { + objectWriteUInt32(this, value, offset, true); + } + return offset + 4 + }; - var action = { type: type, payload: payload }; - var entry = this._actions[type]; - if (!entry) { - if ((process.env.NODE_ENV !== 'production')) { - console.error(("[vuex] unknown action type: " + type)); - } - return + Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) { + value = +value; + offset = offset | 0; + if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000); + if (value < 0) value = 0xffffffff + value + 1; + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = (value >>> 24); + this[offset + 1] = (value >>> 16); + this[offset + 2] = (value >>> 8); + this[offset + 3] = (value & 0xff); + } else { + objectWriteUInt32(this, value, offset, false); } + return offset + 4 + }; - try { - this._actionSubscribers - .slice() // shallow copy to prevent iterator invalidation if subscriber synchronously calls unsubscribe - .filter(function (sub) { return sub.before; }) - .forEach(function (sub) { return sub.before(action, this$1$1.state); }); - } catch (e) { - if ((process.env.NODE_ENV !== 'production')) { - console.warn("[vuex] error in before action subscribers: "); - console.error(e); - } + function checkIEEE754 (buf, value, offset, ext, max, min) { + if (offset + ext > buf.length) throw new RangeError('Index out of range') + if (offset < 0) throw new RangeError('Index out of range') + } + + function writeFloat (buf, value, offset, littleEndian, noAssert) { + if (!noAssert) { + checkIEEE754(buf, value, offset, 4); } + write(buf, value, offset, littleEndian, 23, 4); + return offset + 4 + } - var result = entry.length > 1 - ? Promise.all(entry.map(function (handler) { return handler(payload); })) - : entry[0](payload); + Buffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) { + return writeFloat(this, value, offset, true, noAssert) + }; - return new Promise(function (resolve, reject) { - result.then(function (res) { - try { - this$1$1._actionSubscribers - .filter(function (sub) { return sub.after; }) - .forEach(function (sub) { return sub.after(action, this$1$1.state); }); - } catch (e) { - if ((process.env.NODE_ENV !== 'production')) { - console.warn("[vuex] error in after action subscribers: "); - console.error(e); - } - } - resolve(res); - }, function (error) { - try { - this$1$1._actionSubscribers - .filter(function (sub) { return sub.error; }) - .forEach(function (sub) { return sub.error(action, this$1$1.state, error); }); - } catch (e) { - if ((process.env.NODE_ENV !== 'production')) { - console.warn("[vuex] error in error action subscribers: "); - console.error(e); - } - } - reject(error); - }); - }) + Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) { + return writeFloat(this, value, offset, false, noAssert) }; - Store.prototype.subscribe = function subscribe (fn, options) { - return genericSubscribe(fn, this._subscribers, options) + function writeDouble (buf, value, offset, littleEndian, noAssert) { + if (!noAssert) { + checkIEEE754(buf, value, offset, 8); + } + write(buf, value, offset, littleEndian, 52, 8); + return offset + 8 + } + + Buffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) { + return writeDouble(this, value, offset, true, noAssert) }; - Store.prototype.subscribeAction = function subscribeAction (fn, options) { - var subs = typeof fn === 'function' ? { before: fn } : fn; - return genericSubscribe(subs, this._actionSubscribers, options) + Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) { + return writeDouble(this, value, offset, false, noAssert) }; - Store.prototype.watch = function watch (getter, cb, options) { - var this$1$1 = this; + // copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) + Buffer.prototype.copy = function copy (target, targetStart, start, end) { + if (!start) start = 0; + if (!end && end !== 0) end = this.length; + if (targetStart >= target.length) targetStart = target.length; + if (!targetStart) targetStart = 0; + if (end > 0 && end < start) end = start; + + // Copy 0 bytes; we're done + if (end === start) return 0 + if (target.length === 0 || this.length === 0) return 0 + + // Fatal error conditions + if (targetStart < 0) { + throw new RangeError('targetStart out of bounds') + } + if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds') + if (end < 0) throw new RangeError('sourceEnd out of bounds') - if ((process.env.NODE_ENV !== 'production')) { - assert(typeof getter === 'function', "store.watch only accepts a function."); + // Are we oob? + if (end > this.length) end = this.length; + if (target.length - targetStart < end - start) { + end = target.length - targetStart + start; } - return this._watcherVM.$watch(function () { return getter(this$1$1.state, this$1$1.getters); }, cb, options) + + var len = end - start; + var i; + + if (this === target && start < targetStart && targetStart < end) { + // descending copy from end + for (i = len - 1; i >= 0; --i) { + target[i + targetStart] = this[i + start]; + } + } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) { + // ascending copy from start + for (i = 0; i < len; ++i) { + target[i + targetStart] = this[i + start]; + } + } else { + Uint8Array.prototype.set.call( + target, + this.subarray(start, start + len), + targetStart + ); + } + + return len }; - Store.prototype.replaceState = function replaceState (state) { - var this$1$1 = this; + // Usage: + // buffer.fill(number[, offset[, end]]) + // buffer.fill(buffer[, offset[, end]]) + // buffer.fill(string[, offset[, end]][, encoding]) + Buffer.prototype.fill = function fill (val, start, end, encoding) { + // Handle string cases: + if (typeof val === 'string') { + if (typeof start === 'string') { + encoding = start; + start = 0; + end = this.length; + } else if (typeof end === 'string') { + encoding = end; + end = this.length; + } + if (val.length === 1) { + var code = val.charCodeAt(0); + if (code < 256) { + val = code; + } + } + if (encoding !== undefined && typeof encoding !== 'string') { + throw new TypeError('encoding must be a string') + } + if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) { + throw new TypeError('Unknown encoding: ' + encoding) + } + } else if (typeof val === 'number') { + val = val & 255; + } + + // Invalid ranges are not set to a default, so can range check early. + if (start < 0 || this.length < start || this.length < end) { + throw new RangeError('Out of range index') + } - this._withCommit(function () { - this$1$1._vm._data.$$state = state; - }); - }; + if (end <= start) { + return this + } - Store.prototype.registerModule = function registerModule (path, rawModule, options) { - if ( options === void 0 ) options = {}; + start = start >>> 0; + end = end === undefined ? this.length : end >>> 0; - if (typeof path === 'string') { path = [path]; } + if (!val) val = 0; - if ((process.env.NODE_ENV !== 'production')) { - assert(Array.isArray(path), "module path must be a string or an Array."); - assert(path.length > 0, 'cannot register the root module by using registerModule.'); + var i; + if (typeof val === 'number') { + for (i = start; i < end; ++i) { + this[i] = val; + } + } else { + var bytes = internalIsBuffer(val) + ? val + : utf8ToBytes(new Buffer(val, encoding).toString()); + var len = bytes.length; + for (i = 0; i < end - start; ++i) { + this[i + start] = bytes[i % len]; + } } - this._modules.register(path, rawModule); - installModule(this, this.state, path, this._modules.get(path), options.preserveState); - // reset store to update getters... - resetStoreVM(this, this.state); + return this }; - Store.prototype.unregisterModule = function unregisterModule (path) { - var this$1$1 = this; + // HELPER FUNCTIONS + // ================ - if (typeof path === 'string') { path = [path]; } + var INVALID_BASE64_RE = /[^+\/0-9A-Za-z-_]/g; - if ((process.env.NODE_ENV !== 'production')) { - assert(Array.isArray(path), "module path must be a string or an Array."); + function base64clean (str) { + // Node strips out invalid characters like \n and \t from the string, base64-js does not + str = stringtrim(str).replace(INVALID_BASE64_RE, ''); + // Node converts strings with length < 2 to '' + if (str.length < 2) return '' + // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not + while (str.length % 4 !== 0) { + str = str + '='; } + return str + } - this._modules.unregister(path); - this._withCommit(function () { - var parentState = getNestedState(this$1$1.state, path.slice(0, -1)); - Vue.delete(parentState, path[path.length - 1]); - }); - resetStore(this); - }; + function stringtrim (str) { + if (str.trim) return str.trim() + return str.replace(/^\s+|\s+$/g, '') + } - Store.prototype.hasModule = function hasModule (path) { - if (typeof path === 'string') { path = [path]; } + function toHex (n) { + if (n < 16) return '0' + n.toString(16) + return n.toString(16) + } - if ((process.env.NODE_ENV !== 'production')) { - assert(Array.isArray(path), "module path must be a string or an Array."); - } + function utf8ToBytes (string, units) { + units = units || Infinity; + var codePoint; + var length = string.length; + var leadSurrogate = null; + var bytes = []; + + for (var i = 0; i < length; ++i) { + codePoint = string.charCodeAt(i); + + // is surrogate component + if (codePoint > 0xD7FF && codePoint < 0xE000) { + // last char was a lead + if (!leadSurrogate) { + // no lead yet + if (codePoint > 0xDBFF) { + // unexpected trail + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD); + continue + } else if (i + 1 === length) { + // unpaired lead + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD); + continue + } - return this._modules.isRegistered(path) - }; + // valid lead + leadSurrogate = codePoint; - Store.prototype.hotUpdate = function hotUpdate (newOptions) { - this._modules.update(newOptions); - resetStore(this, true); - }; + continue + } - Store.prototype._withCommit = function _withCommit (fn) { - var committing = this._committing; - this._committing = true; - fn(); - this._committing = committing; - }; + // 2 leads in a row + if (codePoint < 0xDC00) { + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD); + leadSurrogate = codePoint; + continue + } - Object.defineProperties( Store.prototype, prototypeAccessors$1 ); + // valid surrogate pair + codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000; + } else if (leadSurrogate) { + // valid bmp char, but last char was a lead + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD); + } - function genericSubscribe (fn, subs, options) { - if (subs.indexOf(fn) < 0) { - options && options.prepend - ? subs.unshift(fn) - : subs.push(fn); - } - return function () { - var i = subs.indexOf(fn); - if (i > -1) { - subs.splice(i, 1); + leadSurrogate = null; + + // encode utf8 + if (codePoint < 0x80) { + if ((units -= 1) < 0) break + bytes.push(codePoint); + } else if (codePoint < 0x800) { + if ((units -= 2) < 0) break + bytes.push( + codePoint >> 0x6 | 0xC0, + codePoint & 0x3F | 0x80 + ); + } else if (codePoint < 0x10000) { + if ((units -= 3) < 0) break + bytes.push( + codePoint >> 0xC | 0xE0, + codePoint >> 0x6 & 0x3F | 0x80, + codePoint & 0x3F | 0x80 + ); + } else if (codePoint < 0x110000) { + if ((units -= 4) < 0) break + bytes.push( + codePoint >> 0x12 | 0xF0, + codePoint >> 0xC & 0x3F | 0x80, + codePoint >> 0x6 & 0x3F | 0x80, + codePoint & 0x3F | 0x80 + ); + } else { + throw new Error('Invalid code point') } } + + return bytes } - function resetStore (store, hot) { - store._actions = Object.create(null); - store._mutations = Object.create(null); - store._wrappedGetters = Object.create(null); - store._modulesNamespaceMap = Object.create(null); - var state = store.state; - // init all modules - installModule(store, state, [], store._modules.root, true); - // reset vm - resetStoreVM(store, state, hot); + function asciiToBytes (str) { + var byteArray = []; + for (var i = 0; i < str.length; ++i) { + // Node's code seems to be doing this and not & 0x7F.. + byteArray.push(str.charCodeAt(i) & 0xFF); + } + return byteArray } - function resetStoreVM (store, state, hot) { - var oldVm = store._vm; + function utf16leToBytes (str, units) { + var c, hi, lo; + var byteArray = []; + for (var i = 0; i < str.length; ++i) { + if ((units -= 2) < 0) break + + c = str.charCodeAt(i); + hi = c >> 8; + lo = c % 256; + byteArray.push(lo); + byteArray.push(hi); + } - // bind store public getters - store.getters = {}; - // reset local getters cache - store._makeLocalGettersCache = Object.create(null); - var wrappedGetters = store._wrappedGetters; - var computed = {}; - forEachValue(wrappedGetters, function (fn, key) { - // use computed to leverage its lazy-caching mechanism - // direct inline function use will lead to closure preserving oldVm. - // using partial to return function with only arguments preserved in closure environment. - computed[key] = partial(fn, store); - Object.defineProperty(store.getters, key, { - get: function () { return store._vm[key]; }, - enumerable: true // for local getters - }); - }); + return byteArray + } - // use a Vue instance to store the state tree - // suppress warnings just in case the user has added - // some funky global mixins - var silent = Vue.config.silent; - Vue.config.silent = true; - store._vm = new Vue({ - data: { - $$state: state - }, - computed: computed - }); - Vue.config.silent = silent; - // enable strict mode for new vm - if (store.strict) { - enableStrictMode(store); - } + function base64ToBytes (str) { + return toByteArray(base64clean(str)) + } - if (oldVm) { - if (hot) { - // dispatch changes in all subscribed watchers - // to force getter re-evaluation for hot reloading. - store._withCommit(function () { - oldVm._data.$$state = null; - }); - } - Vue.nextTick(function () { return oldVm.$destroy(); }); + function blitBuffer (src, dst, offset, length) { + for (var i = 0; i < length; ++i) { + if ((i + offset >= dst.length) || (i >= src.length)) break + dst[i + offset] = src[i]; } + return i } - function installModule (store, rootState, path, module, hot) { - var isRoot = !path.length; - var namespace = store._modules.getNamespace(path); + function isnan (val) { + return val !== val // eslint-disable-line no-self-compare + } - // register in namespace map - if (module.namespaced) { - if (store._modulesNamespaceMap[namespace] && (process.env.NODE_ENV !== 'production')) { - console.error(("[vuex] duplicate namespace " + namespace + " for the namespaced module " + (path.join('/')))); - } - store._modulesNamespaceMap[namespace] = module; + + // the following is from is-buffer, also by Feross Aboukhadijeh and with same lisence + // The _isBuffer check is for Safari 5-7 support, because it's missing + // Object.prototype.constructor. Remove this eventually + function isBuffer(obj) { + return obj != null && (!!obj._isBuffer || isFastBuffer(obj) || isSlowBuffer(obj)) + } + + function isFastBuffer (obj) { + return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj) + } + + // For Node v0.10 support. Remove this eventually. + function isSlowBuffer (obj) { + return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isFastBuffer(obj.slice(0, 0)) + } + + /** + * Create an Error with the specified message, config, error code, request and response. + * + * @param {string} message The error message. + * @param {string} [code] The error code (for example, 'ECONNABORTED'). + * @param {Object} [config] The config. + * @param {Object} [request] The request. + * @param {Object} [response] The response. + * + * @returns {Error} The created error. + */ + function AxiosError(message, code, config, request, response) { + Error.call(this); + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, this.constructor); + } else { + this.stack = (new Error()).stack; } - // set state - if (!isRoot && !hot) { - var parentState = getNestedState(rootState, path.slice(0, -1)); - var moduleName = path[path.length - 1]; - store._withCommit(function () { - if ((process.env.NODE_ENV !== 'production')) { - if (moduleName in parentState) { - console.warn( - ("[vuex] state field \"" + moduleName + "\" was overridden by a module with the same name at \"" + (path.join('.')) + "\"") - ); - } - } - Vue.set(parentState, moduleName, module.state); - }); + this.message = message; + this.name = 'AxiosError'; + code && (this.code = code); + config && (this.config = config); + request && (this.request = request); + response && (this.response = response); + } + + utils.inherits(AxiosError, Error, { + toJSON: function toJSON() { + return { + // Standard + message: this.message, + name: this.name, + // Microsoft + description: this.description, + number: this.number, + // Mozilla + fileName: this.fileName, + lineNumber: this.lineNumber, + columnNumber: this.columnNumber, + stack: this.stack, + // Axios + config: utils.toJSONObject(this.config), + code: this.code, + status: this.response && this.response.status ? this.response.status : null + }; } + }); - var local = module.context = makeLocalContext(store, namespace, path); + const prototype$1 = AxiosError.prototype; + const descriptors = {}; + + [ + 'ERR_BAD_OPTION_VALUE', + 'ERR_BAD_OPTION', + 'ECONNABORTED', + 'ETIMEDOUT', + 'ERR_NETWORK', + 'ERR_FR_TOO_MANY_REDIRECTS', + 'ERR_DEPRECATED', + 'ERR_BAD_RESPONSE', + 'ERR_BAD_REQUEST', + 'ERR_CANCELED', + 'ERR_NOT_SUPPORT', + 'ERR_INVALID_URL' + // eslint-disable-next-line func-names + ].forEach(code => { + descriptors[code] = {value: code}; + }); - module.forEachMutation(function (mutation, key) { - var namespacedType = namespace + key; - registerMutation(store, namespacedType, mutation, local); - }); + Object.defineProperties(AxiosError, descriptors); + Object.defineProperty(prototype$1, 'isAxiosError', {value: true}); - module.forEachAction(function (action, key) { - var type = action.root ? key : namespace + key; - var handler = action.handler || action; - registerAction(store, type, handler, local); - }); + // eslint-disable-next-line func-names + AxiosError.from = (error, code, config, request, response, customProps) => { + const axiosError = Object.create(prototype$1); - module.forEachGetter(function (getter, key) { - var namespacedType = namespace + key; - registerGetter(store, namespacedType, getter, local); + utils.toFlatObject(error, axiosError, function filter(obj) { + return obj !== Error.prototype; + }, prop => { + return prop !== 'isAxiosError'; }); - module.forEachChild(function (child, key) { - installModule(store, rootState, path.concat(key), child, hot); - }); - } + AxiosError.call(axiosError, error.message, code, config, request, response); - /** - * make localized dispatch, commit, getters and state - * if there is no namespace, just use root ones - */ - function makeLocalContext (store, namespace, path) { - var noNamespace = namespace === ''; + axiosError.cause = error; - var local = { - dispatch: noNamespace ? store.dispatch : function (_type, _payload, _options) { - var args = unifyObjectStyle(_type, _payload, _options); - var payload = args.payload; - var options = args.options; - var type = args.type; + axiosError.name = error.name; - if (!options || !options.root) { - type = namespace + type; - if ((process.env.NODE_ENV !== 'production') && !store._actions[type]) { - console.error(("[vuex] unknown local action type: " + (args.type) + ", global type: " + type)); - return - } - } + customProps && Object.assign(axiosError, customProps); - return store.dispatch(type, payload) - }, + return axiosError; + }; - commit: noNamespace ? store.commit : function (_type, _payload, _options) { - var args = unifyObjectStyle(_type, _payload, _options); - var payload = args.payload; - var options = args.options; - var type = args.type; + // eslint-disable-next-line strict + var httpAdapter = null; - if (!options || !options.root) { - type = namespace + type; - if ((process.env.NODE_ENV !== 'production') && !store._mutations[type]) { - console.error(("[vuex] unknown local mutation type: " + (args.type) + ", global type: " + type)); - return - } - } + /** + * Determines if the given thing is a array or js object. + * + * @param {string} thing - The object or array to be visited. + * + * @returns {boolean} + */ + function isVisitable(thing) { + return utils.isPlainObject(thing) || utils.isArray(thing); + } - store.commit(type, payload, options); - } - }; + /** + * It removes the brackets from the end of a string + * + * @param {string} key - The key of the parameter. + * + * @returns {string} the key without the brackets. + */ + function removeBrackets(key) { + return utils.endsWith(key, '[]') ? key.slice(0, -2) : key; + } - // getters and state object must be gotten lazily - // because they will be changed by vm update - Object.defineProperties(local, { - getters: { - get: noNamespace - ? function () { return store.getters; } - : function () { return makeLocalGetters(store, namespace); } - }, - state: { - get: function () { return getNestedState(store.state, path); } - } - }); + /** + * It takes a path, a key, and a boolean, and returns a string + * + * @param {string} path - The path to the current key. + * @param {string} key - The key of the current object being iterated over. + * @param {string} dots - If true, the key will be rendered with dots instead of brackets. + * + * @returns {string} The path to the current key. + */ + function renderKey(path, key, dots) { + if (!path) return key; + return path.concat(key).map(function each(token, i) { + // eslint-disable-next-line no-param-reassign + token = removeBrackets(token); + return !dots && i ? '[' + token + ']' : token; + }).join(dots ? '.' : ''); + } - return local + /** + * If the array is an array and none of its elements are visitable, then it's a flat array. + * + * @param {Array} arr - The array to check + * + * @returns {boolean} + */ + function isFlatArray(arr) { + return utils.isArray(arr) && !arr.some(isVisitable); } - function makeLocalGetters (store, namespace) { - if (!store._makeLocalGettersCache[namespace]) { - var gettersProxy = {}; - var splitPos = namespace.length; - Object.keys(store.getters).forEach(function (type) { - // skip if the target getter is not match this namespace - if (type.slice(0, splitPos) !== namespace) { return } + const predicates = utils.toFlatObject(utils, {}, null, function filter(prop) { + return /^is[A-Z]/.test(prop); + }); - // extract local getter type - var localType = type.slice(splitPos); + /** + * Convert a data object to FormData + * + * @param {Object} obj + * @param {?Object} [formData] + * @param {?Object} [options] + * @param {Function} [options.visitor] + * @param {Boolean} [options.metaTokens = true] + * @param {Boolean} [options.dots = false] + * @param {?Boolean} [options.indexes = false] + * + * @returns {Object} + **/ - // Add a port to the getters proxy. - // Define as getter property because - // we do not want to evaluate the getters in this time. - Object.defineProperty(gettersProxy, localType, { - get: function () { return store.getters[type]; }, - enumerable: true - }); - }); - store._makeLocalGettersCache[namespace] = gettersProxy; + /** + * It converts an object into a FormData object + * + * @param {Object} obj - The object to convert to form data. + * @param {string} formData - The FormData object to append to. + * @param {Object} options + * + * @returns + */ + function toFormData(obj, formData, options) { + if (!utils.isObject(obj)) { + throw new TypeError('target must be an object'); } - return store._makeLocalGettersCache[namespace] - } + // eslint-disable-next-line no-param-reassign + formData = formData || new (FormData)(); - function registerMutation (store, type, handler, local) { - var entry = store._mutations[type] || (store._mutations[type] = []); - entry.push(function wrappedMutationHandler (payload) { - handler.call(store, local.state, payload); + // eslint-disable-next-line no-param-reassign + options = utils.toFlatObject(options, { + metaTokens: true, + dots: false, + indexes: false + }, false, function defined(option, source) { + // eslint-disable-next-line no-eq-null,eqeqeq + return !utils.isUndefined(source[option]); }); - } - function registerAction (store, type, handler, local) { - var entry = store._actions[type] || (store._actions[type] = []); - entry.push(function wrappedActionHandler (payload) { - var res = handler.call(store, { - dispatch: local.dispatch, - commit: local.commit, - getters: local.getters, - state: local.state, - rootGetters: store.getters, - rootState: store.state - }, payload); - if (!isPromise(res)) { - res = Promise.resolve(res); + const metaTokens = options.metaTokens; + // eslint-disable-next-line no-use-before-define + const visitor = options.visitor || defaultVisitor; + const dots = options.dots; + const indexes = options.indexes; + const _Blob = options.Blob || typeof Blob !== 'undefined' && Blob; + const useBlob = _Blob && utils.isSpecCompliantForm(formData); + + if (!utils.isFunction(visitor)) { + throw new TypeError('visitor must be a function'); + } + + function convertValue(value) { + if (value === null) return ''; + + if (utils.isDate(value)) { + return value.toISOString(); } - if (store._devtoolHook) { - return res.catch(function (err) { - store._devtoolHook.emit('vuex:error', err); - throw err - }) - } else { - return res + + if (!useBlob && utils.isBlob(value)) { + throw new AxiosError('Blob is not supported. Use a Buffer instead.'); } - }); - } - function registerGetter (store, type, rawGetter, local) { - if (store._wrappedGetters[type]) { - if ((process.env.NODE_ENV !== 'production')) { - console.error(("[vuex] duplicate getter key: " + type)); + if (utils.isArrayBuffer(value) || utils.isTypedArray(value)) { + return useBlob && typeof Blob === 'function' ? new Blob([value]) : Buffer.from(value); } - return + + return value; } - store._wrappedGetters[type] = function wrappedGetter (store) { - return rawGetter( - local.state, // local state - local.getters, // local getters - store.state, // root state - store.getters // root getters - ) - }; - } - function enableStrictMode (store) { - store._vm.$watch(function () { return this._data.$$state }, function () { - if ((process.env.NODE_ENV !== 'production')) { - assert(store._committing, "do not mutate vuex store state outside mutation handlers."); + /** + * Default visitor. + * + * @param {*} value + * @param {String|Number} key + * @param {Array} path + * @this {FormData} + * + * @returns {boolean} return true to visit the each prop of the value recursively + */ + function defaultVisitor(value, key, path) { + let arr = value; + + if (value && !path && typeof value === 'object') { + if (utils.endsWith(key, '{}')) { + // eslint-disable-next-line no-param-reassign + key = metaTokens ? key : key.slice(0, -2); + // eslint-disable-next-line no-param-reassign + value = JSON.stringify(value); + } else if ( + (utils.isArray(value) && isFlatArray(value)) || + ((utils.isFileList(value) || utils.endsWith(key, '[]')) && (arr = utils.toArray(value)) + )) { + // eslint-disable-next-line no-param-reassign + key = removeBrackets(key); + + arr.forEach(function each(el, index) { + !(utils.isUndefined(el) || el === null) && formData.append( + // eslint-disable-next-line no-nested-ternary + indexes === true ? renderKey([key], index, dots) : (indexes === null ? key : key + '[]'), + convertValue(el) + ); + }); + return false; + } } - }, { deep: true, sync: true }); - } - function getNestedState (state, path) { - return path.reduce(function (state, key) { return state[key]; }, state) - } + if (isVisitable(value)) { + return true; + } - function unifyObjectStyle (type, payload, options) { - if (isObject$1(type) && type.type) { - options = payload; - payload = type; - type = type.type; - } + formData.append(renderKey(path, key, dots), convertValue(value)); - if ((process.env.NODE_ENV !== 'production')) { - assert(typeof type === 'string', ("expects string as the type, but found " + (typeof type) + ".")); + return false; } - return { type: type, payload: payload, options: options } - } + const stack = []; - function install (_Vue) { - if (Vue && _Vue === Vue) { - if ((process.env.NODE_ENV !== 'production')) { - console.error( - '[vuex] already installed. Vue.use(Vuex) should be called only once.' - ); + const exposedHelpers = Object.assign(predicates, { + defaultVisitor, + convertValue, + isVisitable + }); + + function build(value, path) { + if (utils.isUndefined(value)) return; + + if (stack.indexOf(value) !== -1) { + throw Error('Circular reference detected in ' + path.join('.')); } - return - } - Vue = _Vue; - applyMixin(Vue); - } - /** - * Reduce the code which written in Vue.js for getting the getters - * @param {String} [namespace] - Module's namespace - * @param {Object|Array} getters - * @return {Object} - */ - var mapGetters = normalizeNamespace(function (namespace, getters) { - var res = {}; - if ((process.env.NODE_ENV !== 'production') && !isValidMap(getters)) { - console.error('[vuex] mapGetters: mapper parameter must be either an Array or an Object'); - } - normalizeMap(getters).forEach(function (ref) { - var key = ref.key; - var val = ref.val; + stack.push(value); - // The namespace has been mutated by normalizeNamespace - val = namespace + val; - res[key] = function mappedGetter () { - if (namespace && !getModuleByNamespace(this.$store, 'mapGetters', namespace)) { - return - } - if ((process.env.NODE_ENV !== 'production') && !(val in this.$store.getters)) { - console.error(("[vuex] unknown getter: " + val)); - return + utils.forEach(value, function each(el, key) { + const result = !(utils.isUndefined(el) || el === null) && visitor.call( + formData, el, utils.isString(key) ? key.trim() : key, path, exposedHelpers + ); + + if (result === true) { + build(el, path ? path.concat(key) : [key]); } - return this.$store.getters[val] - }; - // mark vuex getter for devtools - res[key].vuex = true; - }); - return res - }); + }); - /** - * Reduce the code which written in Vue.js for dispatch the action - * @param {String} [namespace] - Module's namespace - * @param {Object|Array} actions # Object's item can be a function which accept `dispatch` function as the first param, it can accept anthor params. You can dispatch action and do any other things in this function. specially, You need to pass anthor params from the mapped function. - * @return {Object} - */ - var mapActions = normalizeNamespace(function (namespace, actions) { - var res = {}; - if ((process.env.NODE_ENV !== 'production') && !isValidMap(actions)) { - console.error('[vuex] mapActions: mapper parameter must be either an Array or an Object'); + stack.pop(); } - normalizeMap(actions).forEach(function (ref) { - var key = ref.key; - var val = ref.val; - res[key] = function mappedAction () { - var args = [], len = arguments.length; - while ( len-- ) args[ len ] = arguments[ len ]; + if (!utils.isObject(obj)) { + throw new TypeError('data must be an object'); + } - // get dispatch function from store - var dispatch = this.$store.dispatch; - if (namespace) { - var module = getModuleByNamespace(this.$store, 'mapActions', namespace); - if (!module) { - return - } - dispatch = module.context.dispatch; - } - return typeof val === 'function' - ? val.apply(this, [dispatch].concat(args)) - : dispatch.apply(this.$store, [val].concat(args)) - }; + build(obj); + + return formData; + } + + /** + * It encodes a string by replacing all characters that are not in the unreserved set with + * their percent-encoded equivalents + * + * @param {string} str - The string to encode. + * + * @returns {string} The encoded string. + */ + function encode$1(str) { + const charMap = { + '!': '%21', + "'": '%27', + '(': '%28', + ')': '%29', + '~': '%7E', + '%20': '+', + '%00': '\x00' + }; + return encodeURIComponent(str).replace(/[!'()~]|%20|%00/g, function replacer(match) { + return charMap[match]; }); - return res - }); + } /** - * Normalize the map - * normalizeMap([1, 2, 3]) => [ { key: 1, val: 1 }, { key: 2, val: 2 }, { key: 3, val: 3 } ] - * normalizeMap({a: 1, b: 2, c: 3}) => [ { key: 'a', val: 1 }, { key: 'b', val: 2 }, { key: 'c', val: 3 } ] - * @param {Array|Object} map - * @return {Object} + * It takes a params object and converts it to a FormData object + * + * @param {Object} params - The parameters to be converted to a FormData object. + * @param {Object} options - The options object passed to the Axios constructor. + * + * @returns {void} */ - function normalizeMap (map) { - if (!isValidMap(map)) { - return [] - } - return Array.isArray(map) - ? map.map(function (key) { return ({ key: key, val: key }); }) - : Object.keys(map).map(function (key) { return ({ key: key, val: map[key] }); }) + function AxiosURLSearchParams(params, options) { + this._pairs = []; + + params && toFormData(params, this, options); } + const prototype = AxiosURLSearchParams.prototype; + + prototype.append = function append(name, value) { + this._pairs.push([name, value]); + }; + + prototype.toString = function toString(encoder) { + const _encode = encoder ? function(value) { + return encoder.call(this, value, encode$1); + } : encode$1; + + return this._pairs.map(function each(pair) { + return _encode(pair[0]) + '=' + _encode(pair[1]); + }, '').join('&'); + }; + /** - * Validate whether given map is valid or not - * @param {*} map - * @return {Boolean} + * It replaces all instances of the characters `:`, `$`, `,`, `+`, `[`, and `]` with their + * URI encoded counterparts + * + * @param {string} val The value to be encoded. + * + * @returns {string} The encoded value. */ - function isValidMap (map) { - return Array.isArray(map) || isObject$1(map) + function encode(val) { + return encodeURIComponent(val). + replace(/%3A/gi, ':'). + replace(/%24/g, '$'). + replace(/%2C/gi, ','). + replace(/%20/g, '+'). + replace(/%5B/gi, '['). + replace(/%5D/gi, ']'); } /** - * Return a function expect two param contains namespace and map. it will normalize the namespace and then the param's function will handle the new namespace and the map. - * @param {Function} fn - * @return {Function} + * Build a URL by appending params to the end + * + * @param {string} url The base of the url (e.g., http://www.google.com) + * @param {object} [params] The params to be appended + * @param {?object} options + * + * @returns {string} The formatted url */ - function normalizeNamespace (fn) { - return function (namespace, map) { - if (typeof namespace !== 'string') { - map = namespace; - namespace = ''; - } else if (namespace.charAt(namespace.length - 1) !== '/') { - namespace += '/'; + function buildURL(url, params, options) { + /*eslint no-param-reassign:0*/ + if (!params) { + return url; + } + + const _encode = options && options.encode || encode; + + const serializeFn = options && options.serialize; + + let serializedParams; + + if (serializeFn) { + serializedParams = serializeFn(params, options); + } else { + serializedParams = utils.isURLSearchParams(params) ? + params.toString() : + new AxiosURLSearchParams(params, options).toString(_encode); + } + + if (serializedParams) { + const hashmarkIndex = url.indexOf("#"); + + if (hashmarkIndex !== -1) { + url = url.slice(0, hashmarkIndex); } - return fn(namespace, map) + url += (url.indexOf('?') === -1 ? '?' : '&') + serializedParams; } + + return url; } - /** - * Search a special module from store by namespace. if module not exist, print error message. - * @param {Object} store - * @param {String} helper - * @param {String} namespace - * @return {Object} - */ - function getModuleByNamespace (store, helper, namespace) { - var module = store._modulesNamespaceMap[namespace]; - if ((process.env.NODE_ENV !== 'production') && !module) { - console.error(("[vuex] module namespace not found in " + helper + "(): " + namespace)); + class InterceptorManager { + constructor() { + this.handlers = []; + } + + /** + * Add a new interceptor to the stack + * + * @param {Function} fulfilled The function to handle `then` for a `Promise` + * @param {Function} rejected The function to handle `reject` for a `Promise` + * + * @return {Number} An ID used to remove interceptor later + */ + use(fulfilled, rejected, options) { + this.handlers.push({ + fulfilled, + rejected, + synchronous: options ? options.synchronous : false, + runWhen: options ? options.runWhen : null + }); + return this.handlers.length - 1; + } + + /** + * Remove an interceptor from the stack + * + * @param {Number} id The ID that was returned by `use` + * + * @returns {Boolean} `true` if the interceptor was removed, `false` otherwise + */ + eject(id) { + if (this.handlers[id]) { + this.handlers[id] = null; + } + } + + /** + * Clear all interceptors from the stack + * + * @returns {void} + */ + clear() { + if (this.handlers) { + this.handlers = []; + } + } + + /** + * Iterate over all the registered interceptors + * + * This method is particularly useful for skipping over any + * interceptors that may have become `null` calling `eject`. + * + * @param {Function} fn The function to call for each interceptor + * + * @returns {void} + */ + forEach(fn) { + utils.forEach(this.handlers, function forEachHandler(h) { + if (h !== null) { + fn(h); + } + }); } - return module } - var bind = function bind(fn, thisArg) { - return function wrap() { - var args = new Array(arguments.length); - for (var i = 0; i < args.length; i++) { - args[i] = arguments[i]; - } - return fn.apply(thisArg, args); - }; + var InterceptorManager$1 = InterceptorManager; + + var transitionalDefaults = { + silentJSONParsing: true, + forcedJSONParsing: true, + clarifyTimeoutError: false }; - // utils is a library of generic helper functions non-specific to axios + var URLSearchParams$1 = typeof URLSearchParams !== 'undefined' ? URLSearchParams : AxiosURLSearchParams; - var toString = Object.prototype.toString; + var FormData$1 = typeof FormData !== 'undefined' ? FormData : null; - /** - * Determine if a value is an Array - * - * @param {Object} val The value to test - * @returns {boolean} True if value is an Array, otherwise false - */ - function isArray(val) { - return toString.call(val) === '[object Array]'; - } + var Blob$1 = typeof Blob !== 'undefined' ? Blob : null; /** - * Determine if a value is undefined + * Determine if we're running in a standard browser environment * - * @param {Object} val The value to test - * @returns {boolean} True if the value is undefined, otherwise false - */ - function isUndefined(val) { - return typeof val === 'undefined'; - } - - /** - * Determine if a value is a Buffer + * This allows axios to run in a web worker, and react-native. + * Both environments support XMLHttpRequest, but not fully standard globals. * - * @param {Object} val The value to test - * @returns {boolean} True if value is a Buffer, otherwise false + * web workers: + * typeof window -> undefined + * typeof document -> undefined + * + * react-native: + * navigator.product -> 'ReactNative' + * nativescript + * navigator.product -> 'NativeScript' or 'NS' + * + * @returns {boolean} */ - function isBuffer(val) { - return val !== null && !isUndefined(val) && val.constructor !== null && !isUndefined(val.constructor) - && typeof val.constructor.isBuffer === 'function' && val.constructor.isBuffer(val); - } + const isStandardBrowserEnv = (() => { + let product; + if (typeof navigator !== 'undefined' && ( + (product = navigator.product) === 'ReactNative' || + product === 'NativeScript' || + product === 'NS') + ) { + return false; + } + + return typeof window !== 'undefined' && typeof document !== 'undefined'; + })(); /** - * Determine if a value is an ArrayBuffer + * Determine if we're running in a standard browser webWorker environment * - * @param {Object} val The value to test - * @returns {boolean} True if value is an ArrayBuffer, otherwise false + * Although the `isStandardBrowserEnv` method indicates that + * `allows axios to run in a web worker`, the WebWorker will still be + * filtered out due to its judgment standard + * `typeof window !== 'undefined' && typeof document !== 'undefined'`. + * This leads to a problem when axios post `FormData` in webWorker */ - function isArrayBuffer(val) { - return toString.call(val) === '[object ArrayBuffer]'; + const isStandardBrowserWebWorkerEnv = (() => { + return ( + typeof WorkerGlobalScope !== 'undefined' && + // eslint-disable-next-line no-undef + self instanceof WorkerGlobalScope && + typeof self.importScripts === 'function' + ); + })(); + + + var platform = { + isBrowser: true, + classes: { + URLSearchParams: URLSearchParams$1, + FormData: FormData$1, + Blob: Blob$1 + }, + isStandardBrowserEnv, + isStandardBrowserWebWorkerEnv, + protocols: ['http', 'https', 'file', 'blob', 'url', 'data'] + }; + + function toURLEncodedForm(data, options) { + return toFormData(data, new platform.classes.URLSearchParams(), Object.assign({ + visitor: function(value, key, path, helpers) { + if (platform.isNode && utils.isBuffer(value)) { + this.append(key, value.toString('base64')); + return false; + } + + return helpers.defaultVisitor.apply(this, arguments); + } + }, options)); } /** - * Determine if a value is a FormData + * It takes a string like `foo[x][y][z]` and returns an array like `['foo', 'x', 'y', 'z'] * - * @param {Object} val The value to test - * @returns {boolean} True if value is an FormData, otherwise false + * @param {string} name - The name of the property to get. + * + * @returns An array of strings. */ - function isFormData(val) { - return (typeof FormData !== 'undefined') && (val instanceof FormData); + function parsePropPath(name) { + // foo[x][y][z] + // foo.x.y.z + // foo-x-y-z + // foo x y z + return utils.matchAll(/\w+|\[(\w*)]/g, name).map(match => { + return match[0] === '[]' ? '' : match[1] || match[0]; + }); } /** - * Determine if a value is a view on an ArrayBuffer + * Convert an array to an object. * - * @param {Object} val The value to test - * @returns {boolean} True if value is a view on an ArrayBuffer, otherwise false + * @param {Array} arr - The array to convert to an object. + * + * @returns An object with the same keys and values as the array. */ - function isArrayBufferView(val) { - var result; - if ((typeof ArrayBuffer !== 'undefined') && (ArrayBuffer.isView)) { - result = ArrayBuffer.isView(val); - } else { - result = (val) && (val.buffer) && (val.buffer instanceof ArrayBuffer); + function arrayToObject(arr) { + const obj = {}; + const keys = Object.keys(arr); + let i; + const len = keys.length; + let key; + for (i = 0; i < len; i++) { + key = keys[i]; + obj[key] = arr[key]; } - return result; + return obj; } /** - * Determine if a value is a String + * It takes a FormData object and returns a JavaScript object * - * @param {Object} val The value to test - * @returns {boolean} True if value is a String, otherwise false - */ - function isString(val) { - return typeof val === 'string'; - } - - /** - * Determine if a value is a Number + * @param {string} formData The FormData object to convert to JSON. * - * @param {Object} val The value to test - * @returns {boolean} True if value is a Number, otherwise false + * @returns {Object | null} The converted object. */ - function isNumber(val) { - return typeof val === 'number'; - } + function formDataToJSON(formData) { + function buildPath(path, value, target, index) { + let name = path[index++]; + const isNumericKey = Number.isFinite(+name); + const isLast = index >= path.length; + name = !name && utils.isArray(target) ? target.length : name; + + if (isLast) { + if (utils.hasOwnProp(target, name)) { + target[name] = [target[name], value]; + } else { + target[name] = value; + } - /** - * Determine if a value is an Object - * - * @param {Object} val The value to test - * @returns {boolean} True if value is an Object, otherwise false - */ - function isObject(val) { - return val !== null && typeof val === 'object'; - } + return !isNumericKey; + } - /** - * Determine if a value is a plain Object - * - * @param {Object} val The value to test - * @return {boolean} True if value is a plain Object, otherwise false - */ - function isPlainObject(val) { - if (toString.call(val) !== '[object Object]') { - return false; + if (!target[name] || !utils.isObject(target[name])) { + target[name] = []; + } + + const result = buildPath(path, value, target[name], index); + + if (result && utils.isArray(target[name])) { + target[name] = arrayToObject(target[name]); + } + + return !isNumericKey; } - var prototype = Object.getPrototypeOf(val); - return prototype === null || prototype === Object.prototype; - } + if (utils.isFormData(formData) && utils.isFunction(formData.entries)) { + const obj = {}; - /** - * Determine if a value is a Date - * - * @param {Object} val The value to test - * @returns {boolean} True if value is a Date, otherwise false - */ - function isDate(val) { - return toString.call(val) === '[object Date]'; + utils.forEachEntry(formData, (name, value) => { + buildPath(parsePropPath(name), value, obj, 0); + }); + + return obj; + } + + return null; } /** - * Determine if a value is a File + * It takes a string, tries to parse it, and if it fails, it returns the stringified version + * of the input * - * @param {Object} val The value to test - * @returns {boolean} True if value is a File, otherwise false + * @param {any} rawValue - The value to be stringified. + * @param {Function} parser - A function that parses a string into a JavaScript object. + * @param {Function} encoder - A function that takes a value and returns a string. + * + * @returns {string} A stringified version of the rawValue. */ - function isFile(val) { - return toString.call(val) === '[object File]'; + function stringifySafely(rawValue, parser, encoder) { + if (utils.isString(rawValue)) { + try { + (parser || JSON.parse)(rawValue); + return utils.trim(rawValue); + } catch (e) { + if (e.name !== 'SyntaxError') { + throw e; + } + } + } + + return (encoder || JSON.stringify)(rawValue); } + const defaults = { + + transitional: transitionalDefaults, + + adapter: ['xhr', 'http'], + + transformRequest: [function transformRequest(data, headers) { + const contentType = headers.getContentType() || ''; + const hasJSONContentType = contentType.indexOf('application/json') > -1; + const isObjectPayload = utils.isObject(data); + + if (isObjectPayload && utils.isHTMLForm(data)) { + data = new FormData(data); + } + + const isFormData = utils.isFormData(data); + + if (isFormData) { + if (!hasJSONContentType) { + return data; + } + return hasJSONContentType ? JSON.stringify(formDataToJSON(data)) : data; + } + + if (utils.isArrayBuffer(data) || + utils.isBuffer(data) || + utils.isStream(data) || + utils.isFile(data) || + utils.isBlob(data) + ) { + return data; + } + if (utils.isArrayBufferView(data)) { + return data.buffer; + } + if (utils.isURLSearchParams(data)) { + headers.setContentType('application/x-www-form-urlencoded;charset=utf-8', false); + return data.toString(); + } + + let isFileList; + + if (isObjectPayload) { + if (contentType.indexOf('application/x-www-form-urlencoded') > -1) { + return toURLEncodedForm(data, this.formSerializer).toString(); + } + + if ((isFileList = utils.isFileList(data)) || contentType.indexOf('multipart/form-data') > -1) { + const _FormData = this.env && this.env.FormData; + + return toFormData( + isFileList ? {'files[]': data} : data, + _FormData && new _FormData(), + this.formSerializer + ); + } + } + + if (isObjectPayload || hasJSONContentType ) { + headers.setContentType('application/json', false); + return stringifySafely(data); + } + + return data; + }], + + transformResponse: [function transformResponse(data) { + const transitional = this.transitional || defaults.transitional; + const forcedJSONParsing = transitional && transitional.forcedJSONParsing; + const JSONRequested = this.responseType === 'json'; + + if (data && utils.isString(data) && ((forcedJSONParsing && !this.responseType) || JSONRequested)) { + const silentJSONParsing = transitional && transitional.silentJSONParsing; + const strictJSONParsing = !silentJSONParsing && JSONRequested; + + try { + return JSON.parse(data); + } catch (e) { + if (strictJSONParsing) { + if (e.name === 'SyntaxError') { + throw AxiosError.from(e, AxiosError.ERR_BAD_RESPONSE, this, null, this.response); + } + throw e; + } + } + } + + return data; + }], + + /** + * A timeout in milliseconds to abort a request. If set to 0 (default) a + * timeout is not created. + */ + timeout: 0, + + xsrfCookieName: 'XSRF-TOKEN', + xsrfHeaderName: 'X-XSRF-TOKEN', + + maxContentLength: -1, + maxBodyLength: -1, + + env: { + FormData: platform.classes.FormData, + Blob: platform.classes.Blob + }, + + validateStatus: function validateStatus(status) { + return status >= 200 && status < 300; + }, + + headers: { + common: { + 'Accept': 'application/json, text/plain, */*', + 'Content-Type': undefined + } + } + }; + + utils.forEach(['delete', 'get', 'head', 'post', 'put', 'patch'], (method) => { + defaults.headers[method] = {}; + }); + + var defaults$1 = defaults; + + // RawAxiosHeaders whose duplicates are ignored by node + // c.f. https://nodejs.org/api/http.html#http_message_headers + const ignoreDuplicateOf = utils.toObjectSet([ + 'age', 'authorization', 'content-length', 'content-type', 'etag', + 'expires', 'from', 'host', 'if-modified-since', 'if-unmodified-since', + 'last-modified', 'location', 'max-forwards', 'proxy-authorization', + 'referer', 'retry-after', 'user-agent' + ]); + /** - * Determine if a value is a Blob + * Parse headers into an object * - * @param {Object} val The value to test - * @returns {boolean} True if value is a Blob, otherwise false + * ``` + * Date: Wed, 27 Aug 2014 08:58:49 GMT + * Content-Type: application/json + * Connection: keep-alive + * Transfer-Encoding: chunked + * ``` + * + * @param {String} rawHeaders Headers needing to be parsed + * + * @returns {Object} Headers parsed into an object */ - function isBlob(val) { - return toString.call(val) === '[object Blob]'; + var parseHeaders = rawHeaders => { + const parsed = {}; + let key; + let val; + let i; + + rawHeaders && rawHeaders.split('\n').forEach(function parser(line) { + i = line.indexOf(':'); + key = line.substring(0, i).trim().toLowerCase(); + val = line.substring(i + 1).trim(); + + if (!key || (parsed[key] && ignoreDuplicateOf[key])) { + return; + } + + if (key === 'set-cookie') { + if (parsed[key]) { + parsed[key].push(val); + } else { + parsed[key] = [val]; + } + } else { + parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val; + } + }); + + return parsed; + }; + + const $internals = Symbol('internals'); + + function normalizeHeader(header) { + return header && String(header).trim().toLowerCase(); } - /** - * Determine if a value is a Function - * - * @param {Object} val The value to test - * @returns {boolean} True if value is a Function, otherwise false - */ - function isFunction(val) { - return toString.call(val) === '[object Function]'; + function normalizeValue(value) { + if (value === false || value == null) { + return value; + } + + return utils.isArray(value) ? value.map(normalizeValue) : String(value); } - /** - * Determine if a value is a Stream - * - * @param {Object} val The value to test - * @returns {boolean} True if value is a Stream, otherwise false - */ - function isStream(val) { - return isObject(val) && isFunction(val.pipe); + function parseTokens(str) { + const tokens = Object.create(null); + const tokensRE = /([^\s,;=]+)\s*(?:=\s*([^,;]+))?/g; + let match; + + while ((match = tokensRE.exec(str))) { + tokens[match[1]] = match[2]; + } + + return tokens; } - /** - * Determine if a value is a URLSearchParams object - * - * @param {Object} val The value to test - * @returns {boolean} True if value is a URLSearchParams object, otherwise false - */ - function isURLSearchParams(val) { - return typeof URLSearchParams !== 'undefined' && val instanceof URLSearchParams; + const isValidHeaderName = (str) => /^[-_a-zA-Z0-9^`|~,!#$%&'*+.]+$/.test(str.trim()); + + function matchHeaderValue(context, value, header, filter, isHeaderNameFilter) { + if (utils.isFunction(filter)) { + return filter.call(this, value, header); + } + + if (isHeaderNameFilter) { + value = header; + } + + if (!utils.isString(value)) return; + + if (utils.isString(filter)) { + return value.indexOf(filter) !== -1; + } + + if (utils.isRegExp(filter)) { + return filter.test(value); + } } - /** - * Trim excess whitespace off the beginning and end of a string - * - * @param {String} str The String to trim - * @returns {String} The String freed of excess whitespace - */ - function trim(str) { - return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, ''); + function formatHeader(header) { + return header.trim() + .toLowerCase().replace(/([a-z\d])(\w*)/g, (w, char, str) => { + return char.toUpperCase() + str; + }); } - /** - * Determine if we're running in a standard browser environment - * - * This allows axios to run in a web worker, and react-native. - * Both environments support XMLHttpRequest, but not fully standard globals. - * - * web workers: - * typeof window -> undefined - * typeof document -> undefined - * - * react-native: - * navigator.product -> 'ReactNative' - * nativescript - * navigator.product -> 'NativeScript' or 'NS' - */ - function isStandardBrowserEnv() { - if (typeof navigator !== 'undefined' && (navigator.product === 'ReactNative' || - navigator.product === 'NativeScript' || - navigator.product === 'NS')) { - return false; - } - return ( - typeof window !== 'undefined' && - typeof document !== 'undefined' - ); + function buildAccessors(obj, header) { + const accessorName = utils.toCamelCase(' ' + header); + + ['get', 'set', 'has'].forEach(methodName => { + Object.defineProperty(obj, methodName + accessorName, { + value: function(arg1, arg2, arg3) { + return this[methodName].call(this, header, arg1, arg2, arg3); + }, + configurable: true + }); + }); } - /** - * Iterate over an Array or an Object invoking a function for each item. - * - * If `obj` is an Array callback will be called passing - * the value, index, and complete array for each item. - * - * If 'obj' is an Object callback will be called passing - * the value, key, and complete object for each property. - * - * @param {Object|Array} obj The object to iterate - * @param {Function} fn The callback to invoke for each item - */ - function forEach(obj, fn) { - // Don't bother if no value provided - if (obj === null || typeof obj === 'undefined') { - return; + class AxiosHeaders { + constructor(headers) { + headers && this.set(headers); } - // Force an array if not already something iterable - if (typeof obj !== 'object') { - /*eslint no-param-reassign:0*/ - obj = [obj]; - } + set(header, valueOrRewrite, rewrite) { + const self = this; - if (isArray(obj)) { - // Iterate over array values - for (var i = 0, l = obj.length; i < l; i++) { - fn.call(null, obj[i], i, obj); - } - } else { - // Iterate over object keys - for (var key in obj) { - if (Object.prototype.hasOwnProperty.call(obj, key)) { - fn.call(null, obj[key], key, obj); + function setHeader(_value, _header, _rewrite) { + const lHeader = normalizeHeader(_header); + + if (!lHeader) { + throw new Error('header name must be a non-empty string'); + } + + const key = utils.findKey(self, lHeader); + + if(!key || self[key] === undefined || _rewrite === true || (_rewrite === undefined && self[key] !== false)) { + self[key || _header] = normalizeValue(_value); } } - } - } - /** - * Accepts varargs expecting each argument to be an object, then - * immutably merges the properties of each object and returns result. - * - * When multiple objects contain the same key the later object in - * the arguments list will take precedence. - * - * Example: - * - * ```js - * var result = merge({foo: 123}, {foo: 456}); - * console.log(result.foo); // outputs 456 - * ``` - * - * @param {Object} obj1 Object to merge - * @returns {Object} Result of all merge properties - */ - function merge(/* obj1, obj2, obj3, ... */) { - var result = {}; - function assignValue(val, key) { - if (isPlainObject(result[key]) && isPlainObject(val)) { - result[key] = merge(result[key], val); - } else if (isPlainObject(val)) { - result[key] = merge({}, val); - } else if (isArray(val)) { - result[key] = val.slice(); + const setHeaders = (headers, _rewrite) => + utils.forEach(headers, (_value, _header) => setHeader(_value, _header, _rewrite)); + + if (utils.isPlainObject(header) || header instanceof this.constructor) { + setHeaders(header, valueOrRewrite); + } else if(utils.isString(header) && (header = header.trim()) && !isValidHeaderName(header)) { + setHeaders(parseHeaders(header), valueOrRewrite); } else { - result[key] = val; + header != null && setHeader(valueOrRewrite, header, rewrite); + } + + return this; + } + + get(header, parser) { + header = normalizeHeader(header); + + if (header) { + const key = utils.findKey(this, header); + + if (key) { + const value = this[key]; + + if (!parser) { + return value; + } + + if (parser === true) { + return parseTokens(value); + } + + if (utils.isFunction(parser)) { + return parser.call(this, value, key); + } + + if (utils.isRegExp(parser)) { + return parser.exec(value); + } + + throw new TypeError('parser must be boolean|regexp|function'); + } } } - for (var i = 0, l = arguments.length; i < l; i++) { - forEach(arguments[i], assignValue); + has(header, matcher) { + header = normalizeHeader(header); + + if (header) { + const key = utils.findKey(this, header); + + return !!(key && this[key] !== undefined && (!matcher || matchHeaderValue(this, this[key], key, matcher))); + } + + return false; } - return result; - } - /** - * Extends object a by mutably adding to it the properties of object b. - * - * @param {Object} a The object to be extended - * @param {Object} b The object to copy properties from - * @param {Object} thisArg The object to bind function to - * @return {Object} The resulting value of object a - */ - function extend(a, b, thisArg) { - forEach(b, function assignValue(val, key) { - if (thisArg && typeof val === 'function') { - a[key] = bind(val, thisArg); + delete(header, matcher) { + const self = this; + let deleted = false; + + function deleteHeader(_header) { + _header = normalizeHeader(_header); + + if (_header) { + const key = utils.findKey(self, _header); + + if (key && (!matcher || matchHeaderValue(self, self[key], key, matcher))) { + delete self[key]; + + deleted = true; + } + } + } + + if (utils.isArray(header)) { + header.forEach(deleteHeader); } else { - a[key] = val; + deleteHeader(header); } - }); - return a; - } - /** - * Remove byte order marker. This catches EF BB BF (the UTF-8 BOM) - * - * @param {string} content with BOM - * @return {string} content value without BOM - */ - function stripBOM(content) { - if (content.charCodeAt(0) === 0xFEFF) { - content = content.slice(1); + return deleted; } - return content; - } - var utils = { - isArray: isArray, - isArrayBuffer: isArrayBuffer, - isBuffer: isBuffer, - isFormData: isFormData, - isArrayBufferView: isArrayBufferView, - isString: isString, - isNumber: isNumber, - isObject: isObject, - isPlainObject: isPlainObject, - isUndefined: isUndefined, - isDate: isDate, - isFile: isFile, - isBlob: isBlob, - isFunction: isFunction, - isStream: isStream, - isURLSearchParams: isURLSearchParams, - isStandardBrowserEnv: isStandardBrowserEnv, - forEach: forEach, - merge: merge, - extend: extend, - trim: trim, - stripBOM: stripBOM - }; + clear(matcher) { + const keys = Object.keys(this); + let i = keys.length; + let deleted = false; - function encode(val) { - return encodeURIComponent(val). - replace(/%3A/gi, ':'). - replace(/%24/g, '$'). - replace(/%2C/gi, ','). - replace(/%20/g, '+'). - replace(/%5B/gi, '['). - replace(/%5D/gi, ']'); - } + while (i--) { + const key = keys[i]; + if(!matcher || matchHeaderValue(this, this[key], key, matcher, true)) { + delete this[key]; + deleted = true; + } + } - /** - * Build a URL by appending params to the end - * - * @param {string} url The base of the url (e.g., http://www.google.com) - * @param {object} [params] The params to be appended - * @returns {string} The formatted url - */ - var buildURL = function buildURL(url, params, paramsSerializer) { - /*eslint no-param-reassign:0*/ - if (!params) { - return url; + return deleted; } - var serializedParams; - if (paramsSerializer) { - serializedParams = paramsSerializer(params); - } else if (utils.isURLSearchParams(params)) { - serializedParams = params.toString(); - } else { - var parts = []; + normalize(format) { + const self = this; + const headers = {}; - utils.forEach(params, function serialize(val, key) { - if (val === null || typeof val === 'undefined') { + utils.forEach(this, (value, header) => { + const key = utils.findKey(headers, header); + + if (key) { + self[key] = normalizeValue(value); + delete self[header]; return; } - if (utils.isArray(val)) { - key = key + '[]'; - } else { - val = [val]; + const normalized = format ? formatHeader(header) : String(header).trim(); + + if (normalized !== header) { + delete self[header]; } - utils.forEach(val, function parseValue(v) { - if (utils.isDate(v)) { - v = v.toISOString(); - } else if (utils.isObject(v)) { - v = JSON.stringify(v); - } - parts.push(encode(key) + '=' + encode(v)); - }); + self[normalized] = normalizeValue(value); + + headers[normalized] = true; }); - serializedParams = parts.join('&'); + return this; } - if (serializedParams) { - var hashmarkIndex = url.indexOf('#'); - if (hashmarkIndex !== -1) { - url = url.slice(0, hashmarkIndex); - } + concat(...targets) { + return this.constructor.concat(this, ...targets); + } - url += (url.indexOf('?') === -1 ? '?' : '&') + serializedParams; + toJSON(asStrings) { + const obj = Object.create(null); + + utils.forEach(this, (value, header) => { + value != null && value !== false && (obj[header] = asStrings && utils.isArray(value) ? value.join(', ') : value); + }); + + return obj; } - return url; - }; + [Symbol.iterator]() { + return Object.entries(this.toJSON())[Symbol.iterator](); + } - function InterceptorManager() { - this.handlers = []; - } + toString() { + return Object.entries(this.toJSON()).map(([header, value]) => header + ': ' + value).join('\n'); + } - /** - * Add a new interceptor to the stack - * - * @param {Function} fulfilled The function to handle `then` for a `Promise` - * @param {Function} rejected The function to handle `reject` for a `Promise` - * - * @return {Number} An ID used to remove interceptor later - */ - InterceptorManager.prototype.use = function use(fulfilled, rejected, options) { - this.handlers.push({ - fulfilled: fulfilled, - rejected: rejected, - synchronous: options ? options.synchronous : false, - runWhen: options ? options.runWhen : null - }); - return this.handlers.length - 1; - }; + get [Symbol.toStringTag]() { + return 'AxiosHeaders'; + } - /** - * Remove an interceptor from the stack - * - * @param {Number} id The ID that was returned by `use` - */ - InterceptorManager.prototype.eject = function eject(id) { - if (this.handlers[id]) { - this.handlers[id] = null; + static from(thing) { + return thing instanceof this ? thing : new this(thing); } - }; - /** - * Iterate over all the registered interceptors - * - * This method is particularly useful for skipping over any - * interceptors that may have become `null` calling `eject`. - * - * @param {Function} fn The function to call for each interceptor - */ - InterceptorManager.prototype.forEach = function forEach(fn) { - utils.forEach(this.handlers, function forEachHandler(h) { - if (h !== null) { - fn(h); + static concat(first, ...targets) { + const computed = new this(first); + + targets.forEach((target) => computed.set(target)); + + return computed; + } + + static accessor(header) { + const internals = this[$internals] = (this[$internals] = { + accessors: {} + }); + + const accessors = internals.accessors; + const prototype = this.prototype; + + function defineAccessor(_header) { + const lHeader = normalizeHeader(_header); + + if (!accessors[lHeader]) { + buildAccessors(prototype, _header); + accessors[lHeader] = true; + } } - }); - }; - var InterceptorManager_1 = InterceptorManager; + utils.isArray(header) ? header.forEach(defineAccessor) : defineAccessor(header); + + return this; + } + } + + AxiosHeaders.accessor(['Content-Type', 'Content-Length', 'Accept', 'Accept-Encoding', 'User-Agent', 'Authorization']); - var normalizeHeaderName = function normalizeHeaderName(headers, normalizedName) { - utils.forEach(headers, function processHeader(value, name) { - if (name !== normalizedName && name.toUpperCase() === normalizedName.toUpperCase()) { - headers[normalizedName] = value; - delete headers[name]; + // reserved names hotfix + utils.reduceDescriptors(AxiosHeaders.prototype, ({value}, key) => { + let mapped = key[0].toUpperCase() + key.slice(1); // map `set` => `Set` + return { + get: () => value, + set(headerValue) { + this[mapped] = headerValue; } - }); - }; + } + }); + + utils.freezeMethods(AxiosHeaders); + + var AxiosHeaders$1 = AxiosHeaders; /** - * Update an Error with the specified config, error code, and response. + * Transform the data for a request or a response * - * @param {Error} error The error to update. - * @param {Object} config The config. - * @param {string} [code] The error code (for example, 'ECONNABORTED'). - * @param {Object} [request] The request. - * @param {Object} [response] The response. - * @returns {Error} The error. + * @param {Array|Function} fns A single function or Array of functions + * @param {?Object} response The response object + * + * @returns {*} The resulting transformed data */ - var enhanceError = function enhanceError(error, config, code, request, response) { - error.config = config; - if (code) { - error.code = code; - } + function transformData(fns, response) { + const config = this || defaults$1; + const context = response || config; + const headers = AxiosHeaders$1.from(context.headers); + let data = context.data; + + utils.forEach(fns, function transform(fn) { + data = fn.call(config, data, headers.normalize(), response ? response.status : undefined); + }); - error.request = request; - error.response = response; - error.isAxiosError = true; + headers.normalize(); - error.toJSON = function toJSON() { - return { - // Standard - message: this.message, - name: this.name, - // Microsoft - description: this.description, - number: this.number, - // Mozilla - fileName: this.fileName, - lineNumber: this.lineNumber, - columnNumber: this.columnNumber, - stack: this.stack, - // Axios - config: this.config, - code: this.code - }; - }; - return error; - }; + return data; + } + + function isCancel(value) { + return !!(value && value.__CANCEL__); + } /** - * Create an Error with the specified message, config, error code, request and response. + * A `CanceledError` is an object that is thrown when an operation is canceled. * - * @param {string} message The error message. - * @param {Object} config The config. - * @param {string} [code] The error code (for example, 'ECONNABORTED'). - * @param {Object} [request] The request. - * @param {Object} [response] The response. - * @returns {Error} The created error. + * @param {string=} message The message. + * @param {Object=} config The config. + * @param {Object=} request The request. + * + * @returns {CanceledError} The created error. */ - var createError = function createError(message, config, code, request, response) { - var error = new Error(message); - return enhanceError(error, config, code, request, response); - }; + function CanceledError(message, config, request) { + // eslint-disable-next-line no-eq-null,eqeqeq + AxiosError.call(this, message == null ? 'canceled' : message, AxiosError.ERR_CANCELED, config, request); + this.name = 'CanceledError'; + } + + utils.inherits(CanceledError, AxiosError, { + __CANCEL__: true + }); /** * Resolve or reject a Promise based on response status. @@ -1775,97 +5306,99 @@ define((function () { 'use strict'; * @param {Function} resolve A function that resolves the promise. * @param {Function} reject A function that rejects the promise. * @param {object} response The response. + * + * @returns {object} The response. */ - var settle = function settle(resolve, reject, response) { - var validateStatus = response.config.validateStatus; + function settle(resolve, reject, response) { + const validateStatus = response.config.validateStatus; if (!response.status || !validateStatus || validateStatus(response.status)) { resolve(response); } else { - reject(createError( + reject(new AxiosError( 'Request failed with status code ' + response.status, + [AxiosError.ERR_BAD_REQUEST, AxiosError.ERR_BAD_RESPONSE][Math.floor(response.status / 100) - 4], response.config, - null, response.request, response )); } - }; + } - var cookies = ( - utils.isStandardBrowserEnv() ? + var cookies = platform.isStandardBrowserEnv ? - // Standard browser envs support document.cookie - (function standardBrowserEnv() { - return { - write: function write(name, value, expires, path, domain, secure) { - var cookie = []; - cookie.push(name + '=' + encodeURIComponent(value)); + // Standard browser envs support document.cookie + (function standardBrowserEnv() { + return { + write: function write(name, value, expires, path, domain, secure) { + const cookie = []; + cookie.push(name + '=' + encodeURIComponent(value)); - if (utils.isNumber(expires)) { - cookie.push('expires=' + new Date(expires).toGMTString()); - } + if (utils.isNumber(expires)) { + cookie.push('expires=' + new Date(expires).toGMTString()); + } - if (utils.isString(path)) { - cookie.push('path=' + path); - } + if (utils.isString(path)) { + cookie.push('path=' + path); + } - if (utils.isString(domain)) { - cookie.push('domain=' + domain); - } + if (utils.isString(domain)) { + cookie.push('domain=' + domain); + } - if (secure === true) { - cookie.push('secure'); - } + if (secure === true) { + cookie.push('secure'); + } - document.cookie = cookie.join('; '); - }, + document.cookie = cookie.join('; '); + }, - read: function read(name) { - var match = document.cookie.match(new RegExp('(^|;\\s*)(' + name + ')=([^;]*)')); - return (match ? decodeURIComponent(match[3]) : null); - }, + read: function read(name) { + const match = document.cookie.match(new RegExp('(^|;\\s*)(' + name + ')=([^;]*)')); + return (match ? decodeURIComponent(match[3]) : null); + }, - remove: function remove(name) { - this.write(name, '', Date.now() - 86400000); - } - }; - })() : + remove: function remove(name) { + this.write(name, '', Date.now() - 86400000); + } + }; + })() : - // Non standard browser env (web workers, react-native) lack needed support. - (function nonStandardBrowserEnv() { - return { - write: function write() {}, - read: function read() { return null; }, - remove: function remove() {} - }; - })() - ); + // Non standard browser env (web workers, react-native) lack needed support. + (function nonStandardBrowserEnv() { + return { + write: function write() {}, + read: function read() { return null; }, + remove: function remove() {} + }; + })(); /** * Determines whether the specified URL is absolute * * @param {string} url The URL to test + * * @returns {boolean} True if the specified URL is absolute, otherwise false */ - var isAbsoluteURL = function isAbsoluteURL(url) { + function isAbsoluteURL(url) { // A URL is considered absolute if it begins with "://" or "//" (protocol-relative URL). // RFC 3986 defines scheme name as a sequence of characters beginning with a letter and followed // by any combination of letters, digits, plus, period, or hyphen. - return /^([a-z][a-z\d\+\-\.]*:)?\/\//i.test(url); - }; + return /^([a-z][a-z\d+\-.]*:)?\/\//i.test(url); + } /** * Creates a new URL by combining the specified URLs * * @param {string} baseURL The base URL * @param {string} relativeURL The relative URL + * * @returns {string} The combined URL */ - var combineURLs = function combineURLs(baseURL, relativeURL) { + function combineURLs(baseURL, relativeURL) { return relativeURL ? baseURL.replace(/\/+$/, '') + '/' + relativeURL.replace(/^\/+/, '') : baseURL; - }; + } /** * Creates a new URL by combining the baseURL with the requestedURL, @@ -1874,150 +5407,207 @@ define((function () { 'use strict'; * * @param {string} baseURL The base URL * @param {string} requestedURL Absolute or relative URL to combine + * * @returns {string} The combined full path */ - var buildFullPath = function buildFullPath(baseURL, requestedURL) { + function buildFullPath(baseURL, requestedURL) { if (baseURL && !isAbsoluteURL(requestedURL)) { return combineURLs(baseURL, requestedURL); } return requestedURL; - }; - - // Headers whose duplicates are ignored by node - // c.f. https://nodejs.org/api/http.html#http_message_headers - var ignoreDuplicateOf = [ - 'age', 'authorization', 'content-length', 'content-type', 'etag', - 'expires', 'from', 'host', 'if-modified-since', 'if-unmodified-since', - 'last-modified', 'location', 'max-forwards', 'proxy-authorization', - 'referer', 'retry-after', 'user-agent' - ]; - - /** - * Parse headers into an object - * - * ``` - * Date: Wed, 27 Aug 2014 08:58:49 GMT - * Content-Type: application/json - * Connection: keep-alive - * Transfer-Encoding: chunked - * ``` - * - * @param {String} headers Headers needing to be parsed - * @returns {Object} Headers parsed into an object - */ - var parseHeaders = function parseHeaders(headers) { - var parsed = {}; - var key; - var val; - var i; - - if (!headers) { return parsed; } - - utils.forEach(headers.split('\n'), function parser(line) { - i = line.indexOf(':'); - key = utils.trim(line.substr(0, i)).toLowerCase(); - val = utils.trim(line.substr(i + 1)); - - if (key) { - if (parsed[key] && ignoreDuplicateOf.indexOf(key) >= 0) { - return; - } - if (key === 'set-cookie') { - parsed[key] = (parsed[key] ? parsed[key] : []).concat([val]); - } else { - parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val; - } - } - }); - - return parsed; - }; + } - var isURLSameOrigin = ( - utils.isStandardBrowserEnv() ? + var isURLSameOrigin = platform.isStandardBrowserEnv ? - // Standard browser envs have full support of the APIs needed to test - // whether the request URL is of the same origin as current location. - (function standardBrowserEnv() { - var msie = /(msie|trident)/i.test(navigator.userAgent); - var urlParsingNode = document.createElement('a'); - var originURL; + // Standard browser envs have full support of the APIs needed to test + // whether the request URL is of the same origin as current location. + (function standardBrowserEnv() { + const msie = /(msie|trident)/i.test(navigator.userAgent); + const urlParsingNode = document.createElement('a'); + let originURL; - /** + /** * Parse a URL to discover it's components * * @param {String} url The URL to be parsed * @returns {Object} */ - function resolveURL(url) { - var href = url; + function resolveURL(url) { + let href = url; - if (msie) { + if (msie) { // IE needs attribute set twice to normalize properties - urlParsingNode.setAttribute('href', href); - href = urlParsingNode.href; - } - urlParsingNode.setAttribute('href', href); - - // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils - return { - href: urlParsingNode.href, - protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '', - host: urlParsingNode.host, - search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '', - hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '', - hostname: urlParsingNode.hostname, - port: urlParsingNode.port, - pathname: (urlParsingNode.pathname.charAt(0) === '/') ? - urlParsingNode.pathname : - '/' + urlParsingNode.pathname - }; + href = urlParsingNode.href; } - originURL = resolveURL(window.location.href); + urlParsingNode.setAttribute('href', href); + + // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils + return { + href: urlParsingNode.href, + protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '', + host: urlParsingNode.host, + search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '', + hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '', + hostname: urlParsingNode.hostname, + port: urlParsingNode.port, + pathname: (urlParsingNode.pathname.charAt(0) === '/') ? + urlParsingNode.pathname : + '/' + urlParsingNode.pathname + }; + } + + originURL = resolveURL(window.location.href); - /** + /** * Determine if a URL shares the same origin as the current location * * @param {String} requestURL The URL to test * @returns {boolean} True if URL shares the same origin, otherwise false */ - return function isURLSameOrigin(requestURL) { - var parsed = (utils.isString(requestURL)) ? resolveURL(requestURL) : requestURL; - return (parsed.protocol === originURL.protocol && - parsed.host === originURL.host); - }; - })() : + return function isURLSameOrigin(requestURL) { + const parsed = (utils.isString(requestURL)) ? resolveURL(requestURL) : requestURL; + return (parsed.protocol === originURL.protocol && + parsed.host === originURL.host); + }; + })() : // Non standard browser envs (web workers, react-native) lack needed support. - (function nonStandardBrowserEnv() { - return function isURLSameOrigin() { - return true; - }; - })() - ); + (function nonStandardBrowserEnv() { + return function isURLSameOrigin() { + return true; + }; + })(); + + function parseProtocol(url) { + const match = /^([-+\w]{1,25})(:?\/\/|:)/.exec(url); + return match && match[1] || ''; + } + + /** + * Calculate data maxRate + * @param {Number} [samplesCount= 10] + * @param {Number} [min= 1000] + * @returns {Function} + */ + function speedometer(samplesCount, min) { + samplesCount = samplesCount || 10; + const bytes = new Array(samplesCount); + const timestamps = new Array(samplesCount); + let head = 0; + let tail = 0; + let firstSampleTS; + + min = min !== undefined ? min : 1000; + + return function push(chunkLength) { + const now = Date.now(); + + const startedAt = timestamps[tail]; + + if (!firstSampleTS) { + firstSampleTS = now; + } + + bytes[head] = chunkLength; + timestamps[head] = now; - var xhr = function xhrAdapter(config) { + let i = tail; + let bytesCount = 0; + + while (i !== head) { + bytesCount += bytes[i++]; + i = i % samplesCount; + } + + head = (head + 1) % samplesCount; + + if (head === tail) { + tail = (tail + 1) % samplesCount; + } + + if (now - firstSampleTS < min) { + return; + } + + const passed = startedAt && now - startedAt; + + return passed ? Math.round(bytesCount * 1000 / passed) : undefined; + }; + } + + function progressEventReducer(listener, isDownloadStream) { + let bytesNotified = 0; + const _speedometer = speedometer(50, 250); + + return e => { + const loaded = e.loaded; + const total = e.lengthComputable ? e.total : undefined; + const progressBytes = loaded - bytesNotified; + const rate = _speedometer(progressBytes); + const inRange = loaded <= total; + + bytesNotified = loaded; + + const data = { + loaded, + total, + progress: total ? (loaded / total) : undefined, + bytes: progressBytes, + rate: rate ? rate : undefined, + estimated: rate && total && inRange ? (total - loaded) / rate : undefined, + event: e + }; + + data[isDownloadStream ? 'download' : 'upload'] = true; + + listener(data); + }; + } + + const isXHRAdapterSupported = typeof XMLHttpRequest !== 'undefined'; + + var xhrAdapter = isXHRAdapterSupported && function (config) { return new Promise(function dispatchXhrRequest(resolve, reject) { - var requestData = config.data; - var requestHeaders = config.headers; - var responseType = config.responseType; + let requestData = config.data; + const requestHeaders = AxiosHeaders$1.from(config.headers).normalize(); + const responseType = config.responseType; + let onCanceled; + function done() { + if (config.cancelToken) { + config.cancelToken.unsubscribe(onCanceled); + } + + if (config.signal) { + config.signal.removeEventListener('abort', onCanceled); + } + } + + let contentType; if (utils.isFormData(requestData)) { - delete requestHeaders['Content-Type']; // Let the browser set it + if (platform.isStandardBrowserEnv || platform.isStandardBrowserWebWorkerEnv) { + requestHeaders.setContentType(false); // Let the browser set it + } else if(!requestHeaders.getContentType(/^\s*multipart\/form-data/)){ + requestHeaders.setContentType('multipart/form-data'); // mobile/desktop app frameworks + } else if(utils.isString(contentType = requestHeaders.getContentType())){ + // fix semicolon duplication issue for ReactNative FormData implementation + requestHeaders.setContentType(contentType.replace(/^\s*(multipart\/form-data);+/, '$1')); + } } - var request = new XMLHttpRequest(); + let request = new XMLHttpRequest(); // HTTP basic authentication if (config.auth) { - var username = config.auth.username || ''; - var password = config.auth.password ? unescape(encodeURIComponent(config.auth.password)) : ''; - requestHeaders.Authorization = 'Basic ' + btoa(username + ':' + password); + const username = config.auth.username || ''; + const password = config.auth.password ? unescape(encodeURIComponent(config.auth.password)) : ''; + requestHeaders.set('Authorization', 'Basic ' + btoa(username + ':' + password)); } - var fullPath = buildFullPath(config.baseURL, config.url); + const fullPath = buildFullPath(config.baseURL, config.url); + request.open(config.method.toUpperCase(), buildURL(fullPath, config.params, config.paramsSerializer), true); // Set the request timeout in MS @@ -2028,19 +5618,27 @@ define((function () { 'use strict'; return; } // Prepare the response - var responseHeaders = 'getAllResponseHeaders' in request ? parseHeaders(request.getAllResponseHeaders()) : null; - var responseData = !responseType || responseType === 'text' || responseType === 'json' ? + const responseHeaders = AxiosHeaders$1.from( + 'getAllResponseHeaders' in request && request.getAllResponseHeaders() + ); + const responseData = !responseType || responseType === 'text' || responseType === 'json' ? request.responseText : request.response; - var response = { + const response = { data: responseData, status: request.status, statusText: request.statusText, headers: responseHeaders, - config: config, - request: request + config, + request }; - settle(resolve, reject, response); + settle(function _resolve(value) { + resolve(value); + done(); + }, function _reject(err) { + reject(err); + done(); + }, response); // Clean up request request = null; @@ -2075,7 +5673,7 @@ define((function () { 'use strict'; return; } - reject(createError('Request aborted', config, 'ECONNABORTED', request)); + reject(new AxiosError('Request aborted', AxiosError.ECONNABORTED, config, request)); // Clean up request request = null; @@ -2085,7 +5683,7 @@ define((function () { 'use strict'; request.onerror = function handleError() { // Real errors are hidden from us by the browser // onerror should only fire if it's a network error - reject(createError('Network Error', config, null, request)); + reject(new AxiosError('Network Error', AxiosError.ERR_NETWORK, config, request)); // Clean up request request = null; @@ -2093,14 +5691,15 @@ define((function () { 'use strict'; // Handle timeout request.ontimeout = function handleTimeout() { - var timeoutErrorMessage = 'timeout of ' + config.timeout + 'ms exceeded'; + let timeoutErrorMessage = config.timeout ? 'timeout of ' + config.timeout + 'ms exceeded' : 'timeout exceeded'; + const transitional = config.transitional || transitionalDefaults; if (config.timeoutErrorMessage) { timeoutErrorMessage = config.timeoutErrorMessage; } - reject(createError( + reject(new AxiosError( timeoutErrorMessage, + transitional.clarifyTimeoutError ? AxiosError.ETIMEDOUT : AxiosError.ECONNABORTED, config, - config.transitional && config.transitional.clarifyTimeoutError ? 'ETIMEDOUT' : 'ECONNABORTED', request)); // Clean up request @@ -2110,27 +5709,23 @@ define((function () { 'use strict'; // Add xsrf header // This is only done if running in a standard browser environment. // Specifically not if we're in a web worker, or react-native. - if (utils.isStandardBrowserEnv()) { + if (platform.isStandardBrowserEnv) { // Add xsrf header - var xsrfValue = (config.withCredentials || isURLSameOrigin(fullPath)) && config.xsrfCookieName ? - cookies.read(config.xsrfCookieName) : - undefined; + const xsrfValue = (config.withCredentials || isURLSameOrigin(fullPath)) + && config.xsrfCookieName && cookies.read(config.xsrfCookieName); if (xsrfValue) { - requestHeaders[config.xsrfHeaderName] = xsrfValue; + requestHeaders.set(config.xsrfHeaderName, xsrfValue); } } + // Remove Content-Type if data is undefined + requestData === undefined && requestHeaders.setContentType(null); + // Add headers to the request if ('setRequestHeader' in request) { - utils.forEach(requestHeaders, function setRequestHeader(val, key) { - if (typeof requestData === 'undefined' && key.toLowerCase() === 'content-type') { - // Remove Content-Type if data is undefined - delete requestHeaders[key]; - } else { - // Otherwise add header to the request - request.setRequestHeader(key, val); - } + utils.forEach(requestHeaders.toJSON(), function setRequestHeader(val, key) { + request.setRequestHeader(key, val); }); } @@ -2146,232 +5741,158 @@ define((function () { 'use strict'; // Handle progress if needed if (typeof config.onDownloadProgress === 'function') { - request.addEventListener('progress', config.onDownloadProgress); + request.addEventListener('progress', progressEventReducer(config.onDownloadProgress, true)); } // Not all browsers support upload events if (typeof config.onUploadProgress === 'function' && request.upload) { - request.upload.addEventListener('progress', config.onUploadProgress); + request.upload.addEventListener('progress', progressEventReducer(config.onUploadProgress)); } - if (config.cancelToken) { + if (config.cancelToken || config.signal) { // Handle cancellation - config.cancelToken.promise.then(function onCanceled(cancel) { + // eslint-disable-next-line func-names + onCanceled = cancel => { if (!request) { return; } - + reject(!cancel || cancel.type ? new CanceledError(null, config, request) : cancel); request.abort(); - reject(cancel); - // Clean up request request = null; - }); + }; + + config.cancelToken && config.cancelToken.subscribe(onCanceled); + if (config.signal) { + config.signal.aborted ? onCanceled() : config.signal.addEventListener('abort', onCanceled); + } } - if (!requestData) { - requestData = null; + const protocol = parseProtocol(fullPath); + + if (protocol && platform.protocols.indexOf(protocol) === -1) { + reject(new AxiosError('Unsupported protocol ' + protocol + ':', AxiosError.ERR_BAD_REQUEST, config)); + return; } + // Send the request - request.send(requestData); + request.send(requestData || null); }); }; - var DEFAULT_CONTENT_TYPE = { - 'Content-Type': 'application/x-www-form-urlencoded' + const knownAdapters = { + http: httpAdapter, + xhr: xhrAdapter }; - function setContentTypeIfUnset(headers, value) { - if (!utils.isUndefined(headers) && utils.isUndefined(headers['Content-Type'])) { - headers['Content-Type'] = value; - } - } - - function getDefaultAdapter() { - var adapter; - if (typeof XMLHttpRequest !== 'undefined') { - // For browsers use XHR adapter - adapter = xhr; - } else if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') { - // For node use HTTP adapter - adapter = xhr; - } - return adapter; - } - - function stringifySafely(rawValue, parser, encoder) { - if (utils.isString(rawValue)) { + utils.forEach(knownAdapters, (fn, value) => { + if (fn) { try { - (parser || JSON.parse)(rawValue); - return utils.trim(rawValue); + Object.defineProperty(fn, 'name', {value}); } catch (e) { - if (e.name !== 'SyntaxError') { - throw e; - } + // eslint-disable-next-line no-empty } + Object.defineProperty(fn, 'adapterName', {value}); } + }); - return (encoder || JSON.stringify)(rawValue); - } + const renderReason = (reason) => `- ${reason}`; - var defaults = { + const isResolvedHandle = (adapter) => utils.isFunction(adapter) || adapter === null || adapter === false; - transitional: { - silentJSONParsing: true, - forcedJSONParsing: true, - clarifyTimeoutError: false - }, + var adapters = { + getAdapter: (adapters) => { + adapters = utils.isArray(adapters) ? adapters : [adapters]; - adapter: getDefaultAdapter(), + const {length} = adapters; + let nameOrAdapter; + let adapter; - transformRequest: [function transformRequest(data, headers) { - normalizeHeaderName(headers, 'Accept'); - normalizeHeaderName(headers, 'Content-Type'); + const rejectedReasons = {}; - if (utils.isFormData(data) || - utils.isArrayBuffer(data) || - utils.isBuffer(data) || - utils.isStream(data) || - utils.isFile(data) || - utils.isBlob(data) - ) { - return data; - } - if (utils.isArrayBufferView(data)) { - return data.buffer; - } - if (utils.isURLSearchParams(data)) { - setContentTypeIfUnset(headers, 'application/x-www-form-urlencoded;charset=utf-8'); - return data.toString(); - } - if (utils.isObject(data) || (headers && headers['Content-Type'] === 'application/json')) { - setContentTypeIfUnset(headers, 'application/json'); - return stringifySafely(data); - } - return data; - }], + for (let i = 0; i < length; i++) { + nameOrAdapter = adapters[i]; + let id; - transformResponse: [function transformResponse(data) { - var transitional = this.transitional; - var silentJSONParsing = transitional && transitional.silentJSONParsing; - var forcedJSONParsing = transitional && transitional.forcedJSONParsing; - var strictJSONParsing = !silentJSONParsing && this.responseType === 'json'; + adapter = nameOrAdapter; - if (strictJSONParsing || (forcedJSONParsing && utils.isString(data) && data.length)) { - try { - return JSON.parse(data); - } catch (e) { - if (strictJSONParsing) { - if (e.name === 'SyntaxError') { - throw enhanceError(e, this, 'E_JSON_PARSE'); - } - throw e; + if (!isResolvedHandle(nameOrAdapter)) { + adapter = knownAdapters[(id = String(nameOrAdapter)).toLowerCase()]; + + if (adapter === undefined) { + throw new AxiosError(`Unknown adapter '${id}'`); } } - } - - return data; - }], - - /** - * A timeout in milliseconds to abort a request. If set to 0 (default) a - * timeout is not created. - */ - timeout: 0, - - xsrfCookieName: 'XSRF-TOKEN', - xsrfHeaderName: 'X-XSRF-TOKEN', - maxContentLength: -1, - maxBodyLength: -1, - - validateStatus: function validateStatus(status) { - return status >= 200 && status < 300; - } - }; - - defaults.headers = { - common: { - 'Accept': 'application/json, text/plain, */*' - } - }; + if (adapter) { + break; + } - utils.forEach(['delete', 'get', 'head'], function forEachMethodNoData(method) { - defaults.headers[method] = {}; - }); + rejectedReasons[id || '#' + i] = adapter; + } - utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) { - defaults.headers[method] = utils.merge(DEFAULT_CONTENT_TYPE); - }); + if (!adapter) { - var defaults_1 = defaults; + const reasons = Object.entries(rejectedReasons) + .map(([id, state]) => `adapter ${id} ` + + (state === false ? 'is not supported by the environment' : 'is not available in the build') + ); - /** - * Transform the data for a request or a response - * - * @param {Object|String} data The data to be transformed - * @param {Array} headers The headers for the request or response - * @param {Array|Function} fns A single function or Array of functions - * @returns {*} The resulting transformed data - */ - var transformData = function transformData(data, headers, fns) { - var context = this || defaults_1; - /*eslint no-param-reassign:0*/ - utils.forEach(fns, function transform(fn) { - data = fn.call(context, data, headers); - }); + let s = length ? + (reasons.length > 1 ? 'since :\n' + reasons.map(renderReason).join('\n') : ' ' + renderReason(reasons[0])) : + 'as no adapter specified'; - return data; - }; + throw new AxiosError( + `There is no suitable adapter to dispatch the request ` + s, + 'ERR_NOT_SUPPORT' + ); + } - var isCancel = function isCancel(value) { - return !!(value && value.__CANCEL__); + return adapter; + }, + adapters: knownAdapters }; /** - * Throws a `Cancel` if cancellation has been requested. + * Throws a `CanceledError` if cancellation has been requested. + * + * @param {Object} config The config that is to be used for the request + * + * @returns {void} */ function throwIfCancellationRequested(config) { if (config.cancelToken) { config.cancelToken.throwIfRequested(); } + + if (config.signal && config.signal.aborted) { + throw new CanceledError(null, config); + } } /** * Dispatch a request to the server using the configured adapter. * * @param {object} config The config that is to be used for the request + * * @returns {Promise} The Promise to be fulfilled */ - var dispatchRequest = function dispatchRequest(config) { + function dispatchRequest(config) { throwIfCancellationRequested(config); - // Ensure headers exist - config.headers = config.headers || {}; + config.headers = AxiosHeaders$1.from(config.headers); // Transform request data config.data = transformData.call( config, - config.data, - config.headers, config.transformRequest ); - // Flatten headers - config.headers = utils.merge( - config.headers.common || {}, - config.headers[config.method] || {}, - config.headers - ); - - utils.forEach( - ['delete', 'get', 'head', 'post', 'put', 'patch', 'common'], - function cleanHeaderConfig(method) { - delete config.headers[method]; - } - ); + if (['post', 'put', 'patch'].indexOf(config.method) !== -1) { + config.headers.setContentType('application/x-www-form-urlencoded', false); + } - var adapter = config.adapter || defaults_1.adapter; + const adapter = adapters.getAdapter(config.adapter || defaults$1.adapter); return adapter(config).then(function onAdapterResolution(response) { throwIfCancellationRequested(config); @@ -2379,11 +5900,12 @@ define((function () { 'use strict'; // Transform response data response.data = transformData.call( config, - response.data, - response.headers, - config.transformResponse + config.transformResponse, + response ); + response.headers = AxiosHeaders$1.from(response.headers); + return response; }, function onAdapterRejection(reason) { if (!isCancel(reason)) { @@ -2393,16 +5915,18 @@ define((function () { 'use strict'; if (reason && reason.response) { reason.response.data = transformData.call( config, - reason.response.data, - reason.response.headers, - config.transformResponse + config.transformResponse, + reason.response ); + reason.response.headers = AxiosHeaders$1.from(reason.response.headers); } } return Promise.reject(reason); }); - }; + } + + const headersToObject = (thing) => thing instanceof AxiosHeaders$1 ? thing.toJSON() : thing; /** * Config-specific merge-function which creates a new config-object @@ -2410,27 +5934,17 @@ define((function () { 'use strict'; * * @param {Object} config1 * @param {Object} config2 + * * @returns {Object} New object resulting from merging config2 to config1 */ - var mergeConfig = function mergeConfig(config1, config2) { + function mergeConfig(config1, config2) { // eslint-disable-next-line no-param-reassign config2 = config2 || {}; - var config = {}; - - var valueFromConfig2Keys = ['url', 'method', 'data']; - var mergeDeepPropertiesKeys = ['headers', 'auth', 'proxy', 'params']; - var defaultToConfig2Keys = [ - 'baseURL', 'transformRequest', 'transformResponse', 'paramsSerializer', - 'timeout', 'timeoutMessage', 'withCredentials', 'adapter', 'responseType', 'xsrfCookieName', - 'xsrfHeaderName', 'onUploadProgress', 'onDownloadProgress', 'decompress', - 'maxContentLength', 'maxBodyLength', 'maxRedirects', 'transport', 'httpAgent', - 'httpsAgent', 'cancelToken', 'socketPath', 'responseEncoding' - ]; - var directMergeKeys = ['validateStatus']; - - function getMergedValue(target, source) { + const config = {}; + + function getMergedValue(target, source, caseless) { if (utils.isPlainObject(target) && utils.isPlainObject(source)) { - return utils.merge(target, source); + return utils.merge.call({caseless}, target, source); } else if (utils.isPlainObject(source)) { return utils.merge({}, source); } else if (utils.isArray(source)) { @@ -2439,210 +5953,117 @@ define((function () { 'use strict'; return source; } - function mergeDeepProperties(prop) { - if (!utils.isUndefined(config2[prop])) { - config[prop] = getMergedValue(config1[prop], config2[prop]); - } else if (!utils.isUndefined(config1[prop])) { - config[prop] = getMergedValue(undefined, config1[prop]); + // eslint-disable-next-line consistent-return + function mergeDeepProperties(a, b, caseless) { + if (!utils.isUndefined(b)) { + return getMergedValue(a, b, caseless); + } else if (!utils.isUndefined(a)) { + return getMergedValue(undefined, a, caseless); } } - utils.forEach(valueFromConfig2Keys, function valueFromConfig2(prop) { - if (!utils.isUndefined(config2[prop])) { - config[prop] = getMergedValue(undefined, config2[prop]); + // eslint-disable-next-line consistent-return + function valueFromConfig2(a, b) { + if (!utils.isUndefined(b)) { + return getMergedValue(undefined, b); } - }); - - utils.forEach(mergeDeepPropertiesKeys, mergeDeepProperties); + } - utils.forEach(defaultToConfig2Keys, function defaultToConfig2(prop) { - if (!utils.isUndefined(config2[prop])) { - config[prop] = getMergedValue(undefined, config2[prop]); - } else if (!utils.isUndefined(config1[prop])) { - config[prop] = getMergedValue(undefined, config1[prop]); + // eslint-disable-next-line consistent-return + function defaultToConfig2(a, b) { + if (!utils.isUndefined(b)) { + return getMergedValue(undefined, b); + } else if (!utils.isUndefined(a)) { + return getMergedValue(undefined, a); } - }); + } - utils.forEach(directMergeKeys, function merge(prop) { + // eslint-disable-next-line consistent-return + function mergeDirectKeys(a, b, prop) { if (prop in config2) { - config[prop] = getMergedValue(config1[prop], config2[prop]); + return getMergedValue(a, b); } else if (prop in config1) { - config[prop] = getMergedValue(undefined, config1[prop]); + return getMergedValue(undefined, a); } - }); - - var axiosKeys = valueFromConfig2Keys - .concat(mergeDeepPropertiesKeys) - .concat(defaultToConfig2Keys) - .concat(directMergeKeys); + } - var otherKeys = Object - .keys(config1) - .concat(Object.keys(config2)) - .filter(function filterAxiosKeys(key) { - return axiosKeys.indexOf(key) === -1; - }); + const mergeMap = { + url: valueFromConfig2, + method: valueFromConfig2, + data: valueFromConfig2, + baseURL: defaultToConfig2, + transformRequest: defaultToConfig2, + transformResponse: defaultToConfig2, + paramsSerializer: defaultToConfig2, + timeout: defaultToConfig2, + timeoutMessage: defaultToConfig2, + withCredentials: defaultToConfig2, + adapter: defaultToConfig2, + responseType: defaultToConfig2, + xsrfCookieName: defaultToConfig2, + xsrfHeaderName: defaultToConfig2, + onUploadProgress: defaultToConfig2, + onDownloadProgress: defaultToConfig2, + decompress: defaultToConfig2, + maxContentLength: defaultToConfig2, + maxBodyLength: defaultToConfig2, + beforeRedirect: defaultToConfig2, + transport: defaultToConfig2, + httpAgent: defaultToConfig2, + httpsAgent: defaultToConfig2, + cancelToken: defaultToConfig2, + socketPath: defaultToConfig2, + responseEncoding: defaultToConfig2, + validateStatus: mergeDirectKeys, + headers: (a, b) => mergeDeepProperties(headersToObject(a), headersToObject(b), true) + }; - utils.forEach(otherKeys, mergeDeepProperties); + utils.forEach(Object.keys(Object.assign({}, config1, config2)), function computeConfigValue(prop) { + const merge = mergeMap[prop] || mergeDeepProperties; + const configValue = merge(config1[prop], config2[prop], prop); + (utils.isUndefined(configValue) && merge !== mergeDirectKeys) || (config[prop] = configValue); + }); return config; - }; + } - var name = "axios"; - var version = "0.21.4"; - var description = "Promise based HTTP client for the browser and node.js"; - var main = "index.js"; - var scripts = { - test: "grunt test", - start: "node ./sandbox/server.js", - build: "NODE_ENV=production grunt build", - preversion: "npm test", - version: "npm run build && grunt version && git add -A dist && git add CHANGELOG.md bower.json package.json", - postversion: "git push && git push --tags", - examples: "node ./examples/server.js", - coveralls: "cat coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js", - fix: "eslint --fix lib/**/*.js" - }; - var repository = { - type: "git", - url: "https://github.com/axios/axios.git" - }; - var keywords = [ - "xhr", - "http", - "ajax", - "promise", - "node" - ]; - var author = "Matt Zabriskie"; - var license = "MIT"; - var bugs = { - url: "https://github.com/axios/axios/issues" - }; - var homepage = "https://axios-http.com"; - var devDependencies = { - coveralls: "^3.0.0", - "es6-promise": "^4.2.4", - grunt: "^1.3.0", - "grunt-banner": "^0.6.0", - "grunt-cli": "^1.2.0", - "grunt-contrib-clean": "^1.1.0", - "grunt-contrib-watch": "^1.0.0", - "grunt-eslint": "^23.0.0", - "grunt-karma": "^4.0.0", - "grunt-mocha-test": "^0.13.3", - "grunt-ts": "^6.0.0-beta.19", - "grunt-webpack": "^4.0.2", - "istanbul-instrumenter-loader": "^1.0.0", - "jasmine-core": "^2.4.1", - karma: "^6.3.2", - "karma-chrome-launcher": "^3.1.0", - "karma-firefox-launcher": "^2.1.0", - "karma-jasmine": "^1.1.1", - "karma-jasmine-ajax": "^0.1.13", - "karma-safari-launcher": "^1.0.0", - "karma-sauce-launcher": "^4.3.6", - "karma-sinon": "^1.0.5", - "karma-sourcemap-loader": "^0.3.8", - "karma-webpack": "^4.0.2", - "load-grunt-tasks": "^3.5.2", - minimist: "^1.2.0", - mocha: "^8.2.1", - sinon: "^4.5.0", - "terser-webpack-plugin": "^4.2.3", - typescript: "^4.0.5", - "url-search-params": "^0.10.0", - webpack: "^4.44.2", - "webpack-dev-server": "^3.11.0" - }; - var browser = { - "./lib/adapters/http.js": "./lib/adapters/xhr.js" - }; - var jsdelivr = "dist/axios.min.js"; - var unpkg = "dist/axios.min.js"; - var typings = "./index.d.ts"; - var dependencies = { - "follow-redirects": "^1.14.0" - }; - var bundlesize = [ - { - path: "./dist/axios.min.js", - threshold: "5kB" - } - ]; - var pkg = { - name: name, - version: version, - description: description, - main: main, - scripts: scripts, - repository: repository, - keywords: keywords, - author: author, - license: license, - bugs: bugs, - homepage: homepage, - devDependencies: devDependencies, - browser: browser, - jsdelivr: jsdelivr, - unpkg: unpkg, - typings: typings, - dependencies: dependencies, - bundlesize: bundlesize - }; - - var validators$1 = {}; + const VERSION = "1.5.1"; + + const validators$1 = {}; // eslint-disable-next-line func-names - ['object', 'boolean', 'number', 'function', 'string', 'symbol'].forEach(function(type, i) { + ['object', 'boolean', 'number', 'function', 'string', 'symbol'].forEach((type, i) => { validators$1[type] = function validator(thing) { return typeof thing === type || 'a' + (i < 1 ? 'n ' : ' ') + type; }; }); - var deprecatedWarnings = {}; - var currentVerArr = pkg.version.split('.'); - - /** - * Compare package versions - * @param {string} version - * @param {string?} thanVersion - * @returns {boolean} - */ - function isOlderVersion(version, thanVersion) { - var pkgVersionArr = thanVersion ? thanVersion.split('.') : currentVerArr; - var destVer = version.split('.'); - for (var i = 0; i < 3; i++) { - if (pkgVersionArr[i] > destVer[i]) { - return true; - } else if (pkgVersionArr[i] < destVer[i]) { - return false; - } - } - return false; - } + const deprecatedWarnings = {}; /** * Transitional option validator - * @param {function|boolean?} validator - * @param {string?} version - * @param {string} message + * + * @param {function|boolean?} validator - set to false if the transitional option has been removed + * @param {string?} version - deprecated version / removed since version + * @param {string?} message - some message with additional info + * * @returns {function} */ validators$1.transitional = function transitional(validator, version, message) { - var isDeprecated = version && isOlderVersion(version); - function formatMessage(opt, desc) { - return '[Axios v' + pkg.version + '] Transitional option \'' + opt + '\'' + desc + (message ? '. ' + message : ''); + return '[Axios v' + VERSION + '] Transitional option \'' + opt + '\'' + desc + (message ? '. ' + message : ''); } // eslint-disable-next-line func-names - return function(value, opt, opts) { + return (value, opt, opts) => { if (validator === false) { - throw new Error(formatMessage(opt, ' has been removed in ' + version)); + throw new AxiosError( + formatMessage(opt, ' has been removed' + (version ? ' in ' + version : '')), + AxiosError.ERR_DEPRECATED + ); } - if (isDeprecated && !deprecatedWarnings[opt]) { + if (version && !deprecatedWarnings[opt]) { deprecatedWarnings[opt] = true; // eslint-disable-next-line no-console console.warn( @@ -2659,162 +6080,205 @@ define((function () { 'use strict'; /** * Assert object's properties type + * * @param {object} options * @param {object} schema * @param {boolean?} allowUnknown + * + * @returns {object} */ function assertOptions(options, schema, allowUnknown) { if (typeof options !== 'object') { - throw new TypeError('options must be an object'); + throw new AxiosError('options must be an object', AxiosError.ERR_BAD_OPTION_VALUE); } - var keys = Object.keys(options); - var i = keys.length; + const keys = Object.keys(options); + let i = keys.length; while (i-- > 0) { - var opt = keys[i]; - var validator = schema[opt]; + const opt = keys[i]; + const validator = schema[opt]; if (validator) { - var value = options[opt]; - var result = value === undefined || validator(value, opt, options); + const value = options[opt]; + const result = value === undefined || validator(value, opt, options); if (result !== true) { - throw new TypeError('option ' + opt + ' must be ' + result); + throw new AxiosError('option ' + opt + ' must be ' + result, AxiosError.ERR_BAD_OPTION_VALUE); } continue; } if (allowUnknown !== true) { - throw Error('Unknown option ' + opt); + throw new AxiosError('Unknown option ' + opt, AxiosError.ERR_BAD_OPTION); } } } var validator = { - isOlderVersion: isOlderVersion, - assertOptions: assertOptions, + assertOptions, validators: validators$1 }; - var validators = validator.validators; + const validators = validator.validators; + /** * Create a new instance of Axios * * @param {Object} instanceConfig The default config for the instance - */ - function Axios(instanceConfig) { - this.defaults = instanceConfig; - this.interceptors = { - request: new InterceptorManager_1(), - response: new InterceptorManager_1() - }; - } - - /** - * Dispatch a request * - * @param {Object} config The config specific for this request (merged with this.defaults) + * @return {Axios} A new instance of Axios */ - Axios.prototype.request = function request(config) { - /*eslint no-param-reassign:0*/ - // Allow for axios('example/url'[, config]) a la fetch API - if (typeof config === 'string') { - config = arguments[1] || {}; - config.url = arguments[0]; - } else { - config = config || {}; + class Axios { + constructor(instanceConfig) { + this.defaults = instanceConfig; + this.interceptors = { + request: new InterceptorManager$1(), + response: new InterceptorManager$1() + }; } - config = mergeConfig(this.defaults, config); + /** + * Dispatch a request + * + * @param {String|Object} configOrUrl The config specific for this request (merged with this.defaults) + * @param {?Object} config + * + * @returns {Promise} The Promise to be fulfilled + */ + request(configOrUrl, config) { + /*eslint no-param-reassign:0*/ + // Allow for axios('example/url'[, config]) a la fetch API + if (typeof configOrUrl === 'string') { + config = config || {}; + config.url = configOrUrl; + } else { + config = configOrUrl || {}; + } - // Set config.method - if (config.method) { - config.method = config.method.toLowerCase(); - } else if (this.defaults.method) { - config.method = this.defaults.method.toLowerCase(); - } else { - config.method = 'get'; - } + config = mergeConfig(this.defaults, config); - var transitional = config.transitional; + const {transitional, paramsSerializer, headers} = config; - if (transitional !== undefined) { - validator.assertOptions(transitional, { - silentJSONParsing: validators.transitional(validators.boolean, '1.0.0'), - forcedJSONParsing: validators.transitional(validators.boolean, '1.0.0'), - clarifyTimeoutError: validators.transitional(validators.boolean, '1.0.0') - }, false); - } + if (transitional !== undefined) { + validator.assertOptions(transitional, { + silentJSONParsing: validators.transitional(validators.boolean), + forcedJSONParsing: validators.transitional(validators.boolean), + clarifyTimeoutError: validators.transitional(validators.boolean) + }, false); + } - // filter out skipped interceptors - var requestInterceptorChain = []; - var synchronousRequestInterceptors = true; - this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) { - if (typeof interceptor.runWhen === 'function' && interceptor.runWhen(config) === false) { - return; + if (paramsSerializer != null) { + if (utils.isFunction(paramsSerializer)) { + config.paramsSerializer = { + serialize: paramsSerializer + }; + } else { + validator.assertOptions(paramsSerializer, { + encode: validators.function, + serialize: validators.function + }, true); + } } - synchronousRequestInterceptors = synchronousRequestInterceptors && interceptor.synchronous; + // Set config.method + config.method = (config.method || this.defaults.method || 'get').toLowerCase(); - requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected); - }); + // Flatten headers + let contextHeaders = headers && utils.merge( + headers.common, + headers[config.method] + ); - var responseInterceptorChain = []; - this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) { - responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected); - }); + headers && utils.forEach( + ['delete', 'get', 'head', 'post', 'put', 'patch', 'common'], + (method) => { + delete headers[method]; + } + ); + + config.headers = AxiosHeaders$1.concat(contextHeaders, headers); + + // filter out skipped interceptors + const requestInterceptorChain = []; + let synchronousRequestInterceptors = true; + this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) { + if (typeof interceptor.runWhen === 'function' && interceptor.runWhen(config) === false) { + return; + } + + synchronousRequestInterceptors = synchronousRequestInterceptors && interceptor.synchronous; + + requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected); + }); + + const responseInterceptorChain = []; + this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) { + responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected); + }); + + let promise; + let i = 0; + let len; - var promise; + if (!synchronousRequestInterceptors) { + const chain = [dispatchRequest.bind(this), undefined]; + chain.unshift.apply(chain, requestInterceptorChain); + chain.push.apply(chain, responseInterceptorChain); + len = chain.length; - if (!synchronousRequestInterceptors) { - var chain = [dispatchRequest, undefined]; + promise = Promise.resolve(config); - Array.prototype.unshift.apply(chain, requestInterceptorChain); - chain = chain.concat(responseInterceptorChain); + while (i < len) { + promise = promise.then(chain[i++], chain[i++]); + } - promise = Promise.resolve(config); - while (chain.length) { - promise = promise.then(chain.shift(), chain.shift()); + return promise; } - return promise; - } + len = requestInterceptorChain.length; + + let newConfig = config; + i = 0; + + while (i < len) { + const onFulfilled = requestInterceptorChain[i++]; + const onRejected = requestInterceptorChain[i++]; + try { + newConfig = onFulfilled(newConfig); + } catch (error) { + onRejected.call(this, error); + break; + } + } - var newConfig = config; - while (requestInterceptorChain.length) { - var onFulfilled = requestInterceptorChain.shift(); - var onRejected = requestInterceptorChain.shift(); try { - newConfig = onFulfilled(newConfig); + promise = dispatchRequest.call(this, newConfig); } catch (error) { - onRejected(error); - break; + return Promise.reject(error); } - } - try { - promise = dispatchRequest(newConfig); - } catch (error) { - return Promise.reject(error); - } + i = 0; + len = responseInterceptorChain.length; - while (responseInterceptorChain.length) { - promise = promise.then(responseInterceptorChain.shift(), responseInterceptorChain.shift()); - } + while (i < len) { + promise = promise.then(responseInterceptorChain[i++], responseInterceptorChain[i++]); + } - return promise; - }; + return promise; + } - Axios.prototype.getUri = function getUri(config) { - config = mergeConfig(this.defaults, config); - return buildURL(config.url, config.params, config.paramsSerializer).replace(/^\?/, ''); - }; + getUri(config) { + config = mergeConfig(this.defaults, config); + const fullPath = buildFullPath(config.baseURL, config.url); + return buildURL(fullPath, config.params, config.paramsSerializer); + } + } // Provide aliases for supported request methods utils.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData(method) { /*eslint func-names:0*/ Axios.prototype[method] = function(url, config) { return this.request(mergeConfig(config || {}, { - method: method, - url: url, + method, + url, data: (config || {}).data })); }; @@ -2822,88 +6286,144 @@ define((function () { 'use strict'; utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) { /*eslint func-names:0*/ - Axios.prototype[method] = function(url, data, config) { - return this.request(mergeConfig(config || {}, { - method: method, - url: url, - data: data - })); - }; - }); - - var Axios_1 = Axios; - /** - * A `Cancel` is an object that is thrown when an operation is canceled. - * - * @class - * @param {string=} message The message. - */ - function Cancel(message) { - this.message = message; - } + function generateHTTPMethod(isForm) { + return function httpMethod(url, data, config) { + return this.request(mergeConfig(config || {}, { + method, + headers: isForm ? { + 'Content-Type': 'multipart/form-data' + } : {}, + url, + data + })); + }; + } - Cancel.prototype.toString = function toString() { - return 'Cancel' + (this.message ? ': ' + this.message : ''); - }; + Axios.prototype[method] = generateHTTPMethod(); - Cancel.prototype.__CANCEL__ = true; + Axios.prototype[method + 'Form'] = generateHTTPMethod(true); + }); - var Cancel_1 = Cancel; + var Axios$1 = Axios; /** * A `CancelToken` is an object that can be used to request cancellation of an operation. * - * @class * @param {Function} executor The executor function. + * + * @returns {CancelToken} */ - function CancelToken(executor) { - if (typeof executor !== 'function') { - throw new TypeError('executor must be a function.'); + class CancelToken { + constructor(executor) { + if (typeof executor !== 'function') { + throw new TypeError('executor must be a function.'); + } + + let resolvePromise; + + this.promise = new Promise(function promiseExecutor(resolve) { + resolvePromise = resolve; + }); + + const token = this; + + // eslint-disable-next-line func-names + this.promise.then(cancel => { + if (!token._listeners) return; + + let i = token._listeners.length; + + while (i-- > 0) { + token._listeners[i](cancel); + } + token._listeners = null; + }); + + // eslint-disable-next-line func-names + this.promise.then = onfulfilled => { + let _resolve; + // eslint-disable-next-line func-names + const promise = new Promise(resolve => { + token.subscribe(resolve); + _resolve = resolve; + }).then(onfulfilled); + + promise.cancel = function reject() { + token.unsubscribe(_resolve); + }; + + return promise; + }; + + executor(function cancel(message, config, request) { + if (token.reason) { + // Cancellation has already been requested + return; + } + + token.reason = new CanceledError(message, config, request); + resolvePromise(token.reason); + }); } - var resolvePromise; - this.promise = new Promise(function promiseExecutor(resolve) { - resolvePromise = resolve; - }); + /** + * Throws a `CanceledError` if cancellation has been requested. + */ + throwIfRequested() { + if (this.reason) { + throw this.reason; + } + } + + /** + * Subscribe to the cancel signal + */ - var token = this; - executor(function cancel(message) { - if (token.reason) { - // Cancellation has already been requested + subscribe(listener) { + if (this.reason) { + listener(this.reason); return; } - token.reason = new Cancel_1(message); - resolvePromise(token.reason); - }); - } + if (this._listeners) { + this._listeners.push(listener); + } else { + this._listeners = [listener]; + } + } - /** - * Throws a `Cancel` if cancellation has been requested. - */ - CancelToken.prototype.throwIfRequested = function throwIfRequested() { - if (this.reason) { - throw this.reason; + /** + * Unsubscribe from the cancel signal + */ + + unsubscribe(listener) { + if (!this._listeners) { + return; + } + const index = this._listeners.indexOf(listener); + if (index !== -1) { + this._listeners.splice(index, 1); + } } - }; - /** - * Returns an object that contains a new `CancelToken` and a function that, when called, - * cancels the `CancelToken`. - */ - CancelToken.source = function source() { - var cancel; - var token = new CancelToken(function executor(c) { - cancel = c; - }); - return { - token: token, - cancel: cancel - }; - }; + /** + * Returns an object that contains a new `CancelToken` and a function that, when called, + * cancels the `CancelToken`. + */ + static source() { + let cancel; + const token = new CancelToken(function executor(c) { + cancel = c; + }); + return { + token, + cancel + }; + } + } - var CancelToken_1 = CancelToken; + var CancelToken$1 = CancelToken; /** * Syntactic sugar for invoking a function and expanding an array for arguments. @@ -2923,77 +6443,168 @@ define((function () { 'use strict'; * ``` * * @param {Function} callback + * * @returns {Function} */ - var spread = function spread(callback) { + function spread(callback) { return function wrap(arr) { return callback.apply(null, arr); }; - }; + } /** * Determines whether the payload is an error thrown by Axios * * @param {*} payload The value to test + * * @returns {boolean} True if the payload is an error thrown by Axios, otherwise false */ - var isAxiosError = function isAxiosError(payload) { - return (typeof payload === 'object') && (payload.isAxiosError === true); + function isAxiosError(payload) { + return utils.isObject(payload) && (payload.isAxiosError === true); + } + + const HttpStatusCode = { + Continue: 100, + SwitchingProtocols: 101, + Processing: 102, + EarlyHints: 103, + Ok: 200, + Created: 201, + Accepted: 202, + NonAuthoritativeInformation: 203, + NoContent: 204, + ResetContent: 205, + PartialContent: 206, + MultiStatus: 207, + AlreadyReported: 208, + ImUsed: 226, + MultipleChoices: 300, + MovedPermanently: 301, + Found: 302, + SeeOther: 303, + NotModified: 304, + UseProxy: 305, + Unused: 306, + TemporaryRedirect: 307, + PermanentRedirect: 308, + BadRequest: 400, + Unauthorized: 401, + PaymentRequired: 402, + Forbidden: 403, + NotFound: 404, + MethodNotAllowed: 405, + NotAcceptable: 406, + ProxyAuthenticationRequired: 407, + RequestTimeout: 408, + Conflict: 409, + Gone: 410, + LengthRequired: 411, + PreconditionFailed: 412, + PayloadTooLarge: 413, + UriTooLong: 414, + UnsupportedMediaType: 415, + RangeNotSatisfiable: 416, + ExpectationFailed: 417, + ImATeapot: 418, + MisdirectedRequest: 421, + UnprocessableEntity: 422, + Locked: 423, + FailedDependency: 424, + TooEarly: 425, + UpgradeRequired: 426, + PreconditionRequired: 428, + TooManyRequests: 429, + RequestHeaderFieldsTooLarge: 431, + UnavailableForLegalReasons: 451, + InternalServerError: 500, + NotImplemented: 501, + BadGateway: 502, + ServiceUnavailable: 503, + GatewayTimeout: 504, + HttpVersionNotSupported: 505, + VariantAlsoNegotiates: 506, + InsufficientStorage: 507, + LoopDetected: 508, + NotExtended: 510, + NetworkAuthenticationRequired: 511, }; + Object.entries(HttpStatusCode).forEach(([key, value]) => { + HttpStatusCode[value] = key; + }); + + var HttpStatusCode$1 = HttpStatusCode; + /** * Create an instance of Axios * * @param {Object} defaultConfig The default config for the instance - * @return {Axios} A new instance of Axios + * + * @returns {Axios} A new instance of Axios */ function createInstance(defaultConfig) { - var context = new Axios_1(defaultConfig); - var instance = bind(Axios_1.prototype.request, context); + const context = new Axios$1(defaultConfig); + const instance = bind(Axios$1.prototype.request, context); // Copy axios.prototype to instance - utils.extend(instance, Axios_1.prototype, context); + utils.extend(instance, Axios$1.prototype, context, {allOwnKeys: true}); // Copy context to instance - utils.extend(instance, context); + utils.extend(instance, context, null, {allOwnKeys: true}); + + // Factory for creating new instances + instance.create = function create(instanceConfig) { + return createInstance(mergeConfig(defaultConfig, instanceConfig)); + }; return instance; } // Create the default instance to be exported - var axios$1 = createInstance(defaults_1); + const axios = createInstance(defaults$1); // Expose Axios class to allow class inheritance - axios$1.Axios = Axios_1; - - // Factory for creating new instances - axios$1.create = function create(instanceConfig) { - return createInstance(mergeConfig(axios$1.defaults, instanceConfig)); - }; + axios.Axios = Axios$1; // Expose Cancel & CancelToken - axios$1.Cancel = Cancel_1; - axios$1.CancelToken = CancelToken_1; - axios$1.isCancel = isCancel; + axios.CanceledError = CanceledError; + axios.CancelToken = CancelToken$1; + axios.isCancel = isCancel; + axios.VERSION = VERSION; + axios.toFormData = toFormData; + + // Expose AxiosError class + axios.AxiosError = AxiosError; + + // alias for CanceledError for backward compatibility + axios.Cancel = axios.CanceledError; // Expose all/spread - axios$1.all = function all(promises) { + axios.all = function all(promises) { return Promise.all(promises); }; - axios$1.spread = spread; + + axios.spread = spread; // Expose isAxiosError - axios$1.isAxiosError = isAxiosError; + axios.isAxiosError = isAxiosError; - var axios_1 = axios$1; + // Expose mergeConfig + axios.mergeConfig = mergeConfig; - // Allow use of default import syntax in TypeScript - var _default = axios$1; - axios_1.default = _default; + axios.AxiosHeaders = AxiosHeaders$1; - var axios = axios_1; + axios.formToJSON = thing => formDataToJSON(utils.isHTMLForm(thing) ? new FormData(thing) : thing); + + axios.getAdapter = adapters.getAdapter; + + axios.HttpStatusCode = HttpStatusCode$1; + + axios.default = axios; + + // this module should only have a default export + var axios$1 = axios; - // var script = { data: () => ({ mode: "edit", @@ -3002,15 +6613,13 @@ define((function () { 'use strict'; config: null, docEditor: null }), - created() { this.mode = this.$route.params.mode; this.fileId = this.$route.params.fileId; this.filePath = this.$route.params.filePath; }, - - methods: { ...mapActions(["showMessage"]), - + methods: { + ...mapActions(["showMessage"]), messageDisplay(desc, status = "danger", title = "") { this.showMessage({ title: title, @@ -3021,24 +6630,20 @@ define((function () { 'use strict'; } }); }, - onRequestClose() { let params = { - item: null + driveAliasAndItem: null }; - if (this.currentFolder) { - params.item = this.currentFolder.path; + params.driveAliasAndItem = "personal/" + this.currentFolder.ownerId + this.currentFolder.path; } - this.$router.push({ - name: "files-personal", + name: "files-spaces-generic", params }); }, - getDocumentServerUrl() { - return axios({ + return axios$1({ method: "GET", url: this.configuration.server + "ocs/v2.php/apps/onlyoffice/api/v1/settings/docserver", headers: { @@ -3048,19 +6653,16 @@ define((function () { 'use strict'; if (!response.data.documentServerUrl) { throw "ONLYOFFICE app is not configured. Please contact admin"; } - return response.data.documentServerUrl; }); }, - create() { return new Promise((resolve, reject) => { if (this.mode != "create") { resolve(); return; } - - axios({ + axios$1({ method: "GET", url: this.configuration.server + "ocs/v2.php/apps/onlyoffice/api/v1/empty/" + this.fileId, headers: { @@ -3071,14 +6673,12 @@ define((function () { 'use strict'; reject(response.data.error); return; } - resolve(); }); }); }, - initConfig() { - return axios({ + return axios$1({ method: "GET", url: this.configuration.server + "ocs/v2.php/apps/onlyoffice/api/v1/config/" + this.fileId, headers: { @@ -3088,7 +6688,6 @@ define((function () { 'use strict'; if (response.data.error) { throw response.data.error; } - this.config = response.data; let events = []; events["onRequestClose"] = this.onRequestClose; @@ -3097,12 +6696,11 @@ define((function () { 'use strict'; this.docEditor = new DocsAPI.DocEditor("iframeEditor", this.config); }); } - }, - computed: { ...mapGetters(["getToken", "configuration", "apps"]), + computed: { + ...mapGetters(["getToken", "configuration", "apps"]), ...mapGetters("Files", ["currentFolder"]) }, - mounted() { this.create().then(() => { return this.getDocumentServerUrl(); @@ -3117,196 +6715,73 @@ define((function () { 'use strict'; this.onRequestClose(); }); } - }; - function normalizeComponent(template, style, script, scopeId, isFunctionalTemplate, moduleIdentifier /* server only */, shadowMode, createInjector, createInjectorSSR, createInjectorShadow) { - if (typeof shadowMode !== 'boolean') { - createInjectorSSR = createInjector; - createInjector = shadowMode; - shadowMode = false; - } - // Vue.extend constructor export interop. - const options = typeof script === 'function' ? script.options : script; - // render functions - if (template && template.render) { - options.render = template.render; - options.staticRenderFns = template.staticRenderFns; - options._compiled = true; - // functional template - if (isFunctionalTemplate) { - options.functional = true; - } - } - // scopedId - if (scopeId) { - options._scopeId = scopeId; - } - let hook; - if (moduleIdentifier) { - // server build - hook = function (context) { - // 2.3 injection - context = - context || // cached call - (this.$vnode && this.$vnode.ssrContext) || // stateful - (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext); // functional - // 2.2 with runInNewContext: true - if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') { - context = __VUE_SSR_CONTEXT__; - } - // inject component styles - if (style) { - style.call(this, createInjectorSSR(context)); - } - // register component module identifier for async chunk inference - if (context && context._registeredComponents) { - context._registeredComponents.add(moduleIdentifier); - } - }; - // used by ssr in case component is cached and beforeCreate - // never gets called - options._ssrRegister = hook; - } - else if (style) { - hook = shadowMode - ? function (context) { - style.call(this, createInjectorShadow(context, this.$root.$options.shadowRoot)); - } - : function (context) { - style.call(this, createInjector(context)); - }; - } - if (hook) { - if (options.functional) { - // register for functional component in vue file - const originalRender = options.render; - options.render = function renderWithStyleInjection(h, context) { - hook.call(context); - return originalRender(h, context); - }; - } - else { - // inject component registration as beforeCreate hook - const existing = options.beforeCreate; - options.beforeCreate = existing ? [].concat(existing, hook) : [hook]; - } - } - return script; - } - - const isOldIE = typeof navigator !== 'undefined' && - /msie [6-9]\\b/.test(navigator.userAgent.toLowerCase()); - function createInjector(context) { - return (id, style) => addStyle(id, style); - } - let HEAD; - const styles = {}; - function addStyle(id, css) { - const group = isOldIE ? css.media || 'default' : id; - const style = styles[group] || (styles[group] = { ids: new Set(), styles: [] }); - if (!style.ids.has(id)) { - style.ids.add(id); - let code = css.source; - if (css.map) { - // https://developer.chrome.com/devtools/docs/javascript-debugging - // this makes source maps inside style tags work properly in Chrome - code += '\n/*# sourceURL=' + css.map.sources[0] + ' */'; - // http://stackoverflow.com/a/26603875 - code += - '\n/*# sourceMappingURL=data:application/json;base64,' + - btoa(unescape(encodeURIComponent(JSON.stringify(css.map)))) + - ' */'; - } - if (!style.element) { - style.element = document.createElement('style'); - style.element.type = 'text/css'; - if (css.media) - style.element.setAttribute('media', css.media); - if (HEAD === undefined) { - HEAD = document.head || document.getElementsByTagName('head')[0]; - } - HEAD.appendChild(style.element); - } - if ('styleSheet' in style.element) { - style.styles.push(code); - style.element.styleSheet.cssText = style.styles - .filter(Boolean) - .join('\n'); - } - else { - const index = style.ids.size - 1; - const textNode = document.createTextNode(code); - const nodes = style.element.childNodes; - if (nodes[index]) - style.element.removeChild(nodes[index]); - if (nodes.length) - style.element.insertBefore(textNode, nodes[index]); - else - style.element.appendChild(textNode); - } - } + const _hoisted_1 = /*#__PURE__*/vue.createElementVNode("div", { + id: "app" + }, [/*#__PURE__*/vue.createElementVNode("div", { + id: "iframeEditor" + })], -1 /* HOISTED */); + const _hoisted_2 = [_hoisted_1]; + function render(_ctx, _cache, $props, $setup, $data, $options) { + return vue.openBlock(), vue.createElementBlock("main", null, _hoisted_2); } - /* script */ - const __vue_script__ = script; + function styleInject(css, ref) { + if ( ref === void 0 ) ref = {}; + var insertAt = ref.insertAt; - /* template */ - var __vue_render__ = function () { - var _vm = this; - var _h = _vm.$createElement; - _vm._self._c || _h; - return _vm._m(0) - }; - var __vue_staticRenderFns__ = [ - function () { - var _vm = this; - var _h = _vm.$createElement; - var _c = _vm._self._c || _h; - return _c("main", [ - _c("div", { attrs: { id: "app" } }, [ - _c("div", { attrs: { id: "iframeEditor" } }), - ]), - ]) - }, - ]; - __vue_render__._withStripped = true; + if (!css || typeof document === 'undefined') { return; } - /* style */ - const __vue_inject_styles__ = function (inject) { - if (!inject) return - inject("data-v-404880d3_0", { source: "\n#app {\n width: 100%;\n}\n#app > iframe {\n position: absolute;\n}\n", map: {"version":3,"sources":["D:\\onlyoffice-owncloud-web\\src\\editor.vue"],"names":[],"mappings":";AAoJA;IACA,WAAA;AACA;AACA;IACA,kBAAA;AACA","file":"editor.vue","sourcesContent":["\r\n\r\n\r\n\r\n"]}, media: undefined }); + var head = document.head || document.getElementsByTagName('head')[0]; + var style = document.createElement('style'); + style.type = 'text/css'; - }; - /* scoped */ - const __vue_scope_id__ = undefined; - /* module identifier */ - const __vue_module_identifier__ = undefined; - /* functional template */ - const __vue_is_functional_template__ = false; - /* style inject SSR */ - - /* style inject shadow dom */ - + if (insertAt === 'top') { + if (head.firstChild) { + head.insertBefore(style, head.firstChild); + } else { + head.appendChild(style); + } + } else { + head.appendChild(style); + } - - const __vue_component__ = /*#__PURE__*/normalizeComponent( - { render: __vue_render__, staticRenderFns: __vue_staticRenderFns__ }, - __vue_inject_styles__, - __vue_script__, - __vue_scope_id__, - __vue_is_functional_template__, - __vue_module_identifier__, - false, - createInjector, - undefined, - undefined - ); + if (style.styleSheet) { + style.styleSheet.cssText = css; + } else { + style.appendChild(document.createTextNode(css)); + } + } + + var css_248z = "\n#app {\r\n width: 100%;\n}\n#app > iframe {\r\n position: fixed;\r\n height: calc(100vh - 52px);\r\n right: 0;\n}\r\n"; + styleInject(css_248z); + + script.render = render; + script.__file = "src/editor.vue"; + + /** + * + * (c) Copyright Ascensio System SIA 2023 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ const routes = [{ path: "/editor/:fileId/:filePath/:mode", components: { - fullscreen: __vue_component__ + fullscreen: script }, name: "editor", meta: { @@ -3326,10 +6801,9 @@ define((function () { 'use strict'; menuTitle($gettext) { return $gettext("Document"); }, - icon: "x-office-document" }, - routes: ["files-personal", "files-favorites", "files-shared-with-others", "files-shared-with-me", "files-public-list"] + routes: ["files-spaces-generic", "files-common-favorites", "files-shares-with-others", "files-shares-with-me", "files-trash-generic", "files-public-link"] }, { extension: "xlsx", routeName: "onlyoffice-editor", @@ -3338,10 +6812,9 @@ define((function () { 'use strict'; menuTitle($gettext) { return $gettext("Spreadsheet"); }, - icon: "x-office-spreadsheet" }, - routes: ["files-personal", "files-favorites", "files-shared-with-others", "files-shared-with-me", "files-public-list"] + routes: ["files-spaces-generic", "files-common-favorites", "files-shares-with-others", "files-shares-with-me", "files-trash-generic", "files-public-link"] }, { extension: "pptx", routeName: "onlyoffice-editor", @@ -3350,10 +6823,9 @@ define((function () { 'use strict'; menuTitle($gettext) { return $gettext("Presentation"); }, - icon: "x-office-presentation" }, - routes: ["files-personal", "files-favorites", "files-shared-with-others", "files-shared-with-me", "files-public-list"] + routes: ["files-spaces-generic", "files-common-favorites", "files-shares-with-others", "files-shares-with-me", "files-trash-generic", "files-public-link"] }] }; var app = { From 529fe6e763d8fa67975e954cc85396ff785d13df Mon Sep 17 00:00:00 2001 From: Kseniya Fedoruk Date: Mon, 16 Oct 2023 14:10:45 +0300 Subject: [PATCH 002/114] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 22321fd4..eed9196d 100644 --- a/README.md +++ b/README.md @@ -208,6 +208,8 @@ The instruction on enabling _master key_ based encryption is available in the of ``` To disable this check running, enter 0 value. +* When accessing a document without download permission, file printing and using the system clipboard are not available. Copying and pasting within the editor is available via buttons in the editor toolbar and in the context menu. + ## ONLYOFFICE Docs editions ONLYOFFICE offers different versions of its online document editors that can be deployed on your own servers. From fe6d569b0710722c5e66b3f069576d0b5653dc2e Mon Sep 17 00:00:00 2001 From: Sergey Linnik Date: Fri, 27 Oct 2023 12:12:13 +0300 Subject: [PATCH 003/114] using l10n --- templates/settings.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/settings.php b/templates/settings.php index 94a840cc..c3b810d3 100644 --- a/templates/settings.php +++ b/templates/settings.php @@ -100,7 +100,7 @@
-

ONLYOFFICE Docs Cloud

+

t("ONLYOFFICE Docs Cloud")) ?>

t("Easily launch the editors in the cloud without downloading and installation")) ?>

From ce5687a6ea27dc4581825dfb19fade2822a3dd2b Mon Sep 17 00:00:00 2001 From: Sergey Linnik Date: Mon, 6 Nov 2023 13:56:41 +0300 Subject: [PATCH 004/114] Fix log comment --- controller/editorcontroller.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controller/editorcontroller.php b/controller/editorcontroller.php index b21e6c92..552dd06f 100644 --- a/controller/editorcontroller.php +++ b/controller/editorcontroller.php @@ -1078,7 +1078,7 @@ public function url($filePath) { return ["error" => $this->trans->t("File not found")]; } if (!$file->isReadable()) { - $this->logger->error("Folder for saving file without permission: $dir", ["app" => $this->appName]); + $this->logger->error("File without permission: $dir", ["app" => $this->appName]); return ["error" => $this->trans->t("You do not have enough permissions to view the file")]; } From 62cc9b973f6e4730eb3e0d58e47cef9616203856 Mon Sep 17 00:00:00 2001 From: Maria-Sukhova Date: Wed, 8 Nov 2023 12:58:58 +0300 Subject: [PATCH 005/114] edited zh_CN --- l10n/zh_CN.js | 34 +++++++++++++++++----------------- l10n/zh_CN.json | 34 +++++++++++++++++----------------- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/l10n/zh_CN.js b/l10n/zh_CN.js index f732f498..5c454330 100644 --- a/l10n/zh_CN.js +++ b/l10n/zh_CN.js @@ -2,24 +2,24 @@ OC.L10N.register( "onlyoffice", { "Access denied" : "禁止访问", - "Invalid request" : "非法请求", + "Invalid request": "无效请求", "Files not found" : "文件未找到", "File not found" : "文件未找到", "Not permitted" : "没有权限", "Download failed" : "下载失败", - "The required folder was not found" : "必须的文件夹未找到", - "You don't have enough permission to create" : "没有足够权限创建文件", + "The required folder was not found": "未找到所需文件夹", + "You don't have enough permission to create": "没有足够权限创建文档", "Template not found" : "模板未找到", "Can't create file" : "无法创建文件", - "Format is not supported" : "文件格式不支持", - "Conversion is not required" : "无需文件转换", - "Failed to download converted file" : "转换后的文件下载失败", + "Format is not supported": "格式不支持", + "Conversion is not required": "无需转换", + "Failed to download converted file": "无法下载转换后的文件", "ONLYOFFICE app is not configured. Please contact admin" : "ONLYOFFICE未配置,请联系管理员。", "FileId is empty" : "文件ID为空", "You do not have enough permissions to view the file" : "您没有足够权限浏览该文件", "Error occurred in the document service" : "文档服务内部发生异常", "Not supported version" : "不支持的版本", - "ONLYOFFICE cannot be reached. Please contact admin" : "ONLYOFFICE服务器无法连接,请联系管理员。", + "ONLYOFFICE cannot be reached. Please contact admin": "ONLYOFFICE 服务器无法连接,请联系管理员。", "Loading, please wait." : "载入中,请稍后...", "File created" : "文件已创建", "Open in ONLYOFFICE" : "用 ONLYOFFICE 打开", @@ -27,7 +27,7 @@ OC.L10N.register( "Document" : "文档", "Spreadsheet" : "电子表格", "Presentation" : "演示文稿", - "Error when trying to connect" : "连接是发生异常", + "Error when trying to connect": "连接时发生异常", "Settings have been successfully updated" : "设置已保存", "Server can't read xml" : "服务器无法读取XML", "Bad Response. Errors: " : "错误的返回: ", @@ -36,10 +36,10 @@ OC.L10N.register( "Encryption App is enabled, the application cannot work. You can continue working with the application if you enable master key." : "加密应用程序已启用,应用程序无法工作。如果启用主密钥,则可以继续使用该应用程序。", "ONLYOFFICE Docs address" : "ONLYOFFICE Docs地址", "Advanced server settings" : "更多设置", - "ONLYOFFICE Docs address for internal requests from the server" : "用于服务器内部的ONLYOFFICE Docs的地址", - "Server address for internal requests from ONLYOFFICE Docs" : "用于ONLYOFFICE Docs内部请求的服务器的地址", + "ONLYOFFICE Docs address for internal requests from the server": "服务器内部请求 ONLYOFFICE Docs 的地址", + "Server address for internal requests from ONLYOFFICE Docs": "ONLYOFFICE Docs 内部请求服务器的地址", "Secret key (leave blank to disable)" : "秘钥(留空为关闭)", - "Open file in the same tab" : "在相同的切签中打开", + "Open file in the same tab": "在相同的标签页中打开", "The default application for opening the format": "默认关联的文件格式", "Open the file for editing (due to format restrictions, the data might be lost when saving to the formats from the list below)" : "默认的文件编辑器 (由于文件格式限制,保存为下列格式时,数据可能会缺失)", "View details" : "查看详情", @@ -64,10 +64,10 @@ OC.L10N.register( "File saved" : "文件已保存", "Insert image" : "插入图片", "Select recipients" : "选择接收者", - "Connect to demo ONLYOFFICE Docs server" : "连接到 ONLYOFFICE Docs 服务器的演示", - "This is a public test server, please do not use it for private sensitive data. The server will be available during a 30-day period." : "这是公开的测试服务器,请勿用于隐私数据。服务器试用期限为30天。", - "The 30-day test period is over, you can no longer connect to demo ONLYOFFICE Docs server." : "30天试用期已结束,无法连接ONLYOFFICE Docs 服务器的演示。", - "You are using public demo ONLYOFFICE Docs server. Please do not store private sensitive data." : "您正在使用公开ONLYOFFICE Docs服务器的演示,请勿存储隐私数据。", + "Connect to demo ONLYOFFICE Docs server": "连接到 ONLYOFFICE Docs 演示服务器", + "This is a public test server, please do not use it for private sensitive data. The server will be available during a 30-day period.": "这是公开的测试服务器,请勿存储隐私数据。服务器试用期限为30天。", + "The 30-day test period is over, you can no longer connect to demo ONLYOFFICE Docs server.": "30天试用期已结束,无法连接ONLYOFFICE Docs 演示服务器。", + "You are using public demo ONLYOFFICE Docs server. Please do not store private sensitive data.": "您正在使用 ONLYOFFICE Docs 公开的演示服务器,请勿存储隐私数据。", "Select file to compare" : "选择文件比较", "Review mode for viewing": "审阅模式浏览", "Markup": "修订", @@ -95,11 +95,11 @@ OC.L10N.register( "File has been converted. Its content might look different.": "文件已被转换。其内容可能看起来有所不同。", "Download as": "下载为", "Download": "下载", - "Origin format": "原产地格式", + "Origin format": "原格式", "Failed to send notification": "发送通知失败", "Notification sent successfully": "通知发送成功", "%1\$s mentioned in the %2\$s: \"%3\$s\".": "%1\$s 在 %2\$s: \"%3\$s\"中提到了您.", - "Choose a format to convert {fileName}": "选择要转换{fileName}的格式", + "Choose a format to convert {fileName}": "转换 {fileName} 为选中的格式", "Form template": "表单模板", "Form template from existing text file": "用现有的文本文件创建模板", "Create form": "创建表单", diff --git a/l10n/zh_CN.json b/l10n/zh_CN.json index dec2a79e..100dc87c 100644 --- a/l10n/zh_CN.json +++ b/l10n/zh_CN.json @@ -1,23 +1,23 @@ { "translations": { "Access denied" : "禁止访问", - "Invalid request" : "非法请求", + "Invalid request" : "无效请求", "Files not found" : "文件未找到", "File not found" : "文件未找到", "Not permitted" : "没有权限", "Download failed" : "下载失败", - "The required folder was not found" : "必须的文件夹未找到", - "You don't have enough permission to create" : "没有足够权限创建文件", + "The required folder was not found" : "未找到所需文件夹", + "You don't have enough permission to create" : "没有足够权限创建文档", "Template not found" : "模板未找到", "Can't create file" : "无法创建文件", - "Format is not supported" : "文件格式不支持", - "Conversion is not required" : "无需文件转换", - "Failed to download converted file" : "转换后的文件下载失败", + "Format is not supported" : "格式不支持", + "Conversion is not required" : "无需转换", + "Failed to download converted file" : "无法下载转换后的文件", "ONLYOFFICE app is not configured. Please contact admin" : "ONLYOFFICE未配置,请联系管理员。", "FileId is empty" : "文件ID为空", "You do not have enough permissions to view the file" : "您没有足够权限浏览该文件", "Error occurred in the document service" : "文档服务内部发生异常", "Not supported version" : "不支持的版本", - "ONLYOFFICE cannot be reached. Please contact admin" : "ONLYOFFICE服务器无法连接,请联系管理员。", + "ONLYOFFICE cannot be reached. Please contact admin" : "ONLYOFFICE 服务器无法连接,请联系管理员。", "Loading, please wait." : "载入中,请稍后...", "File created" : "文件已创建", "Open in ONLYOFFICE" : "用 ONLYOFFICE 打开", @@ -25,7 +25,7 @@ "Document" : "文档", "Spreadsheet" : "电子表格", "Presentation" : "演示文稿", - "Error when trying to connect" : "连接是发生异常", + "Error when trying to connect" : "连接时发生异常", "Settings have been successfully updated" : "设置已保存", "Server can't read xml" : "服务器无法读取XML", "Bad Response. Errors: " : "错误的返回: ", @@ -34,10 +34,10 @@ "Encryption App is enabled, the application cannot work. You can continue working with the application if you enable master key." : "加密应用程序已启用,应用程序无法工作。如果启用主密钥,则可以继续使用该应用程序。", "ONLYOFFICE Docs address" : "ONLYOFFICE Docs地址", "Advanced server settings" : "更多设置", - "ONLYOFFICE Docs address for internal requests from the server" : "用于服务器内部的ONLYOFFICE Docs的地址", - "Server address for internal requests from ONLYOFFICE Docs" : "用于ONLYOFFICE Docs内部请求的服务器的地址", + "ONLYOFFICE Docs address for internal requests from the server" : "服务器内部请求 ONLYOFFICE Docs 的地址", + "Server address for internal requests from ONLYOFFICE Docs" : "ONLYOFFICE Docs 内部请求服务器的地址", "Secret key (leave blank to disable)" : "秘钥(留空为关闭)", - "Open file in the same tab" : "在相同的切签中打开", + "Open file in the same tab" : "在相同的标签页中打开", "The default application for opening the format": "默认关联的文件格式", "Open the file for editing (due to format restrictions, the data might be lost when saving to the formats from the list below)" : "默认的文件编辑器 (由于文件格式限制,保存为下列格式时,数据可能会缺失)", "View details" : "查看详情", @@ -62,10 +62,10 @@ "File saved" : "文件已保存", "Insert image" : "插入图片", "Select recipients" : "选择接收者", - "Connect to demo ONLYOFFICE Docs server" : "连接到 ONLYOFFICE Docs 服务器的演示", - "This is a public test server, please do not use it for private sensitive data. The server will be available during a 30-day period." : "这是公开的测试服务器,请勿用于隐私数据。服务器试用期限为30天。", - "The 30-day test period is over, you can no longer connect to demo ONLYOFFICE Docs server." : "30天试用期已结束,无法连接ONLYOFFICE Docs 服务器的演示。", - "You are using public demo ONLYOFFICE Docs server. Please do not store private sensitive data." : "您正在使用公开ONLYOFFICE Docs服务器的演示,请勿存储隐私数据。", + "Connect to demo ONLYOFFICE Docs server" : "连接到 ONLYOFFICE Docs 演示服务器", + "This is a public test server, please do not use it for private sensitive data. The server will be available during a 30-day period." : "这是公开的测试服务器,请勿存储隐私数据。服务器试用期限为30天。", + "The 30-day test period is over, you can no longer connect to demo ONLYOFFICE Docs server." : "30天试用期已结束,无法连接ONLYOFFICE Docs 演示服务器。", + "You are using public demo ONLYOFFICE Docs server. Please do not store private sensitive data." : "您正在使用 ONLYOFFICE Docs 公开的演示服务器,请勿存储隐私数据。", "Select file to compare" : "选择文件比较", "Review mode for viewing": "审阅模式浏览", "Markup": "修订", @@ -93,11 +93,11 @@ "File has been converted. Its content might look different.": "文件已被转换。其内容可能看起来有所不同。", "Download as": "下载为", "Download": "下载", - "Origin format": "原产地格式", + "Origin format": "原格式", "Failed to send notification": "发送通知失败", "Notification sent successfully": "通知发送成功", "%1$s mentioned in the %2$s: \"%3$s\".": "%1$s 在 %2$s: \"%3$s\"中提到了您.", - "Choose a format to convert {fileName}": "选择要转换{fileName}的格式", + "Choose a format to convert {fileName}": "转换 {fileName} 为选中的格式", "Form template": "表单模板", "Form template from existing text file": "用现有的文本文件创建模板", "Create form": "创建表单", From 1d52a1b87b5fe1c684bc0e034a4b08e5c1ac9df6 Mon Sep 17 00:00:00 2001 From: Maria-Sukhova Date: Thu, 30 Nov 2023 18:25:35 +0300 Subject: [PATCH 006/114] updated sv, pl, nl --- l10n/nl.js | 14 +++++++++++++- l10n/nl.json | 14 +++++++++++++- l10n/pl.js | 16 +++++++++++++++- l10n/pl.json | 16 +++++++++++++++- l10n/sv.js | 15 ++++++++++++++- l10n/sv.json | 15 ++++++++++++++- 6 files changed, 84 insertions(+), 6 deletions(-) diff --git a/l10n/nl.js b/l10n/nl.js index b050da28..c0157064 100644 --- a/l10n/nl.js +++ b/l10n/nl.js @@ -111,6 +111,18 @@ OC.L10N.register( "Default editor theme": "Standaard editor thema", "Light": "Licht", "Classic Light": "Klassiek Licht", - "Dark": "Donker" + "Dark": "Donker", + "This feature is unavailable due to encryption settings.": "Deze functie is niet beschikbaar vanwege versleutelingsinstellingen.", + "Enable plugins": "Plug-ins inschakelen", + "Enable document protection for": "Documentbeveiliging inschakelen voor", + "All users": "Alle gebruikers", + "Owner only": "Alleen eigenaar", + "Authorization header (leave blank to use default header)": "Autorisatieheader (laat leeg om de standaard header te gebruiken)", + "ONLYOFFICE server is not available": "ONLYOFFICE server is niet beschikbaar", + "Please check the settings to resolve the problem.": "Controleer de instellingen om het probleem op te lossen.", + "View settings": "Bekijk instellingen", + "ONLYOFFICE Docs Cloud": "ONLYOFFICE Docs Cloud", + "Easily launch the editors in the cloud without downloading and installation": "Start de editors gemakkelijk in de cloud zonder te hoeven downloaden en te installeren", + "Get Now": "Download Nu" }, "nplurals=2; plural=(n != 1);"); diff --git a/l10n/nl.json b/l10n/nl.json index c17c867a..96f55b0f 100644 --- a/l10n/nl.json +++ b/l10n/nl.json @@ -109,6 +109,18 @@ "Default editor theme": "Standaard editor thema", "Light": "Licht", "Classic Light": "Klassiek Licht", - "Dark": "Donker" + "Dark": "Donker", + "This feature is unavailable due to encryption settings.": "Deze functie is niet beschikbaar vanwege versleutelingsinstellingen.", + "Enable plugins": "Plug-ins inschakelen", + "Enable document protection for": "Documentbeveiliging inschakelen voor", + "All users": "Alle gebruikers", + "Owner only": "Alleen eigenaar", + "Authorization header (leave blank to use default header)": "Autorisatieheader (laat leeg om de standaard header te gebruiken)", + "ONLYOFFICE server is not available": "ONLYOFFICE server is niet beschikbaar", + "Please check the settings to resolve the problem.": "Controleer de instellingen om het probleem op te lossen.", + "View settings": "Bekijk instellingen", + "ONLYOFFICE Docs Cloud": "ONLYOFFICE Docs Cloud", + "Easily launch the editors in the cloud without downloading and installation": "Start de editors gemakkelijk in de cloud zonder te hoeven downloaden en te installeren", + "Get Now": "Download Nu" },"pluralForm" :"nplurals=2; plural=(n != 1);" } \ No newline at end of file diff --git a/l10n/pl.js b/l10n/pl.js index 6a54a02f..15646175 100644 --- a/l10n/pl.js +++ b/l10n/pl.js @@ -107,8 +107,22 @@ OC.L10N.register( "Create new Form template": "Utwórz nowy szablon formularza", "Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online": "Zaktualizuj ONLYOFFICE Docs do wersji 7.0, aby działały w formularzach do wypełniania online", "Security": "Bezpieczeństwo", + "Run document macros": "Uruchom makra dokumentu", + "Default editor theme": "Domyślny motyw edytora", "Light": "Jasny", "Classic Light": "Klasyczny jasny", - "Dark": "Ciemny" + "Dark": "Ciemny", + "This feature is unavailable due to encryption settings.": "Dana funkcja jest niedostępna ze względu na ustawienia szyfrowania.", + "Enable plugins": "Włącz wtyczki", + "Enable document protection for": "Włącz ochronę dokumentów dla", + "All users": "Wszystkich użytkowników", + "Owner only": "Tylko właściciela", + "Authorization header (leave blank to use default header)": "Nagłówek autoryzacji (pozostaw puste pole, aby użyć domyślnego nagłówka)", + "ONLYOFFICE server is not available": "Serwer ONLYOFFICE jest niedostępny", + "Please check the settings to resolve the problem.": "Sprawdź ustawienia, aby rozwiązać problem.", + "View settings": "Zobacz ustawienia", + "ONLYOFFICE Docs Cloud": "ONLYOFFICE Docs Cloud", + "Easily launch the editors in the cloud without downloading and installation": "Z łatwością uruchamiaj edytory w chmurze bez konieczności pobierania czy instalacji", + "Get Now": "Wypróbuj teraz" }, "nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);"); \ No newline at end of file diff --git a/l10n/pl.json b/l10n/pl.json index d16a3835..d76aa75f 100644 --- a/l10n/pl.json +++ b/l10n/pl.json @@ -105,8 +105,22 @@ "Create new Form template": "Utwórz nowy szablon formularza", "Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online": "Zaktualizuj ONLYOFFICE Docs do wersji 7.0, aby działały w formularzach do wypełniania online", "Security": "Bezpieczeństwo", + "Run document macros": "Uruchom makra dokumentu", + "Default editor theme": "Domyślny motyw edytora", "Light": "Jasny", "Classic Light": "Klasyczny jasny", - "Dark": "Ciemny" + "Dark": "Ciemny", + "This feature is unavailable due to encryption settings.": "Dana funkcja jest niedostępna ze względu na ustawienia szyfrowania.", + "Enable plugins": "Włącz wtyczki", + "Enable document protection for": "Włącz ochronę dokumentów dla", + "All users": "Wszystkich użytkowników", + "Owner only": "Tylko właściciela", + "Authorization header (leave blank to use default header)" : "Nagłówek autoryzacji (pozostaw puste pole, aby użyć domyślnego nagłówka)", + "ONLYOFFICE server is not available": "Serwer ONLYOFFICE jest niedostępny", + "Please check the settings to resolve the problem.": "Sprawdź ustawienia, aby rozwiązać problem.", + "View settings": "Zobacz ustawienia", + "ONLYOFFICE Docs Cloud": "ONLYOFFICE Docs Cloud", + "Easily launch the editors in the cloud without downloading and installation": "Z łatwością uruchamiaj edytory w chmurze bez konieczności pobierania czy instalacji", + "Get Now": "Wypróbuj teraz" },"pluralForm" :"nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);" } \ No newline at end of file diff --git a/l10n/sv.js b/l10n/sv.js index 9f5a7164..8e405982 100644 --- a/l10n/sv.js +++ b/l10n/sv.js @@ -107,8 +107,21 @@ OC.L10N.register( "Create new Form template": "Skapa ny formulärmall", "Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online": "Uppdatera ONLYOFFICE Docs till version 7.0 för att arbeta med ifyllbart onlineformulär", "Security": "Säkerhet", + "Run document macros": "Kör dokumentmakron", "Light": "Ljus", "Classic Light": "Klassiskt ljus", - "Dark": "Mörk" + "Dark": "Mörk", + "This feature is unavailable due to encryption settings.": "Denna funktion är otillgänglig på grund av krypteringsinställningar.", + "Enable plugins": "Aktivera plugins", + "Enable document protection for": "Aktivera dokumentsskydd för", + "All users": "Alla användare", + "Owner only": "Endast ägaren", + "Authorization header (leave blank to use default header)": "Autentiseringshuvud (lämna tom för att använda standardhuvud)", + "ONLYOFFICE server is not available": "ONLYOFFICE-servern är inte tillgänglig", + "Please check the settings to resolve the problem.": "Kontrollera inställningarna för att åtgärda problemet.", + "View settings": "Visa inställningar", + "ONLYOFFICE Docs Cloud": "ONLYOFFICE Docs-moln", + "Easily launch the editors in the cloud without downloading and installation": "Starta redigerarna i molnet enkelt utan nedladdning och installation", + "Get Now": "Skaffa nu" }, "nplurals=2; plural=(n != 1);"); diff --git a/l10n/sv.json b/l10n/sv.json index 82483a92..e1fa4f18 100644 --- a/l10n/sv.json +++ b/l10n/sv.json @@ -105,8 +105,21 @@ "Create new Form template": "Skapa ny formulärmall", "Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online": "Uppdatera ONLYOFFICE Docs till version 7.0 för att arbeta med ifyllbart onlineformulär", "Security": "Säkerhet", + "Run document macros": "Kör dokumentmakron", "Light": "Ljus", "Classic Light": "Klassiskt ljus", - "Dark": "Mörk" + "Dark": "Mörk", + "This feature is unavailable due to encryption settings.": "Denna funktion är otillgänglig på grund av krypteringsinställningar.", + "Enable plugins": "Aktivera plugins", + "Enable document protection for": "Aktivera dokumentsskydd för", + "All users": "Alla användare", + "Owner only": "Endast ägaren", + "Authorization header (leave blank to use default header)" : "Autentiseringshuvud (lämna tom för att använda standardhuvud)", + "ONLYOFFICE server is not available": "ONLYOFFICE-servern är inte tillgänglig", + "Please check the settings to resolve the problem.": "Kontrollera inställningarna för att åtgärda problemet.", + "View settings": "Visa inställningar", + "ONLYOFFICE Docs Cloud": "ONLYOFFICE Docs-moln", + "Easily launch the editors in the cloud without downloading and installation": "Starta redigerarna i molnet enkelt utan nedladdning och installation", + "Get Now": "Skaffa nu" },"pluralForm" :"nplurals=2; plural=(n != 1);" } \ No newline at end of file From cebc9c971c38a661e24dc985ffb68f8d8c309788 Mon Sep 17 00:00:00 2001 From: Kseniya Fedoruk Date: Fri, 8 Dec 2023 13:37:13 +0300 Subject: [PATCH 007/114] Update README.md --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 22321fd4..891ffaf2 100644 --- a/README.md +++ b/README.md @@ -272,12 +272,18 @@ The table below will help you to make the right choice. | Font and paragraph formatting | + | + | | Object insertion | + | + | | Transitions | + | + | +| Animations | + | + | | Presenter mode | + | + | | Notes | + | + | | **Form creator features** | **Community Edition** | **Enterprise Edition** | | Adding form fields | + | + | | Form preview | + | + | | Saving as PDF | + | + | +| **Working with PDF** | **Community Edition** | **Enterprise Edition** | +| Text annotations (highlight, underline, cross out) | + | + | +| Comments | + | + | +| Freehand drawings | + | + | +| Form filling | + | + | | | [Get it now](https://www.onlyoffice.com/download-docs.aspx?utm_source=github&utm_medium=cpc&utm_campaign=GitHubOwncloud#docs-community) | [Start Free Trial](https://www.onlyoffice.com/download-docs.aspx?utm_source=github&utm_medium=cpc&utm_campaign=GitHubOwncloud#docs-enterprise) | \* If supported by DMS. From 5fd9f3b43672b20931929f0be5133d710ce52f43 Mon Sep 17 00:00:00 2001 From: rivexe Date: Fri, 15 Dec 2023 12:32:15 +0300 Subject: [PATCH 008/114] if jwt header is used, show advanced settings --- js/settings.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/js/settings.js b/js/settings.js index c3a53c31..f60bd02b 100644 --- a/js/settings.js +++ b/js/settings.js @@ -29,7 +29,8 @@ }; if ($("#onlyofficeInternalUrl").val().length - || $("#onlyofficeStorageUrl").val().length) { + || $("#onlyofficeStorageUrl").val().length + || $("#onlyofficeJwtHeader").val().length) { advToogle(); } From d74e938e53162e19aba663cf4a5eee3a9ecfc204 Mon Sep 17 00:00:00 2001 From: rivexe Date: Mon, 18 Dec 2023 13:40:11 +0300 Subject: [PATCH 009/114] PSR-1, same position of braces after function and oop-constructs --- appinfo/application.php | 1 - controller/callbackcontroller.php | 3 --- controller/editorapicontroller.php | 14 ++++------- controller/editorcontroller.php | 4 ---- controller/federationcontroller.php | 1 - controller/joblistcontroller.php | 1 - controller/settingsapicontroller.php | 1 - controller/settingscontroller.php | 4 ---- controller/templatecontroller.php | 2 -- controller/webassetcontroller.php | 1 - lib/adminsettings.php | 1 - lib/appconfig.php | 5 +--- lib/command/documentserver.php | 13 +++++------ lib/cron/editorscheck.php | 4 +--- lib/crypt.php | 1 - lib/documentservice.php | 15 ++---------- lib/fileutility.php | 8 ++----- lib/fileversions.php | 1 - lib/hookhandler.php | 1 - lib/hooks.php | 1 - lib/keymanager.php | 1 - lib/notifier.php | 1 - lib/preview.php | 2 -- lib/remoteinstance.php | 1 - lib/templatemanager.php | 1 - lib/versionmanager.php | 35 ++++++++++++++-------------- templates/editor.php | 6 ++--- templates/settings.php | 8 +++---- 28 files changed, 40 insertions(+), 97 deletions(-) diff --git a/appinfo/application.php b/appinfo/application.php index 3e0b9eaf..47e87bbf 100644 --- a/appinfo/application.php +++ b/appinfo/application.php @@ -42,7 +42,6 @@ use OCA\Onlyoffice\Preview; class Application extends App { - /** * Application configuration * diff --git a/controller/callbackcontroller.php b/controller/callbackcontroller.php index 05704c9f..11cd2aa5 100644 --- a/controller/callbackcontroller.php +++ b/controller/callbackcontroller.php @@ -52,7 +52,6 @@ * Save the file without authentication. */ class CallbackController extends Controller { - /** * Root folder * @@ -177,7 +176,6 @@ public function __construct($AppName, * @CORS */ public function download($doc) { - list ($hashData, $error) = $this->crypt->ReadHash($doc); if ($hashData === null) { $this->logger->error("Download with empty or not correct hash: $error", ["app" => $this->appName]); @@ -390,7 +388,6 @@ public function emptyfile($doc) { * @CORS */ public function track($doc, $users, $key, $status, $url, $token, $history, $changesurl, $forcesavetype, $actions, $filetype) { - list ($hashData, $error) = $this->crypt->ReadHash($doc); if ($hashData === null) { $this->logger->error("Track with empty or not correct hash: $error", ["app" => $this->appName]); diff --git a/controller/editorapicontroller.php b/controller/editorapicontroller.php index c836127c..5bde4c42 100644 --- a/controller/editorapicontroller.php +++ b/controller/editorapicontroller.php @@ -49,7 +49,6 @@ * Controller with the main functions */ class EditorApiController extends OCSController { - /** * Current user session * @@ -241,7 +240,6 @@ public function fillempty($fileId) { * @CORS */ public function config($fileId, $filePath = null, $shareToken = null, $version = 0, $inframe = false, $desktop = false, $template = false, $anchor = null) { - $user = $this->userSession->getUser(); $userId = null; $accountId = null; @@ -316,8 +314,7 @@ public function config($fileId, $filePath = null, $shareToken = null, $version = $fileStorage = $file->getStorage(); if (empty($shareToken) && $fileStorage->instanceOfStorage("\OCA\Files_Sharing\SharedStorage")) { $storageShare = $fileStorage->getShare(); - if (method_exists($storageShare, "getAttributes")) - { + if (method_exists($storageShare, "getAttributes")) { $attributes = $storageShare->getAttributes(); $permissionsDownload = $attributes->getAttribute("permissions", "download"); @@ -362,7 +359,6 @@ public function config($fileId, $filePath = null, $shareToken = null, $version = if ($version < 1 && (\OC::$server->getConfig()->getAppValue("files", "enable_lock_file_action", "no") === "yes") && $fileStorage->instanceOfStorage(IPersistentLockingStorage::class)) { - $locks = $fileStorage->getLocks($file->getFileInfo()->getInternalPath(), false); if (count($locks) > 0) { $activeLock = $locks[0]; @@ -421,7 +417,6 @@ public function config($fileId, $filePath = null, $shareToken = null, $version = && $file->isUpdateable() && !$isPersistentLock && (empty($shareToken) || ($share->getPermissions() & Constants::PERMISSION_UPDATE) === Constants::PERMISSION_UPDATE)) { - $params["document"]["permissions"]["changeHistory"] = true; } @@ -490,7 +485,7 @@ public function config($fileId, $filePath = null, $shareToken = null, $version = $templatesList = TemplateManager::GetGlobalTemplates($file->getMimeType()); if (!empty($templatesList)) { $templates = []; - foreach($templatesList as $templateItem) { + foreach ($templatesList as $templateItem) { $createParam["templateId"] = $templateItem->getId(); $createParam["name"] = $templateItem->getName(); @@ -616,7 +611,6 @@ private function getFile($userId, $fileId, $filePath = null, $template = false) * @return string */ private function getUrl($file, $user = null, $shareToken = null, $version = 0, $changes = false, $template = false) { - $data = [ "action" => "download", "fileId" => $file->getId() @@ -714,12 +708,12 @@ private function setCustomization($params) { } //default is true - if($this->config->GetCustomizationMacros() === false) { + if ($this->config->GetCustomizationMacros() === false) { $params["editorConfig"]["customization"]["macros"] = false; } //default is true - if($this->config->GetCustomizationPlugins() === false) { + if ($this->config->GetCustomizationPlugins() === false) { $params["editorConfig"]["customization"]["plugins"] = false; } diff --git a/controller/editorcontroller.php b/controller/editorcontroller.php index 552dd06f..c26c095d 100644 --- a/controller/editorcontroller.php +++ b/controller/editorcontroller.php @@ -55,7 +55,6 @@ * Controller with the main functions */ class EditorController extends Controller { - /** * Current user session * @@ -498,7 +497,6 @@ public function mention($fileId, $anchor, $comment, $emails) { if (!$isAvailable && $file->getFileInfo()->getMountPoint() instanceof \OCA\Files_External\Config\ExternalMountPoint) { - $recipientFolder = $this->root->getUserFolder($recipientId); $recipientFile = $recipientFolder->getById($file->getId()); @@ -972,7 +970,6 @@ public function version($fileId, $version) { if ($version > 1 && count($versions) >= $version - 1 && FileVersions::hasChanges($ownerId, $fileId, $versionId)) { - $changesUrl = $this->getUrl($file, $user, null, $version, true); $result["changesUrl"] = $changesUrl; @@ -1338,7 +1335,6 @@ private function getFile($userId, $fileId, $filePath = null, $template = false) * @return string */ private function getUrl($file, $user = null, $shareToken = null, $version = 0, $changes = false, $template = false) { - $data = [ "action" => "download", "fileId" => $file->getId() diff --git a/controller/federationcontroller.php b/controller/federationcontroller.php index f6526b68..1914cc45 100644 --- a/controller/federationcontroller.php +++ b/controller/federationcontroller.php @@ -38,7 +38,6 @@ * OCS handler */ class FederationController extends OCSController { - /** * Logger * diff --git a/controller/joblistcontroller.php b/controller/joblistcontroller.php index c2722692..97e71627 100644 --- a/controller/joblistcontroller.php +++ b/controller/joblistcontroller.php @@ -39,7 +39,6 @@ * @package OCA\Onlyoffice\Controller */ class JobListController extends Controller { - /** * Logger * diff --git a/controller/settingsapicontroller.php b/controller/settingsapicontroller.php index cc9521f8..b684c90e 100644 --- a/controller/settingsapicontroller.php +++ b/controller/settingsapicontroller.php @@ -30,7 +30,6 @@ * Settings controller for the administration page */ class SettingsApiController extends OCSController { - /** * Url generator service * diff --git a/controller/settingscontroller.php b/controller/settingscontroller.php index 5e112e51..65c06dd5 100644 --- a/controller/settingscontroller.php +++ b/controller/settingscontroller.php @@ -36,7 +36,6 @@ * Settings controller for the administration page */ class SettingsController extends Controller { - /** * l10n service * @@ -232,7 +231,6 @@ public function SaveCommon($defFormats, $reviewDisplay, $theme ) { - $this->config->SetDefaultFormats($defFormats); $this->config->SetEditableFormats($editFormats); $this->config->SetSameTab($sameTab); @@ -265,7 +263,6 @@ public function SaveSecurity($plugins, $macros, $protection ) { - $this->config->SetCustomizationPlugins($plugins); $this->config->SetCustomizationMacros($macros); $this->config->SetProtection($protection); @@ -280,7 +277,6 @@ public function SaveSecurity($plugins, * @return array */ public function ClearHistory() { - FileVersions::clearHistory(); return [ diff --git a/controller/templatecontroller.php b/controller/templatecontroller.php index d9977750..b87238ae 100644 --- a/controller/templatecontroller.php +++ b/controller/templatecontroller.php @@ -30,7 +30,6 @@ * Template controller for template manage */ class TemplateController extends Controller { - /** * l10n service * @@ -90,7 +89,6 @@ public function GetTemplates() { * @return array */ public function AddTemplate() { - $file = $this->request->getUploadedFile("file"); if (!is_null($file)) { diff --git a/controller/webassetcontroller.php b/controller/webassetcontroller.php index 200db7c4..b5b9e3b9 100644 --- a/controller/webassetcontroller.php +++ b/controller/webassetcontroller.php @@ -33,7 +33,6 @@ * @package OCA\Onlyoffice\Controller */ class WebAssetController extends Controller { - /** * @var ILogger */ diff --git a/lib/adminsettings.php b/lib/adminsettings.php index 84994fa3..79b68135 100644 --- a/lib/adminsettings.php +++ b/lib/adminsettings.php @@ -25,7 +25,6 @@ * Settings controller for the administration page */ class AdminSettings implements ISettings { - public function __construct() { } diff --git a/lib/appconfig.php b/lib/appconfig.php index 0dd9b699..0d585bc6 100644 --- a/lib/appconfig.php +++ b/lib/appconfig.php @@ -31,7 +31,6 @@ * @package OCA\Onlyoffice */ class AppConfig { - /** * Application name * @@ -309,7 +308,6 @@ class AppConfig { * @param string $AppName - application name */ public function __construct($AppName) { - $this->appName = $AppName; $this->config = \OC::$server->getConfig(); @@ -501,8 +499,7 @@ public function ReplaceDocumentServerUrlToInternal($url) { $from = $parsedUrl["scheme"] . "://" . $parsedUrl["host"] . (array_key_exists("port", $parsedUrl) ? (":" . $parsedUrl["port"]) : "") . $from; } - if ($from !== $documentServerUrl) - { + if ($from !== $documentServerUrl) { $this->logger->debug("Replace url from $from to $documentServerUrl", ["app" => $this->appName]); $url = str_replace($from, $documentServerUrl, $url); } diff --git a/lib/command/documentserver.php b/lib/command/documentserver.php index 4e750ed4..0be5d368 100644 --- a/lib/command/documentserver.php +++ b/lib/command/documentserver.php @@ -32,7 +32,6 @@ use OCA\Onlyoffice\Crypt; class DocumentServer extends Command { - /** * Application configuration * @@ -86,9 +85,9 @@ protected function configure() { ->setName("onlyoffice:documentserver") ->setDescription("Manage document server") ->addOption("check", - null, - InputOption::VALUE_NONE, - "Check connection document server"); + null, + InputOption::VALUE_NONE, + "Check connection document server"); } /** @@ -103,18 +102,18 @@ protected function execute(InputInterface $input, OutputInterface $output) { $check = $input->getOption("check"); $documentserver = $this->config->GetDocumentServerUrl(true); - if(empty($documentserver)) { + if (empty($documentserver)) { $output->writeln("Document server is not configured"); return 1; } - if($check) { + if ($check) { $documentService = new DocumentService($this->trans, $this->config); list ($error, $version) = $documentService->checkDocServiceUrl($this->urlGenerator, $this->crypt); $this->config->SetSettingsError($error); - if(!empty($error)) { + if (!empty($error)) { $output->writeln("Error connection: $error"); return 1; } else { diff --git a/lib/cron/editorscheck.php b/lib/cron/editorscheck.php index c826bcfd..2be7644a 100644 --- a/lib/cron/editorscheck.php +++ b/lib/cron/editorscheck.php @@ -37,7 +37,6 @@ * */ class EditorsCheck extends TimedJob { - /** * Application name * @@ -134,7 +133,7 @@ protected function run($argument) { $host = parse_url($fileUrl)["host"]; if ($host === "localhost" || $host === "127.0.0.1") { $this->logger->debug("Localhost is not alowed for cron editors availability check. Please provide server address for internal requests from ONLYOFFICE Docs", ["app" => $this->appName]); - return; + return; } $this->logger->debug("ONLYOFFICE check started by cron", ["app" => $this->appName]); @@ -188,5 +187,4 @@ private function notifyAdmins() { $notificationManager->notify($notification); } } - } diff --git a/lib/crypt.php b/lib/crypt.php index 5b81ab40..730b2932 100644 --- a/lib/crypt.php +++ b/lib/crypt.php @@ -27,7 +27,6 @@ * @package OCA\Onlyoffice */ class Crypt { - /** * Application configuration * diff --git a/lib/documentservice.php b/lib/documentservice.php index ead9d9d4..f7fc2012 100644 --- a/lib/documentservice.php +++ b/lib/documentservice.php @@ -29,7 +29,6 @@ * @package OCA\Onlyoffice */ class DocumentService { - /** * Application name * @@ -173,12 +172,12 @@ function SendRequestToConvertService($document_uri, $from_extension, $to_extensi libxml_use_internal_errors(true); if (!function_exists("simplexml_load_file")) { - throw new \Exception($this->trans->t("Server can't read xml")); + throw new \Exception($this->trans->t("Server can't read xml")); } $response_data = simplexml_load_string($response_xml_data); if (!$response_data) { $exc = $this->trans->t("Bad Response. Errors: "); - foreach(libxml_get_errors() as $error) { + foreach (libxml_get_errors() as $error) { $exc = $exc . "\t" . $error->message; } throw new \Exception ($exc); @@ -242,7 +241,6 @@ function ProcessConvServResponceError($errorCode) { * @return bool */ function HealthcheckRequest() { - $documentServerUrl = $this->config->GetDocumentServerInternalUrl(); if (empty($documentServerUrl)) { @@ -264,7 +262,6 @@ function HealthcheckRequest() { * @return array */ function CommandRequest($method) { - $documentServerUrl = $this->config->GetDocumentServerInternalUrl(); if (empty($documentServerUrl)) { @@ -381,31 +378,26 @@ public function checkDocServiceUrl($urlGenerator, $crypt) { $version = null; try { - if (preg_match("/^https:\/\//i", $urlGenerator->getAbsoluteURL("/")) && preg_match("/^http:\/\//i", $this->config->GetDocumentServerUrl())) { throw new \Exception($this->trans->t("Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required.")); } - } catch (\Exception $e) { $logger->logException($e, ["message" => "Protocol on check error", "app" => self::$appName]); return [$e->getMessage(), $version]; } try { - $healthcheckResponse = $this->HealthcheckRequest(); if (!$healthcheckResponse) { throw new \Exception($this->trans->t("Bad healthcheck status")); } - } catch (\Exception $e) { $logger->logException($e, ["message" => "HealthcheckRequest on check error", "app" => self::$appName]); return [$e->getMessage(), $version]; } try { - $commandResponse = $this->CommandRequest("version"); $logger->debug("CommandRequest on check: " . json_encode($commandResponse), ["app" => self::$appName]); @@ -419,7 +411,6 @@ public function checkDocServiceUrl($urlGenerator, $crypt) { if ($versionF > 0.0 && $versionF <= 6.0) { throw new \Exception($this->trans->t("Not supported version")); } - } catch (\Exception $e) { $logger->logException($e, ["message" => "CommandRequest on check error", "app" => self::$appName]); return [$e->getMessage(), $version]; @@ -427,7 +418,6 @@ public function checkDocServiceUrl($urlGenerator, $crypt) { $convertedFileUri = null; try { - $hashUrl = $crypt->GetHash(["action" => "empty"]); $fileUrl = $urlGenerator->linkToRouteAbsolute(self::$appName . ".callback.emptyfile", ["doc" => $hashUrl]); if (!$this->config->UseDemo() && !empty($this->config->GetStorageUrl())) { @@ -435,7 +425,6 @@ public function checkDocServiceUrl($urlGenerator, $crypt) { } $convertedFileUri = $this->GetConvertedUri($fileUrl, "docx", "docx", "check_" . rand()); - } catch (\Exception $e) { $logger->logException($e, ["message" => "GetConvertedUri on check error", "app" => self::$appName]); return [$e->getMessage(), $version]; diff --git a/lib/fileutility.php b/lib/fileutility.php index 29b61406..d7e0d06a 100644 --- a/lib/fileutility.php +++ b/lib/fileutility.php @@ -38,7 +38,6 @@ * @package OCA\Onlyoffice */ class FileUtility { - /** * Application name * @@ -222,7 +221,6 @@ public function getKey($file, $origin = false) { if ($origin && RemoteInstance::isRemoteFile($file)) { - $key = RemoteInstance::getRemoteKey($file); if (!empty($key)) { return $key; @@ -272,10 +270,8 @@ public function hasPermissionAttribute($file, $attribute = "download") { * * @return string */ - private function GUID() - { - if (function_exists("com_create_guid") === true) - { + private function GUID() { + if (function_exists("com_create_guid") === true) { return trim(com_create_guid(), "{}"); } diff --git a/lib/fileversions.php b/lib/fileversions.php index c0eb145d..77bdb8e0 100644 --- a/lib/fileversions.php +++ b/lib/fileversions.php @@ -34,7 +34,6 @@ * @package OCA\Onlyoffice */ class FileVersions { - /** * Application name * diff --git a/lib/hookhandler.php b/lib/hookhandler.php index 175c9f14..d2dd7242 100644 --- a/lib/hookhandler.php +++ b/lib/hookhandler.php @@ -31,7 +31,6 @@ * @package OCA\Onlyoffice */ class HookHandler { - public static function PublicPage() { $appName = "onlyoffice"; diff --git a/lib/hooks.php b/lib/hooks.php index 2a3eaac0..ae86d445 100644 --- a/lib/hooks.php +++ b/lib/hooks.php @@ -32,7 +32,6 @@ * @package OCA\Onlyoffice */ class Hooks { - /** * Application name * diff --git a/lib/keymanager.php b/lib/keymanager.php index 8c76bfee..70f84a4b 100644 --- a/lib/keymanager.php +++ b/lib/keymanager.php @@ -25,7 +25,6 @@ * @package OCA\Onlyoffice */ class KeyManager { - /** * Table name */ diff --git a/lib/notifier.php b/lib/notifier.php index 42773a4b..97a3ca41 100644 --- a/lib/notifier.php +++ b/lib/notifier.php @@ -27,7 +27,6 @@ use OCP\Notification\INotifier; class Notifier implements INotifier { - /** * Application name * diff --git a/lib/preview.php b/lib/preview.php index 026da674..3bf456f6 100644 --- a/lib/preview.php +++ b/lib/preview.php @@ -45,7 +45,6 @@ * @package OCA\Onlyoffice */ class Preview implements IProvider2 { - /** * Application name * @@ -302,7 +301,6 @@ public function getThumbnail($file, $maxX, $maxY, $scalingup) { * @return string */ private function getUrl($file, $user = null, $version = 0) { - $data = [ "action" => "download", "fileId" => $file->getId() diff --git a/lib/remoteinstance.php b/lib/remoteinstance.php index 9ac739cd..58eb3a95 100644 --- a/lib/remoteinstance.php +++ b/lib/remoteinstance.php @@ -29,7 +29,6 @@ * @package OCA\Onlyoffice */ class RemoteInstance { - /** * App name */ diff --git a/lib/templatemanager.php b/lib/templatemanager.php index eff5ab69..04c202c4 100644 --- a/lib/templatemanager.php +++ b/lib/templatemanager.php @@ -28,7 +28,6 @@ * @package OCA\Onlyoffice */ class TemplateManager { - /** * Application name * diff --git a/lib/versionmanager.php b/lib/versionmanager.php index 69c266c3..77beaaa0 100644 --- a/lib/versionmanager.php +++ b/lib/versionmanager.php @@ -36,7 +36,6 @@ * @package OCA\Onlyoffice */ class VersionManager { - /** * Application name * @@ -131,7 +130,7 @@ public function getVersionsForFile($user, $file) { $fileId = $file->getId(); - try{ + try { $userFolder = $this->rootFolder->getUserFolder($user->getUID()); $nodes = $userFolder->getById($fileId); $sourceFile = $nodes[0]; @@ -150,11 +149,11 @@ public function getVersionsForFile($user, $file) { $sourceFilePath = $userFolder->getRelativePath($sourceFile->getPath()); $propsVersions = $this->storage->getVersions($ownerId, $sourceFilePath); - foreach($propsVersions as $propVersion) { + foreach ($propsVersions as $propVersion) { $version = new Version($propVersion["timestamp"], - $propVersion["version"], - $propVersion["path"], - $file); + $propVersion["version"], + $propVersion["path"], + $file); array_push($versions, $version); } @@ -169,21 +168,21 @@ public function getVersionsForFile($user, $file) { * */ public function rollback($version) { - $sourceFile = $version->getSourceFile(); + $sourceFile = $version->getSourceFile(); - $ownerId = null; - $owner = $sourceFile->getOwner(); - if (!empty($owner)) { - $ownerId = $owner->getUID(); - } + $ownerId = null; + $owner = $sourceFile->getOwner(); + if (!empty($owner)) { + $ownerId = $owner->getUID(); + } - $path = $version->getPath(); - $revision = $version->getTimestamp(); + $path = $version->getPath(); + $revision = $version->getTimestamp(); - $versionFile = $this->getVersionFile($owner, $sourceFile, $revision); - $versionFileInfo = $versionFile->getFileInfo(); - $versionPath = $versionFileInfo->getInternalPath(); + $versionFile = $this->getVersionFile($owner, $sourceFile, $revision); + $versionFileInfo = $versionFile->getFileInfo(); + $versionPath = $versionFileInfo->getInternalPath(); - $this->storage->restoreVersion($ownerId, $path, $versionPath, $revision); + $this->storage->restoreVersion($ownerId, $path, $versionPath, $revision); } } diff --git a/templates/editor.php b/templates/editor.php index 936fcb80..4f9e8ddc 100644 --- a/templates/editor.php +++ b/templates/editor.php @@ -17,9 +17,9 @@ * */ - style("onlyoffice", "editor"); - script("onlyoffice", "desktop"); - script("onlyoffice", "editor"); +style("onlyoffice", "editor"); +script("onlyoffice", "desktop"); +script("onlyoffice", "editor"); ?>
diff --git a/templates/settings.php b/templates/settings.php index c3b810d3..cd4e6779 100644 --- a/templates/settings.php +++ b/templates/settings.php @@ -17,10 +17,10 @@ * */ - style("onlyoffice", "settings"); - style("onlyoffice", "template"); - script("onlyoffice", "settings"); - script("onlyoffice", "template"); +style("onlyoffice", "settings"); +style("onlyoffice", "template"); +script("onlyoffice", "settings"); +script("onlyoffice", "template"); ?>

From 2f8135082ae1a952a20f0100dbf59ae493d2ec15 Mon Sep 17 00:00:00 2001 From: rivexe Date: Mon, 18 Dec 2023 13:43:00 +0300 Subject: [PATCH 010/114] use elseif statement --- controller/callbackcontroller.php | 2 +- controller/editorapicontroller.php | 2 +- controller/editorcontroller.php | 4 ++-- controller/settingsapicontroller.php | 2 +- lib/appconfig.php | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/controller/callbackcontroller.php b/controller/callbackcontroller.php index 11cd2aa5..cd6e1b3e 100644 --- a/controller/callbackcontroller.php +++ b/controller/callbackcontroller.php @@ -496,7 +496,7 @@ public function track($doc, $users, $key, $status, $url, $token, $history, $chan if ($this->config->checkEncryptionModule() === "master") { \OC_User::setIncognitoMode(true); - } else if (!empty($userId)) { + } elseif (!empty($userId)) { \OC_Util::setupFS($userId); } diff --git a/controller/editorapicontroller.php b/controller/editorapicontroller.php index 5bde4c42..ba57fbb5 100644 --- a/controller/editorapicontroller.php +++ b/controller/editorapicontroller.php @@ -443,7 +443,7 @@ public function config($fileId, $filePath = null, $shareToken = null, $version = $folderLink = $this->urlGenerator->linkToRouteAbsolute("files_sharing.sharecontroller.showShare", $linkAttr); } } - } else if (!empty($userId)) { + } elseif (!empty($userId)) { $userFolder = $this->root->getUserFolder($userId); $folderPath = $userFolder->getRelativePath($file->getParent()->getPath()); if (!empty($folderPath)) { diff --git a/controller/editorcontroller.php b/controller/editorcontroller.php index c26c095d..d4d007cb 100644 --- a/controller/editorcontroller.php +++ b/controller/editorcontroller.php @@ -875,7 +875,7 @@ public function history($fileId) { "id" => $this->buildUserId($author["id"]), "name" => $author["name"] ]; - } else if ($owner !== null) { + } elseif ($owner !== null) { $historyItem["user"] = [ "id" => $this->buildUserId($ownerId), "name" => $owner->getDisplayName() @@ -1398,7 +1398,7 @@ private function getAccessList($file) { if ($share->getShareType() === Share::SHARE_TYPE_GROUP) { $group = $this->groupManager->get($shareWith); $accessList = $group->getUsers(); - } else if ($share->getShareType() === Share::SHARE_TYPE_USER) { + } elseif ($share->getShareType() === Share::SHARE_TYPE_USER) { array_push($accessList, $this->userManager->get($shareWith)); } diff --git a/controller/settingsapicontroller.php b/controller/settingsapicontroller.php index b684c90e..8c02ed2a 100644 --- a/controller/settingsapicontroller.php +++ b/controller/settingsapicontroller.php @@ -73,7 +73,7 @@ public function GetDocServerUrl() { $url = $this->config->GetDocumentServerUrl(); if (!$this->config->SettingsAreSuccessful()) { $url = ""; - } else if (!preg_match("/^https?:\/\//i", $url)) { + } elseif (!preg_match("/^https?:\/\//i", $url)) { $url = $this->urlGenerator->getAbsoluteURL($url); } diff --git a/lib/appconfig.php b/lib/appconfig.php index 0d585bc6..3aeed811 100644 --- a/lib/appconfig.php +++ b/lib/appconfig.php @@ -1175,7 +1175,7 @@ public function FormatsSetting() { public function ShareAttributesVersion() { if (\version_compare(\implode(".", \OCP\Util::getVersion()), "10.3.0", ">=")) { return "v2"; - } else if (\version_compare(\implode(".", \OCP\Util::getVersion()), "10.2.0", ">=")) { + } elseif (\version_compare(\implode(".", \OCP\Util::getVersion()), "10.2.0", ">=")) { return "v1"; } return ""; From 3ea29ff7de203289a6467a758d4a817befc88bd8 Mon Sep 17 00:00:00 2001 From: rivexe Date: Mon, 18 Dec 2023 13:45:45 +0300 Subject: [PATCH 011/114] function declaration without spaces --- appinfo/application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appinfo/application.php b/appinfo/application.php index 47e87bbf..78b8bb68 100644 --- a/appinfo/application.php +++ b/appinfo/application.php @@ -110,7 +110,7 @@ function () { $previewManager = $container->query(IPreview::class); if ($this->appConfig->GetPreview()) { - $previewManager->registerProvider(Preview::getMimeTypeRegex(), function() use ($container) { + $previewManager->registerProvider(Preview::getMimeTypeRegex(), function () use ($container) { return $container->query(Preview::class); }); } From 6780434651a69defb04e45cf089e40bfa7df34fd Mon Sep 17 00:00:00 2001 From: rivexe Date: Mon, 18 Dec 2023 13:51:37 +0300 Subject: [PATCH 012/114] method argument space --- appinfo/application.php | 6 ++- controller/callbackcontroller.php | 25 +++++----- controller/editorapicontroller.php | 27 +++++----- controller/editorcontroller.php | 29 +++++------ controller/federationcontroller.php | 15 +++--- controller/settingsapicontroller.php | 11 +++-- controller/settingscontroller.php | 74 +++++++++++++++------------- controller/templatecontroller.php | 11 +++-- controller/webassetcontroller.php | 2 +- lib/command/documentserver.php | 16 +++--- lib/cron/editorscheck.php | 16 +++--- lib/fileutility.php | 14 +++--- lib/keymanager.php | 3 +- lib/notifier.php | 13 ++--- lib/preview.php | 23 ++++----- lib/version.php | 11 +++-- lib/versionmanager.php | 6 ++- 17 files changed, 164 insertions(+), 138 deletions(-) diff --git a/appinfo/application.php b/appinfo/application.php index 78b8bb68..598698b6 100644 --- a/appinfo/application.php +++ b/appinfo/application.php @@ -66,7 +66,8 @@ public function __construct(array $urlParams = []) { // Default script and style if configured $eventDispatcher = \OC::$server->getEventDispatcher(); - $eventDispatcher->addListener("OCA\Files::loadAdditionalScripts", + $eventDispatcher->addListener( + "OCA\Files::loadAdditionalScripts", function () { if (!empty($this->appConfig->GetDocumentServerUrl()) && $this->appConfig->SettingsAreSuccessful() @@ -83,7 +84,8 @@ function () { Util::addStyle("onlyoffice", "template"); Util::addStyle("onlyoffice", "main"); } - }); + } + ); Util::connectHook("OCP\Share", "share_link_access", Hookhandler::class, "PublicPage"); diff --git a/controller/callbackcontroller.php b/controller/callbackcontroller.php index cd6e1b3e..59b43ece 100644 --- a/controller/callbackcontroller.php +++ b/controller/callbackcontroller.php @@ -137,17 +137,18 @@ class CallbackController extends Controller { * @param Crypt $crypt - hash generator * @param IManager $shareManager - Share manager */ - public function __construct($AppName, - IRequest $request, - IRootFolder $root, - IUserSession $userSession, - IUserManager $userManager, - IL10N $trans, - ILogger $logger, - AppConfig $config, - Crypt $crypt, - IManager $shareManager - ) { + public function __construct( + $AppName, + IRequest $request, + IRootFolder $root, + IUserSession $userSession, + IUserManager $userManager, + IL10N $trans, + ILogger $logger, + AppConfig $config, + Crypt $crypt, + IManager $shareManager + ) { parent::__construct($AppName, $request); $this->root = $root; @@ -503,7 +504,7 @@ public function track($doc, $users, $key, $status, $url, $token, $history, $chan list ($file, $error) = empty($shareToken) ? $this->getFile($userId, $fileId, $filePath) : $this->getFileByToken($fileId, $shareToken); if (isset($error)) { - $this->logger->error("track error: $fileId " . json_encode($error->getData()), ["app" => $this->appName]); + $this->logger->error("track error: $fileId " . json_encode($error->getData()), ["app" => $this->appName]); return $error; } diff --git a/controller/editorapicontroller.php b/controller/editorapicontroller.php index ba57fbb5..f9d3c238 100644 --- a/controller/editorapicontroller.php +++ b/controller/editorapicontroller.php @@ -138,19 +138,20 @@ class EditorApiController extends OCSController { * @param ISession $ISession - Session * @param ITagManager $tagManager - Tag manager */ - public function __construct($AppName, - IRequest $request, - IRootFolder $root, - IUserSession $userSession, - IURLGenerator $urlGenerator, - IL10N $trans, - ILogger $logger, - AppConfig $config, - Crypt $crypt, - IManager $shareManager, - ISession $session, - ITagManager $tagManager - ) { + public function __construct( + $AppName, + IRequest $request, + IRootFolder $root, + IUserSession $userSession, + IURLGenerator $urlGenerator, + IL10N $trans, + ILogger $logger, + AppConfig $config, + Crypt $crypt, + IManager $shareManager, + ISession $session, + ITagManager $tagManager + ) { parent::__construct($AppName, $request); $this->userSession = $userSession; diff --git a/controller/editorcontroller.php b/controller/editorcontroller.php index d4d007cb..e1e78fad 100644 --- a/controller/editorcontroller.php +++ b/controller/editorcontroller.php @@ -154,20 +154,21 @@ class EditorController extends Controller { * @param ISession $session - Session * @param IGroupManager $groupManager - Group manager */ - public function __construct($AppName, - IRequest $request, - IRootFolder $root, - IUserSession $userSession, - IUserManager $userManager, - IURLGenerator $urlGenerator, - IL10N $trans, - ILogger $logger, - AppConfig $config, - Crypt $crypt, - IManager $shareManager, - ISession $session, - IGroupManager $groupManager - ) { + public function __construct( + $AppName, + IRequest $request, + IRootFolder $root, + IUserSession $userSession, + IUserManager $userManager, + IURLGenerator $urlGenerator, + IL10N $trans, + ILogger $logger, + AppConfig $config, + Crypt $crypt, + IManager $shareManager, + ISession $session, + IGroupManager $groupManager + ) { parent::__construct($AppName, $request); $this->userSession = $userSession; diff --git a/controller/federationcontroller.php b/controller/federationcontroller.php index 1914cc45..79a1da23 100644 --- a/controller/federationcontroller.php +++ b/controller/federationcontroller.php @@ -67,13 +67,14 @@ class FederationController extends OCSController { * @param IManager $shareManager - Share manager * @param IManager $ISession - Session */ - public function __construct($AppName, - IRequest $request, - IL10N $trans, - ILogger $logger, - IManager $shareManager, - ISession $session - ) { + public function __construct( + $AppName, + IRequest $request, + IL10N $trans, + ILogger $logger, + IManager $shareManager, + ISession $session + ) { parent::__construct($AppName, $request); $this->logger = $logger; diff --git a/controller/settingsapicontroller.php b/controller/settingsapicontroller.php index 8c02ed2a..edba87b9 100644 --- a/controller/settingsapicontroller.php +++ b/controller/settingsapicontroller.php @@ -50,11 +50,12 @@ class SettingsApiController extends OCSController { * @param IURLGenerator $urlGenerator - url generator service * @param AppConfig $config - application configuration */ - public function __construct($AppName, - IRequest $request, - IURLGenerator $urlGenerator, - AppConfig $config - ) { + public function __construct( + $AppName, + IRequest $request, + IURLGenerator $urlGenerator, + AppConfig $config + ) { parent::__construct($AppName, $request); $this->urlGenerator = $urlGenerator; diff --git a/controller/settingscontroller.php b/controller/settingscontroller.php index 65c06dd5..67d5c27c 100644 --- a/controller/settingscontroller.php +++ b/controller/settingscontroller.php @@ -80,14 +80,15 @@ class SettingsController extends Controller { * @param AppConfig $config - application configuration * @param Crypt $crypt - hash generator */ - public function __construct($AppName, - IRequest $request, - IURLGenerator $urlGenerator, - IL10N $trans, - ILogger $logger, - AppConfig $config, - Crypt $crypt - ) { + public function __construct( + $AppName, + IRequest $request, + IURLGenerator $urlGenerator, + IL10N $trans, + ILogger $logger, + AppConfig $config, + Crypt $crypt + ) { parent::__construct($AppName, $request); $this->urlGenerator = $urlGenerator; @@ -149,14 +150,15 @@ public function index() { * * @return array */ - public function SaveAddress($documentserver, - $documentserverInternal, - $storageUrl, - $verifyPeerOff, - $secret, - $jwtHeader, - $demo - ) { + public function SaveAddress( + $documentserver, + $documentserverInternal, + $storageUrl, + $verifyPeerOff, + $secret, + $jwtHeader, + $demo + ) { $error = null; if (!$this->config->SelectDemo($demo === true)) { $error = $this->trans->t("The 30-day test period is over, you can no longer connect to demo ONLYOFFICE Docs server."); @@ -216,21 +218,22 @@ public function SaveAddress($documentserver, * * @return array */ - public function SaveCommon($defFormats, - $editFormats, - $sameTab, - $preview, - $versionHistory, - $limitGroups, - $chat, - $compactHeader, - $feedback, - $forcesave, - $help, - $toolbarNoTabs, - $reviewDisplay, - $theme - ) { + public function SaveCommon( + $defFormats, + $editFormats, + $sameTab, + $preview, + $versionHistory, + $limitGroups, + $chat, + $compactHeader, + $feedback, + $forcesave, + $help, + $toolbarNoTabs, + $reviewDisplay, + $theme + ) { $this->config->SetDefaultFormats($defFormats); $this->config->SetEditableFormats($editFormats); $this->config->SetSameTab($sameTab); @@ -259,10 +262,11 @@ public function SaveCommon($defFormats, * * @return array */ - public function SaveSecurity($plugins, - $macros, - $protection - ) { + public function SaveSecurity( + $plugins, + $macros, + $protection + ) { $this->config->SetCustomizationPlugins($plugins); $this->config->SetCustomizationMacros($macros); $this->config->SetProtection($protection); diff --git a/controller/templatecontroller.php b/controller/templatecontroller.php index b87238ae..30eaf4ac 100644 --- a/controller/templatecontroller.php +++ b/controller/templatecontroller.php @@ -49,11 +49,12 @@ class TemplateController extends Controller { * @param IRequest $request - request object * @param IL10N $trans - l10n service */ - public function __construct($AppName, - IRequest $request, - IL10N $trans, - ILogger $logger - ) { + public function __construct( + $AppName, + IRequest $request, + IL10N $trans, + ILogger $logger + ) { parent::__construct($AppName, $request); $this->trans = $trans; diff --git a/controller/webassetcontroller.php b/controller/webassetcontroller.php index b5b9e3b9..39fafc9a 100644 --- a/controller/webassetcontroller.php +++ b/controller/webassetcontroller.php @@ -59,7 +59,7 @@ public function __construct($AppName, IRequest $request, ILogger $logger) { * @return Response */ public function get(): Response { - $basePath = \dirname(__DIR__,1); + $basePath = \dirname(__DIR__, 1); $filePath = \realpath( $basePath . '/js/web/onlyoffice.js'); try { return new DataDisplayResponse(\file_get_contents($filePath), Http::STATUS_OK, [ diff --git a/lib/command/documentserver.php b/lib/command/documentserver.php index 0be5d368..bd58d28a 100644 --- a/lib/command/documentserver.php +++ b/lib/command/documentserver.php @@ -66,10 +66,12 @@ class DocumentServer extends Command { * @param IURLGenerator $urlGenerator - url generator service * @param Crypt $crypt - hash generator */ - public function __construct(AppConfig $config, - IL10N $trans, - IURLGenerator $urlGenerator, - Crypt $crypt) { + public function __construct( + AppConfig $config, + IL10N $trans, + IURLGenerator $urlGenerator, + Crypt $crypt + ) { parent::__construct(); $this->config = $config; $this->trans = $trans; @@ -84,10 +86,12 @@ protected function configure() { $this ->setName("onlyoffice:documentserver") ->setDescription("Manage document server") - ->addOption("check", + ->addOption( + "check", null, InputOption::VALUE_NONE, - "Check connection document server"); + "Check connection document server" + ); } /** diff --git a/lib/cron/editorscheck.php b/lib/cron/editorscheck.php index 2be7644a..cfb7310b 100644 --- a/lib/cron/editorscheck.php +++ b/lib/cron/editorscheck.php @@ -94,13 +94,15 @@ class EditorsCheck extends TimedJob { * @param IL10N $trans - l10n service * @param Crypt $crypt - crypt service */ - public function __construct(string $AppName, - IURLGenerator $urlGenerator, - ITimeFactory $time, - AppConfig $config, - IL10N $trans, - Crypt $crypt, - IGroupManager $groupManager) { + public function __construct( + string $AppName, + IURLGenerator $urlGenerator, + ITimeFactory $time, + AppConfig $config, + IL10N $trans, + Crypt $crypt, + IGroupManager $groupManager + ) { $this->appName = $AppName; $this->urlGenerator = $urlGenerator; diff --git a/lib/fileutility.php b/lib/fileutility.php index d7e0d06a..51522f7e 100644 --- a/lib/fileutility.php +++ b/lib/fileutility.php @@ -88,12 +88,14 @@ class FileUtility { * @param IManager $shareManager - Share manager * @param IManager $ISession - Session */ - public function __construct($AppName, - IL10N $trans, - ILogger $logger, - AppConfig $config, - IManager $shareManager, - ISession $session) { + public function __construct( + $AppName, + IL10N $trans, + ILogger $logger, + AppConfig $config, + IManager $shareManager, + ISession $session + ) { $this->appName = $AppName; $this->trans = $trans; $this->logger = $logger; diff --git a/lib/keymanager.php b/lib/keymanager.php index 70f84a4b..7ce6c0ad 100644 --- a/lib/keymanager.php +++ b/lib/keymanager.php @@ -80,7 +80,8 @@ public static function set($fileId, $key) { */ public static function delete($fileId, $unlock = false) { $connection = \OC::$server->getDatabaseConnection(); - $delete = $connection->prepare(" + $delete = $connection->prepare( + " DELETE FROM `*PREFIX*" . self::TableName_Key . "` WHERE `file_id` = ? " . ($unlock === false ? "AND `lock` != 1" : "") diff --git a/lib/notifier.php b/lib/notifier.php index 97a3ca41..689a5b8d 100644 --- a/lib/notifier.php +++ b/lib/notifier.php @@ -69,12 +69,13 @@ class Notifier implements INotifier { * @param ILogger $logger - logger * @param IUserManager $userManager - user manager */ - public function __construct(string $appName, - IFactory $l10nFactory, - IURLGenerator $urlGenerator, - ILogger $logger, - IUserManager $userManager - ) { + public function __construct( + string $appName, + IFactory $l10nFactory, + IURLGenerator $urlGenerator, + ILogger $logger, + IUserManager $userManager + ) { $this->appName = $appName; $this->l10nFactory = $l10nFactory; $this->urlGenerator = $urlGenerator; diff --git a/lib/preview.php b/lib/preview.php index 3bf456f6..34ad744a 100644 --- a/lib/preview.php +++ b/lib/preview.php @@ -170,17 +170,18 @@ class Preview implements IProvider2 { * @param ISession $session - session * @param IUserManager $userManager - user manager */ - public function __construct(string $appName, - IRootFolder $root, - ILogger $logger, - IL10N $trans, - AppConfig $config, - IURLGenerator $urlGenerator, - Crypt $crypt, - IManager $shareManager, - ISession $session, - IUserManager $userManager - ) { + public function __construct( + string $appName, + IRootFolder $root, + ILogger $logger, + IL10N $trans, + AppConfig $config, + IURLGenerator $urlGenerator, + Crypt $crypt, + IManager $shareManager, + ISession $session, + IUserManager $userManager + ) { $this->appName = $appName; $this->root = $root; $this->logger = $logger; diff --git a/lib/version.php b/lib/version.php index c56a28cb..e415bbb3 100644 --- a/lib/version.php +++ b/lib/version.php @@ -61,11 +61,12 @@ class Version { * @param int $revisionId - revision id * @param FileInfo $sourceFileInfo - source file info */ - public function __construct(int $timestamp, - int $revisionId, - string $path, - FileInfo $sourceFileInfo - ) { + public function __construct( + int $timestamp, + int $revisionId, + string $path, + FileInfo $sourceFileInfo + ) { $this->timestamp = $timestamp; $this->revisionId = $revisionId; $this->path = $path; diff --git a/lib/versionmanager.php b/lib/versionmanager.php index 77beaaa0..2f479a7d 100644 --- a/lib/versionmanager.php +++ b/lib/versionmanager.php @@ -150,10 +150,12 @@ public function getVersionsForFile($user, $file) { $propsVersions = $this->storage->getVersions($ownerId, $sourceFilePath); foreach ($propsVersions as $propVersion) { - $version = new Version($propVersion["timestamp"], + $version = new Version( + $propVersion["timestamp"], $propVersion["version"], $propVersion["path"], - $file); + $file + ); array_push($versions, $version); } From d81369f546c43420c449f6fec27d0c07f875d0c7 Mon Sep 17 00:00:00 2001 From: rivexe Date: Mon, 18 Dec 2023 13:53:10 +0300 Subject: [PATCH 013/114] no spaces after function name --- controller/callbackcontroller.php | 14 +++++++------- controller/editorapicontroller.php | 4 ++-- controller/editorcontroller.php | 20 ++++++++++---------- controller/federationcontroller.php | 4 ++-- controller/settingscontroller.php | 2 +- lib/command/documentserver.php | 2 +- lib/cron/editorscheck.php | 2 +- lib/documentservice.php | 2 +- lib/fileutility.php | 4 ++-- lib/fileversions.php | 18 +++++++++--------- lib/hooks.php | 2 +- lib/preview.php | 2 +- 12 files changed, 38 insertions(+), 38 deletions(-) diff --git a/controller/callbackcontroller.php b/controller/callbackcontroller.php index 59b43ece..2d294519 100644 --- a/controller/callbackcontroller.php +++ b/controller/callbackcontroller.php @@ -177,7 +177,7 @@ public function __construct( * @CORS */ public function download($doc) { - list ($hashData, $error) = $this->crypt->ReadHash($doc); + list($hashData, $error) = $this->crypt->ReadHash($doc); if ($hashData === null) { $this->logger->error("Download with empty or not correct hash: $error", ["app" => $this->appName]); return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN); @@ -241,7 +241,7 @@ public function download($doc) { } $shareToken = isset($hashData->shareToken) ? $hashData->shareToken : null; - list ($file, $error) = empty($shareToken) ? $this->getFile($userId, $fileId, null, $changes ? null : $version, $template) : $this->getFileByToken($fileId, $shareToken, $changes ? null : $version); + list($file, $error) = empty($shareToken) ? $this->getFile($userId, $fileId, null, $changes ? null : $version, $template) : $this->getFileByToken($fileId, $shareToken, $changes ? null : $version); if (isset($error)) { return $error; @@ -322,7 +322,7 @@ public function download($doc) { public function emptyfile($doc) { $this->logger->debug("Download empty", ["app" => $this->appName]); - list ($hashData, $error) = $this->crypt->ReadHash($doc); + list($hashData, $error) = $this->crypt->ReadHash($doc); if ($hashData === null) { $this->logger->error("Download empty with empty or not correct hash: $error", ["app" => $this->appName]); return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN); @@ -389,7 +389,7 @@ public function emptyfile($doc) { * @CORS */ public function track($doc, $users, $key, $status, $url, $token, $history, $changesurl, $forcesavetype, $actions, $filetype) { - list ($hashData, $error) = $this->crypt->ReadHash($doc); + list($hashData, $error) = $this->crypt->ReadHash($doc); if ($hashData === null) { $this->logger->error("Track with empty or not correct hash: $error", ["app" => $this->appName]); return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN); @@ -501,7 +501,7 @@ public function track($doc, $users, $key, $status, $url, $token, $history, $chan \OC_Util::setupFS($userId); } - list ($file, $error) = empty($shareToken) ? $this->getFile($userId, $fileId, $filePath) : $this->getFileByToken($fileId, $shareToken); + list($file, $error) = empty($shareToken) ? $this->getFile($userId, $fileId, $filePath) : $this->getFileByToken($fileId, $shareToken); if (isset($error)) { $this->logger->error("track error: $fileId " . json_encode($error->getData()), ["app" => $this->appName]); @@ -645,7 +645,7 @@ private function getFile($userId, $fileId, $filePath = null, $version = 0, $temp if ($owner !== null) { if ($owner->getUID() !== $userId) { - list ($file, $error) = $this->getFile($owner->getUID(), $file->getId()); + list($file, $error) = $this->getFile($owner->getUID(), $file->getId()); if (isset($error)) { return [null, $error]; @@ -674,7 +674,7 @@ private function getFile($userId, $fileId, $filePath = null, $version = 0, $temp * @return array */ private function getFileByToken($fileId, $shareToken, $version = 0) { - list ($share, $error) = $this->getShare($shareToken); + list($share, $error) = $this->getShare($shareToken); if (isset($error)) { return [null, $error]; diff --git a/controller/editorapicontroller.php b/controller/editorapicontroller.php index f9d3c238..52eee6e7 100644 --- a/controller/editorapicontroller.php +++ b/controller/editorapicontroller.php @@ -188,7 +188,7 @@ public function fillempty($fileId) { $userId = $this->userSession->getUser()->getUID(); - list ($file, $error, $share) = $this->getFile($userId, $fileId); + list($file, $error, $share) = $this->getFile($userId, $fileId); if (isset($error)) { $this->logger->error("Fill empty: $fileId $error", ["app" => $this->appName]); return new JSONResponse(["error" => $error]); @@ -249,7 +249,7 @@ public function config($fileId, $filePath = null, $shareToken = null, $version = $accountId = $user->getAccountId(); } - list ($file, $error, $share) = empty($shareToken) ? $this->getFile($userId, $fileId, $filePath, $template) : $this->fileUtility->getFileByToken($fileId, $shareToken); + list($file, $error, $share) = empty($shareToken) ? $this->getFile($userId, $fileId, $filePath, $template) : $this->fileUtility->getFileByToken($fileId, $shareToken); if (isset($error)) { $this->logger->error("Config: $fileId $error", ["app" => $this->appName]); diff --git a/controller/editorcontroller.php b/controller/editorcontroller.php index e1e78fad..7ee9fc9e 100644 --- a/controller/editorcontroller.php +++ b/controller/editorcontroller.php @@ -219,7 +219,7 @@ public function create($name, $dir, $templateId = null, $targetPath = null, $sha $userId = $user->getUID(); $userFolder = $this->root->getUserFolder($userId); } else { - list ($userFolder, $error, $share) = $this->fileUtility->getNodeByToken($shareToken); + list($userFolder, $error, $share) = $this->fileUtility->getNodeByToken($shareToken); if (isset($error)) { $this->logger->error("Create: $error", ["app" => $this->appName]); @@ -359,7 +359,7 @@ public function users($fileId) { $currentUser = $this->userSession->getUser(); $currentUserId = $currentUser->getUID(); - list ($file, $error, $share) = $this->getFile($currentUserId, $fileId); + list($file, $error, $share) = $this->getFile($currentUserId, $fileId); if (isset($error)) { $this->logger->error("Users: $fileId $error", ["app" => $this->appName]); return $result; @@ -451,7 +451,7 @@ public function mention($fileId, $anchor, $comment, $emails) { $userId = $user->getUID(); } - list ($file, $error, $share) = $this->getFile($userId, $fileId); + list($file, $error, $share) = $this->getFile($userId, $fileId); if (isset($error)) { $this->logger->error("Mention: $fileId $error", ["app" => $this->appName]); return ["error" => $this->trans->t("Failed to send notification")]; @@ -565,7 +565,7 @@ public function reference($referenceData, $path = null) { $fileId = (integer)($referenceData["fileKey"] ?? 0); if (!empty($fileId) && $referenceData["instanceId"] === $this->config->GetSystemValue("instanceid", true)) { - list ($file, $error, $share) = $this->getFile($userId, $fileId); + list($file, $error, $share) = $this->getFile($userId, $fileId); } $userFolder = $this->root->getUserFolder($userId); @@ -629,7 +629,7 @@ public function convert($fileId, $shareToken = null) { $userId = $user->getUID(); } - list ($file, $error, $share) = empty($shareToken) ? $this->getFile($userId, $fileId) : $this->fileUtility->getFileByToken($fileId, $shareToken); + list($file, $error, $share) = empty($shareToken) ? $this->getFile($userId, $fileId) : $this->fileUtility->getFileByToken($fileId, $shareToken); if (isset($error)) { $this->logger->error("Convertion: $fileId $error", ["app" => $this->appName]); @@ -800,7 +800,7 @@ public function history($fileId) { $userId = $user->getUID(); } - list ($file, $error, $share) = $this->getFile($userId, $fileId); + list($file, $error, $share) = $this->getFile($userId, $fileId); if (isset($error)) { $this->logger->error("History: $fileId $error", ["app" => $this->appName]); @@ -919,7 +919,7 @@ public function version($fileId, $version) { $userId = $user->getUID(); } - list ($file, $error, $share) = $this->getFile($userId, $fileId); + list($file, $error, $share) = $this->getFile($userId, $fileId); if (isset($error)) { $this->logger->error("History: $fileId $error", ["app" => $this->appName]); @@ -1021,7 +1021,7 @@ public function restore($fileId, $version) { $userId = $user->getUID(); } - list ($file, $error, $share) = $this->getFile($userId, $fileId); + list($file, $error, $share) = $this->getFile($userId, $fileId); if (isset($error)) { $this->logger->error("Restore: $fileId $error", ["app" => $this->appName]); @@ -1132,7 +1132,7 @@ public function download($fileId, $toExtension = null, $template = false) { $userId = $user->getUID(); } - list ($file, $error, $share) = $this->getFile($userId, $fileId); + list($file, $error, $share) = $this->getFile($userId, $fileId); if (isset($error)) { $this->logger->error("Download: $fileId $error", ["app" => $this->appName]); @@ -1209,7 +1209,7 @@ public function index($fileId, $filePath = null, $shareToken = null, $version = $shareBy = null; if (!empty($shareToken) && !$this->userSession->isLoggedIn()) { - list ($share, $error) = $this->fileUtility->getShare($shareToken); + list($share, $error) = $this->fileUtility->getShare($shareToken); if (!empty($share)) { $shareBy = $share->getSharedBy(); } diff --git a/controller/federationcontroller.php b/controller/federationcontroller.php index 79a1da23..69462b89 100644 --- a/controller/federationcontroller.php +++ b/controller/federationcontroller.php @@ -96,7 +96,7 @@ public function __construct( * @PublicPage */ public function key($shareToken, $path) { - list ($file, $error, $share) = $this->fileUtility->getFileByToken(null, $shareToken, $path); + list($file, $error, $share) = $this->fileUtility->getFileByToken(null, $shareToken, $path); if (isset($error)) { $this->logger->error("Federated getFileByToken: $error", ["app" => $this->appName]); @@ -127,7 +127,7 @@ public function key($shareToken, $path) { * @PublicPage */ public function keylock($shareToken, $path, $lock, $fs) { - list ($file, $error, $share) = $this->fileUtility->getFileByToken(null, $shareToken, $path); + list($file, $error, $share) = $this->fileUtility->getFileByToken(null, $shareToken, $path); if (isset($error)) { $this->logger->error("Federated getFileByToken: $error", ["app" => $this->appName]); diff --git a/controller/settingscontroller.php b/controller/settingscontroller.php index 67d5c27c..4d3ba471 100644 --- a/controller/settingscontroller.php +++ b/controller/settingscontroller.php @@ -177,7 +177,7 @@ public function SaveAddress( $documentserver = $this->config->GetDocumentServerUrl(); if (!empty($documentserver)) { $documentService = new DocumentService($this->trans, $this->config); - list ($error, $version) = $documentService->checkDocServiceUrl($this->urlGenerator, $this->crypt); + list($error, $version) = $documentService->checkDocServiceUrl($this->urlGenerator, $this->crypt); $this->config->SetSettingsError($error); } diff --git a/lib/command/documentserver.php b/lib/command/documentserver.php index bd58d28a..e402c69a 100644 --- a/lib/command/documentserver.php +++ b/lib/command/documentserver.php @@ -114,7 +114,7 @@ protected function execute(InputInterface $input, OutputInterface $output) { if ($check) { $documentService = new DocumentService($this->trans, $this->config); - list ($error, $version) = $documentService->checkDocServiceUrl($this->urlGenerator, $this->crypt); + list($error, $version) = $documentService->checkDocServiceUrl($this->urlGenerator, $this->crypt); $this->config->SetSettingsError($error); if (!empty($error)) { diff --git a/lib/cron/editorscheck.php b/lib/cron/editorscheck.php index cfb7310b..69065c4f 100644 --- a/lib/cron/editorscheck.php +++ b/lib/cron/editorscheck.php @@ -141,7 +141,7 @@ protected function run($argument) { $this->logger->debug("ONLYOFFICE check started by cron", ["app" => $this->appName]); $documentService = new DocumentService($this->trans, $this->config); - list ($error, $version) = $documentService->checkDocServiceUrl($this->urlGenerator, $this->crypt); + list($error, $version) = $documentService->checkDocServiceUrl($this->urlGenerator, $this->crypt); if (!empty($error)) { $this->logger->info("ONLYOFFICE server is not available", ["app" => $this->appName]); $this->config->SetSettingsError($error); diff --git a/lib/documentservice.php b/lib/documentservice.php index f7fc2012..e540ca31 100644 --- a/lib/documentservice.php +++ b/lib/documentservice.php @@ -180,7 +180,7 @@ function SendRequestToConvertService($document_uri, $from_extension, $to_extensi foreach (libxml_get_errors() as $error) { $exc = $exc . "\t" . $error->message; } - throw new \Exception ($exc); + throw new \Exception($exc); } return $response_data; diff --git a/lib/fileutility.php b/lib/fileutility.php index 51522f7e..a4ec1fa3 100644 --- a/lib/fileutility.php +++ b/lib/fileutility.php @@ -114,7 +114,7 @@ public function __construct( * @return array */ public function getFileByToken($fileId, $shareToken, $path = null) { - list ($node, $error, $share) = $this->getNodeByToken($shareToken); + list($node, $error, $share) = $this->getNodeByToken($shareToken); if (isset($error)) { return [null, $error, null]; @@ -157,7 +157,7 @@ public function getFileByToken($fileId, $shareToken, $path = null) { * @return array */ public function getNodeByToken($shareToken) { - list ($share, $error) = $this->getShare($shareToken); + list($share, $error) = $this->getShare($shareToken); if (isset($error)) { return [null, $error, null]; diff --git a/lib/fileversions.php b/lib/fileversions.php index 77bdb8e0..eec3be35 100644 --- a/lib/fileversions.php +++ b/lib/fileversions.php @@ -145,7 +145,7 @@ public static function getHistoryData($ownerId, $fileId, $versionId, $prevVersio return null; } - list ($view, $path) = self::getView($ownerId, $fileId); + list($view, $path) = self::getView($ownerId, $fileId); if ($view === null) { return null; } @@ -195,7 +195,7 @@ public static function hasChanges($ownerId, $fileId, $versionId) { return false; } - list ($view, $path) = self::getView($ownerId, $fileId); + list($view, $path) = self::getView($ownerId, $fileId); if ($view === null) { return false; } @@ -218,7 +218,7 @@ public static function getChangesFile($ownerId, $fileId, $versionId) { return null; } - list ($view, $path) = self::getView($ownerId, $fileId); + list($view, $path) = self::getView($ownerId, $fileId); if ($view === null) { return null; } @@ -268,7 +268,7 @@ public static function saveHistory($fileInfo, $history, $changes, $prevVersion) $fileId = $fileInfo->getId(); $versionId = $fileInfo->getMtime(); - list ($view, $path) = self::getView($ownerId, $fileId, true); + list($view, $path) = self::getView($ownerId, $fileId, true); try { $changesPath = $path . "/" . $versionId . self::$changesExt; @@ -301,7 +301,7 @@ public static function deleteAllVersions($ownerId, $fileId = null) { return; } - list ($view, $path) = self::getView($ownerId, $fileId); + list($view, $path) = self::getView($ownerId, $fileId); if ($view === null) { return; } @@ -328,7 +328,7 @@ public static function deleteVersion($ownerId, $fileId, $versionId) { return; } - list ($view, $path) = self::getView($ownerId, $fileId); + list($view, $path) = self::getView($ownerId, $fileId); if ($view === null) { return null; } @@ -394,7 +394,7 @@ public static function saveAuthor($fileInfo, $author) { $fileId = $fileInfo->getId(); $versionId = $fileInfo->getMtime(); - list ($view, $path) = self::getView($ownerId, $fileId, true); + list($view, $path) = self::getView($ownerId, $fileId, true); try { $authorPath = $path . "/" . $versionId . self::$authorExt; @@ -426,7 +426,7 @@ public static function getAuthor($ownerId, $fileId, $versionId) { return null; } - list ($view, $path) = self::getView($ownerId, $fileId); + list($view, $path) = self::getView($ownerId, $fileId); if ($view === null) { return null; } @@ -463,7 +463,7 @@ public static function deleteAuthor($ownerId, $fileId, $versionId) { return; } - list ($view, $path) = self::getView($ownerId, $fileId); + list($view, $path) = self::getView($ownerId, $fileId); if ($view === null) { return null; } diff --git a/lib/hooks.php b/lib/hooks.php index ae86d445..c14b710a 100644 --- a/lib/hooks.php +++ b/lib/hooks.php @@ -131,7 +131,7 @@ public static function fileVersionDelete($params) { } try { - list ($filePath, $versionId) = FileVersions::splitPathVersion($pathVersion); + list($filePath, $versionId) = FileVersions::splitPathVersion($pathVersion); if (empty($filePath)) { return; } diff --git a/lib/preview.php b/lib/preview.php index 34ad744a..2debb58d 100644 --- a/lib/preview.php +++ b/lib/preview.php @@ -260,7 +260,7 @@ public function getThumbnail($file, $maxX, $maxY, $scalingup) { $this->logger->debug("getThumbnail " . $file->getPath() . " $maxX $maxY", ["app" => $this->appName]); - list ($fileUrl, $extension, $key) = $this->getFileParam($file); + list($fileUrl, $extension, $key) = $this->getFileParam($file); if ($fileUrl === null || $extension === null || $key === null) { return false; } From fb4630584f7241fe42b8ecddde74b4e1beebc00b Mon Sep 17 00:00:00 2001 From: rivexe Date: Mon, 18 Dec 2023 14:41:34 +0300 Subject: [PATCH 014/114] no spaces inside parenthesis --- controller/webassetcontroller.php | 2 +- lib/documentservice.php | 2 +- lib/fileutility.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/controller/webassetcontroller.php b/controller/webassetcontroller.php index 39fafc9a..3e03ab7f 100644 --- a/controller/webassetcontroller.php +++ b/controller/webassetcontroller.php @@ -60,7 +60,7 @@ public function __construct($AppName, IRequest $request, ILogger $logger) { */ public function get(): Response { $basePath = \dirname(__DIR__, 1); - $filePath = \realpath( $basePath . '/js/web/onlyoffice.js'); + $filePath = \realpath($basePath . '/js/web/onlyoffice.js'); try { return new DataDisplayResponse(\file_get_contents($filePath), Http::STATUS_OK, [ 'Content-Type' => "text/javascript", diff --git a/lib/documentservice.php b/lib/documentservice.php index e540ca31..387a4bc3 100644 --- a/lib/documentservice.php +++ b/lib/documentservice.php @@ -68,7 +68,7 @@ public function __construct(IL10N $trans, AppConfig $appConfig) { */ public static function GenerateRevisionId($expected_key) { if (strlen($expected_key) > 20) { - $expected_key = crc32( $expected_key); + $expected_key = crc32($expected_key); } $key = preg_replace("[^0-9-.a-zA-Z_=]", "_", $expected_key); $key = substr($key, 0, min(array(strlen($key), 20))); diff --git a/lib/fileutility.php b/lib/fileutility.php index a4ec1fa3..fd464faa 100644 --- a/lib/fileutility.php +++ b/lib/fileutility.php @@ -231,7 +231,7 @@ public function getKey($file, $origin = false) { $key = KeyManager::get($fileId); - if (empty($key) ) { + if (empty($key)) { $instanceId = $this->config->GetSystemValue("instanceid", true); $key = $instanceId . "_" . $this->GUID(); From e0cb9b79552cf9f7c0b1ffc6abbff3fd045764e0 Mon Sep 17 00:00:00 2001 From: rivexe Date: Mon, 18 Dec 2023 14:43:22 +0300 Subject: [PATCH 015/114] no trailing whitespace --- lib/preview.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/preview.php b/lib/preview.php index 2debb58d..00d1ea89 100644 --- a/lib/preview.php +++ b/lib/preview.php @@ -231,7 +231,7 @@ public function isAvailable(FileInfo $fileInfo) { if ($this->config->GetPreview() !== true) { return false; } - if (!$fileInfo + if (!$fileInfo || $fileInfo->getSize() === 0 || $fileInfo->getSize() > $this->config->GetLimitThumbSize()) { return false; From 44738fe27e27af0a0d72042edfd76630e71d995b Mon Sep 17 00:00:00 2001 From: rivexe Date: Mon, 18 Dec 2023 14:44:18 +0300 Subject: [PATCH 016/114] no trailing whitespace in comment --- controller/callbackcontroller.php | 2 +- controller/joblistcontroller.php | 12 ++++++------ lib/documentservice.php | 2 +- lib/hookhandler.php | 2 +- lib/version.php | 22 +++++++++++----------- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/controller/callbackcontroller.php b/controller/callbackcontroller.php index 2d294519..20d53d0c 100644 --- a/controller/callbackcontroller.php +++ b/controller/callbackcontroller.php @@ -602,7 +602,7 @@ public function track($doc, $users, $key, $status, $url, $token, $history, $chan * @param string $filePath - file path * @param integer $version - file version * @param bool $template - file is template - * + * * @return array */ private function getFile($userId, $fileId, $filePath = null, $version = 0, $template = false) { diff --git a/controller/joblistcontroller.php b/controller/joblistcontroller.php index 97e71627..a1138043 100644 --- a/controller/joblistcontroller.php +++ b/controller/joblistcontroller.php @@ -41,14 +41,14 @@ class JobListController extends Controller { /** * Logger - * + * * @var ILogger */ private $logger; /** * Job list - * + * * @var IJobList */ private $jobList; @@ -78,7 +78,7 @@ public function __construct($AppName, IRequest $request, ILogger $logger, AppCon /** * Add a job to list - * + * * @param IJob|string $job */ private function addJob($job) { @@ -90,7 +90,7 @@ private function addJob($job) { /** * Remove a job from list - * + * * @param IJob|string $job */ private function removeJob($job) { @@ -102,7 +102,7 @@ private function removeJob($job) { /** * Add or remove EditorsCheck job depending on the value of _editors_check_interval - * + * */ private function checkEditorsCheckJob() { if ($this->config->GetEditorsCheckInterval() > 0) { @@ -114,7 +114,7 @@ private function checkEditorsCheckJob() { /** * Method for sequentially calling checks of all jobs - * + * */ public function checkAllJobs() { $this->checkEditorsCheckJob(); diff --git a/lib/documentservice.php b/lib/documentservice.php index 387a4bc3..d068869f 100644 --- a/lib/documentservice.php +++ b/lib/documentservice.php @@ -370,7 +370,7 @@ public function Request($url, $method = "get", $opts = null) { * * @param OCP\IURLGenerator $urlGenerator - url generator * @param OCA\Onlyoffice\Crypt $crypt -crypt - * + * * @return array */ public function checkDocServiceUrl($urlGenerator, $crypt) { diff --git a/lib/hookhandler.php b/lib/hookhandler.php index d2dd7242..fe74c171 100644 --- a/lib/hookhandler.php +++ b/lib/hookhandler.php @@ -25,7 +25,7 @@ /** * Class HookHandler - * + * * handles hooks * * @package OCA\Onlyoffice diff --git a/lib/version.php b/lib/version.php index e415bbb3..adb409b9 100644 --- a/lib/version.php +++ b/lib/version.php @@ -28,31 +28,31 @@ * @package OCA\Onlyoffice */ class Version { - /** + /** * Time of creation - * - * @var int + * + * @var int * */ private $timestamp; - /** + /** * Version file - * - * @var int|string + * + * @var int|string * */ private $revisionId; - /** + /** * File path * - * @var string + * @var string * */ private $path; - /** + /** * Source file properties - * - * @var FileInfo + * + * @var FileInfo * */ private $sourceFileInfo; From 076d01f28181f6ab77f3015d274f7b594c346dbd Mon Sep 17 00:00:00 2001 From: rivexe Date: Mon, 18 Dec 2023 14:45:16 +0300 Subject: [PATCH 017/114] single blank line at eof --- controller/federationcontroller.php | 2 +- controller/settingsapicontroller.php | 2 +- controller/templatecontroller.php | 2 +- lib/command/documentserver.php | 2 +- lib/fileversions.php | 2 +- lib/hooks.php | 2 +- lib/keymanager.php | 2 +- lib/preview.php | 2 +- lib/remoteinstance.php | 2 +- lib/templatemanager.php | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/controller/federationcontroller.php b/controller/federationcontroller.php index 69462b89..c4858ac0 100644 --- a/controller/federationcontroller.php +++ b/controller/federationcontroller.php @@ -166,4 +166,4 @@ public function healthcheck() { return new Result(["alive" => true]); } -} \ No newline at end of file +} diff --git a/controller/settingsapicontroller.php b/controller/settingsapicontroller.php index edba87b9..83e2f6e8 100644 --- a/controller/settingsapicontroller.php +++ b/controller/settingsapicontroller.php @@ -80,4 +80,4 @@ public function GetDocServerUrl() { return new JSONResponse(["documentServerUrl" => $url]); } -} \ No newline at end of file +} diff --git a/controller/templatecontroller.php b/controller/templatecontroller.php index 30eaf4ac..85e83904 100644 --- a/controller/templatecontroller.php +++ b/controller/templatecontroller.php @@ -158,4 +158,4 @@ public function DeleteTemplate($templateId) { $this->logger->debug("Template: deleted " . $templates[0]->getName(), ["app" => $this->appName]); return []; } -} \ No newline at end of file +} diff --git a/lib/command/documentserver.php b/lib/command/documentserver.php index e402c69a..33c589f2 100644 --- a/lib/command/documentserver.php +++ b/lib/command/documentserver.php @@ -129,4 +129,4 @@ protected function execute(InputInterface $input, OutputInterface $output) { $output->writeln("The current document server: $documentserver"); return 0; } -} \ No newline at end of file +} diff --git a/lib/fileversions.php b/lib/fileversions.php index eec3be35..a0e5342b 100644 --- a/lib/fileversions.php +++ b/lib/fileversions.php @@ -474,4 +474,4 @@ public static function deleteAuthor($ownerId, $fileId, $versionId) { $logger->debug("deleteAuthor $authorPath", ["app" => self::$appName]); } } -} \ No newline at end of file +} diff --git a/lib/hooks.php b/lib/hooks.php index c14b710a..87632d2f 100644 --- a/lib/hooks.php +++ b/lib/hooks.php @@ -182,4 +182,4 @@ public static function fileVersionRestore($params) { \OC::$server->getLogger()->logException($e, ["message" => "Hook: fileVersionRestore " . json_encode($params), "app" => self::$appName]); } } -} \ No newline at end of file +} diff --git a/lib/keymanager.php b/lib/keymanager.php index 7ce6c0ad..1507283a 100644 --- a/lib/keymanager.php +++ b/lib/keymanager.php @@ -146,4 +146,4 @@ public static function wasForcesave($fileId) { return $fs === "1"; } -} \ No newline at end of file +} diff --git a/lib/preview.php b/lib/preview.php index 00d1ea89..f6399193 100644 --- a/lib/preview.php +++ b/lib/preview.php @@ -390,4 +390,4 @@ private function getFileParam($file) { return [$fileUrl, $fileExtension, $key]; } -} \ No newline at end of file +} diff --git a/lib/remoteinstance.php b/lib/remoteinstance.php index 58eb3a95..0616dfaf 100644 --- a/lib/remoteinstance.php +++ b/lib/remoteinstance.php @@ -279,4 +279,4 @@ public static function isRemoteFile($file) { $alive = RemoteInstance::healthCheck($storage->getRemote()); return $alive; } -} \ No newline at end of file +} diff --git a/lib/templatemanager.php b/lib/templatemanager.php index 04c202c4..f0e11dcd 100644 --- a/lib/templatemanager.php +++ b/lib/templatemanager.php @@ -214,4 +214,4 @@ public static function GetEmptyTemplatePath($lang, $ext) { "zh_CN" => "zh-CN", "zh_TW" => "zh-TW" ]; -} \ No newline at end of file +} From 7c42af831939aed2112447ea9337c680477f9527 Mon Sep 17 00:00:00 2001 From: rivexe Date: Mon, 18 Dec 2023 14:46:45 +0300 Subject: [PATCH 018/114] single line after imports --- lib/version.php | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/version.php b/lib/version.php index adb409b9..c5a6f981 100644 --- a/lib/version.php +++ b/lib/version.php @@ -21,7 +21,6 @@ use OCP\Files\FileInfo; - /** * Version file * From 696b4aca2b3d6ab3dea734bc9768407e2a591c61 Mon Sep 17 00:00:00 2001 From: rivexe Date: Mon, 18 Dec 2023 14:48:19 +0300 Subject: [PATCH 019/114] visibility required --- controller/editorapicontroller.php | 2 +- lib/documentservice.php | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/controller/editorapicontroller.php b/controller/editorapicontroller.php index 52eee6e7..29c2099d 100644 --- a/controller/editorapicontroller.php +++ b/controller/editorapicontroller.php @@ -122,7 +122,7 @@ class EditorApiController extends OCSController { /** * Mobile regex from https://github.com/ONLYOFFICE/CommunityServer/blob/v9.1.1/web/studio/ASC.Web.Studio/web.appsettings.config#L35 */ - const USER_AGENT_MOBILE = "/android|avantgo|playbook|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od|ad)|iris|kindle|lge |maemo|midp|mmp|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\\/|plucker|pocket|psp|symbian|treo|up\\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i"; + public const USER_AGENT_MOBILE = "/android|avantgo|playbook|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od|ad)|iris|kindle|lge |maemo|midp|mmp|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\\/|plucker|pocket|psp|symbian|treo|up\\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i"; /** * @param string $AppName - application name diff --git a/lib/documentservice.php b/lib/documentservice.php index d068869f..faa894ee 100644 --- a/lib/documentservice.php +++ b/lib/documentservice.php @@ -85,7 +85,7 @@ public static function GenerateRevisionId($expected_key) { * * @return string */ - function GetConvertedUri($document_uri, $from_extension, $to_extension, $document_revision_id) { + public function GetConvertedUri($document_uri, $from_extension, $to_extension, $document_revision_id) { $responceFromConvertService = $this->SendRequestToConvertService($document_uri, $from_extension, $to_extension, $document_revision_id, false); $errorElement = $responceFromConvertService->Error; @@ -113,7 +113,7 @@ function GetConvertedUri($document_uri, $from_extension, $to_extension, $documen * * @return array */ - function SendRequestToConvertService($document_uri, $from_extension, $to_extension, $document_revision_id, $is_async) { + public function SendRequestToConvertService($document_uri, $from_extension, $to_extension, $document_revision_id, $is_async) { $documentServerUrl = $this->config->GetDocumentServerInternalUrl(); if (empty($documentServerUrl)) { @@ -193,7 +193,7 @@ function SendRequestToConvertService($document_uri, $from_extension, $to_extensi * * @return null */ - function ProcessConvServResponceError($errorCode) { + public function ProcessConvServResponceError($errorCode) { $errorMessageTemplate = $this->trans->t("Error occurred in the document service"); $errorMessage = ""; @@ -240,7 +240,7 @@ function ProcessConvServResponceError($errorCode) { * * @return bool */ - function HealthcheckRequest() { + public function HealthcheckRequest() { $documentServerUrl = $this->config->GetDocumentServerInternalUrl(); if (empty($documentServerUrl)) { @@ -261,7 +261,7 @@ function HealthcheckRequest() { * * @return array */ - function CommandRequest($method) { + public function CommandRequest($method) { $documentServerUrl = $this->config->GetDocumentServerInternalUrl(); if (empty($documentServerUrl)) { @@ -309,7 +309,7 @@ function CommandRequest($method) { * * @return null */ - function ProcessCommandServResponceError($errorCode) { + public function ProcessCommandServResponceError($errorCode) { $errorMessageTemplate = $this->trans->t("Error occurred in the document service"); $errorMessage = ""; From 79555b55cc0c1386a76ca17fcd3d5dc6167588cc Mon Sep 17 00:00:00 2001 From: rivexe Date: Mon, 18 Dec 2023 14:52:00 +0300 Subject: [PATCH 020/114] oc native function invocation --- controller/callbackcontroller.php | 18 +++++++++--------- controller/editorapicontroller.php | 10 +++++----- controller/editorcontroller.php | 28 ++++++++++++++-------------- controller/templatecontroller.php | 2 +- lib/appconfig.php | 26 +++++++++++++------------- lib/documentservice.php | 12 ++++++------ lib/fileutility.php | 2 +- lib/fileversions.php | 2 +- lib/keymanager.php | 4 ++-- lib/preview.php | 2 +- lib/remoteinstance.php | 2 +- lib/templatemanager.php | 6 +++--- templates/settings.php | 10 +++++----- 13 files changed, 62 insertions(+), 62 deletions(-) diff --git a/controller/callbackcontroller.php b/controller/callbackcontroller.php index 20d53d0c..bd407f7f 100644 --- a/controller/callbackcontroller.php +++ b/controller/callbackcontroller.php @@ -202,7 +202,7 @@ public function download($doc) { return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN); } - $header = substr($header, strlen("Bearer ")); + $header = substr($header, \strlen("Bearer ")); try { $decodedHeader = \Firebase\JWT\JWT::decode($header, new \Firebase\JWT\Key($this->config->GetDocumentServerSecret(), "HS256")); @@ -275,7 +275,7 @@ public function download($doc) { $versions = array_reverse($this->versionManager->getVersionsForFile($owner, $file->getFileInfo())); $versionId = null; - if ($version > count($versions)) { + if ($version > \count($versions)) { $versionId = $file->getFileInfo()->getMtime(); } else { $fileVersion = array_values($versions)[$version - 1]; @@ -339,7 +339,7 @@ public function emptyfile($doc) { return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN); } - $header = substr($header, strlen("Bearer ")); + $header = substr($header, \strlen("Bearer ")); try { $decodedHeader = \Firebase\JWT\JWT::decode($header, new \Firebase\JWT\Key($this->config->GetDocumentServerSecret(), "HS256")); @@ -417,7 +417,7 @@ public function track($doc, $users, $key, $status, $url, $token, $history, $chan return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN); } - $header = substr($header, strlen("Bearer ")); + $header = substr($header, \strlen("Bearer ")); try { $decodedHeader = \Firebase\JWT\JWT::decode($header, new \Firebase\JWT\Key($this->config->GetDocumentServerSecret(), "HS256")); @@ -625,7 +625,7 @@ private function getFile($userId, $fileId, $filePath = null, $version = 0, $temp $file = $files[0]; - if (count($files) > 1 && !empty($filePath)) { + if (\count($files) > 1 && !empty($filePath)) { $filePath = "/" . $userId . "/files" . $filePath; foreach ($files as $curFile) { if ($curFile->getPath() === $filePath) { @@ -654,7 +654,7 @@ private function getFile($userId, $fileId, $filePath = null, $version = 0, $temp $versions = array_reverse($this->versionManager->getVersionsForFile($owner, $file->getFileInfo())); - if ($version <= count($versions)) { + if ($version <= \count($versions)) { $fileVersion = array_values($versions)[$version - 1]; $file = $this->versionManager->getVersionFile($owner, $file->getFileInfo(), $fileVersion->getRevisionId()); } @@ -709,7 +709,7 @@ private function getFileByToken($fileId, $shareToken, $version = 0) { if ($owner !== null) { $versions = array_reverse($this->versionManager->getVersionsForFile($owner, $file->getFileInfo())); - if ($version <= count($versions)) { + if ($version <= \count($versions)) { $fileVersion = array_values($versions)[$version - 1]; $file = $this->versionManager->getVersionFile($owner, $file->getFileInfo(), $fileVersion->getRevisionId()); } @@ -757,8 +757,8 @@ private function parseUserId($userId) { $instanceId = $this->config->GetSystemValue("instanceid", true); $instanceId = $instanceId . "_"; - if (substr($userId, 0, strlen($instanceId)) === $instanceId) { - return substr($userId, strlen($instanceId)); + if (substr($userId, 0, \strlen($instanceId)) === $instanceId) { + return substr($userId, \strlen($instanceId)); } return $userId; diff --git a/controller/editorapicontroller.php b/controller/editorapicontroller.php index 29c2099d..d1c5851e 100644 --- a/controller/editorapicontroller.php +++ b/controller/editorapicontroller.php @@ -266,7 +266,7 @@ public function config($fileId, $filePath = null, $shareToken = null, $version = $fileName = $file->getName(); $ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION)); - $format = !empty($ext) && array_key_exists($ext, $this->config->FormatsSetting()) ? $this->config->FormatsSetting()[$ext] : null; + $format = !empty($ext) && \array_key_exists($ext, $this->config->FormatsSetting()) ? $this->config->FormatsSetting()[$ext] : null; if (!isset($format)) { $this->logger->info("Format is not supported for editing: $fileName", ["app" => $this->appName]); return new JSONResponse(["error" => $this->trans->t("Format is not supported")]); @@ -281,7 +281,7 @@ public function config($fileId, $filePath = null, $shareToken = null, $version = if ($owner !== null) { $versions = array_reverse($this->versionManager->getVersionsForFile($owner, $file->getFileInfo())); - if ($version <= count($versions)) { + if ($version <= \count($versions)) { $fileVersion = array_values($versions)[$version - 1]; $key = $this->fileUtility->getVersionKey($fileVersion); @@ -361,7 +361,7 @@ public function config($fileId, $filePath = null, $shareToken = null, $version = && (\OC::$server->getConfig()->getAppValue("files", "enable_lock_file_action", "no") === "yes") && $fileStorage->instanceOfStorage(IPersistentLockingStorage::class)) { $locks = $fileStorage->getLocks($file->getFileInfo()->getInternalPath(), false); - if (count($locks) > 0) { + if (\count($locks) > 0) { $activeLock = $locks[0]; if ($accountId !== $activeLock->getOwnerAccountId()) { @@ -582,7 +582,7 @@ private function getFile($userId, $fileId, $filePath = null, $template = false) $file = $files[0]; - if (count($files) > 1 && !empty($filePath)) { + if (\count($files) > 1 && !empty($filePath)) { $filePath = "/" . $userId . "/files" . $filePath; foreach ($files as $curFile) { if ($curFile->getPath() === $filePath) { @@ -763,7 +763,7 @@ private function setCustomization($params) { private function isFavorite($fileId) { $currentTags = $this->tagManager->load("files")->getTagsForObjects([$fileId]); if ($currentTags) { - return in_array(Tags::TAG_FAVORITE, $currentTags[$fileId]); + return \in_array(Tags::TAG_FAVORITE, $currentTags[$fileId]); } return false; diff --git a/controller/editorcontroller.php b/controller/editorcontroller.php index 7ee9fc9e..c22faff1 100644 --- a/controller/editorcontroller.php +++ b/controller/editorcontroller.php @@ -377,7 +377,7 @@ public function users($fileId) { foreach ($currentUserGroups as $currentUserGroup) { $group = $this->groupManager->get($currentUserGroup); foreach ($group->getUsers() as $user) { - if (!in_array($user, $users)) { + if (!\in_array($user, $users)) { array_push($users, $user); } } @@ -391,7 +391,7 @@ public function users($fileId) { if (!$all) { $accessList = $this->getAccessList($file); foreach ($accessList as $accessUser) { - if (!in_array($accessUser, $users)) { + if (!\in_array($accessUser, $users)) { array_push($users, $accessUser); } } @@ -439,7 +439,7 @@ public function mention($fileId, $anchor, $comment, $emails) { $recipients = $this->userManager->getByEmail($email); foreach ($recipients as $recipient) { $recipientId = $recipient->getUID(); - if (!in_array($recipientId, $recipientIds)) { + if (!\in_array($recipientId, $recipientIds)) { array_push($recipientIds, $recipientId); } } @@ -465,9 +465,9 @@ public function mention($fileId, $anchor, $comment, $emails) { //Length from ownCloud: //https://github.com/owncloud/core/blob/master/lib/private/Notification/Notification.php#L181 $maxLen = 64; - if (strlen($comment) > $maxLen) { + if (\strlen($comment) > $maxLen) { $ending = "..."; - $comment = substr($comment, 0, ($maxLen - strlen($ending))) . $ending; + $comment = substr($comment, 0, ($maxLen - \strlen($ending))) . $ending; } $notificationManager = \OC::$server->getNotificationManager(); @@ -494,7 +494,7 @@ public function mention($fileId, $anchor, $comment, $emails) { foreach ($recipientIds as $recipientId) { $recipient = $this->userManager->get($recipientId); - $isAvailable = in_array($recipient, $accessList); + $isAvailable = \in_array($recipient, $accessList); if (!$isAvailable && $file->getFileInfo()->getMountPoint() instanceof \OCA\Files_External\Config\ExternalMountPoint) { @@ -692,7 +692,7 @@ public function convert($fileId, $shareToken = null) { return ["error" => $this->trans->t("Failed to download converted file")]; } - $fileNameWithoutExt = substr($fileName, 0, strlen($fileName) - strlen($ext) - 1); + $fileNameWithoutExt = substr($fileName, 0, \strlen($fileName) - \strlen($ext) - 1); $newFileName = $folder->getNonExistingName($fileNameWithoutExt . "." . $internalExtension); try { @@ -944,7 +944,7 @@ public function version($fileId, $version) { $key = null; $fileUrl = null; $versionId = null; - if ($version > count($versions)) { + if ($version > \count($versions)) { $key = $this->fileUtility->getKey($file, true); $versionId = $file->getFileInfo()->getMtime(); @@ -969,7 +969,7 @@ public function version($fileId, $version) { ]; if ($version > 1 - && count($versions) >= $version - 1 + && \count($versions) >= $version - 1 && FileVersions::hasChanges($ownerId, $fileId, $versionId)) { $changesUrl = $this->getUrl($file, $user, null, $version, true); $result["changesUrl"] = $changesUrl; @@ -1040,7 +1040,7 @@ public function restore($fileId, $version) { $versions = array_reverse($this->versionManager->getVersionsForFile($owner, $file->getFileInfo())); } - if (count($versions) >= $version) { + if (\count($versions) >= $version) { $fileVersion = array_values($versions)[$version - 1]; $this->versionManager->rollback($fileVersion); } @@ -1173,7 +1173,7 @@ public function download($fileId, $toExtension = null, $template = false) { return $this->renderError($this->trans->t("Failed to download converted file")); } - $fileNameWithoutExt = substr($fileName, 0, strlen($fileName) - strlen($ext) - 1); + $fileNameWithoutExt = substr($fileName, 0, \strlen($fileName) - \strlen($ext) - 1); $newFileName = $fileNameWithoutExt . "." . $toExtension; $formats = $this->config->FormatsSetting(); @@ -1306,7 +1306,7 @@ private function getFile($userId, $fileId, $filePath = null, $template = false) $file = $files[0]; - if (count($files) > 1 && !empty($filePath)) { + if (\count($files) > 1 && !empty($filePath)) { $filePath = "/" . $userId . "/files" . $filePath; foreach ($files as $curFile) { if ($curFile->getPath() === $filePath) { @@ -1404,13 +1404,13 @@ private function getAccessList($file) { } foreach ($accessList as $accessUser) { - if (!in_array($accessUser, $result)) { + if (!\in_array($accessUser, $result)) { array_push($result, $accessUser); } } } - if (!in_array($file->getOwner(), $result)) { + if (!\in_array($file->getOwner(), $result)) { array_push($result, $file->getOwner()); } diff --git a/controller/templatecontroller.php b/controller/templatecontroller.php index 85e83904..d72c819b 100644 --- a/controller/templatecontroller.php +++ b/controller/templatecontroller.php @@ -92,7 +92,7 @@ public function GetTemplates() { public function AddTemplate() { $file = $this->request->getUploadedFile("file"); - if (!is_null($file)) { + if (!\is_null($file)) { if (is_uploaded_file($file["tmp_name"]) && $file["error"] === 0) { if (!TemplateManager::IsTemplateType($file["name"])) { return [ diff --git a/lib/appconfig.php b/lib/appconfig.php index 3aeed811..dae6547c 100644 --- a/lib/appconfig.php +++ b/lib/appconfig.php @@ -327,7 +327,7 @@ public function GetSystemValue($key, $system = false) { return $this->config->getSystemValue($key); } if (!empty($this->config->getSystemValue($this->appName)) - && array_key_exists($key, $this->config->getSystemValue($this->appName))) { + && \array_key_exists($key, $this->config->getSystemValue($this->appName))) { return $this->config->getSystemValue($this->appName)[$key]; } return null; @@ -404,7 +404,7 @@ public function UseDemo() { */ public function SetDocumentServerUrl($documentServer) { $documentServer = trim($documentServer); - if (strlen($documentServer) > 0) { + if (\strlen($documentServer) > 0) { $documentServer = rtrim($documentServer, "/") . "/"; if (!preg_match("/(^https?:\/\/)|^\//i", $documentServer)) { $documentServer = "http://" . $documentServer; @@ -434,7 +434,7 @@ public function GetDocumentServerUrl($origin = false) { } if ($url !== "/") { $url = rtrim($url, "/"); - if (strlen($url) > 0) { + if (\strlen($url) > 0) { $url = $url . "/"; } } @@ -448,7 +448,7 @@ public function GetDocumentServerUrl($origin = false) { */ public function SetDocumentServerInternalUrl($documentServerInternal) { $documentServerInternal = rtrim(trim($documentServerInternal), "/"); - if (strlen($documentServerInternal) > 0) { + if (\strlen($documentServerInternal) > 0) { $documentServerInternal = $documentServerInternal . "/"; if (!preg_match("/^https?:\/\//i", $documentServerInternal)) { $documentServerInternal = "http://" . $documentServerInternal; @@ -496,7 +496,7 @@ public function ReplaceDocumentServerUrlToInternal($url) { if (!preg_match("/^https?:\/\//i", $from)) { $parsedUrl = parse_url($url); - $from = $parsedUrl["scheme"] . "://" . $parsedUrl["host"] . (array_key_exists("port", $parsedUrl) ? (":" . $parsedUrl["port"]) : "") . $from; + $from = $parsedUrl["scheme"] . "://" . $parsedUrl["host"] . (\array_key_exists("port", $parsedUrl) ? (":" . $parsedUrl["port"]) : "") . $from; } if ($from !== $documentServerUrl) { @@ -515,7 +515,7 @@ public function ReplaceDocumentServerUrlToInternal($url) { */ public function SetStorageUrl($storageUrl) { $storageUrl = rtrim(trim($storageUrl), "/"); - if (strlen($storageUrl) > 0) { + if (\strlen($storageUrl) > 0) { $storageUrl = $storageUrl . "/"; if (!preg_match("/^https?:\/\//i", $storageUrl)) { $storageUrl = "http://" . $storageUrl; @@ -944,7 +944,7 @@ public function GetCustomizationPlugins() { * @param array $groups - the list of groups */ public function SetLimitGroups($groups) { - if (!is_array($groups)) { + if (!\is_array($groups)) { $groups = array(); } $value = json_encode($groups); @@ -964,7 +964,7 @@ public function GetLimitGroups() { return array(); } $groups = json_decode($value, true); - if (!is_array($groups)) { + if (!\is_array($groups)) { $groups = array(); } return $groups; @@ -980,17 +980,17 @@ public function GetLimitGroups() { public function isUserAllowedToUse($userId = null) { // no user -> no $userSession = \OC::$server->getUserSession(); - if (is_null($userId) && ($userSession === null || !$userSession->isLoggedIn())) { + if (\is_null($userId) && ($userSession === null || !$userSession->isLoggedIn())) { return false; } $groups = $this->GetLimitGroups(); // no group set -> all users are allowed - if (count($groups) === 0) { + if (\count($groups) === 0) { return true; } - if (is_null($userId)) { + if (\is_null($userId)) { $user = $userSession->getUser(); } else { $user = \OC::$server->getUserManager()->get($userId); @@ -1157,14 +1157,14 @@ public function FormatsSetting() { $defFormats = $this->GetDefaultFormats(); foreach ($defFormats as $format => $setting) { - if (array_key_exists($format, $result)) { + if (\array_key_exists($format, $result)) { $result[$format]["def"] = ($setting === true || $setting === "true"); } } $editFormats = $this->GetEditableFormats(); foreach ($editFormats as $format => $setting) { - if (array_key_exists($format, $result)) { + if (\array_key_exists($format, $result)) { $result[$format]["edit"] = ($setting === true || $setting === "true"); } } diff --git a/lib/documentservice.php b/lib/documentservice.php index faa894ee..981e20ef 100644 --- a/lib/documentservice.php +++ b/lib/documentservice.php @@ -67,11 +67,11 @@ public function __construct(IL10N $trans, AppConfig $appConfig) { * @return string */ public static function GenerateRevisionId($expected_key) { - if (strlen($expected_key) > 20) { + if (\strlen($expected_key) > 20) { $expected_key = crc32($expected_key); } $key = preg_replace("[^0-9-.a-zA-Z_=]", "_", $expected_key); - $key = substr($key, 0, min(array(strlen($key), 20))); + $key = substr($key, 0, min(array(\strlen($key), 20))); return $key; } @@ -171,7 +171,7 @@ public function SendRequestToConvertService($document_uri, $from_extension, $to_ $response_xml_data = $this->Request($urlToConverter, "post", $opts); libxml_use_internal_errors(true); - if (!function_exists("simplexml_load_file")) { + if (!\function_exists("simplexml_load_file")) { throw new \Exception($this->trans->t("Server can't read xml")); } $response_data = simplexml_load_string($response_xml_data); @@ -349,10 +349,10 @@ public function Request($url, $method = "get", $opts = null) { if (null === $opts) { $opts = array(); } - if (substr($url, 0, strlen("https")) === "https" && $this->config->GetVerifyPeerOff()) { + if (substr($url, 0, \strlen("https")) === "https" && $this->config->GetVerifyPeerOff()) { $opts["verify"] = false; } - if (!array_key_exists("timeout", $opts)) { + if (!\array_key_exists("timeout", $opts)) { $opts["timeout"] = 60; } @@ -407,7 +407,7 @@ public function checkDocServiceUrl($urlGenerator, $crypt) { } $version = $commandResponse->version; - $versionF = floatval($version); + $versionF = \floatval($version); if ($versionF > 0.0 && $versionF <= 6.0) { throw new \Exception($this->trans->t("Not supported version")); } diff --git a/lib/fileutility.php b/lib/fileutility.php index fd464faa..3233511e 100644 --- a/lib/fileutility.php +++ b/lib/fileutility.php @@ -273,7 +273,7 @@ public function hasPermissionAttribute($file, $attribute = "download") { * @return string */ private function GUID() { - if (function_exists("com_create_guid") === true) { + if (\function_exists("com_create_guid") === true) { return trim(com_create_guid(), "{}"); } diff --git a/lib/fileversions.php b/lib/fileversions.php index a0e5342b..e690f1f3 100644 --- a/lib/fileversions.php +++ b/lib/fileversions.php @@ -75,7 +75,7 @@ public static function splitPathVersion($pathVersion) { return false; } $filePath = substr($pathVersion, 0, $pos); - $versionId = substr($pathVersion, 2 + $pos - strlen($pathVersion)); + $versionId = substr($pathVersion, 2 + $pos - \strlen($pathVersion)); return [$filePath, $versionId]; } diff --git a/lib/keymanager.php b/lib/keymanager.php index 1507283a..1ab475c9 100644 --- a/lib/keymanager.php +++ b/lib/keymanager.php @@ -47,7 +47,7 @@ public static function get($fileId) { $result = $select->execute([$fileId]); $keys = $result ? $select->fetch() : []; - $key = is_array($keys) && isset($keys["key"]) ? $keys["key"] : ""; + $key = \is_array($keys) && isset($keys["key"]) ? $keys["key"] : ""; return $key; } @@ -142,7 +142,7 @@ public static function wasForcesave($fileId) { $result = $select->execute([$fileId]); $rows = $result ? $select->fetch() : []; - $fs = is_array($rows) && isset($rows["fs"]) ? $rows["fs"] : ""; + $fs = \is_array($rows) && isset($rows["fs"]) ? $rows["fs"] : ""; return $fs === "1"; } diff --git a/lib/preview.php b/lib/preview.php index f6399193..86e7444f 100644 --- a/lib/preview.php +++ b/lib/preview.php @@ -236,7 +236,7 @@ public function isAvailable(FileInfo $fileInfo) { || $fileInfo->getSize() > $this->config->GetLimitThumbSize()) { return false; } - if (!in_array($fileInfo->getMimetype(), self::$capabilities, true)) { + if (!\in_array($fileInfo->getMimetype(), self::$capabilities, true)) { return false; } return true; diff --git a/lib/remoteinstance.php b/lib/remoteinstance.php index 0616dfaf..0d5c00db 100644 --- a/lib/remoteinstance.php +++ b/lib/remoteinstance.php @@ -117,7 +117,7 @@ public static function healthCheck($remote) { $logger = \OC::$server->getLogger(); $remote = rtrim($remote, "/") . "/"; - if (in_array($remote, self::$healthRemote)) { + if (\in_array($remote, self::$healthRemote)) { $logger->debug("Remote instance " . $remote . " from local cache status " . $dbremote["status"], ["app" => self::App_Name]); return true; } diff --git a/lib/templatemanager.php b/lib/templatemanager.php index f0e11dcd..c90a9e4f 100644 --- a/lib/templatemanager.php +++ b/lib/templatemanager.php @@ -73,7 +73,7 @@ public static function GetGlobalTemplates($mimetype = null) { $templatesList = $templateDir->getDirectoryListing(); if (!empty($mimetype) - && is_array($templatesList) && count($templatesList) > 0) { + && \is_array($templatesList) && \count($templatesList) > 0) { $templatesList = $templateDir->searchByMime($mimetype); } @@ -171,11 +171,11 @@ public static function GetEmptyTemplate($fileName) { * @return string */ public static function GetEmptyTemplatePath($lang, $ext) { - if (!array_key_exists($lang, self::$localPath)) { + if (!\array_key_exists($lang, self::$localPath)) { $lang = "en"; } - return dirname(__DIR__) . DIRECTORY_SEPARATOR . "assets" . DIRECTORY_SEPARATOR . self::$localPath[$lang] . DIRECTORY_SEPARATOR . "new" . $ext; + return \dirname(__DIR__) . DIRECTORY_SEPARATOR . "assets" . DIRECTORY_SEPARATOR . self::$localPath[$lang] . DIRECTORY_SEPARATOR . "new" . $ext; } /** diff --git a/templates/settings.php b/templates/settings.php index cd4e6779..83a17f5d 100644 --- a/templates/settings.php +++ b/templates/settings.php @@ -119,7 +119,7 @@

0) { ?>checked="checked" /> + 0) { ?>checked="checked" />
" @@ -148,12 +148,12 @@

t("The default application for opening the format")) ?>

$setting) { ?> - +
checked="checked" /> + checked="checked" />
@@ -166,12 +166,12 @@

$setting) { ?> - +
checked="checked" /> + checked="checked" />
From cab0f82b541705961cf8044ade52f6479ca27b22 Mon Sep 17 00:00:00 2001 From: rivexe Date: Mon, 18 Dec 2023 14:53:07 +0300 Subject: [PATCH 021/114] oc short array syntax --- controller/editorcontroller.php | 6 +++--- lib/appconfig.php | 14 +++++++------- lib/documentservice.php | 4 ++-- lib/versionmanager.php | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/controller/editorcontroller.php b/controller/editorcontroller.php index c22faff1..7e32f805 100644 --- a/controller/editorcontroller.php +++ b/controller/editorcontroller.php @@ -817,7 +817,7 @@ public function history($fileId) { $ownerId = $owner->getUID(); } - $versions = array(); + $versions = []; if ($this->versionManager->available && $owner !== null) { $versions = array_reverse($this->versionManager->getVersionsForFile($owner, $file->getFileInfo())); @@ -932,7 +932,7 @@ public function version($fileId, $version) { $owner = null; $ownerId = null; - $versions = array(); + $versions = []; if ($this->versionManager->available) { $owner = $file->getFileInfo()->getOwner(); if ($owner !== null) { @@ -1033,7 +1033,7 @@ public function restore($fileId, $version) { } $owner = null; - $versions = array(); + $versions = []; if ($this->versionManager->available) { $owner = $file->getFileInfo()->getOwner(); if ($owner !== null) { diff --git a/lib/appconfig.php b/lib/appconfig.php index dae6547c..c20ecc56 100644 --- a/lib/appconfig.php +++ b/lib/appconfig.php @@ -608,7 +608,7 @@ public function SetDefaultFormats($formats) { private function GetDefaultFormats() { $value = $this->config->getAppValue($this->appName, $this->_defFormats, ""); if (empty($value)) { - return array(); + return []; } return json_decode($value, true); } @@ -633,7 +633,7 @@ public function SetEditableFormats($formats) { private function GetEditableFormats() { $value = $this->config->getAppValue($this->appName, $this->_editFormats, ""); if (empty($value)) { - return array(); + return []; } return json_decode($value, true); } @@ -850,7 +850,7 @@ public function GetCustomizationToolbarNoTabs() { * @param string $value - review mode */ public function SetCustomizationReviewDisplay($value) { - $this->logger->info("Set review mode: " . $value, array("app" => $this->appName)); + $this->logger->info("Set review mode: " . $value, ["app" => $this->appName]); $this->config->setAppValue($this->appName, $this->_customizationReviewDisplay, $value); } @@ -877,7 +877,7 @@ public function GetCustomizationReviewDisplay() { * @param string $value - theme */ public function SetCustomizationTheme($value) { - $this->logger->info("Set theme: " . $value, array("app" => $this->appName)); + $this->logger->info("Set theme: " . $value, ["app" => $this->appName]); $this->config->setAppValue($this->appName, $this->_customizationTheme, $value); } @@ -945,7 +945,7 @@ public function GetCustomizationPlugins() { */ public function SetLimitGroups($groups) { if (!\is_array($groups)) { - $groups = array(); + $groups = []; } $value = json_encode($groups); $this->logger->info("Set groups: $value", ["app" => $this->appName]); @@ -961,11 +961,11 @@ public function SetLimitGroups($groups) { public function GetLimitGroups() { $value = $this->config->getAppValue($this->appName, $this->_groups, ""); if (empty($value)) { - return array(); + return []; } $groups = json_decode($value, true); if (!\is_array($groups)) { - $groups = array(); + $groups = []; } return $groups; } diff --git a/lib/documentservice.php b/lib/documentservice.php index 981e20ef..0b4e59cd 100644 --- a/lib/documentservice.php +++ b/lib/documentservice.php @@ -71,7 +71,7 @@ public static function GenerateRevisionId($expected_key) { $expected_key = crc32($expected_key); } $key = preg_replace("[^0-9-.a-zA-Z_=]", "_", $expected_key); - $key = substr($key, 0, min(array(\strlen($key), 20))); + $key = substr($key, 0, min([\strlen($key), 20])); return $key; } @@ -347,7 +347,7 @@ public function Request($url, $method = "get", $opts = null) { $client = $httpClientService->newClient(); if (null === $opts) { - $opts = array(); + $opts = []; } if (substr($url, 0, \strlen("https")) === "https" && $this->config->GetVerifyPeerOff()) { $opts["verify"] = false; diff --git a/lib/versionmanager.php b/lib/versionmanager.php index 2f479a7d..6598afe4 100644 --- a/lib/versionmanager.php +++ b/lib/versionmanager.php @@ -126,7 +126,7 @@ public function getVersionFile($user, $sourceFile, $version) { * @return array */ public function getVersionsForFile($user, $file) { - $versions = array(); + $versions = []; $fileId = $file->getId(); From 72d008ecb109b0dbe3bd76aa5d9634fd1b255d47 Mon Sep 17 00:00:00 2001 From: rivexe Date: Mon, 18 Dec 2023 14:55:00 +0300 Subject: [PATCH 022/114] oc no extra blank lines --- appinfo/application.php | 1 - controller/callbackcontroller.php | 2 -- 2 files changed, 3 deletions(-) diff --git a/appinfo/application.php b/appinfo/application.php index 598698b6..5fd530a1 100644 --- a/appinfo/application.php +++ b/appinfo/application.php @@ -153,7 +153,6 @@ function () { return $c->query("ServerContainer")->getURLGenerator(); }); - // Controllers $container->registerService("SettingsController", function ($c) { return new SettingsController( diff --git a/controller/callbackcontroller.php b/controller/callbackcontroller.php index bd407f7f..fec40cea 100644 --- a/controller/callbackcontroller.php +++ b/controller/callbackcontroller.php @@ -163,7 +163,6 @@ public function __construct( $this->versionManager = new VersionManager($AppName, $root); } - /** * Downloading file by the document service * @@ -593,7 +592,6 @@ public function track($doc, $users, $key, $status, $url, $token, $history, $chan return new JSONResponse(["error" => $result], Http::STATUS_OK); } - /** * Getting file by identifier * From d3188fa3b35a6009ba1658186e10bb74e7ebfdcc Mon Sep 17 00:00:00 2001 From: rivexe Date: Mon, 18 Dec 2023 14:56:14 +0300 Subject: [PATCH 023/114] oc no is_null function --- controller/templatecontroller.php | 2 +- lib/appconfig.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/controller/templatecontroller.php b/controller/templatecontroller.php index d72c819b..4990bfb5 100644 --- a/controller/templatecontroller.php +++ b/controller/templatecontroller.php @@ -92,7 +92,7 @@ public function GetTemplates() { public function AddTemplate() { $file = $this->request->getUploadedFile("file"); - if (!\is_null($file)) { + if (null !== $file) { if (is_uploaded_file($file["tmp_name"]) && $file["error"] === 0) { if (!TemplateManager::IsTemplateType($file["name"])) { return [ diff --git a/lib/appconfig.php b/lib/appconfig.php index c20ecc56..0c9ccde9 100644 --- a/lib/appconfig.php +++ b/lib/appconfig.php @@ -980,7 +980,7 @@ public function GetLimitGroups() { public function isUserAllowedToUse($userId = null) { // no user -> no $userSession = \OC::$server->getUserSession(); - if (\is_null($userId) && ($userSession === null || !$userSession->isLoggedIn())) { + if (null === $userId && ($userSession === null || !$userSession->isLoggedIn())) { return false; } @@ -990,7 +990,7 @@ public function isUserAllowedToUse($userId = null) { return true; } - if (\is_null($userId)) { + if (null === $userId) { $user = $userSession->getUser(); } else { $user = \OC::$server->getUserManager()->get($userId); From 0ae1875985dd1c47cec487674a219f4265e0009e Mon Sep 17 00:00:00 2001 From: rivexe Date: Mon, 18 Dec 2023 14:58:14 +0300 Subject: [PATCH 024/114] oc yoda style ('equal' => false, 'identical' => false) --- controller/templatecontroller.php | 2 +- lib/appconfig.php | 4 ++-- lib/documentservice.php | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/controller/templatecontroller.php b/controller/templatecontroller.php index 4990bfb5..98aa3da3 100644 --- a/controller/templatecontroller.php +++ b/controller/templatecontroller.php @@ -92,7 +92,7 @@ public function GetTemplates() { public function AddTemplate() { $file = $this->request->getUploadedFile("file"); - if (null !== $file) { + if ($file !== null) { if (is_uploaded_file($file["tmp_name"]) && $file["error"] === 0) { if (!TemplateManager::IsTemplateType($file["name"])) { return [ diff --git a/lib/appconfig.php b/lib/appconfig.php index 0c9ccde9..ddbe49f1 100644 --- a/lib/appconfig.php +++ b/lib/appconfig.php @@ -980,7 +980,7 @@ public function GetLimitGroups() { public function isUserAllowedToUse($userId = null) { // no user -> no $userSession = \OC::$server->getUserSession(); - if (null === $userId && ($userSession === null || !$userSession->isLoggedIn())) { + if ($userId === null && ($userSession === null || !$userSession->isLoggedIn())) { return false; } @@ -990,7 +990,7 @@ public function isUserAllowedToUse($userId = null) { return true; } - if (null === $userId) { + if ($userId === null) { $user = $userSession->getUser(); } else { $user = \OC::$server->getUserManager()->get($userId); diff --git a/lib/documentservice.php b/lib/documentservice.php index 0b4e59cd..73828716 100644 --- a/lib/documentservice.php +++ b/lib/documentservice.php @@ -346,7 +346,7 @@ public function Request($url, $method = "get", $opts = null) { $httpClientService = \OC::$server->getHTTPClientService(); $client = $httpClientService->newClient(); - if (null === $opts) { + if ($opts === null) { $opts = []; } if (substr($url, 0, \strlen("https")) === "https" && $this->config->GetVerifyPeerOff()) { From 432b831675b98428a6e7d7e68e8827b074819241 Mon Sep 17 00:00:00 2001 From: rivexe Date: Mon, 18 Dec 2023 15:10:22 +0300 Subject: [PATCH 025/114] add ruleset.xml --- ruleset.xml | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 ruleset.xml diff --git a/ruleset.xml b/ruleset.xml new file mode 100644 index 00000000..b3a2c934 --- /dev/null +++ b/ruleset.xml @@ -0,0 +1,72 @@ + + + ownCloud coding standard + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From e0f8feaf6ff8dc118ff5a6280696a586573c0963 Mon Sep 17 00:00:00 2001 From: Stepan Mayorov Date: Mon, 18 Dec 2023 15:28:24 +0300 Subject: [PATCH 026/114] Update lint-phpcs.yml --- .github/workflows/lint-phpcs.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/lint-phpcs.yml b/.github/workflows/lint-phpcs.yml index e63a7781..be5bea29 100644 --- a/.github/workflows/lint-phpcs.yml +++ b/.github/workflows/lint-phpcs.yml @@ -1,9 +1,11 @@ name: Lint on: + workflow_dispatch: push: - pull_request: branches: [master] + pull_request: + branches: [master, develop, linter-formatting] permissions: contents: read @@ -23,4 +25,4 @@ jobs: tools: composer, cs2pr, phpcs - name: Run phpcs run: | - phpcs --standard=PSR2 --extensions=php,module,inc,install --ignore=node_modules,bower_components,vendor,3rdparty --warning-severity=0 ./ \ No newline at end of file + phpcs --standard=./ruleset.xml --extensions=php,module,inc,install --ignore=node_modules,bower_components,vendor,3rdparty --warning-severity=0 ./ From 3284d99d78c83697862b9c0425ed83592a79f3c5 Mon Sep 17 00:00:00 2001 From: rivexe Date: Mon, 18 Dec 2023 15:56:53 +0300 Subject: [PATCH 027/114] set TAB indent --- appinfo/application.php | 422 ++-- appinfo/routes.php | 72 +- controller/callbackcontroller.php | 1462 +++++++------- controller/editorapicontroller.php | 1438 ++++++------- controller/editorcontroller.php | 2804 +++++++++++++------------- controller/federationcontroller.php | 256 +-- controller/joblistcontroller.php | 146 +- controller/settingsapicontroller.php | 90 +- controller/settingscontroller.php | 534 ++--- controller/templatecontroller.php | 256 +-- controller/webassetcontroller.php | 80 +- lib/adminsettings.php | 52 +- lib/appconfig.php | 2454 +++++++++++----------- lib/command/documentserver.php | 194 +- lib/cron/editorscheck.php | 304 +-- lib/crypt.php | 84 +- lib/documentservice.php | 820 ++++---- lib/fileutility.php | 512 ++--- lib/fileversions.php | 880 ++++---- lib/hookhandler.php | 24 +- lib/hooks.php | 300 +-- lib/keymanager.php | 176 +- lib/notifier.php | 212 +- lib/preview.php | 690 +++---- lib/remoteinstance.php | 476 ++--- lib/templatemanager.php | 372 ++-- lib/version.php | 144 +- lib/versionmanager.php | 302 +-- 28 files changed, 7778 insertions(+), 7778 deletions(-) diff --git a/appinfo/application.php b/appinfo/application.php index 5fd530a1..1d21f078 100644 --- a/appinfo/application.php +++ b/appinfo/application.php @@ -42,215 +42,215 @@ use OCA\Onlyoffice\Preview; class Application extends App { - /** - * Application configuration - * - * @var AppConfig - */ - public $appConfig; - - /** - * Hash generator - * - * @var Crypt - */ - public $crypt; - - public function __construct(array $urlParams = []) { - $appName = "onlyoffice"; - - parent::__construct($appName, $urlParams); - - $this->appConfig = new AppConfig($appName); - $this->crypt = new Crypt($this->appConfig); - - // Default script and style if configured - $eventDispatcher = \OC::$server->getEventDispatcher(); - $eventDispatcher->addListener( - "OCA\Files::loadAdditionalScripts", - function () { - if (!empty($this->appConfig->GetDocumentServerUrl()) - && $this->appConfig->SettingsAreSuccessful() - && $this->appConfig->isUserAllowedToUse()) { - Util::addScript("onlyoffice", "desktop"); - Util::addScript("onlyoffice", "main"); - Util::addScript("onlyoffice", "share"); - Util::addScript("onlyoffice", "template"); - - if ($this->appConfig->GetSameTab()) { - Util::addScript("onlyoffice", "listener"); - } - - Util::addStyle("onlyoffice", "template"); - Util::addStyle("onlyoffice", "main"); - } - } - ); - - Util::connectHook("OCP\Share", "share_link_access", Hookhandler::class, "PublicPage"); - - require_once __DIR__ . "/../3rdparty/jwt/BeforeValidException.php"; - require_once __DIR__ . "/../3rdparty/jwt/ExpiredException.php"; - require_once __DIR__ . "/../3rdparty/jwt/SignatureInvalidException.php"; - require_once __DIR__ . "/../3rdparty/jwt/CachedKeySet.php"; - require_once __DIR__ . "/../3rdparty/jwt/JWT.php"; - require_once __DIR__ . "/../3rdparty/jwt/JWK.php"; - require_once __DIR__ . "/../3rdparty/jwt/Key.php"; - - // Set the leeway for the JWT library in case the system clock is a second off - \Firebase\JWT\JWT::$leeway = $this->appConfig->GetJwtLeeway(); - - $container = $this->getContainer(); - - $detector = $container->query(IMimeTypeDetector::class); - $detector->getAllMappings(); - $detector->registerType("ott", "application/vnd.oasis.opendocument.text-template"); - $detector->registerType("ots", "application/vnd.oasis.opendocument.spreadsheet-template"); - $detector->registerType("otp", "application/vnd.oasis.opendocument.presentation-template"); - $detector->registerType("docxf", "application/vnd.openxmlformats-officedocument.wordprocessingml.document.docxf"); - $detector->registerType("oform", "application/vnd.openxmlformats-officedocument.wordprocessingml.document.oform"); - - $previewManager = $container->query(IPreview::class); - if ($this->appConfig->GetPreview()) { - $previewManager->registerProvider(Preview::getMimeTypeRegex(), function () use ($container) { - return $container->query(Preview::class); - }); - } - - $notificationManager = \OC::$server->getNotificationManager(); - $notificationManager->registerNotifier(function () use ($appName) { - return new Notifier( - $appName, - \OC::$server->getL10NFactory(), - \OC::$server->getURLGenerator(), - \OC::$server->getLogger(), - \OC::$server->getUserManager() - ); - }, function () use ($appName) { - return [ - "id" => $appName, - "name" => $appName, - ]; - }); - - $container->registerService("L10N", function ($c) { - return $c->query("ServerContainer")->getL10N($c->query("AppName")); - }); - - $container->registerService("RootStorage", function ($c) { - return $c->query("ServerContainer")->getRootFolder(); - }); - - $container->registerService("UserSession", function ($c) { - return $c->query("ServerContainer")->getUserSession(); - }); - - $container->registerService("Logger", function ($c) { - return $c->query("ServerContainer")->getLogger(); - }); - - $container->registerService("URLGenerator", function ($c) { - return $c->query("ServerContainer")->getURLGenerator(); - }); - - // Controllers - $container->registerService("SettingsController", function ($c) { - return new SettingsController( - $c->query("AppName"), - $c->query("Request"), - $c->query("URLGenerator"), - $c->query("L10N"), - $c->query("Logger"), - $this->appConfig, - $this->crypt - ); - }); - - $container->registerService("SettingsApiController", function ($c) { - return new SettingsApiController( - $c->query("AppName"), - $c->query("Request"), - $c->query("URLGenerator"), - $this->appConfig - ); - }); - - $container->registerService("EditorController", function ($c) { - return new EditorController( - $c->query("AppName"), - $c->query("Request"), - $c->query("RootStorage"), - $c->query("UserSession"), - $c->query("ServerContainer")->getUserManager(), - $c->query("URLGenerator"), - $c->query("L10N"), - $c->query("Logger"), - $this->appConfig, - $this->crypt, - $c->query("IManager"), - $c->query("Session"), - $c->query("ServerContainer")->getGroupManager() - ); - }); - - $container->registerService("EditorApiController", function ($c) { - return new EditorApiController( - $c->query("AppName"), - $c->query("Request"), - $c->query("RootStorage"), - $c->query("UserSession"), - $c->query("URLGenerator"), - $c->query("L10N"), - $c->query("Logger"), - $this->appConfig, - $this->crypt, - $c->query("IManager"), - $c->query("Session"), - $c->get(ITagManager::class) - ); - }); - - $container->registerService("CallbackController", function ($c) { - return new CallbackController( - $c->query("AppName"), - $c->query("Request"), - $c->query("RootStorage"), - $c->query("UserSession"), - $c->query("ServerContainer")->getUserManager(), - $c->query("L10N"), - $c->query("Logger"), - $this->appConfig, - $this->crypt, - $c->query("IManager") - ); - }); - - $container->registerService("TemplateController", function ($c) { - return new TemplateController( - $c->query("AppName"), - $c->query("Request"), - $c->query("L10N"), - $c->query("Logger") - ); - }); - - $container->registerService("WebAssetController", function ($c) { - return new WebAssetController( - $c->query("AppName"), - $c->query("Request"), - $c->query("Logger") - ); - }); - - $checkBackgroundJobs = new JobListController( - $container->query("AppName"), - $container->query("Request"), - $container->query("Logger"), - $this->appConfig, - $container->query(IJobList::class) - ); - $checkBackgroundJobs->checkAllJobs(); - - Hooks::connectHooks(); - } + /** + * Application configuration + * + * @var AppConfig + */ + public $appConfig; + + /** + * Hash generator + * + * @var Crypt + */ + public $crypt; + + public function __construct(array $urlParams = []) { + $appName = "onlyoffice"; + + parent::__construct($appName, $urlParams); + + $this->appConfig = new AppConfig($appName); + $this->crypt = new Crypt($this->appConfig); + + // Default script and style if configured + $eventDispatcher = \OC::$server->getEventDispatcher(); + $eventDispatcher->addListener( + "OCA\Files::loadAdditionalScripts", + function () { + if (!empty($this->appConfig->GetDocumentServerUrl()) + && $this->appConfig->SettingsAreSuccessful() + && $this->appConfig->isUserAllowedToUse()) { + Util::addScript("onlyoffice", "desktop"); + Util::addScript("onlyoffice", "main"); + Util::addScript("onlyoffice", "share"); + Util::addScript("onlyoffice", "template"); + + if ($this->appConfig->GetSameTab()) { + Util::addScript("onlyoffice", "listener"); + } + + Util::addStyle("onlyoffice", "template"); + Util::addStyle("onlyoffice", "main"); + } + } + ); + + Util::connectHook("OCP\Share", "share_link_access", Hookhandler::class, "PublicPage"); + + require_once __DIR__ . "/../3rdparty/jwt/BeforeValidException.php"; + require_once __DIR__ . "/../3rdparty/jwt/ExpiredException.php"; + require_once __DIR__ . "/../3rdparty/jwt/SignatureInvalidException.php"; + require_once __DIR__ . "/../3rdparty/jwt/CachedKeySet.php"; + require_once __DIR__ . "/../3rdparty/jwt/JWT.php"; + require_once __DIR__ . "/../3rdparty/jwt/JWK.php"; + require_once __DIR__ . "/../3rdparty/jwt/Key.php"; + + // Set the leeway for the JWT library in case the system clock is a second off + \Firebase\JWT\JWT::$leeway = $this->appConfig->GetJwtLeeway(); + + $container = $this->getContainer(); + + $detector = $container->query(IMimeTypeDetector::class); + $detector->getAllMappings(); + $detector->registerType("ott", "application/vnd.oasis.opendocument.text-template"); + $detector->registerType("ots", "application/vnd.oasis.opendocument.spreadsheet-template"); + $detector->registerType("otp", "application/vnd.oasis.opendocument.presentation-template"); + $detector->registerType("docxf", "application/vnd.openxmlformats-officedocument.wordprocessingml.document.docxf"); + $detector->registerType("oform", "application/vnd.openxmlformats-officedocument.wordprocessingml.document.oform"); + + $previewManager = $container->query(IPreview::class); + if ($this->appConfig->GetPreview()) { + $previewManager->registerProvider(Preview::getMimeTypeRegex(), function () use ($container) { + return $container->query(Preview::class); + }); + } + + $notificationManager = \OC::$server->getNotificationManager(); + $notificationManager->registerNotifier(function () use ($appName) { + return new Notifier( + $appName, + \OC::$server->getL10NFactory(), + \OC::$server->getURLGenerator(), + \OC::$server->getLogger(), + \OC::$server->getUserManager() + ); + }, function () use ($appName) { + return [ + "id" => $appName, + "name" => $appName, + ]; + }); + + $container->registerService("L10N", function ($c) { + return $c->query("ServerContainer")->getL10N($c->query("AppName")); + }); + + $container->registerService("RootStorage", function ($c) { + return $c->query("ServerContainer")->getRootFolder(); + }); + + $container->registerService("UserSession", function ($c) { + return $c->query("ServerContainer")->getUserSession(); + }); + + $container->registerService("Logger", function ($c) { + return $c->query("ServerContainer")->getLogger(); + }); + + $container->registerService("URLGenerator", function ($c) { + return $c->query("ServerContainer")->getURLGenerator(); + }); + + // Controllers + $container->registerService("SettingsController", function ($c) { + return new SettingsController( + $c->query("AppName"), + $c->query("Request"), + $c->query("URLGenerator"), + $c->query("L10N"), + $c->query("Logger"), + $this->appConfig, + $this->crypt + ); + }); + + $container->registerService("SettingsApiController", function ($c) { + return new SettingsApiController( + $c->query("AppName"), + $c->query("Request"), + $c->query("URLGenerator"), + $this->appConfig + ); + }); + + $container->registerService("EditorController", function ($c) { + return new EditorController( + $c->query("AppName"), + $c->query("Request"), + $c->query("RootStorage"), + $c->query("UserSession"), + $c->query("ServerContainer")->getUserManager(), + $c->query("URLGenerator"), + $c->query("L10N"), + $c->query("Logger"), + $this->appConfig, + $this->crypt, + $c->query("IManager"), + $c->query("Session"), + $c->query("ServerContainer")->getGroupManager() + ); + }); + + $container->registerService("EditorApiController", function ($c) { + return new EditorApiController( + $c->query("AppName"), + $c->query("Request"), + $c->query("RootStorage"), + $c->query("UserSession"), + $c->query("URLGenerator"), + $c->query("L10N"), + $c->query("Logger"), + $this->appConfig, + $this->crypt, + $c->query("IManager"), + $c->query("Session"), + $c->get(ITagManager::class) + ); + }); + + $container->registerService("CallbackController", function ($c) { + return new CallbackController( + $c->query("AppName"), + $c->query("Request"), + $c->query("RootStorage"), + $c->query("UserSession"), + $c->query("ServerContainer")->getUserManager(), + $c->query("L10N"), + $c->query("Logger"), + $this->appConfig, + $this->crypt, + $c->query("IManager") + ); + }); + + $container->registerService("TemplateController", function ($c) { + return new TemplateController( + $c->query("AppName"), + $c->query("Request"), + $c->query("L10N"), + $c->query("Logger") + ); + }); + + $container->registerService("WebAssetController", function ($c) { + return new WebAssetController( + $c->query("AppName"), + $c->query("Request"), + $c->query("Logger") + ); + }); + + $checkBackgroundJobs = new JobListController( + $container->query("AppName"), + $container->query("Request"), + $container->query("Logger"), + $this->appConfig, + $container->query(IJobList::class) + ); + $checkBackgroundJobs->checkAllJobs(); + + Hooks::connectHooks(); + } } diff --git a/appinfo/routes.php b/appinfo/routes.php index 1f9b0199..82e0270a 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -18,40 +18,40 @@ */ return [ - "routes" => [ - ["name" => "callback#download", "url" => "/download", "verb" => "GET"], - ["name" => "callback#emptyfile", "url" => "/empty", "verb" => "GET"], - ["name" => "callback#track", "url" => "/track", "verb" => "POST"], - ["name" => "editor#create_new", "url" => "/new", "verb" => "GET"], - ["name" => "editor#download", "url" => "/downloadas", "verb" => "GET"], - ["name" => "editor#index", "url" => "/{fileId}", "verb" => "GET"], - ["name" => "editor#public_page", "url" => "/s/{shareToken}", "verb" => "GET"], - ["name" => "editor#users", "url" => "/ajax/users", "verb" => "GET"], - ["name" => "editor#mention", "url" => "/ajax/mention", "verb" => "POST"], - ["name" => "editor#reference", "url" => "/ajax/reference", "verb" => "POST"], - ["name" => "editor#create", "url" => "/ajax/new", "verb" => "POST"], - ["name" => "editor#convert", "url" => "/ajax/convert", "verb" => "POST"], - ["name" => "editor#save", "url" => "/ajax/save", "verb" => "POST"], - ["name" => "editor#url", "url" => "/ajax/url", "verb" => "GET"], - ["name" => "editor#history", "url" => "/ajax/history", "verb" => "GET"], - ["name" => "editor#version", "url" => "/ajax/version", "verb" => "GET"], - ["name" => "editor#restore", "url" => "/ajax/restore", "verb" => "PUT"], - ["name" => "settings#save_address", "url" => "/ajax/settings/address", "verb" => "PUT"], - ["name" => "settings#save_common", "url" => "/ajax/settings/common", "verb" => "PUT"], - ["name" => "settings#save_security", "url" => "/ajax/settings/security", "verb" => "PUT"], - ["name" => "settings#get_settings", "url" => "/ajax/settings", "verb" => "GET"], - ["name" => "settings#clear_history", "url" => "/ajax/settings/history", "verb" => "DELETE"], - ["name" => "template#add_template", "url" => "/ajax/template", "verb" => "POST"], - ["name" => "template#get_templates", "url" => "/ajax/template", "verb" => "GET"], - ["name" => "template#delete_template", "url" => "/ajax/template", "verb" => "DELETE"], - ["name" => "webasset#get", "url" => "/js/onlyoffice.js", "verb" => "GET"], - ], - "ocs" => [ - ["name" => "federation#key", "url" => "/api/v1/key", "verb" => "POST"], - ["name" => "federation#keylock", "url" => "/api/v1/keylock", "verb" => "POST"], - ["name" => "federation#healthcheck", "url" => "/api/v1/healthcheck", "verb" => "GET"], - ["name" => "editorapi#config", "url" => "/api/v1/config/{fileId}", "verb" => "GET"], - ["name" => "editorapi#fillempty", "url" => "/api/v1/empty/{fileId}", "verb" => "GET"], - ["name" => "settingsapi#get_doc_server_url", "url" => "/api/v1/settings/docserver", "verb" => "GET"], - ] + "routes" => [ + ["name" => "callback#download", "url" => "/download", "verb" => "GET"], + ["name" => "callback#emptyfile", "url" => "/empty", "verb" => "GET"], + ["name" => "callback#track", "url" => "/track", "verb" => "POST"], + ["name" => "editor#create_new", "url" => "/new", "verb" => "GET"], + ["name" => "editor#download", "url" => "/downloadas", "verb" => "GET"], + ["name" => "editor#index", "url" => "/{fileId}", "verb" => "GET"], + ["name" => "editor#public_page", "url" => "/s/{shareToken}", "verb" => "GET"], + ["name" => "editor#users", "url" => "/ajax/users", "verb" => "GET"], + ["name" => "editor#mention", "url" => "/ajax/mention", "verb" => "POST"], + ["name" => "editor#reference", "url" => "/ajax/reference", "verb" => "POST"], + ["name" => "editor#create", "url" => "/ajax/new", "verb" => "POST"], + ["name" => "editor#convert", "url" => "/ajax/convert", "verb" => "POST"], + ["name" => "editor#save", "url" => "/ajax/save", "verb" => "POST"], + ["name" => "editor#url", "url" => "/ajax/url", "verb" => "GET"], + ["name" => "editor#history", "url" => "/ajax/history", "verb" => "GET"], + ["name" => "editor#version", "url" => "/ajax/version", "verb" => "GET"], + ["name" => "editor#restore", "url" => "/ajax/restore", "verb" => "PUT"], + ["name" => "settings#save_address", "url" => "/ajax/settings/address", "verb" => "PUT"], + ["name" => "settings#save_common", "url" => "/ajax/settings/common", "verb" => "PUT"], + ["name" => "settings#save_security", "url" => "/ajax/settings/security", "verb" => "PUT"], + ["name" => "settings#get_settings", "url" => "/ajax/settings", "verb" => "GET"], + ["name" => "settings#clear_history", "url" => "/ajax/settings/history", "verb" => "DELETE"], + ["name" => "template#add_template", "url" => "/ajax/template", "verb" => "POST"], + ["name" => "template#get_templates", "url" => "/ajax/template", "verb" => "GET"], + ["name" => "template#delete_template", "url" => "/ajax/template", "verb" => "DELETE"], + ["name" => "webasset#get", "url" => "/js/onlyoffice.js", "verb" => "GET"], + ], + "ocs" => [ + ["name" => "federation#key", "url" => "/api/v1/key", "verb" => "POST"], + ["name" => "federation#keylock", "url" => "/api/v1/keylock", "verb" => "POST"], + ["name" => "federation#healthcheck", "url" => "/api/v1/healthcheck", "verb" => "GET"], + ["name" => "editorapi#config", "url" => "/api/v1/config/{fileId}", "verb" => "GET"], + ["name" => "editorapi#fillempty", "url" => "/api/v1/empty/{fileId}", "verb" => "GET"], + ["name" => "settingsapi#get_doc_server_url", "url" => "/api/v1/settings/docserver", "verb" => "GET"], + ] ]; diff --git a/controller/callbackcontroller.php b/controller/callbackcontroller.php index fec40cea..f9e1509e 100644 --- a/controller/callbackcontroller.php +++ b/controller/callbackcontroller.php @@ -52,735 +52,735 @@ * Save the file without authentication. */ class CallbackController extends Controller { - /** - * Root folder - * - * @var IRootFolder - */ - private $root; - - /** - * User session - * - * @var IUserSession - */ - private $userSession; - - /** - * User manager - * - * @var IUserManager - */ - private $userManager; - - /** - * l10n service - * - * @var IL10N - */ - private $trans; - - /** - * Logger - * - * @var OCP\ILogger - */ - private $logger; - - /** - * Application configuration - * - * @var AppConfig - */ - private $config; - - /** - * Hash generator - * - * @var Crypt - */ - private $crypt; - - /** - * Share manager - * - * @var IManager - */ - private $shareManager; - - /** - * File version manager - * - * @var VersionManager - */ - private $versionManager; - - /** - * Status of the document - */ - private const TrackerStatus_Editing = 1; - private const TrackerStatus_MustSave = 2; - private const TrackerStatus_Corrupted = 3; - private const TrackerStatus_Closed = 4; - private const TrackerStatus_ForceSave = 6; - private const TrackerStatus_CorruptedForceSave = 7; - - /** - * @param string $AppName - application name - * @param IRequest $request - request object - * @param IRootFolder $root - root folder - * @param IUserSession $userSession - user session - * @param IUserManager $userManager - user manager - * @param IL10N $trans - l10n service - * @param ILogger $logger - logger - * @param AppConfig $config - application configuration - * @param Crypt $crypt - hash generator - * @param IManager $shareManager - Share manager - */ - public function __construct( - $AppName, - IRequest $request, - IRootFolder $root, - IUserSession $userSession, - IUserManager $userManager, - IL10N $trans, - ILogger $logger, - AppConfig $config, - Crypt $crypt, - IManager $shareManager - ) { - parent::__construct($AppName, $request); - - $this->root = $root; - $this->userSession = $userSession; - $this->userManager = $userManager; - $this->trans = $trans; - $this->logger = $logger; - $this->config = $config; - $this->crypt = $crypt; - $this->shareManager = $shareManager; - - $this->versionManager = new VersionManager($AppName, $root); - } - - /** - * Downloading file by the document service - * - * @param string $doc - verification token with the file identifier - * - * @return DataDownloadResponse|JSONResponse - * - * @NoAdminRequired - * @NoCSRFRequired - * @PublicPage - * @CORS - */ - public function download($doc) { - list($hashData, $error) = $this->crypt->ReadHash($doc); - if ($hashData === null) { - $this->logger->error("Download with empty or not correct hash: $error", ["app" => $this->appName]); - return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN); - } - if ($hashData->action !== "download") { - $this->logger->error("Download with other action", ["app" => $this->appName]); - return new JSONResponse(["message" => $this->trans->t("Invalid request")], Http::STATUS_BAD_REQUEST); - } - - $fileId = $hashData->fileId; - $version = isset($hashData->version) ? $hashData->version : null; - $changes = isset($hashData->changes) ? $hashData->changes : false; - $template = isset($hashData->template) ? $hashData->template : false; - $this->logger->debug("Download: $fileId ($version)" . ($changes ? " changes" : ""), ["app" => $this->appName]); - - if (!$this->userSession->isLoggedIn() - && !$changes) { - if (!empty($this->config->GetDocumentServerSecret())) { - $header = \OC::$server->getRequest()->getHeader($this->config->JwtHeader()); - if (empty($header)) { - $this->logger->error("Download without jwt", ["app" => $this->appName]); - return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN); - } - - $header = substr($header, \strlen("Bearer ")); - - try { - $decodedHeader = \Firebase\JWT\JWT::decode($header, new \Firebase\JWT\Key($this->config->GetDocumentServerSecret(), "HS256")); - } catch (\UnexpectedValueException $e) { - $this->logger->logException($e, ["message" => "Download with invalid jwt", "app" => $this->appName]); - return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN); - } - } - } - - $userId = null; - - $user = null; - if ($this->userSession->isLoggedIn()) { - $user = $this->userSession->getUser(); - $userId = $user->getUID(); - } else { - \OC_Util::tearDownFS(); - - if (isset($hashData->userId)) { - $userId = $hashData->userId; - - $user = $this->userManager->get($userId); - if (!empty($user)) { - \OC_User::setUserId($userId); - } - - if ($this->config->checkEncryptionModule() === "master") { - \OC_User::setIncognitoMode(true); - } else { - if (!empty($user)) { - \OC_Util::setupFS($userId); - } - } - } - } - - $shareToken = isset($hashData->shareToken) ? $hashData->shareToken : null; - list($file, $error) = empty($shareToken) ? $this->getFile($userId, $fileId, null, $changes ? null : $version, $template) : $this->getFileByToken($fileId, $shareToken, $changes ? null : $version); - - if (isset($error)) { - return $error; - } - - if ($this->userSession->isLoggedIn() && !$file->isReadable()) { - $this->logger->error("Download without access right", ["app" => $this->appName]); - return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN); - } - - if (empty($user) - && $this->config->checkEncryptionModule() !== "master") { - $owner = $file->getFileInfo()->getOwner(); - if ($owner !== null) { - \OC_Util::setupFS($owner->getUID()); - } - } - - if ($changes) { - if ($this->versionManager->available !== true) { - $this->logger->error("Download changes: versionManager is null", ["app" => $this->appName]); - return new JSONResponse(["message" => $this->trans->t("Invalid request")], Http::STATUS_BAD_REQUEST); - } - - $owner = $file->getFileInfo()->getOwner(); - if ($owner === null) { - $this->logger->error("Download: changes owner of $fileId was not found", ["app" => $this->appName]); - return new JSONResponse(["message" => $this->trans->t("Files not found")], Http::STATUS_NOT_FOUND); - } - - $versions = array_reverse($this->versionManager->getVersionsForFile($owner, $file->getFileInfo())); - - $versionId = null; - if ($version > \count($versions)) { - $versionId = $file->getFileInfo()->getMtime(); - } else { - $fileVersion = array_values($versions)[$version - 1]; - - $versionId = $fileVersion->getRevisionId(); - } - - $changesFile = FileVersions::getChangesFile($owner->getUID(), $fileId, $versionId); - if ($changesFile === null) { - $this->logger->error("Download: changes $fileId ($version) was not found", ["app" => $this->appName]); - return new JSONResponse(["message" => $this->trans->t("Files not found")], Http::STATUS_NOT_FOUND); - } - - $file = $changesFile; - } - - try { - $response = new DataDownloadResponse($file->getContent(), $file->getName(), $file->getMimeType()); - - if ($changes) { - $response = \OC_Response::setOptionsRequestHeaders($response); - } - - return $response; - } catch (NotPermittedException $e) { - $this->logger->logException($e, ["message" => "Download Not permitted: $fileId ($version)", "app" => $this->appName]); - return new JSONResponse(["message" => $this->trans->t("Not permitted")], Http::STATUS_FORBIDDEN); - } - return new JSONResponse(["message" => $this->trans->t("Download failed")], Http::STATUS_INTERNAL_SERVER_ERROR); - } - - /** - * Downloading empty file by the document service - * - * @param string $doc - verification token with the file identifier - * - * @return DataDownloadResponse|JSONResponse - * - * @NoAdminRequired - * @NoCSRFRequired - * @PublicPage - * @CORS - */ - public function emptyfile($doc) { - $this->logger->debug("Download empty", ["app" => $this->appName]); - - list($hashData, $error) = $this->crypt->ReadHash($doc); - if ($hashData === null) { - $this->logger->error("Download empty with empty or not correct hash: $error", ["app" => $this->appName]); - return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN); - } - if ($hashData->action !== "empty") { - $this->logger->error("Download empty with other action", ["app" => $this->appName]); - return new JSONResponse(["message" => $this->trans->t("Invalid request")], Http::STATUS_BAD_REQUEST); - } - - if (!empty($this->config->GetDocumentServerSecret())) { - $header = \OC::$server->getRequest()->getHeader($this->config->JwtHeader()); - if (empty($header)) { - $this->logger->error("Download empty without jwt", ["app" => $this->appName]); - return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN); - } - - $header = substr($header, \strlen("Bearer ")); - - try { - $decodedHeader = \Firebase\JWT\JWT::decode($header, new \Firebase\JWT\Key($this->config->GetDocumentServerSecret(), "HS256")); - } catch (\UnexpectedValueException $e) { - $this->logger->logException($e, ["message" => "Download empty with invalid jwt", "app" => $this->appName]); - return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN); - } - } - - $templatePath = TemplateManager::GetEmptyTemplatePath("en", ".docx"); - - $template = file_get_contents($templatePath); - if (!$template) { - $this->logger->info("Template for download empty not found: $templatePath", ["app" => $this->appName]); - return new JSONResponse(["message" => $this->trans->t("File not found")], Http::STATUS_NOT_FOUND); - } - - try { - return new DataDownloadResponse($template, "new.docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"); - } catch (NotPermittedException $e) { - $this->logger->logException($e, ["message" => "Download Not permitted", "app" => $this->appName]); - return new JSONResponse(["message" => $this->trans->t("Not permitted")], Http::STATUS_FORBIDDEN); - } - return new JSONResponse(["message" => $this->trans->t("Download failed")], Http::STATUS_INTERNAL_SERVER_ERROR); - } - - /** - * Handle request from the document server with the document status information - * - * @param string $doc - verification token with the file identifier - * @param array $users - the list of the identifiers of the users - * @param string $key - the edited document identifier - * @param integer $status - the edited status - * @param string $url - the link to the edited document to be saved - * @param string $token - request signature - * @param array $history - file history - * @param string $changesurl - link to file changes - * @param integer $forcesavetype - the type of force save action - * @param array $actions - the array of action - * @param string $filetype - extension of the document that is downloaded from the link specified with the url parameter - * - * @return array - * - * @NoAdminRequired - * @NoCSRFRequired - * @PublicPage - * @CORS - */ - public function track($doc, $users, $key, $status, $url, $token, $history, $changesurl, $forcesavetype, $actions, $filetype) { - list($hashData, $error) = $this->crypt->ReadHash($doc); - if ($hashData === null) { - $this->logger->error("Track with empty or not correct hash: $error", ["app" => $this->appName]); - return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN); - } - if ($hashData->action !== "track") { - $this->logger->error("Track with other action", ["app" => $this->appName]); - return new JSONResponse(["message" => $this->trans->t("Invalid request")], Http::STATUS_BAD_REQUEST); - } - - $fileId = $hashData->fileId; - $this->logger->debug("Track: $fileId status $status", ["app" => $this->appName]); - - if (!empty($this->config->GetDocumentServerSecret())) { - if (!empty($token)) { - try { - $payload = \Firebase\JWT\JWT::decode($token, new \Firebase\JWT\Key($this->config->GetDocumentServerSecret(), "HS256")); - } catch (\UnexpectedValueException $e) { - $this->logger->logException($e, ["message" => "Track with invalid jwt in body", "app" => $this->appName]); - return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN); - } - } else { - $header = \OC::$server->getRequest()->getHeader($this->config->JwtHeader()); - if (empty($header)) { - $this->logger->error("Track without jwt", ["app" => $this->appName]); - return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN); - } - - $header = substr($header, \strlen("Bearer ")); - - try { - $decodedHeader = \Firebase\JWT\JWT::decode($header, new \Firebase\JWT\Key($this->config->GetDocumentServerSecret(), "HS256")); - - $payload = $decodedHeader->payload; - } catch (\UnexpectedValueException $e) { - $this->logger->logException($e, ["message" => "Track with invalid jwt", "app" => $this->appName]); - return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN); - } - } - - $users = isset($payload->users) ? $payload->users : null; - $key = $payload->key; - $status = $payload->status; - $url = isset($payload->url) ? $payload->url : null; - } - - $result = 1; - switch ($status) { - case self::TrackerStatus_MustSave: - case self::TrackerStatus_Corrupted: - case self::TrackerStatus_ForceSave: - case self::TrackerStatus_CorruptedForceSave: - if (empty($url)) { - $this->logger->error("Track without url: $fileId status $status", ["app" => $this->appName]); - return new JSONResponse(["message" => "Url not found"], Http::STATUS_BAD_REQUEST); - } - - try { - $shareToken = isset($hashData->shareToken) ? $hashData->shareToken : null; - $filePath = null; - - \OC_Util::tearDownFS(); - - $isForcesave = $status === self::TrackerStatus_ForceSave || $status === self::TrackerStatus_CorruptedForceSave; - - // author of the latest changes - $userId = $this->parseUserId($users[0]); - - if ($isForcesave - && $forcesavetype === 1 - && !empty($actions)) { - // the user who clicked Save - $userId = $this->parseUserId($actions[0]["userid"]); - } - - $user = $this->userManager->get($userId); - if (!empty($user)) { - \OC_User::setUserId($userId); - } else { - if (empty($shareToken)) { - $this->logger->error("Track without token: $fileId status $status", ["app" => $this->appName]); - return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN); - } - - $this->logger->debug("Track $fileId by token for $userId", ["app" => $this->appName]); - } - - // owner of file from the callback link - $ownerId = $hashData->ownerId; - $owner = $this->userManager->get($ownerId); - - if (!empty($owner)) { - $userId = $ownerId; - } else { - $callbackUserId = $hashData->userId; - $callbackUser = $this->userManager->get($callbackUserId); - - if (!empty($callbackUser)) { - // author of the callback link - $userId = $callbackUserId; - - // path for author of the callback link - $filePath = $hashData->filePath; - } - } - - if ($this->config->checkEncryptionModule() === "master") { - \OC_User::setIncognitoMode(true); - } elseif (!empty($userId)) { - \OC_Util::setupFS($userId); - } - - list($file, $error) = empty($shareToken) ? $this->getFile($userId, $fileId, $filePath) : $this->getFileByToken($fileId, $shareToken); - - if (isset($error)) { - $this->logger->error("track error: $fileId " . json_encode($error->getData()), ["app" => $this->appName]); - return $error; - } - - $url = $this->config->ReplaceDocumentServerUrlToInternal($url); - - $prevVersion = $file->getFileInfo()->getMtime(); - $fileName = $file->getName(); - $curExt = strtolower(pathinfo($fileName, PATHINFO_EXTENSION)); - $downloadExt = $filetype; - - $documentService = new DocumentService($this->trans, $this->config); - if ($downloadExt !== $curExt) { - $key = DocumentService::GenerateRevisionId($fileId . $url); - - try { - $this->logger->debug("Converted from $downloadExt to $curExt", ["app" => $this->appName]); - $url = $documentService->GetConvertedUri($url, $downloadExt, $curExt, $key); - } catch (\Exception $e) { - $this->logger->logException($e, ["message" => "Converted on save error", "app" => $this->appName]); - return new JSONResponse(["message" => $e->getMessage()], Http::STATUS_INTERNAL_SERVER_ERROR); - } - } - - $newData = $documentService->Request($url); - - $prevIsForcesave = KeyManager::wasForcesave($fileId); - - if (RemoteInstance::isRemoteFile($file)) { - $isLock = RemoteInstance::lockRemoteKey($file, $isForcesave, null); - if ($isForcesave && !$isLock) { - break; - } - } else { - KeyManager::lock($fileId, $isForcesave); - } - - $this->logger->debug("Track put content " . $file->getPath(), ["app" => $this->appName]); - $this->retryOperation(function () use ($file, $newData) { - return $file->putContent($newData); - }); - - if (RemoteInstance::isRemoteFile($file)) { - if ($isForcesave) { - RemoteInstance::lockRemoteKey($file, false, $isForcesave); - } - } else { - KeyManager::lock($fileId, false); - KeyManager::setForcesave($fileId, $isForcesave); - } - - if (!$isForcesave - && !$prevIsForcesave - && $this->versionManager->available - && $this->config->GetVersionHistory()) { - $changes = null; - if (!empty($changesurl)) { - $changesurl = $this->config->ReplaceDocumentServerUrlToInternal($changesurl); - $changes = $documentService->Request($changesurl); - } - FileVersions::saveHistory($file->getFileInfo(), $history, $changes, $prevVersion); - } - - if (!empty($user) && $this->config->GetVersionHistory()) { - FileVersions::saveAuthor($file->getFileInfo(), $user); - } - - if ($this->config->checkEncryptionModule() === "master" - && !$isForcesave) { - KeyManager::delete($fileId); - } - - $result = 0; - } catch (\Exception $e) { - $this->logger->logException($e, ["message" => "Track: $fileId status $status error", "app" => $this->appName]); - } - break; - - case self::TrackerStatus_Editing: - case self::TrackerStatus_Closed: - $result = 0; - break; - } - - $this->logger->debug("Track: $fileId status $status result $result", ["app" => $this->appName]); - - return new JSONResponse(["error" => $result], Http::STATUS_OK); - } - - /** - * Getting file by identifier - * - * @param string $userId - user identifier - * @param integer $fileId - file identifier - * @param string $filePath - file path - * @param integer $version - file version - * @param bool $template - file is template - * - * @return array - */ - private function getFile($userId, $fileId, $filePath = null, $version = 0, $template = false) { - if (empty($fileId)) { - return [null, new JSONResponse(["message" => $this->trans->t("FileId is empty")], Http::STATUS_BAD_REQUEST)]; - } - - try { - $folder = !$template ? $this->root->getUserFolder($userId) : TemplateManager::GetGlobalTemplateDir(); - $files = $folder->getById($fileId); - } catch (\Exception $e) { - $this->logger->logException($e, ["message" => "getFile: $fileId", "app" => $this->appName]); - return [null, new JSONResponse(["message" => $this->trans->t("Invalid request")], Http::STATUS_BAD_REQUEST)]; - } - - if (empty($files)) { - $this->logger->error("Files not found: $fileId", ["app" => $this->appName]); - return [null, new JSONResponse(["message" => $this->trans->t("Files not found")], Http::STATUS_NOT_FOUND)]; - } - - $file = $files[0]; - - if (\count($files) > 1 && !empty($filePath)) { - $filePath = "/" . $userId . "/files" . $filePath; - foreach ($files as $curFile) { - if ($curFile->getPath() === $filePath) { - $file = $curFile; - break; - } - } - } - - if (!($file instanceof File)) { - $this->logger->error("File not found: $fileId", ["app" => $this->appName]); - return [null, new JSONResponse(["message" => $this->trans->t("File not found")], Http::STATUS_NOT_FOUND)]; - } - - if ($version > 0 && $this->versionManager->available) { - $owner = $file->getFileInfo()->getOwner(); - - if ($owner !== null) { - if ($owner->getUID() !== $userId) { - list($file, $error) = $this->getFile($owner->getUID(), $file->getId()); - - if (isset($error)) { - return [null, $error]; - } - } - - $versions = array_reverse($this->versionManager->getVersionsForFile($owner, $file->getFileInfo())); - - if ($version <= \count($versions)) { - $fileVersion = array_values($versions)[$version - 1]; - $file = $this->versionManager->getVersionFile($owner, $file->getFileInfo(), $fileVersion->getRevisionId()); - } - } - } - - return [$file, null]; - } - - /** - * Getting file by token - * - * @param integer $fileId - file identifier - * @param string $shareToken - access token - * @param integer $version - file version - * - * @return array - */ - private function getFileByToken($fileId, $shareToken, $version = 0) { - list($share, $error) = $this->getShare($shareToken); - - if (isset($error)) { - return [null, $error]; - } - - try { - $node = $share->getNode(); - } catch (NotFoundException $e) { - $this->logger->logException($e, ["message" => "getFileByToken error", "app" => $this->appName]); - return [null, new JSONResponse(["message" => $this->trans->t("File not found")], Http::STATUS_NOT_FOUND)]; - } - - if ($node instanceof Folder) { - try { - $files = $node->getById($fileId); - } catch (\Exception $e) { - $this->logger->logException($e, ["message" => "getFileByToken: $fileId", "app" => $this->appName]); - return [null, new JSONResponse(["message" => $this->trans->t("Invalid request")], Http::STATUS_NOT_FOUND)]; - } - - if (empty($files)) { - return [null, new JSONResponse(["message" => $this->trans->t("File not found")], Http::STATUS_NOT_FOUND)]; - } - $file = $files[0]; - } else { - $file = $node; - } - - if ($version > 0 && $this->versionManager->available) { - $owner = $file->getFileInfo()->getOwner(); - - if ($owner !== null) { - $versions = array_reverse($this->versionManager->getVersionsForFile($owner, $file->getFileInfo())); - - if ($version <= \count($versions)) { - $fileVersion = array_values($versions)[$version - 1]; - $file = $this->versionManager->getVersionFile($owner, $file->getFileInfo(), $fileVersion->getRevisionId()); - } - } - } - - return [$file, null]; - } - - /** - * Getting share by token - * - * @param string $shareToken - access token - * - * @return array - */ - private function getShare($shareToken) { - if (empty($shareToken)) { - return [null, new JSONResponse(["message" => $this->trans->t("FileId is empty")], Http::STATUS_BAD_REQUEST)]; - } - - $share = null; - try { - $share = $this->shareManager->getShareByToken($shareToken); - } catch (ShareNotFound $e) { - $this->logger->logException($e, ["message" => "getShare error", "app" => $this->appName]); - $share = null; - } - - if ($share === null || $share === false) { - return [null, new JSONResponse(["message" => $this->trans->t("You do not have enough permissions to view the file")], Http::STATUS_FORBIDDEN)]; - } - - return [$share, null]; - } - - /** - * Parse user identifier for current instance - * - * @param string $userId - unique user identifier - * - * @return string - */ - private function parseUserId($userId) { - $instanceId = $this->config->GetSystemValue("instanceid", true); - $instanceId = $instanceId . "_"; - - if (substr($userId, 0, \strlen($instanceId)) === $instanceId) { - return substr($userId, \strlen($instanceId)); - } - - return $userId; - } - - /** - * Retry operation if a LockedException occurred - * Other exceptions will still be thrown - * - * @param callable $operation - * - * @throws LockedException - */ - private function retryOperation(callable $operation) { - $i = 0; - while (true) { - try { - return $operation(); - } catch (LockedException $e) { - if (++$i === 4) { - throw $e; - } - } - usleep(500000); - } - } + /** + * Root folder + * + * @var IRootFolder + */ + private $root; + + /** + * User session + * + * @var IUserSession + */ + private $userSession; + + /** + * User manager + * + * @var IUserManager + */ + private $userManager; + + /** + * l10n service + * + * @var IL10N + */ + private $trans; + + /** + * Logger + * + * @var OCP\ILogger + */ + private $logger; + + /** + * Application configuration + * + * @var AppConfig + */ + private $config; + + /** + * Hash generator + * + * @var Crypt + */ + private $crypt; + + /** + * Share manager + * + * @var IManager + */ + private $shareManager; + + /** + * File version manager + * + * @var VersionManager + */ + private $versionManager; + + /** + * Status of the document + */ + private const TrackerStatus_Editing = 1; + private const TrackerStatus_MustSave = 2; + private const TrackerStatus_Corrupted = 3; + private const TrackerStatus_Closed = 4; + private const TrackerStatus_ForceSave = 6; + private const TrackerStatus_CorruptedForceSave = 7; + + /** + * @param string $AppName - application name + * @param IRequest $request - request object + * @param IRootFolder $root - root folder + * @param IUserSession $userSession - user session + * @param IUserManager $userManager - user manager + * @param IL10N $trans - l10n service + * @param ILogger $logger - logger + * @param AppConfig $config - application configuration + * @param Crypt $crypt - hash generator + * @param IManager $shareManager - Share manager + */ + public function __construct( + $AppName, + IRequest $request, + IRootFolder $root, + IUserSession $userSession, + IUserManager $userManager, + IL10N $trans, + ILogger $logger, + AppConfig $config, + Crypt $crypt, + IManager $shareManager + ) { + parent::__construct($AppName, $request); + + $this->root = $root; + $this->userSession = $userSession; + $this->userManager = $userManager; + $this->trans = $trans; + $this->logger = $logger; + $this->config = $config; + $this->crypt = $crypt; + $this->shareManager = $shareManager; + + $this->versionManager = new VersionManager($AppName, $root); + } + + /** + * Downloading file by the document service + * + * @param string $doc - verification token with the file identifier + * + * @return DataDownloadResponse|JSONResponse + * + * @NoAdminRequired + * @NoCSRFRequired + * @PublicPage + * @CORS + */ + public function download($doc) { + list($hashData, $error) = $this->crypt->ReadHash($doc); + if ($hashData === null) { + $this->logger->error("Download with empty or not correct hash: $error", ["app" => $this->appName]); + return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN); + } + if ($hashData->action !== "download") { + $this->logger->error("Download with other action", ["app" => $this->appName]); + return new JSONResponse(["message" => $this->trans->t("Invalid request")], Http::STATUS_BAD_REQUEST); + } + + $fileId = $hashData->fileId; + $version = isset($hashData->version) ? $hashData->version : null; + $changes = isset($hashData->changes) ? $hashData->changes : false; + $template = isset($hashData->template) ? $hashData->template : false; + $this->logger->debug("Download: $fileId ($version)" . ($changes ? " changes" : ""), ["app" => $this->appName]); + + if (!$this->userSession->isLoggedIn() + && !$changes) { + if (!empty($this->config->GetDocumentServerSecret())) { + $header = \OC::$server->getRequest()->getHeader($this->config->JwtHeader()); + if (empty($header)) { + $this->logger->error("Download without jwt", ["app" => $this->appName]); + return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN); + } + + $header = substr($header, \strlen("Bearer ")); + + try { + $decodedHeader = \Firebase\JWT\JWT::decode($header, new \Firebase\JWT\Key($this->config->GetDocumentServerSecret(), "HS256")); + } catch (\UnexpectedValueException $e) { + $this->logger->logException($e, ["message" => "Download with invalid jwt", "app" => $this->appName]); + return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN); + } + } + } + + $userId = null; + + $user = null; + if ($this->userSession->isLoggedIn()) { + $user = $this->userSession->getUser(); + $userId = $user->getUID(); + } else { + \OC_Util::tearDownFS(); + + if (isset($hashData->userId)) { + $userId = $hashData->userId; + + $user = $this->userManager->get($userId); + if (!empty($user)) { + \OC_User::setUserId($userId); + } + + if ($this->config->checkEncryptionModule() === "master") { + \OC_User::setIncognitoMode(true); + } else { + if (!empty($user)) { + \OC_Util::setupFS($userId); + } + } + } + } + + $shareToken = isset($hashData->shareToken) ? $hashData->shareToken : null; + list($file, $error) = empty($shareToken) ? $this->getFile($userId, $fileId, null, $changes ? null : $version, $template) : $this->getFileByToken($fileId, $shareToken, $changes ? null : $version); + + if (isset($error)) { + return $error; + } + + if ($this->userSession->isLoggedIn() && !$file->isReadable()) { + $this->logger->error("Download without access right", ["app" => $this->appName]); + return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN); + } + + if (empty($user) + && $this->config->checkEncryptionModule() !== "master") { + $owner = $file->getFileInfo()->getOwner(); + if ($owner !== null) { + \OC_Util::setupFS($owner->getUID()); + } + } + + if ($changes) { + if ($this->versionManager->available !== true) { + $this->logger->error("Download changes: versionManager is null", ["app" => $this->appName]); + return new JSONResponse(["message" => $this->trans->t("Invalid request")], Http::STATUS_BAD_REQUEST); + } + + $owner = $file->getFileInfo()->getOwner(); + if ($owner === null) { + $this->logger->error("Download: changes owner of $fileId was not found", ["app" => $this->appName]); + return new JSONResponse(["message" => $this->trans->t("Files not found")], Http::STATUS_NOT_FOUND); + } + + $versions = array_reverse($this->versionManager->getVersionsForFile($owner, $file->getFileInfo())); + + $versionId = null; + if ($version > \count($versions)) { + $versionId = $file->getFileInfo()->getMtime(); + } else { + $fileVersion = array_values($versions)[$version - 1]; + + $versionId = $fileVersion->getRevisionId(); + } + + $changesFile = FileVersions::getChangesFile($owner->getUID(), $fileId, $versionId); + if ($changesFile === null) { + $this->logger->error("Download: changes $fileId ($version) was not found", ["app" => $this->appName]); + return new JSONResponse(["message" => $this->trans->t("Files not found")], Http::STATUS_NOT_FOUND); + } + + $file = $changesFile; + } + + try { + $response = new DataDownloadResponse($file->getContent(), $file->getName(), $file->getMimeType()); + + if ($changes) { + $response = \OC_Response::setOptionsRequestHeaders($response); + } + + return $response; + } catch (NotPermittedException $e) { + $this->logger->logException($e, ["message" => "Download Not permitted: $fileId ($version)", "app" => $this->appName]); + return new JSONResponse(["message" => $this->trans->t("Not permitted")], Http::STATUS_FORBIDDEN); + } + return new JSONResponse(["message" => $this->trans->t("Download failed")], Http::STATUS_INTERNAL_SERVER_ERROR); + } + + /** + * Downloading empty file by the document service + * + * @param string $doc - verification token with the file identifier + * + * @return DataDownloadResponse|JSONResponse + * + * @NoAdminRequired + * @NoCSRFRequired + * @PublicPage + * @CORS + */ + public function emptyfile($doc) { + $this->logger->debug("Download empty", ["app" => $this->appName]); + + list($hashData, $error) = $this->crypt->ReadHash($doc); + if ($hashData === null) { + $this->logger->error("Download empty with empty or not correct hash: $error", ["app" => $this->appName]); + return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN); + } + if ($hashData->action !== "empty") { + $this->logger->error("Download empty with other action", ["app" => $this->appName]); + return new JSONResponse(["message" => $this->trans->t("Invalid request")], Http::STATUS_BAD_REQUEST); + } + + if (!empty($this->config->GetDocumentServerSecret())) { + $header = \OC::$server->getRequest()->getHeader($this->config->JwtHeader()); + if (empty($header)) { + $this->logger->error("Download empty without jwt", ["app" => $this->appName]); + return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN); + } + + $header = substr($header, \strlen("Bearer ")); + + try { + $decodedHeader = \Firebase\JWT\JWT::decode($header, new \Firebase\JWT\Key($this->config->GetDocumentServerSecret(), "HS256")); + } catch (\UnexpectedValueException $e) { + $this->logger->logException($e, ["message" => "Download empty with invalid jwt", "app" => $this->appName]); + return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN); + } + } + + $templatePath = TemplateManager::GetEmptyTemplatePath("en", ".docx"); + + $template = file_get_contents($templatePath); + if (!$template) { + $this->logger->info("Template for download empty not found: $templatePath", ["app" => $this->appName]); + return new JSONResponse(["message" => $this->trans->t("File not found")], Http::STATUS_NOT_FOUND); + } + + try { + return new DataDownloadResponse($template, "new.docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"); + } catch (NotPermittedException $e) { + $this->logger->logException($e, ["message" => "Download Not permitted", "app" => $this->appName]); + return new JSONResponse(["message" => $this->trans->t("Not permitted")], Http::STATUS_FORBIDDEN); + } + return new JSONResponse(["message" => $this->trans->t("Download failed")], Http::STATUS_INTERNAL_SERVER_ERROR); + } + + /** + * Handle request from the document server with the document status information + * + * @param string $doc - verification token with the file identifier + * @param array $users - the list of the identifiers of the users + * @param string $key - the edited document identifier + * @param integer $status - the edited status + * @param string $url - the link to the edited document to be saved + * @param string $token - request signature + * @param array $history - file history + * @param string $changesurl - link to file changes + * @param integer $forcesavetype - the type of force save action + * @param array $actions - the array of action + * @param string $filetype - extension of the document that is downloaded from the link specified with the url parameter + * + * @return array + * + * @NoAdminRequired + * @NoCSRFRequired + * @PublicPage + * @CORS + */ + public function track($doc, $users, $key, $status, $url, $token, $history, $changesurl, $forcesavetype, $actions, $filetype) { + list($hashData, $error) = $this->crypt->ReadHash($doc); + if ($hashData === null) { + $this->logger->error("Track with empty or not correct hash: $error", ["app" => $this->appName]); + return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN); + } + if ($hashData->action !== "track") { + $this->logger->error("Track with other action", ["app" => $this->appName]); + return new JSONResponse(["message" => $this->trans->t("Invalid request")], Http::STATUS_BAD_REQUEST); + } + + $fileId = $hashData->fileId; + $this->logger->debug("Track: $fileId status $status", ["app" => $this->appName]); + + if (!empty($this->config->GetDocumentServerSecret())) { + if (!empty($token)) { + try { + $payload = \Firebase\JWT\JWT::decode($token, new \Firebase\JWT\Key($this->config->GetDocumentServerSecret(), "HS256")); + } catch (\UnexpectedValueException $e) { + $this->logger->logException($e, ["message" => "Track with invalid jwt in body", "app" => $this->appName]); + return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN); + } + } else { + $header = \OC::$server->getRequest()->getHeader($this->config->JwtHeader()); + if (empty($header)) { + $this->logger->error("Track without jwt", ["app" => $this->appName]); + return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN); + } + + $header = substr($header, \strlen("Bearer ")); + + try { + $decodedHeader = \Firebase\JWT\JWT::decode($header, new \Firebase\JWT\Key($this->config->GetDocumentServerSecret(), "HS256")); + + $payload = $decodedHeader->payload; + } catch (\UnexpectedValueException $e) { + $this->logger->logException($e, ["message" => "Track with invalid jwt", "app" => $this->appName]); + return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN); + } + } + + $users = isset($payload->users) ? $payload->users : null; + $key = $payload->key; + $status = $payload->status; + $url = isset($payload->url) ? $payload->url : null; + } + + $result = 1; + switch ($status) { + case self::TrackerStatus_MustSave: + case self::TrackerStatus_Corrupted: + case self::TrackerStatus_ForceSave: + case self::TrackerStatus_CorruptedForceSave: + if (empty($url)) { + $this->logger->error("Track without url: $fileId status $status", ["app" => $this->appName]); + return new JSONResponse(["message" => "Url not found"], Http::STATUS_BAD_REQUEST); + } + + try { + $shareToken = isset($hashData->shareToken) ? $hashData->shareToken : null; + $filePath = null; + + \OC_Util::tearDownFS(); + + $isForcesave = $status === self::TrackerStatus_ForceSave || $status === self::TrackerStatus_CorruptedForceSave; + + // author of the latest changes + $userId = $this->parseUserId($users[0]); + + if ($isForcesave + && $forcesavetype === 1 + && !empty($actions)) { + // the user who clicked Save + $userId = $this->parseUserId($actions[0]["userid"]); + } + + $user = $this->userManager->get($userId); + if (!empty($user)) { + \OC_User::setUserId($userId); + } else { + if (empty($shareToken)) { + $this->logger->error("Track without token: $fileId status $status", ["app" => $this->appName]); + return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN); + } + + $this->logger->debug("Track $fileId by token for $userId", ["app" => $this->appName]); + } + + // owner of file from the callback link + $ownerId = $hashData->ownerId; + $owner = $this->userManager->get($ownerId); + + if (!empty($owner)) { + $userId = $ownerId; + } else { + $callbackUserId = $hashData->userId; + $callbackUser = $this->userManager->get($callbackUserId); + + if (!empty($callbackUser)) { + // author of the callback link + $userId = $callbackUserId; + + // path for author of the callback link + $filePath = $hashData->filePath; + } + } + + if ($this->config->checkEncryptionModule() === "master") { + \OC_User::setIncognitoMode(true); + } elseif (!empty($userId)) { + \OC_Util::setupFS($userId); + } + + list($file, $error) = empty($shareToken) ? $this->getFile($userId, $fileId, $filePath) : $this->getFileByToken($fileId, $shareToken); + + if (isset($error)) { + $this->logger->error("track error: $fileId " . json_encode($error->getData()), ["app" => $this->appName]); + return $error; + } + + $url = $this->config->ReplaceDocumentServerUrlToInternal($url); + + $prevVersion = $file->getFileInfo()->getMtime(); + $fileName = $file->getName(); + $curExt = strtolower(pathinfo($fileName, PATHINFO_EXTENSION)); + $downloadExt = $filetype; + + $documentService = new DocumentService($this->trans, $this->config); + if ($downloadExt !== $curExt) { + $key = DocumentService::GenerateRevisionId($fileId . $url); + + try { + $this->logger->debug("Converted from $downloadExt to $curExt", ["app" => $this->appName]); + $url = $documentService->GetConvertedUri($url, $downloadExt, $curExt, $key); + } catch (\Exception $e) { + $this->logger->logException($e, ["message" => "Converted on save error", "app" => $this->appName]); + return new JSONResponse(["message" => $e->getMessage()], Http::STATUS_INTERNAL_SERVER_ERROR); + } + } + + $newData = $documentService->Request($url); + + $prevIsForcesave = KeyManager::wasForcesave($fileId); + + if (RemoteInstance::isRemoteFile($file)) { + $isLock = RemoteInstance::lockRemoteKey($file, $isForcesave, null); + if ($isForcesave && !$isLock) { + break; + } + } else { + KeyManager::lock($fileId, $isForcesave); + } + + $this->logger->debug("Track put content " . $file->getPath(), ["app" => $this->appName]); + $this->retryOperation(function () use ($file, $newData) { + return $file->putContent($newData); + }); + + if (RemoteInstance::isRemoteFile($file)) { + if ($isForcesave) { + RemoteInstance::lockRemoteKey($file, false, $isForcesave); + } + } else { + KeyManager::lock($fileId, false); + KeyManager::setForcesave($fileId, $isForcesave); + } + + if (!$isForcesave + && !$prevIsForcesave + && $this->versionManager->available + && $this->config->GetVersionHistory()) { + $changes = null; + if (!empty($changesurl)) { + $changesurl = $this->config->ReplaceDocumentServerUrlToInternal($changesurl); + $changes = $documentService->Request($changesurl); + } + FileVersions::saveHistory($file->getFileInfo(), $history, $changes, $prevVersion); + } + + if (!empty($user) && $this->config->GetVersionHistory()) { + FileVersions::saveAuthor($file->getFileInfo(), $user); + } + + if ($this->config->checkEncryptionModule() === "master" + && !$isForcesave) { + KeyManager::delete($fileId); + } + + $result = 0; + } catch (\Exception $e) { + $this->logger->logException($e, ["message" => "Track: $fileId status $status error", "app" => $this->appName]); + } + break; + + case self::TrackerStatus_Editing: + case self::TrackerStatus_Closed: + $result = 0; + break; + } + + $this->logger->debug("Track: $fileId status $status result $result", ["app" => $this->appName]); + + return new JSONResponse(["error" => $result], Http::STATUS_OK); + } + + /** + * Getting file by identifier + * + * @param string $userId - user identifier + * @param integer $fileId - file identifier + * @param string $filePath - file path + * @param integer $version - file version + * @param bool $template - file is template + * + * @return array + */ + private function getFile($userId, $fileId, $filePath = null, $version = 0, $template = false) { + if (empty($fileId)) { + return [null, new JSONResponse(["message" => $this->trans->t("FileId is empty")], Http::STATUS_BAD_REQUEST)]; + } + + try { + $folder = !$template ? $this->root->getUserFolder($userId) : TemplateManager::GetGlobalTemplateDir(); + $files = $folder->getById($fileId); + } catch (\Exception $e) { + $this->logger->logException($e, ["message" => "getFile: $fileId", "app" => $this->appName]); + return [null, new JSONResponse(["message" => $this->trans->t("Invalid request")], Http::STATUS_BAD_REQUEST)]; + } + + if (empty($files)) { + $this->logger->error("Files not found: $fileId", ["app" => $this->appName]); + return [null, new JSONResponse(["message" => $this->trans->t("Files not found")], Http::STATUS_NOT_FOUND)]; + } + + $file = $files[0]; + + if (\count($files) > 1 && !empty($filePath)) { + $filePath = "/" . $userId . "/files" . $filePath; + foreach ($files as $curFile) { + if ($curFile->getPath() === $filePath) { + $file = $curFile; + break; + } + } + } + + if (!($file instanceof File)) { + $this->logger->error("File not found: $fileId", ["app" => $this->appName]); + return [null, new JSONResponse(["message" => $this->trans->t("File not found")], Http::STATUS_NOT_FOUND)]; + } + + if ($version > 0 && $this->versionManager->available) { + $owner = $file->getFileInfo()->getOwner(); + + if ($owner !== null) { + if ($owner->getUID() !== $userId) { + list($file, $error) = $this->getFile($owner->getUID(), $file->getId()); + + if (isset($error)) { + return [null, $error]; + } + } + + $versions = array_reverse($this->versionManager->getVersionsForFile($owner, $file->getFileInfo())); + + if ($version <= \count($versions)) { + $fileVersion = array_values($versions)[$version - 1]; + $file = $this->versionManager->getVersionFile($owner, $file->getFileInfo(), $fileVersion->getRevisionId()); + } + } + } + + return [$file, null]; + } + + /** + * Getting file by token + * + * @param integer $fileId - file identifier + * @param string $shareToken - access token + * @param integer $version - file version + * + * @return array + */ + private function getFileByToken($fileId, $shareToken, $version = 0) { + list($share, $error) = $this->getShare($shareToken); + + if (isset($error)) { + return [null, $error]; + } + + try { + $node = $share->getNode(); + } catch (NotFoundException $e) { + $this->logger->logException($e, ["message" => "getFileByToken error", "app" => $this->appName]); + return [null, new JSONResponse(["message" => $this->trans->t("File not found")], Http::STATUS_NOT_FOUND)]; + } + + if ($node instanceof Folder) { + try { + $files = $node->getById($fileId); + } catch (\Exception $e) { + $this->logger->logException($e, ["message" => "getFileByToken: $fileId", "app" => $this->appName]); + return [null, new JSONResponse(["message" => $this->trans->t("Invalid request")], Http::STATUS_NOT_FOUND)]; + } + + if (empty($files)) { + return [null, new JSONResponse(["message" => $this->trans->t("File not found")], Http::STATUS_NOT_FOUND)]; + } + $file = $files[0]; + } else { + $file = $node; + } + + if ($version > 0 && $this->versionManager->available) { + $owner = $file->getFileInfo()->getOwner(); + + if ($owner !== null) { + $versions = array_reverse($this->versionManager->getVersionsForFile($owner, $file->getFileInfo())); + + if ($version <= \count($versions)) { + $fileVersion = array_values($versions)[$version - 1]; + $file = $this->versionManager->getVersionFile($owner, $file->getFileInfo(), $fileVersion->getRevisionId()); + } + } + } + + return [$file, null]; + } + + /** + * Getting share by token + * + * @param string $shareToken - access token + * + * @return array + */ + private function getShare($shareToken) { + if (empty($shareToken)) { + return [null, new JSONResponse(["message" => $this->trans->t("FileId is empty")], Http::STATUS_BAD_REQUEST)]; + } + + $share = null; + try { + $share = $this->shareManager->getShareByToken($shareToken); + } catch (ShareNotFound $e) { + $this->logger->logException($e, ["message" => "getShare error", "app" => $this->appName]); + $share = null; + } + + if ($share === null || $share === false) { + return [null, new JSONResponse(["message" => $this->trans->t("You do not have enough permissions to view the file")], Http::STATUS_FORBIDDEN)]; + } + + return [$share, null]; + } + + /** + * Parse user identifier for current instance + * + * @param string $userId - unique user identifier + * + * @return string + */ + private function parseUserId($userId) { + $instanceId = $this->config->GetSystemValue("instanceid", true); + $instanceId = $instanceId . "_"; + + if (substr($userId, 0, \strlen($instanceId)) === $instanceId) { + return substr($userId, \strlen($instanceId)); + } + + return $userId; + } + + /** + * Retry operation if a LockedException occurred + * Other exceptions will still be thrown + * + * @param callable $operation + * + * @throws LockedException + */ + private function retryOperation(callable $operation) { + $i = 0; + while (true) { + try { + return $operation(); + } catch (LockedException $e) { + if (++$i === 4) { + throw $e; + } + } + usleep(500000); + } + } } diff --git a/controller/editorapicontroller.php b/controller/editorapicontroller.php index d1c5851e..bd212e99 100644 --- a/controller/editorapicontroller.php +++ b/controller/editorapicontroller.php @@ -49,723 +49,723 @@ * Controller with the main functions */ class EditorApiController extends OCSController { - /** - * Current user session - * - * @var IUserSession - */ - private $userSession; - - /** - * Root folder - * - * @var IRootFolder - */ - private $root; - - /** - * Url generator service - * - * @var IURLGenerator - */ - private $urlGenerator; - - /** - * l10n service - * - * @var IL10N - */ - private $trans; - - /** - * Logger - * - * @var ILogger - */ - private $logger; - - /** - * Application configuration - * - * @var AppConfig - */ - private $config; - - /** - * Hash generator - * - * @var Crypt - */ - private $crypt; - - /** - * File utility - * - * @var FileUtility - */ - private $fileUtility; - - /** - * File version manager - * - * @var VersionManager - */ - private $versionManager; - - /** - * Tag manager - * - * @var ITagManager - */ - private $tagManager; - - /** - * Mobile regex from https://github.com/ONLYOFFICE/CommunityServer/blob/v9.1.1/web/studio/ASC.Web.Studio/web.appsettings.config#L35 - */ - public const USER_AGENT_MOBILE = "/android|avantgo|playbook|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od|ad)|iris|kindle|lge |maemo|midp|mmp|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\\/|plucker|pocket|psp|symbian|treo|up\\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i"; - - /** - * @param string $AppName - application name - * @param IRequest $request - request object - * @param IRootFolder $root - root folder - * @param IUserSession $userSession - current user session - * @param IURLGenerator $urlGenerator - url generator service - * @param IL10N $trans - l10n service - * @param ILogger $logger - logger - * @param AppConfig $config - application configuration - * @param Crypt $crypt - hash generator - * @param IManager $shareManager - Share manager - * @param ISession $ISession - Session - * @param ITagManager $tagManager - Tag manager - */ - public function __construct( - $AppName, - IRequest $request, - IRootFolder $root, - IUserSession $userSession, - IURLGenerator $urlGenerator, - IL10N $trans, - ILogger $logger, - AppConfig $config, - Crypt $crypt, - IManager $shareManager, - ISession $session, - ITagManager $tagManager - ) { - parent::__construct($AppName, $request); - - $this->userSession = $userSession; - $this->root = $root; - $this->urlGenerator = $urlGenerator; - $this->trans = $trans; - $this->logger = $logger; - $this->config = $config; - $this->crypt = $crypt; - $this->tagManager = $tagManager; - - $this->versionManager = new VersionManager($AppName, $root); - - $this->fileUtility = new FileUtility($AppName, $trans, $logger, $config, $shareManager, $session); - } - - /** - * Filling empty file an template - * - * @param int $fileId - file identificator - * - * @return JSONResponse - * - * @NoAdminRequired - * @PublicPage - */ - public function fillempty($fileId) { - $this->logger->debug("Fill empty: $fileId", ["app" => $this->appName]); - - if (empty($fileId)) { - $this->logger->error("File for filling was not found: $fileId", ["app" => $this->appName]); - return new JSONResponse(["error" => $this->trans->t("FileId is empty")]); - } - - $userId = $this->userSession->getUser()->getUID(); - - list($file, $error, $share) = $this->getFile($userId, $fileId); - if (isset($error)) { - $this->logger->error("Fill empty: $fileId $error", ["app" => $this->appName]); - return new JSONResponse(["error" => $error]); - } - - if ($file->getSize() > 0) { - $this->logger->error("File is't empty: $fileId", ["app" => $this->appName]); - return new JSONResponse(["error" => $this->trans->t("Not permitted")]); - } - - if (!$file->isUpdateable()) { - $this->logger->error("File without permission: $fileId", ["app" => $this->appName]); - return new JSONResponse(["error" => $this->trans->t("Not permitted")]); - } - - $name = $file->getName(); - $template = TemplateManager::GetEmptyTemplate($name); - - if (!$template) { - $this->logger->error("Template for file filling not found: $name ($fileId)", ["app" => $this->appName]); - return new JSONResponse(["error" => $this->trans->t("Template not found")]); - } - - try { - $file->putContent($template); - } catch (NotPermittedException $e) { - $this->logger->logException($e, ["message" => "Can't put file: $name", "app" => $this->appName]); - return new JSONResponse(["error" => $this->trans->t("Can't create file")]); - } - - return new JSONResponse([ - ]); - } - - /** - * Collecting the file parameters for the document service - * - * @param integer $fileId - file identifier - * @param string $filePath - file path - * @param string $shareToken - access token - * @param integer $version - file version - * @param bool $inframe - open in frame - * @param bool $desktop - desktop label - * @param bool $template - file is template - * - * @return JSONResponse - * - * @NoAdminRequired - * @PublicPage - * @CORS - */ - public function config($fileId, $filePath = null, $shareToken = null, $version = 0, $inframe = false, $desktop = false, $template = false, $anchor = null) { - $user = $this->userSession->getUser(); - $userId = null; - $accountId = null; - if (!empty($user)) { - $userId = $user->getUID(); - $accountId = $user->getAccountId(); - } - - list($file, $error, $share) = empty($shareToken) ? $this->getFile($userId, $fileId, $filePath, $template) : $this->fileUtility->getFileByToken($fileId, $shareToken); - - if (isset($error)) { - $this->logger->error("Config: $fileId $error", ["app" => $this->appName]); - return new JSONResponse(["error" => $error]); - } - - $checkUserAllowGroups = $userId; - if (!empty($share)) { - $checkUserAllowGroups = $share->getSharedBy(); - } - if (!$this->config->isUserAllowedToUse($checkUserAllowGroups)) { - return new JSONResponse(["error" => $this->trans->t("Not permitted")]); - } - - $fileName = $file->getName(); - $ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION)); - $format = !empty($ext) && \array_key_exists($ext, $this->config->FormatsSetting()) ? $this->config->FormatsSetting()[$ext] : null; - if (!isset($format)) { - $this->logger->info("Format is not supported for editing: $fileName", ["app" => $this->appName]); - return new JSONResponse(["error" => $this->trans->t("Format is not supported")]); - } - - $fileUrl = $this->getUrl($file, $user, $shareToken, $version, null, $template); - - $key = null; - if ($version > 0 - && $this->versionManager->available) { - $owner = $file->getFileInfo()->getOwner(); - if ($owner !== null) { - $versions = array_reverse($this->versionManager->getVersionsForFile($owner, $file->getFileInfo())); - - if ($version <= \count($versions)) { - $fileVersion = array_values($versions)[$version - 1]; - - $key = $this->fileUtility->getVersionKey($fileVersion); - } - } - } - if ($key === null) { - $key = $this->fileUtility->getKey($file, true); - } - $key = DocumentService::GenerateRevisionId($key); - - $params = [ - "document" => [ - "fileType" => $ext, - "key" => $key, - "permissions" => [], - "title" => $fileName, - "url" => $fileUrl, - "referenceData" => [ - "fileKey" => $file->getId(), - "instanceId" => $this->config->GetSystemValue("instanceid", true), - ], - ], - "documentType" => $format["type"], - "editorConfig" => [ - "lang" => str_replace("_", "-", \OC::$server->getL10NFactory("")->get("")->getLanguageCode()) - ] - ]; - - $restrictedEditing = false; - $fileStorage = $file->getStorage(); - if (empty($shareToken) && $fileStorage->instanceOfStorage("\OCA\Files_Sharing\SharedStorage")) { - $storageShare = $fileStorage->getShare(); - if (method_exists($storageShare, "getAttributes")) { - $attributes = $storageShare->getAttributes(); - - $permissionsDownload = $attributes->getAttribute("permissions", "download"); - if ($permissionsDownload !== null) { - $params["document"]["permissions"]["download"] = $params["document"]["permissions"]["print"] = $params["document"]["permissions"]["copy"] = $permissionsDownload === true; - } - - if (isset($format["review"]) && $format["review"]) { - $permissionsReviewOnly = $attributes->getAttribute($this->appName, "review"); - if ($permissionsReviewOnly !== null && $permissionsReviewOnly === true) { - $restrictedEditing = true; - $params["document"]["permissions"]["review"] = true; - } - } - - if (isset($format["fillForms"]) && $format["fillForms"]) { - $permissionsFillFormsOnly = $attributes->getAttribute($this->appName, "fillForms"); - if ($permissionsFillFormsOnly !== null && $permissionsFillFormsOnly === true) { - $restrictedEditing = true; - $params["document"]["permissions"]["fillForms"] = true; - } - } - - if (isset($format["comment"]) && $format["comment"]) { - $permissionsCommentOnly = $attributes->getAttribute($this->appName, "comment"); - if ($permissionsCommentOnly !== null && $permissionsCommentOnly === true) { - $restrictedEditing = true; - $params["document"]["permissions"]["comment"] = true; - } - } - - if (isset($format["modifyFilter"]) && $format["modifyFilter"]) { - $permissionsModifyFilter = $attributes->getAttribute($this->appName, "modifyFilter"); - if ($permissionsModifyFilter !== null) { - $params["document"]["permissions"]["modifyFilter"] = $permissionsModifyFilter === true; - } - } - } - } - - $isPersistentLock = false; - if ($version < 1 - && (\OC::$server->getConfig()->getAppValue("files", "enable_lock_file_action", "no") === "yes") - && $fileStorage->instanceOfStorage(IPersistentLockingStorage::class)) { - $locks = $fileStorage->getLocks($file->getFileInfo()->getInternalPath(), false); - if (\count($locks) > 0) { - $activeLock = $locks[0]; - - if ($accountId !== $activeLock->getOwnerAccountId()) { - $isPersistentLock = true; - $lockOwner = $activeLock->getOwner(); - $this->logger->debug("File $fileId is locked by $lockOwner", ["app" => $this->appName]); - } - } - } - - $canEdit = isset($format["edit"]) && $format["edit"]; - $canFillForms = isset($format["fillForms"]) && $format["fillForms"]; - $editable = $version < 1 - && !$template - && $file->isUpdateable() - && !$isPersistentLock - && (empty($shareToken) || ($share->getPermissions() & Constants::PERMISSION_UPDATE) === Constants::PERMISSION_UPDATE); - $params["document"]["permissions"]["edit"] = $editable; - if (($editable || $restrictedEditing) && $canEdit || $canFillForms) { - $ownerId = null; - $owner = $file->getOwner(); - if (!empty($owner)) { - $ownerId = $owner->getUID(); - } - - $canProtect = true; - if ($this->config->GetProtection() === "owner") { - $canProtect = $ownerId === $userId; - } - $params["document"]["permissions"]["protect"] = $canProtect; - - if (isset($shareToken)) { - $params["document"]["permissions"]["chat"] = false; - $params["document"]["permissions"]["protect"] = false; - } - - $hashCallback = $this->crypt->GetHash(["userId" => $userId, "ownerId" => $ownerId, "fileId" => $file->getId(), "filePath" => $filePath, "shareToken" => $shareToken, "action" => "track"]); - $callback = $this->urlGenerator->linkToRouteAbsolute($this->appName . ".callback.track", ["doc" => $hashCallback]); - - if (!$this->config->UseDemo() && !empty($this->config->GetStorageUrl())) { - $callback = str_replace($this->urlGenerator->getAbsoluteURL("/"), $this->config->GetStorageUrl(), $callback); - } - - $params["editorConfig"]["callbackUrl"] = $callback; - } else { - $params["editorConfig"]["mode"] = "view"; - } - - if (\OC::$server->getRequest()->isUserAgent([$this::USER_AGENT_MOBILE])) { - $params["type"] = "mobile"; - } - - if (!$template - && $file->isUpdateable() - && !$isPersistentLock - && (empty($shareToken) || ($share->getPermissions() & Constants::PERMISSION_UPDATE) === Constants::PERMISSION_UPDATE)) { - $params["document"]["permissions"]["changeHistory"] = true; - } - - if (!empty($userId)) { - $params["editorConfig"]["user"] = [ - "id" => $this->buildUserId($userId), - "name" => $user->getDisplayName() - ]; - } - - $folderLink = null; - - if (!empty($shareToken)) { - $node = $share->getNode(); - if ($node instanceof Folder) { - $sharedFolder = $node; - $folderPath = $sharedFolder->getRelativePath($file->getParent()->getPath()); - if (!empty($folderPath)) { - $linkAttr = [ - "path" => $folderPath, - "scrollto" => $file->getName(), - "token" => $shareToken - ]; - $folderLink = $this->urlGenerator->linkToRouteAbsolute("files_sharing.sharecontroller.showShare", $linkAttr); - } - } - } elseif (!empty($userId)) { - $userFolder = $this->root->getUserFolder($userId); - $folderPath = $userFolder->getRelativePath($file->getParent()->getPath()); - if (!empty($folderPath)) { - $linkAttr = [ - "dir" => $folderPath, - "scrollto" => $file->getName() - ]; - $folderLink = $this->urlGenerator->linkToRouteAbsolute("files.view.index", $linkAttr); - } - - switch ($params["documentType"]) { - case "word": - $createName = $this->trans->t("Document") . ".docx"; - break; - case "cell": - $createName = $this->trans->t("Spreadsheet") . ".xlsx"; - break; - case "slide": - $createName = $this->trans->t("Presentation") . ".pptx"; - break; - } - - $createParam = [ - "dir" => "/", - "name" => $createName - ]; - - if (!empty($folderPath)) { - $folder = $userFolder->get($folderPath); - if (!empty($folder) && $folder->isCreatable()) { - $createParam["dir"] = $folderPath; - } - } - - $createUrl = $this->urlGenerator->linkToRouteAbsolute($this->appName . ".editor.create_new", $createParam); - - $params["editorConfig"]["createUrl"] = urldecode($createUrl); - - $templatesList = TemplateManager::GetGlobalTemplates($file->getMimeType()); - if (!empty($templatesList)) { - $templates = []; - foreach ($templatesList as $templateItem) { - $createParam["templateId"] = $templateItem->getId(); - $createParam["name"] = $templateItem->getName(); - - array_push($templates, [ - "image" => "", - "title" => $templateItem->getName(), - "url" => urldecode($this->urlGenerator->linkToRouteAbsolute($this->appName . ".editor.create_new", $createParam)) - ]); - } - - $params["editorConfig"]["templates"] = $templates; - } - - if (!$template) { - $params["document"]["info"]["favorite"] = $this->isFavorite($fileId); - } - $params["_file_path"] = $userFolder->getRelativePath($file->getPath()); - } - - if ($folderLink !== null - && $this->config->GetSystemValue($this->config->_customization_goback) !== false) { - $params["editorConfig"]["customization"]["goback"] = [ - "url" => $folderLink - ]; - - if (!$desktop) { - if ($this->config->GetSameTab()) { - $params["editorConfig"]["customization"]["goback"]["blank"] = false; - if ($inframe === true) { - $params["editorConfig"]["customization"]["goback"]["requestClose"] = true; - } - } - } - } - - if ($inframe === true) { - $params["_files_sharing"] = \OC::$server->getAppManager()->isEnabledForUser("files_sharing"); - } - - $params = $this->setCustomization($params); - - if ($this->config->UseDemo()) { - $params["editorConfig"]["tenant"] = $this->config->GetSystemValue("instanceid", true); - } - - if ($anchor !== null) { - try { - $actionLink = json_decode($anchor, true); - - $params["editorConfig"]["actionLink"] = $actionLink; - } catch (\Exception $e) { - $this->logger->logException($e, ["message" => "Config: $fileId decode $anchor", "app" => $this->appName]); - } - } - - if (!empty($this->config->GetDocumentServerSecret())) { - $token = \Firebase\JWT\JWT::encode($params, $this->config->GetDocumentServerSecret(), "HS256"); - $params["token"] = $token; - } - - $this->logger->debug("Config is generated for: $fileId ($version) with key $key", ["app" => $this->appName]); - - return new JSONResponse($params); - } - - /** - * Getting file by identifier - * - * @param string $userId - user identifier - * @param integer $fileId - file identifier - * @param string $filePath - file path - * @param bool $template - file is template - * - * @return array - */ - private function getFile($userId, $fileId, $filePath = null, $template = false) { - if (empty($fileId)) { - return [null, $this->trans->t("FileId is empty"), null]; - } - - try { - $folder = !$template ? $this->root->getUserFolder($userId) : TemplateManager::GetGlobalTemplateDir(); - $files = $folder->getById($fileId); - } catch (\Exception $e) { - $this->logger->logException($e, ["message" => "getFile: $fileId", "app" => $this->appName]); - return [null, $this->trans->t("Invalid request"), null]; - } - - if (empty($files)) { - $this->logger->info("Files not found: $fileId", ["app" => $this->appName]); - return [null, $this->trans->t("File not found"), null]; - } - - $file = $files[0]; - - if (\count($files) > 1 && !empty($filePath)) { - $filePath = "/" . $userId . "/files" . $filePath; - foreach ($files as $curFile) { - if ($curFile->getPath() === $filePath) { - $file = $curFile; - break; - } - } - } - - if (!$file->isReadable()) { - return [null, $this->trans->t("You do not have enough permissions to view the file"), null]; - } - - return [$file, null, null]; - } - - /** - * Generate secure link to download document - * - * @param File $file - file - * @param IUser $user - user with access - * @param string $shareToken - access token - * @param integer $version - file version - * @param bool $changes - is required url to file changes - * @param bool $template - file is template - * - * @return string - */ - private function getUrl($file, $user = null, $shareToken = null, $version = 0, $changes = false, $template = false) { - $data = [ - "action" => "download", - "fileId" => $file->getId() - ]; - - $userId = null; - if (!empty($user)) { - $userId = $user->getUID(); - $data["userId"] = $userId; - } - if (!empty($shareToken)) { - $data["shareToken"] = $shareToken; - } - if ($version > 0) { - $data["version"] = $version; - } - if ($changes) { - $data["changes"] = true; - } - if ($template) { - $data["template"] = true; - } - - $hashUrl = $this->crypt->GetHash($data); - - $fileUrl = $this->urlGenerator->linkToRouteAbsolute($this->appName . ".callback.download", ["doc" => $hashUrl]); - - if (!$this->config->UseDemo() && !empty($this->config->GetStorageUrl())) { - $fileUrl = str_replace($this->urlGenerator->getAbsoluteURL("/"), $this->config->GetStorageUrl(), $fileUrl); - } - - return $fileUrl; - } - - /** - * Generate unique user identifier - * - * @param string $userId - current user identifier - * - * @return string - */ - private function buildUserId($userId) { - $instanceId = $this->config->GetSystemValue("instanceid", true); - $userId = $instanceId . "_" . $userId; - return $userId; - } - - /** - * Set customization parameters - * - * @param array params - file parameters - * - * @return array - */ - private function setCustomization($params) { - //default is true - if ($this->config->GetCustomizationChat() === false) { - $params["editorConfig"]["customization"]["chat"] = false; - } - - //default is false - if ($this->config->GetCustomizationCompactHeader() === true) { - $params["editorConfig"]["customization"]["compactHeader"] = true; - } - - //default is false - if ($this->config->GetCustomizationFeedback() === true) { - $params["editorConfig"]["customization"]["feedback"] = true; - } - - //default is false - if ($this->config->GetCustomizationForcesave() === true) { - $params["editorConfig"]["customization"]["forcesave"] = true; - } - - //default is true - if ($this->config->GetCustomizationHelp() === false) { - $params["editorConfig"]["customization"]["help"] = false; - } - - //default is original - $reviewDisplay = $this->config->GetCustomizationReviewDisplay(); - if ($reviewDisplay !== "original") { - $params["editorConfig"]["customization"]["reviewDisplay"] = $reviewDisplay; - } - - $theme = $this->config->GetCustomizationTheme(); - if (isset($theme)) { - $params["editorConfig"]["customization"]["uiTheme"] = $theme; - } - - //default is false - if ($this->config->GetCustomizationToolbarNoTabs() === true) { - $params["editorConfig"]["customization"]["toolbarNoTabs"] = true; - } - - //default is true - if ($this->config->GetCustomizationMacros() === false) { - $params["editorConfig"]["customization"]["macros"] = false; - } - - //default is true - if ($this->config->GetCustomizationPlugins() === false) { - $params["editorConfig"]["customization"]["plugins"] = false; - } - - /* from system config */ - - $autosave = $this->config->GetSystemValue($this->config->_customization_autosave); - if (isset($autosave)) { - $params["editorConfig"]["customization"]["autosave"] = $autosave; - } - - $customer = $this->config->GetSystemValue($this->config->_customization_customer); - if (isset($customer)) { - $params["editorConfig"]["customization"]["customer"] = $customer; - } - - $loaderLogo = $this->config->GetSystemValue($this->config->_customization_loaderLogo); - if (isset($loaderLogo)) { - $params["editorConfig"]["customization"]["loaderLogo"] = $loaderLogo; - } - - $loaderName = $this->config->GetSystemValue($this->config->_customization_loaderName); - if (isset($loaderName)) { - $params["editorConfig"]["customization"]["loaderName"] = $loaderName; - } - - $logo = $this->config->GetSystemValue($this->config->_customization_logo); - if (isset($logo)) { - $params["editorConfig"]["customization"]["logo"] = $logo; - } - - $zoom = $this->config->GetSystemValue($this->config->_customization_zoom); - if (isset($zoom)) { - $params["editorConfig"]["customization"]["zoom"] = $zoom; - } - - return $params; - } - - /** - * Check file favorite - * - * @param integer $fileId - file identifier - * - * @return bool - */ - private function isFavorite($fileId) { - $currentTags = $this->tagManager->load("files")->getTagsForObjects([$fileId]); - if ($currentTags) { - return \in_array(Tags::TAG_FAVORITE, $currentTags[$fileId]); - } - - return false; - } + /** + * Current user session + * + * @var IUserSession + */ + private $userSession; + + /** + * Root folder + * + * @var IRootFolder + */ + private $root; + + /** + * Url generator service + * + * @var IURLGenerator + */ + private $urlGenerator; + + /** + * l10n service + * + * @var IL10N + */ + private $trans; + + /** + * Logger + * + * @var ILogger + */ + private $logger; + + /** + * Application configuration + * + * @var AppConfig + */ + private $config; + + /** + * Hash generator + * + * @var Crypt + */ + private $crypt; + + /** + * File utility + * + * @var FileUtility + */ + private $fileUtility; + + /** + * File version manager + * + * @var VersionManager + */ + private $versionManager; + + /** + * Tag manager + * + * @var ITagManager + */ + private $tagManager; + + /** + * Mobile regex from https://github.com/ONLYOFFICE/CommunityServer/blob/v9.1.1/web/studio/ASC.Web.Studio/web.appsettings.config#L35 + */ + public const USER_AGENT_MOBILE = "/android|avantgo|playbook|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od|ad)|iris|kindle|lge |maemo|midp|mmp|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\\/|plucker|pocket|psp|symbian|treo|up\\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i"; + + /** + * @param string $AppName - application name + * @param IRequest $request - request object + * @param IRootFolder $root - root folder + * @param IUserSession $userSession - current user session + * @param IURLGenerator $urlGenerator - url generator service + * @param IL10N $trans - l10n service + * @param ILogger $logger - logger + * @param AppConfig $config - application configuration + * @param Crypt $crypt - hash generator + * @param IManager $shareManager - Share manager + * @param ISession $ISession - Session + * @param ITagManager $tagManager - Tag manager + */ + public function __construct( + $AppName, + IRequest $request, + IRootFolder $root, + IUserSession $userSession, + IURLGenerator $urlGenerator, + IL10N $trans, + ILogger $logger, + AppConfig $config, + Crypt $crypt, + IManager $shareManager, + ISession $session, + ITagManager $tagManager + ) { + parent::__construct($AppName, $request); + + $this->userSession = $userSession; + $this->root = $root; + $this->urlGenerator = $urlGenerator; + $this->trans = $trans; + $this->logger = $logger; + $this->config = $config; + $this->crypt = $crypt; + $this->tagManager = $tagManager; + + $this->versionManager = new VersionManager($AppName, $root); + + $this->fileUtility = new FileUtility($AppName, $trans, $logger, $config, $shareManager, $session); + } + + /** + * Filling empty file an template + * + * @param int $fileId - file identificator + * + * @return JSONResponse + * + * @NoAdminRequired + * @PublicPage + */ + public function fillempty($fileId) { + $this->logger->debug("Fill empty: $fileId", ["app" => $this->appName]); + + if (empty($fileId)) { + $this->logger->error("File for filling was not found: $fileId", ["app" => $this->appName]); + return new JSONResponse(["error" => $this->trans->t("FileId is empty")]); + } + + $userId = $this->userSession->getUser()->getUID(); + + list($file, $error, $share) = $this->getFile($userId, $fileId); + if (isset($error)) { + $this->logger->error("Fill empty: $fileId $error", ["app" => $this->appName]); + return new JSONResponse(["error" => $error]); + } + + if ($file->getSize() > 0) { + $this->logger->error("File is't empty: $fileId", ["app" => $this->appName]); + return new JSONResponse(["error" => $this->trans->t("Not permitted")]); + } + + if (!$file->isUpdateable()) { + $this->logger->error("File without permission: $fileId", ["app" => $this->appName]); + return new JSONResponse(["error" => $this->trans->t("Not permitted")]); + } + + $name = $file->getName(); + $template = TemplateManager::GetEmptyTemplate($name); + + if (!$template) { + $this->logger->error("Template for file filling not found: $name ($fileId)", ["app" => $this->appName]); + return new JSONResponse(["error" => $this->trans->t("Template not found")]); + } + + try { + $file->putContent($template); + } catch (NotPermittedException $e) { + $this->logger->logException($e, ["message" => "Can't put file: $name", "app" => $this->appName]); + return new JSONResponse(["error" => $this->trans->t("Can't create file")]); + } + + return new JSONResponse([ + ]); + } + + /** + * Collecting the file parameters for the document service + * + * @param integer $fileId - file identifier + * @param string $filePath - file path + * @param string $shareToken - access token + * @param integer $version - file version + * @param bool $inframe - open in frame + * @param bool $desktop - desktop label + * @param bool $template - file is template + * + * @return JSONResponse + * + * @NoAdminRequired + * @PublicPage + * @CORS + */ + public function config($fileId, $filePath = null, $shareToken = null, $version = 0, $inframe = false, $desktop = false, $template = false, $anchor = null) { + $user = $this->userSession->getUser(); + $userId = null; + $accountId = null; + if (!empty($user)) { + $userId = $user->getUID(); + $accountId = $user->getAccountId(); + } + + list($file, $error, $share) = empty($shareToken) ? $this->getFile($userId, $fileId, $filePath, $template) : $this->fileUtility->getFileByToken($fileId, $shareToken); + + if (isset($error)) { + $this->logger->error("Config: $fileId $error", ["app" => $this->appName]); + return new JSONResponse(["error" => $error]); + } + + $checkUserAllowGroups = $userId; + if (!empty($share)) { + $checkUserAllowGroups = $share->getSharedBy(); + } + if (!$this->config->isUserAllowedToUse($checkUserAllowGroups)) { + return new JSONResponse(["error" => $this->trans->t("Not permitted")]); + } + + $fileName = $file->getName(); + $ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION)); + $format = !empty($ext) && \array_key_exists($ext, $this->config->FormatsSetting()) ? $this->config->FormatsSetting()[$ext] : null; + if (!isset($format)) { + $this->logger->info("Format is not supported for editing: $fileName", ["app" => $this->appName]); + return new JSONResponse(["error" => $this->trans->t("Format is not supported")]); + } + + $fileUrl = $this->getUrl($file, $user, $shareToken, $version, null, $template); + + $key = null; + if ($version > 0 + && $this->versionManager->available) { + $owner = $file->getFileInfo()->getOwner(); + if ($owner !== null) { + $versions = array_reverse($this->versionManager->getVersionsForFile($owner, $file->getFileInfo())); + + if ($version <= \count($versions)) { + $fileVersion = array_values($versions)[$version - 1]; + + $key = $this->fileUtility->getVersionKey($fileVersion); + } + } + } + if ($key === null) { + $key = $this->fileUtility->getKey($file, true); + } + $key = DocumentService::GenerateRevisionId($key); + + $params = [ + "document" => [ + "fileType" => $ext, + "key" => $key, + "permissions" => [], + "title" => $fileName, + "url" => $fileUrl, + "referenceData" => [ + "fileKey" => $file->getId(), + "instanceId" => $this->config->GetSystemValue("instanceid", true), + ], + ], + "documentType" => $format["type"], + "editorConfig" => [ + "lang" => str_replace("_", "-", \OC::$server->getL10NFactory("")->get("")->getLanguageCode()) + ] + ]; + + $restrictedEditing = false; + $fileStorage = $file->getStorage(); + if (empty($shareToken) && $fileStorage->instanceOfStorage("\OCA\Files_Sharing\SharedStorage")) { + $storageShare = $fileStorage->getShare(); + if (method_exists($storageShare, "getAttributes")) { + $attributes = $storageShare->getAttributes(); + + $permissionsDownload = $attributes->getAttribute("permissions", "download"); + if ($permissionsDownload !== null) { + $params["document"]["permissions"]["download"] = $params["document"]["permissions"]["print"] = $params["document"]["permissions"]["copy"] = $permissionsDownload === true; + } + + if (isset($format["review"]) && $format["review"]) { + $permissionsReviewOnly = $attributes->getAttribute($this->appName, "review"); + if ($permissionsReviewOnly !== null && $permissionsReviewOnly === true) { + $restrictedEditing = true; + $params["document"]["permissions"]["review"] = true; + } + } + + if (isset($format["fillForms"]) && $format["fillForms"]) { + $permissionsFillFormsOnly = $attributes->getAttribute($this->appName, "fillForms"); + if ($permissionsFillFormsOnly !== null && $permissionsFillFormsOnly === true) { + $restrictedEditing = true; + $params["document"]["permissions"]["fillForms"] = true; + } + } + + if (isset($format["comment"]) && $format["comment"]) { + $permissionsCommentOnly = $attributes->getAttribute($this->appName, "comment"); + if ($permissionsCommentOnly !== null && $permissionsCommentOnly === true) { + $restrictedEditing = true; + $params["document"]["permissions"]["comment"] = true; + } + } + + if (isset($format["modifyFilter"]) && $format["modifyFilter"]) { + $permissionsModifyFilter = $attributes->getAttribute($this->appName, "modifyFilter"); + if ($permissionsModifyFilter !== null) { + $params["document"]["permissions"]["modifyFilter"] = $permissionsModifyFilter === true; + } + } + } + } + + $isPersistentLock = false; + if ($version < 1 + && (\OC::$server->getConfig()->getAppValue("files", "enable_lock_file_action", "no") === "yes") + && $fileStorage->instanceOfStorage(IPersistentLockingStorage::class)) { + $locks = $fileStorage->getLocks($file->getFileInfo()->getInternalPath(), false); + if (\count($locks) > 0) { + $activeLock = $locks[0]; + + if ($accountId !== $activeLock->getOwnerAccountId()) { + $isPersistentLock = true; + $lockOwner = $activeLock->getOwner(); + $this->logger->debug("File $fileId is locked by $lockOwner", ["app" => $this->appName]); + } + } + } + + $canEdit = isset($format["edit"]) && $format["edit"]; + $canFillForms = isset($format["fillForms"]) && $format["fillForms"]; + $editable = $version < 1 + && !$template + && $file->isUpdateable() + && !$isPersistentLock + && (empty($shareToken) || ($share->getPermissions() & Constants::PERMISSION_UPDATE) === Constants::PERMISSION_UPDATE); + $params["document"]["permissions"]["edit"] = $editable; + if (($editable || $restrictedEditing) && $canEdit || $canFillForms) { + $ownerId = null; + $owner = $file->getOwner(); + if (!empty($owner)) { + $ownerId = $owner->getUID(); + } + + $canProtect = true; + if ($this->config->GetProtection() === "owner") { + $canProtect = $ownerId === $userId; + } + $params["document"]["permissions"]["protect"] = $canProtect; + + if (isset($shareToken)) { + $params["document"]["permissions"]["chat"] = false; + $params["document"]["permissions"]["protect"] = false; + } + + $hashCallback = $this->crypt->GetHash(["userId" => $userId, "ownerId" => $ownerId, "fileId" => $file->getId(), "filePath" => $filePath, "shareToken" => $shareToken, "action" => "track"]); + $callback = $this->urlGenerator->linkToRouteAbsolute($this->appName . ".callback.track", ["doc" => $hashCallback]); + + if (!$this->config->UseDemo() && !empty($this->config->GetStorageUrl())) { + $callback = str_replace($this->urlGenerator->getAbsoluteURL("/"), $this->config->GetStorageUrl(), $callback); + } + + $params["editorConfig"]["callbackUrl"] = $callback; + } else { + $params["editorConfig"]["mode"] = "view"; + } + + if (\OC::$server->getRequest()->isUserAgent([$this::USER_AGENT_MOBILE])) { + $params["type"] = "mobile"; + } + + if (!$template + && $file->isUpdateable() + && !$isPersistentLock + && (empty($shareToken) || ($share->getPermissions() & Constants::PERMISSION_UPDATE) === Constants::PERMISSION_UPDATE)) { + $params["document"]["permissions"]["changeHistory"] = true; + } + + if (!empty($userId)) { + $params["editorConfig"]["user"] = [ + "id" => $this->buildUserId($userId), + "name" => $user->getDisplayName() + ]; + } + + $folderLink = null; + + if (!empty($shareToken)) { + $node = $share->getNode(); + if ($node instanceof Folder) { + $sharedFolder = $node; + $folderPath = $sharedFolder->getRelativePath($file->getParent()->getPath()); + if (!empty($folderPath)) { + $linkAttr = [ + "path" => $folderPath, + "scrollto" => $file->getName(), + "token" => $shareToken + ]; + $folderLink = $this->urlGenerator->linkToRouteAbsolute("files_sharing.sharecontroller.showShare", $linkAttr); + } + } + } elseif (!empty($userId)) { + $userFolder = $this->root->getUserFolder($userId); + $folderPath = $userFolder->getRelativePath($file->getParent()->getPath()); + if (!empty($folderPath)) { + $linkAttr = [ + "dir" => $folderPath, + "scrollto" => $file->getName() + ]; + $folderLink = $this->urlGenerator->linkToRouteAbsolute("files.view.index", $linkAttr); + } + + switch ($params["documentType"]) { + case "word": + $createName = $this->trans->t("Document") . ".docx"; + break; + case "cell": + $createName = $this->trans->t("Spreadsheet") . ".xlsx"; + break; + case "slide": + $createName = $this->trans->t("Presentation") . ".pptx"; + break; + } + + $createParam = [ + "dir" => "/", + "name" => $createName + ]; + + if (!empty($folderPath)) { + $folder = $userFolder->get($folderPath); + if (!empty($folder) && $folder->isCreatable()) { + $createParam["dir"] = $folderPath; + } + } + + $createUrl = $this->urlGenerator->linkToRouteAbsolute($this->appName . ".editor.create_new", $createParam); + + $params["editorConfig"]["createUrl"] = urldecode($createUrl); + + $templatesList = TemplateManager::GetGlobalTemplates($file->getMimeType()); + if (!empty($templatesList)) { + $templates = []; + foreach ($templatesList as $templateItem) { + $createParam["templateId"] = $templateItem->getId(); + $createParam["name"] = $templateItem->getName(); + + array_push($templates, [ + "image" => "", + "title" => $templateItem->getName(), + "url" => urldecode($this->urlGenerator->linkToRouteAbsolute($this->appName . ".editor.create_new", $createParam)) + ]); + } + + $params["editorConfig"]["templates"] = $templates; + } + + if (!$template) { + $params["document"]["info"]["favorite"] = $this->isFavorite($fileId); + } + $params["_file_path"] = $userFolder->getRelativePath($file->getPath()); + } + + if ($folderLink !== null + && $this->config->GetSystemValue($this->config->_customization_goback) !== false) { + $params["editorConfig"]["customization"]["goback"] = [ + "url" => $folderLink + ]; + + if (!$desktop) { + if ($this->config->GetSameTab()) { + $params["editorConfig"]["customization"]["goback"]["blank"] = false; + if ($inframe === true) { + $params["editorConfig"]["customization"]["goback"]["requestClose"] = true; + } + } + } + } + + if ($inframe === true) { + $params["_files_sharing"] = \OC::$server->getAppManager()->isEnabledForUser("files_sharing"); + } + + $params = $this->setCustomization($params); + + if ($this->config->UseDemo()) { + $params["editorConfig"]["tenant"] = $this->config->GetSystemValue("instanceid", true); + } + + if ($anchor !== null) { + try { + $actionLink = json_decode($anchor, true); + + $params["editorConfig"]["actionLink"] = $actionLink; + } catch (\Exception $e) { + $this->logger->logException($e, ["message" => "Config: $fileId decode $anchor", "app" => $this->appName]); + } + } + + if (!empty($this->config->GetDocumentServerSecret())) { + $token = \Firebase\JWT\JWT::encode($params, $this->config->GetDocumentServerSecret(), "HS256"); + $params["token"] = $token; + } + + $this->logger->debug("Config is generated for: $fileId ($version) with key $key", ["app" => $this->appName]); + + return new JSONResponse($params); + } + + /** + * Getting file by identifier + * + * @param string $userId - user identifier + * @param integer $fileId - file identifier + * @param string $filePath - file path + * @param bool $template - file is template + * + * @return array + */ + private function getFile($userId, $fileId, $filePath = null, $template = false) { + if (empty($fileId)) { + return [null, $this->trans->t("FileId is empty"), null]; + } + + try { + $folder = !$template ? $this->root->getUserFolder($userId) : TemplateManager::GetGlobalTemplateDir(); + $files = $folder->getById($fileId); + } catch (\Exception $e) { + $this->logger->logException($e, ["message" => "getFile: $fileId", "app" => $this->appName]); + return [null, $this->trans->t("Invalid request"), null]; + } + + if (empty($files)) { + $this->logger->info("Files not found: $fileId", ["app" => $this->appName]); + return [null, $this->trans->t("File not found"), null]; + } + + $file = $files[0]; + + if (\count($files) > 1 && !empty($filePath)) { + $filePath = "/" . $userId . "/files" . $filePath; + foreach ($files as $curFile) { + if ($curFile->getPath() === $filePath) { + $file = $curFile; + break; + } + } + } + + if (!$file->isReadable()) { + return [null, $this->trans->t("You do not have enough permissions to view the file"), null]; + } + + return [$file, null, null]; + } + + /** + * Generate secure link to download document + * + * @param File $file - file + * @param IUser $user - user with access + * @param string $shareToken - access token + * @param integer $version - file version + * @param bool $changes - is required url to file changes + * @param bool $template - file is template + * + * @return string + */ + private function getUrl($file, $user = null, $shareToken = null, $version = 0, $changes = false, $template = false) { + $data = [ + "action" => "download", + "fileId" => $file->getId() + ]; + + $userId = null; + if (!empty($user)) { + $userId = $user->getUID(); + $data["userId"] = $userId; + } + if (!empty($shareToken)) { + $data["shareToken"] = $shareToken; + } + if ($version > 0) { + $data["version"] = $version; + } + if ($changes) { + $data["changes"] = true; + } + if ($template) { + $data["template"] = true; + } + + $hashUrl = $this->crypt->GetHash($data); + + $fileUrl = $this->urlGenerator->linkToRouteAbsolute($this->appName . ".callback.download", ["doc" => $hashUrl]); + + if (!$this->config->UseDemo() && !empty($this->config->GetStorageUrl())) { + $fileUrl = str_replace($this->urlGenerator->getAbsoluteURL("/"), $this->config->GetStorageUrl(), $fileUrl); + } + + return $fileUrl; + } + + /** + * Generate unique user identifier + * + * @param string $userId - current user identifier + * + * @return string + */ + private function buildUserId($userId) { + $instanceId = $this->config->GetSystemValue("instanceid", true); + $userId = $instanceId . "_" . $userId; + return $userId; + } + + /** + * Set customization parameters + * + * @param array params - file parameters + * + * @return array + */ + private function setCustomization($params) { + //default is true + if ($this->config->GetCustomizationChat() === false) { + $params["editorConfig"]["customization"]["chat"] = false; + } + + //default is false + if ($this->config->GetCustomizationCompactHeader() === true) { + $params["editorConfig"]["customization"]["compactHeader"] = true; + } + + //default is false + if ($this->config->GetCustomizationFeedback() === true) { + $params["editorConfig"]["customization"]["feedback"] = true; + } + + //default is false + if ($this->config->GetCustomizationForcesave() === true) { + $params["editorConfig"]["customization"]["forcesave"] = true; + } + + //default is true + if ($this->config->GetCustomizationHelp() === false) { + $params["editorConfig"]["customization"]["help"] = false; + } + + //default is original + $reviewDisplay = $this->config->GetCustomizationReviewDisplay(); + if ($reviewDisplay !== "original") { + $params["editorConfig"]["customization"]["reviewDisplay"] = $reviewDisplay; + } + + $theme = $this->config->GetCustomizationTheme(); + if (isset($theme)) { + $params["editorConfig"]["customization"]["uiTheme"] = $theme; + } + + //default is false + if ($this->config->GetCustomizationToolbarNoTabs() === true) { + $params["editorConfig"]["customization"]["toolbarNoTabs"] = true; + } + + //default is true + if ($this->config->GetCustomizationMacros() === false) { + $params["editorConfig"]["customization"]["macros"] = false; + } + + //default is true + if ($this->config->GetCustomizationPlugins() === false) { + $params["editorConfig"]["customization"]["plugins"] = false; + } + + /* from system config */ + + $autosave = $this->config->GetSystemValue($this->config->_customization_autosave); + if (isset($autosave)) { + $params["editorConfig"]["customization"]["autosave"] = $autosave; + } + + $customer = $this->config->GetSystemValue($this->config->_customization_customer); + if (isset($customer)) { + $params["editorConfig"]["customization"]["customer"] = $customer; + } + + $loaderLogo = $this->config->GetSystemValue($this->config->_customization_loaderLogo); + if (isset($loaderLogo)) { + $params["editorConfig"]["customization"]["loaderLogo"] = $loaderLogo; + } + + $loaderName = $this->config->GetSystemValue($this->config->_customization_loaderName); + if (isset($loaderName)) { + $params["editorConfig"]["customization"]["loaderName"] = $loaderName; + } + + $logo = $this->config->GetSystemValue($this->config->_customization_logo); + if (isset($logo)) { + $params["editorConfig"]["customization"]["logo"] = $logo; + } + + $zoom = $this->config->GetSystemValue($this->config->_customization_zoom); + if (isset($zoom)) { + $params["editorConfig"]["customization"]["zoom"] = $zoom; + } + + return $params; + } + + /** + * Check file favorite + * + * @param integer $fileId - file identifier + * + * @return bool + */ + private function isFavorite($fileId) { + $currentTags = $this->tagManager->load("files")->getTagsForObjects([$fileId]); + if ($currentTags) { + return \in_array(Tags::TAG_FAVORITE, $currentTags[$fileId]); + } + + return false; + } } diff --git a/controller/editorcontroller.php b/controller/editorcontroller.php index 7e32f805..20cfcac4 100644 --- a/controller/editorcontroller.php +++ b/controller/editorcontroller.php @@ -55,1406 +55,1406 @@ * Controller with the main functions */ class EditorController extends Controller { - /** - * Current user session - * - * @var IUserSession - */ - private $userSession; - - /** - * Current user manager - * - * @var IUserManager - */ - private $userManager; - - /** - * Root folder - * - * @var IRootFolder - */ - private $root; - - /** - * Url generator service - * - * @var IURLGenerator - */ - private $urlGenerator; - - /** - * l10n service - * - * @var IL10N - */ - private $trans; - - /** - * Logger - * - * @var ILogger - */ - private $logger; - - /** - * Application configuration - * - * @var AppConfig - */ - private $config; - - /** - * Hash generator - * - * @var Crypt - */ - private $crypt; - - /** - * File utility - * - * @var FileUtility - */ - private $fileUtility; - - /** - * File version manager - * - * @var VersionManager - */ - private $versionManager; - - /** - * Share manager - * - * @var IManager - */ - private $shareManager; - - /** - * Group manager - * - * @var IGroupManager - */ - private $groupManager; - - /** - * @param string $AppName - application name - * @param IRequest $request - request object - * @param IRootFolder $root - root folder - * @param IUserSession $userSession - current user session - * @param IUserManager $userManager - current user manager - * @param IURLGenerator $urlGenerator - url generator service - * @param IL10N $trans - l10n service - * @param ILogger $logger - logger - * @param AppConfig $config - application configuration - * @param Crypt $crypt - hash generator - * @param IManager $shareManager - Share manager - * @param ISession $session - Session - * @param IGroupManager $groupManager - Group manager - */ - public function __construct( - $AppName, - IRequest $request, - IRootFolder $root, - IUserSession $userSession, - IUserManager $userManager, - IURLGenerator $urlGenerator, - IL10N $trans, - ILogger $logger, - AppConfig $config, - Crypt $crypt, - IManager $shareManager, - ISession $session, - IGroupManager $groupManager - ) { - parent::__construct($AppName, $request); - - $this->userSession = $userSession; - $this->userManager = $userManager; - $this->root = $root; - $this->urlGenerator = $urlGenerator; - $this->trans = $trans; - $this->logger = $logger; - $this->config = $config; - $this->crypt = $crypt; - $this->shareManager = $shareManager; - $this->groupManager = $groupManager; - - $this->versionManager = new VersionManager($AppName, $root); - - $this->fileUtility = new FileUtility($AppName, $trans, $logger, $config, $shareManager, $session); - } - - /** - * Create new file in folder - * - * @param string $name - file name - * @param string $dir - folder path - * @param string $templateId - file identifier - * @param string $targetPath - file path for using as template for create - * @param string $shareToken - access token - * - * @return array - * - * @NoAdminRequired - * @PublicPage - */ - public function create($name, $dir, $templateId = null, $targetPath = null, $shareToken = null) { - $this->logger->debug("Create: $name", ["app" => $this->appName]); - - if (empty($shareToken) && !$this->config->isUserAllowedToUse()) { - return ["error" => $this->trans->t("Not permitted")]; - } - - if (empty($name)) { - $this->logger->error("File name for creation was not found: $name", ["app" => $this->appName]); - return ["error" => $this->trans->t("Template not found")]; - } - - $user = null; - if (empty($shareToken)) { - $user = $this->userSession->getUser(); - $userId = $user->getUID(); - $userFolder = $this->root->getUserFolder($userId); - } else { - list($userFolder, $error, $share) = $this->fileUtility->getNodeByToken($shareToken); - - if (isset($error)) { - $this->logger->error("Create: $error", ["app" => $this->appName]); - return ["error" => $error]; - } - - if ($userFolder instanceof File) { - return ["error" => $this->trans->t("You don't have enough permission to create")]; - } - - if (!empty($shareToken) && ($share->getPermissions() & Constants::PERMISSION_CREATE) === 0) { - $this->logger->error("Create in public folder without access", ["app" => $this->appName]); - return ["error" => $this->trans->t("You do not have enough permissions to view the file")]; - } - } - - $folder = $userFolder->get($dir); - - if ($folder === null) { - $this->logger->error("Folder for file creation was not found: $dir", ["app" => $this->appName]); - return ["error" => $this->trans->t("The required folder was not found")]; - } - if (!($folder->isCreatable() && $folder->isUpdateable())) { - $this->logger->error("Folder for file creation without permission: $dir", ["app" => $this->appName]); - return ["error" => $this->trans->t("You don't have enough permission to create")]; - } - - if (!empty($templateId)) { - $templateFile = TemplateManager::GetTemplate($templateId); - if ($templateFile) { - $template = $templateFile->getContent(); - } - } elseif (!empty($targetPath)) { - $targetFile = $userFolder->get($targetPath); - - $canDownload = $this->fileUtility->hasPermissionAttribute($targetFile); - if (!$canDownload) { - return ["error" => $this->trans->t("Not permitted")]; - } - - $targetId = $targetFile->getId(); - $targetName = $targetFile->getName(); - $targetExt = strtolower(pathinfo($targetName, PATHINFO_EXTENSION)); - $targetKey = $this->fileUtility->getKey($targetFile); - - $fileUrl = $this->getUrl($targetFile, $user, $shareToken); - - $ext = strtolower(pathinfo($name, PATHINFO_EXTENSION)); - $documentService = new DocumentService($this->trans, $this->config); - try { - $newFileUri = $documentService->GetConvertedUri($fileUrl, $targetExt, $ext, $targetKey); - } catch (\Exception $e) { - $this->logger->logException($e, ["message" => "GetConvertedUri: " . $targetFile->getId(), "app" => $this->appName]); - return ["error" => $e->getMessage()]; - } - $template = $documentService->Request($newFileUri); - } else { - $template = TemplateManager::GetEmptyTemplate($name); - } - - if (!$template) { - $this->logger->error("Template for file creation not found: $name ($templateId)", ["app" => $this->appName]); - return ["error" => $this->trans->t("Template not found")]; - } - - $name = $folder->getNonExistingName($name); - - try { - $file = $folder->newFile($name); - - $file->putContent($template); - } catch (NotPermittedException $e) { - $this->logger->logException($e, ["message" => "Can't create file: $name", "app" => $this->appName]); - return ["error" => $this->trans->t("Can't create file")]; - } catch (ForbiddenException $e) { - $this->logger->logException($e, ["message" => "Can't put file: $name", "app" => $this->appName]); - return ["error" => $this->trans->t("Can't create file")]; - } - - $fileInfo = $file->getFileInfo(); - - $result = Helper::formatFileInfo($fileInfo); - return $result; - } - - /** - * Create new file in folder from editor - * - * @param string $name - file name - * @param string $dir - folder path - * @param string $templateId - file identifier - * - * @return TemplateResponse|RedirectResponse - * - * @NoAdminRequired - * @NoCSRFRequired - */ - public function createNew($name, $dir, $templateId = null) { - $this->logger->debug("Create from editor: $name in $dir", ["app" => $this->appName]); - - $result = $this->create($name, $dir, $templateId); - if (isset($result["error"])) { - return $this->renderError($result["error"]); - } - - $openEditor = $this->urlGenerator->linkToRouteAbsolute($this->appName . ".editor.index", ["fileId" => $result["id"]]); - return new RedirectResponse($openEditor); - } - - /** - * Get users - * - * @param $fileId - file identifier - * - * @return array - * - * @NoAdminRequired - * @NoCSRFRequired - */ - public function users($fileId) { - $this->logger->debug("Search users", ["app" => $this->appName]); - $result = []; - - if (!$this->config->isUserAllowedToUse()) { - return $result; - } - - if (!$this->allowEnumeration()) { - return $result; - } - - $autocompleteMemberGroup = false; - if ($this->limitEnumerationToGroups()) { - $autocompleteMemberGroup = true; - } - - $currentUser = $this->userSession->getUser(); - $currentUserId = $currentUser->getUID(); - - list($file, $error, $share) = $this->getFile($currentUserId, $fileId); - if (isset($error)) { - $this->logger->error("Users: $fileId $error", ["app" => $this->appName]); - return $result; - } - - $canShare = (($file->getPermissions() & Constants::PERMISSION_SHARE) === Constants::PERMISSION_SHARE); - - $shareMemberGroups = $this->shareManager->shareWithGroupMembersOnly(); - - $all = false; - $users = []; - if ($canShare) { - if ($shareMemberGroups || $autocompleteMemberGroup) { - $currentUserGroups = $this->groupManager->getUserGroupIds($currentUser); - foreach ($currentUserGroups as $currentUserGroup) { - $group = $this->groupManager->get($currentUserGroup); - foreach ($group->getUsers() as $user) { - if (!\in_array($user, $users)) { - array_push($users, $user); - } - } - } - } else { - $users = $this->userManager->search(""); - $all = true; - } - } - - if (!$all) { - $accessList = $this->getAccessList($file); - foreach ($accessList as $accessUser) { - if (!\in_array($accessUser, $users)) { - array_push($users, $accessUser); - } - } - } - - foreach ($users as $user) { - $email = $user->getEMailAddress(); - if ($user->getUID() != $currentUserId && !empty($email)) { - array_push($result, [ - "email" => $email, - "name" => $user->getDisplayName() - ]); - } - } - - return $result; - } - - /** - * Send notify about mention - * - * @param int $fileId - file identifier - * @param string $anchor - the anchor on target content - * @param string $comment - comment - * @param array $emails - emails array to whom to send notify - * - * @return array - * - * @NoAdminRequired - * @NoCSRFRequired - */ - public function mention($fileId, $anchor, $comment, $emails) { - $this->logger->debug("mention: from $fileId to " . json_encode($emails), ["app" => $this->appName]); - - if (!$this->config->isUserAllowedToUse()) { - return ["error" => $this->trans->t("Not permitted")]; - } - - if (empty($emails)) { - return ["error" => $this->trans->t("Failed to send notification")]; - } - - $recipientIds = []; - foreach ($emails as $email) { - $recipients = $this->userManager->getByEmail($email); - foreach ($recipients as $recipient) { - $recipientId = $recipient->getUID(); - if (!\in_array($recipientId, $recipientIds)) { - array_push($recipientIds, $recipientId); - } - } - } - - $user = $this->userSession->getUser(); - $userId = null; - if (!empty($user)) { - $userId = $user->getUID(); - } - - list($file, $error, $share) = $this->getFile($userId, $fileId); - if (isset($error)) { - $this->logger->error("Mention: $fileId $error", ["app" => $this->appName]); - return ["error" => $this->trans->t("Failed to send notification")]; - } - - foreach ($emails as $email) { - $substrToDelete = "+" . $email . " "; - $comment = str_replace($substrToDelete, "", $comment); - } - - //Length from ownCloud: - //https://github.com/owncloud/core/blob/master/lib/private/Notification/Notification.php#L181 - $maxLen = 64; - if (\strlen($comment) > $maxLen) { - $ending = "..."; - $comment = substr($comment, 0, ($maxLen - \strlen($ending))) . $ending; - } - - $notificationManager = \OC::$server->getNotificationManager(); - $notification = $notificationManager->createNotification(); - $notification->setApp($this->appName) - ->setDateTime(new \DateTime()) - ->setObject("mention", $comment) - ->setSubject("mention_info", [ - "notifierId" => $userId, - "fileId" => $file->getId(), - "fileName" => $file->getName(), - "anchor" => $anchor - ]); - - $shareMemberGroups = $this->shareManager->shareWithGroupMembersOnly(); - $canShare = ($file->getPermissions() & Constants::PERMISSION_SHARE) === Constants::PERMISSION_SHARE; - - $currentUserGroups = []; - if ($shareMemberGroups) { - $currentUserGroups = $this->groupManager->getUserGroupIds($user); - } - - $accessList = $this->getAccessList($file); - - foreach ($recipientIds as $recipientId) { - $recipient = $this->userManager->get($recipientId); - $isAvailable = \in_array($recipient, $accessList); - - if (!$isAvailable - && $file->getFileInfo()->getMountPoint() instanceof \OCA\Files_External\Config\ExternalMountPoint) { - $recipientFolder = $this->root->getUserFolder($recipientId); - $recipientFile = $recipientFolder->getById($file->getId()); - - $isAvailable = !empty($recipientFile); - } - - if (!$isAvailable) { - if (!$canShare) { - continue; - } - if ($shareMemberGroups) { - $recipientGroups = $this->groupManager->getUserGroupIds($recipient); - if (empty(array_intersect($currentUserGroups, $recipientGroups))) { - continue; - } - } - - $share = $this->shareManager->newShare(); - $share->setNode($file) - ->setShareType(Share::SHARE_TYPE_USER) - ->setSharedBy($userId) - ->setSharedWith($recipientId) - ->setShareOwner($userId) - ->setPermissions(Constants::PERMISSION_READ); - - $this->shareManager->createShare($share); - - $this->logger->debug("mention: share $fileId to $recipientId", ["app" => $this->appName]); - } - - $notification->setUser($recipientId); - - $notificationManager->notify($notification); - } - - return ["message" => $this->trans->t("Notification sent successfully")]; - } - - /** - * Reference data - * - * @param array $referenceData - reference data - * @param string $path - file path - * - * @return array - * - * @NoAdminRequired - * @PublicPage - */ - public function reference($referenceData, $path = null) { - $this->logger->debug("reference: " . json_encode($referenceData) . " $path", ["app" => $this->appName]); - - if (!$this->config->isUserAllowedToUse()) { - return ["error" => $this->trans->t("Not permitted")]; - } - - $user = $this->userSession->getUser(); - if (empty($user)) { - return ["error" => $this->trans->t("Not permitted")]; - } - - $userId = $user->getUID(); - - $file = null; - $fileId = (integer)($referenceData["fileKey"] ?? 0); - if (!empty($fileId) - && $referenceData["instanceId"] === $this->config->GetSystemValue("instanceid", true)) { - list($file, $error, $share) = $this->getFile($userId, $fileId); - } - - $userFolder = $this->root->getUserFolder($userId); - if ($file === null - && $path !== null - && $userFolder->nodeExists($path)) { - $node = $userFolder->get($path); - if ($node instanceof File - && $node->isReadable()) { - $file = $node; - } - } - - if ($file === null) { - $this->logger->error("Reference not found: $fileId $path", ["app" => $this->appName]); - return ["error" => $this->trans->t("File not found")]; - } - - $fileName = $file->getName(); - $ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION)); - - $response = [ - "fileType" => $ext, - "path" => $userFolder->getRelativePath($file->getPath()), - "referenceData" => [ - "fileKey" => $file->getId(), - "instanceId" => $this->config->GetSystemValue("instanceid", true), - ], - "url" => $this->getUrl($file, $user), - ]; - - if (!empty($this->config->GetDocumentServerSecret())) { - $token = \Firebase\JWT\JWT::encode($response, $this->config->GetDocumentServerSecret(), "HS256"); - $response["token"] = $token; - } - - return $response; - } - - /** - * Conversion file to Office Open XML format - * - * @param integer $fileId - file identifier - * @param string $shareToken - access token - * - * @return array - * - * @NoAdminRequired - * @PublicPage - */ - public function convert($fileId, $shareToken = null) { - $this->logger->debug("Convert: $fileId", ["app" => $this->appName]); - - if (empty($shareToken) && !$this->config->isUserAllowedToUse()) { - return ["error" => $this->trans->t("Not permitted")]; - } - - $user = $this->userSession->getUser(); - $userId = null; - if (!empty($user)) { - $userId = $user->getUID(); - } - - list($file, $error, $share) = empty($shareToken) ? $this->getFile($userId, $fileId) : $this->fileUtility->getFileByToken($fileId, $shareToken); - - if (isset($error)) { - $this->logger->error("Convertion: $fileId $error", ["app" => $this->appName]); - return ["error" => $error]; - } - - if (!empty($shareToken) && ($share->getPermissions() & Constants::PERMISSION_CREATE) === 0) { - $this->logger->error("Convertion in public folder without access: $fileId", ["app" => $this->appName]); - return ["error" => $this->trans->t("You do not have enough permissions to view the file")]; - } - - $canDownload = $this->fileUtility->hasPermissionAttribute($file); - if (!$canDownload) { - return ["error" => $this->trans->t("Not permitted")]; - } - - $fileName = $file->getName(); - $ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION)); - $format = $this->config->FormatsSetting()[$ext]; - if (!isset($format)) { - $this->logger->info("Format for convertion not supported: $fileName", ["app" => $this->appName]); - return ["error" => $this->trans->t("Format is not supported")]; - } - - if (!isset($format["conv"]) || $format["conv"] !== true) { - $this->logger->info("Conversion is not required: $fileName", ["app" => $this->appName]); - return ["error" => $this->trans->t("Conversion is not required")]; - } - - $internalExtension = "docx"; - switch ($format["type"]) { - case "cell": - $internalExtension = "xlsx"; - break; - case "slide": - $internalExtension = "pptx"; - break; - } - - $newFileUri = null; - $documentService = new DocumentService($this->trans, $this->config); - $key = $this->fileUtility->getKey($file); - $fileUrl = $this->getUrl($file, $user, $shareToken); - try { - $newFileUri = $documentService->GetConvertedUri($fileUrl, $ext, $internalExtension, $key); - } catch (\Exception $e) { - $this->logger->logException($e, ["message" => "GetConvertedUri: " . $file->getId(), "app" => $this->appName]); - return ["error" => $e->getMessage()]; - } - - $folder = $file->getParent(); - if (!($folder->isCreatable() && $folder->isUpdateable())) { - $folder = $this->root->getUserFolder($userId); - } - - try { - $newData = $documentService->Request($newFileUri); - } catch (\Exception $e) { - $this->logger->logException($e, ["message" => "Failed to download converted file", "app" => $this->appName]); - return ["error" => $this->trans->t("Failed to download converted file")]; - } - - $fileNameWithoutExt = substr($fileName, 0, \strlen($fileName) - \strlen($ext) - 1); - $newFileName = $folder->getNonExistingName($fileNameWithoutExt . "." . $internalExtension); - - try { - $file = $folder->newFile($newFileName); - - $file->putContent($newData); - } catch (NotPermittedException $e) { - $this->logger->logException($e, ["message" => "Can't create file: $newFileName", "app" => $this->appName]); - return ["error" => $this->trans->t("Can't create file")]; - } catch (ForbiddenException $e) { - $this->logger->logException($e, ["message" => "Can't put file: $newFileName", "app" => $this->appName]); - return ["error" => $this->trans->t("Can't create file")]; - } - - $fileInfo = $file->getFileInfo(); - - $result = Helper::formatFileInfo($fileInfo); - return $result; - } - - /** - * Save file to folder - * - * @param string $name - file name - * @param string $dir - folder path - * @param string $url - file url - * - * @return array - * - * @NoAdminRequired - * @PublicPage - */ - public function save($name, $dir, $url) { - $this->logger->debug("Save: $name", ["app" => $this->appName]); - - if (!$this->config->isUserAllowedToUse()) { - return ["error" => $this->trans->t("Not permitted")]; - } - - $userId = $this->userSession->getUser()->getUID(); - $userFolder = $this->root->getUserFolder($userId); - - $folder = $userFolder->get($dir); - - if ($folder === null) { - $this->logger->error("Folder for saving file was not found: $dir", ["app" => $this->appName]); - return ["error" => $this->trans->t("The required folder was not found")]; - } - if (!($folder->isCreatable() && $folder->isUpdateable())) { - $this->logger->error("Folder for saving file without permission: $dir", ["app" => $this->appName]); - return ["error" => $this->trans->t("You don't have enough permission to create")]; - } - - $url = $this->config->ReplaceDocumentServerUrlToInternal($url); - - try { - $documentService = new DocumentService($this->trans, $this->config); - $newData = $documentService->Request($url); - } catch (\Exception $e) { - $this->logger->logException($e, ["message" => "Failed to download file for saving", "app" => $this->appName]); - return ["error" => $this->trans->t("Download failed")]; - } - - $name = $folder->getNonExistingName($name); - - try { - $file = $folder->newFile($name); - - $file->putContent($newData); - } catch (NotPermittedException $e) { - $this->logger->logException($e, ["message" => "Can't save file: $name", "app" => $this->appName]); - return ["error" => $this->trans->t("Can't create file")]; - } catch (ForbiddenException $e) { - $this->logger->logException($e, ["message" => "Can't put file: $name", "app" => $this->appName]); - return ["error" => $this->trans->t("Can't create file")]; - } - - $fileInfo = $file->getFileInfo(); - - $result = Helper::formatFileInfo($fileInfo); - return $result; - } - - /** - * Get versions history for file - * - * @param integer $fileId - file identifier - * - * @return array - * - * @NoAdminRequired - */ - public function history($fileId) { - $this->logger->debug("Request history for: $fileId", ["app" => $this->appName]); - - if (!$this->config->isUserAllowedToUse()) { - return ["error" => $this->trans->t("Not permitted")]; - } - - $history = []; - - $user = $this->userSession->getUser(); - $userId = null; - if (!empty($user)) { - $userId = $user->getUID(); - } - - list($file, $error, $share) = $this->getFile($userId, $fileId); - - if (isset($error)) { - $this->logger->error("History: $fileId $error", ["app" => $this->appName]); - return ["error" => $error]; - } - - if ($fileId === 0) { - $fileId = $file->getId(); - } - - $ownerId = null; - $owner = $file->getFileInfo()->getOwner(); - if ($owner !== null) { - $ownerId = $owner->getUID(); - } - - $versions = []; - if ($this->versionManager->available - && $owner !== null) { - $versions = array_reverse($this->versionManager->getVersionsForFile($owner, $file->getFileInfo())); - } - - $prevVersion = ""; - $versionNum = 0; - foreach ($versions as $version) { - $versionNum = $versionNum + 1; - - $key = $this->fileUtility->getVersionKey($version); - $key = DocumentService::GenerateRevisionId($key); - - $historyItem = [ - "created" => $version->getTimestamp(), - "key" => $key, - "version" => $versionNum - ]; - - $versionId = $version->getRevisionId(); - - $author = FileVersions::getAuthor($ownerId, $fileId, $versionId); - $authorId = $author !== null ? $author["id"] : $ownerId; - $authorName = $author !== null ? $author["name"] : $owner->getDisplayName(); - - $historyItem["user"] = [ - "id" => $this->buildUserId($authorId), - "name" => $authorName - ]; - - $historyData = FileVersions::getHistoryData($ownerId, $fileId, $versionId, $prevVersion); - if ($historyData !== null) { - $historyItem["changes"] = $historyData["changes"]; - $historyItem["serverVersion"] = $historyData["serverVersion"]; - } - - $prevVersion = $versionId; - - array_push($history, $historyItem); - } - - $key = $this->fileUtility->getKey($file, true); - $key = DocumentService::GenerateRevisionId($key); - - $historyItem = [ - "created" => $file->getMTime(), - "key" => $key, - "version" => $versionNum + 1 - ]; - - $versionId = $file->getFileInfo()->getMtime(); - - $author = FileVersions::getAuthor($ownerId, $fileId, $versionId); - if ($author !== null) { - $historyItem["user"] = [ - "id" => $this->buildUserId($author["id"]), - "name" => $author["name"] - ]; - } elseif ($owner !== null) { - $historyItem["user"] = [ - "id" => $this->buildUserId($ownerId), - "name" => $owner->getDisplayName() - ]; - } - - $historyData = FileVersions::getHistoryData($ownerId, $fileId, $versionId, $prevVersion); - if ($historyData !== null) { - $historyItem["changes"] = $historyData["changes"]; - $historyItem["serverVersion"] = $historyData["serverVersion"]; - } - - array_push($history, $historyItem); - - return $history; - } - - /** - * Get file attributes of specific version - * - * @param integer $fileId - file identifier - * @param integer $version - file version - * - * @return array - * - * @NoAdminRequired - */ - public function version($fileId, $version) { - $this->logger->debug("Request version for: $fileId ($version)", ["app" => $this->appName]); - - if (!$this->config->isUserAllowedToUse()) { - return ["error" => $this->trans->t("Not permitted")]; - } - - $version = empty($version) ? null : $version; - - $user = $this->userSession->getUser(); - $userId = null; - if (!empty($user)) { - $userId = $user->getUID(); - } - - list($file, $error, $share) = $this->getFile($userId, $fileId); - - if (isset($error)) { - $this->logger->error("History: $fileId $error", ["app" => $this->appName]); - return ["error" => $error]; - } - - if ($fileId === 0) { - $fileId = $file->getId(); - } - - $owner = null; - $ownerId = null; - $versions = []; - if ($this->versionManager->available) { - $owner = $file->getFileInfo()->getOwner(); - if ($owner !== null) { - $ownerId = $owner->getUID(); - $versions = array_reverse($this->versionManager->getVersionsForFile($owner, $file->getFileInfo())); - } - } - - $key = null; - $fileUrl = null; - $versionId = null; - if ($version > \count($versions)) { - $key = $this->fileUtility->getKey($file, true); - $versionId = $file->getFileInfo()->getMtime(); - - $fileUrl = $this->getUrl($file, $user); - } else { - $fileVersion = array_values($versions)[$version - 1]; - - $key = $this->fileUtility->getVersionKey($fileVersion); - $versionId = $fileVersion->getRevisionId(); - - $fileUrl = $this->getUrl($file, $user, null, $version); - } - $key = DocumentService::GenerateRevisionId($key); - $fileName = $file->getName(); - $ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION)); - - $result = [ - "fileType" => $ext, - "url" => $fileUrl, - "version" => $version, - "key" => $key - ]; - - if ($version > 1 - && \count($versions) >= $version - 1 - && FileVersions::hasChanges($ownerId, $fileId, $versionId)) { - $changesUrl = $this->getUrl($file, $user, null, $version, true); - $result["changesUrl"] = $changesUrl; - - $prevVersion = array_values($versions)[$version - 2]; - $prevVersionKey = $this->fileUtility->getVersionKey($prevVersion); - $prevVersionKey = DocumentService::GenerateRevisionId($prevVersionKey); - - $prevVersionUrl = $this->getUrl($file, $user, null, $version - 1); - - $result["previous"] = [ - "fileType" => $ext, - "key" => $prevVersionKey, - "url" => $prevVersionUrl - ]; - } - - if (!empty($this->config->GetDocumentServerSecret())) { - $token = \Firebase\JWT\JWT::encode($result, $this->config->GetDocumentServerSecret(), "HS256"); - $result["token"] = $token; - } - - return $result; - } - - /** - * Restore file version - * - * @param integer $fileId - file identifier - * @param integer $version - file version - * - * @return array - * - * @NoAdminRequired - * @PublicPage - */ - public function restore($fileId, $version) { - $this->logger->debug("Request restore version for: $fileId ($version)", ["app" => $this->appName]); - - if (!$this->config->isUserAllowedToUse()) { - return ["error" => $this->trans->t("Not permitted")]; - } - - $version = empty($version) ? null : $version; - - $user = $this->userSession->getUser(); - $userId = null; - if (!empty($user)) { - $userId = $user->getUID(); - } - - list($file, $error, $share) = $this->getFile($userId, $fileId); - - if (isset($error)) { - $this->logger->error("Restore: $fileId $error", ["app" => $this->appName]); - return ["error" => $error]; - } - - if ($fileId === 0) { - $fileId = $file->getId(); - } - - $owner = null; - $versions = []; - if ($this->versionManager->available) { - $owner = $file->getFileInfo()->getOwner(); - if ($owner !== null) { - $versions = array_reverse($this->versionManager->getVersionsForFile($owner, $file->getFileInfo())); - } - - if (\count($versions) >= $version) { - $fileVersion = array_values($versions)[$version - 1]; - $this->versionManager->rollback($fileVersion); - } - } - - return $this->history($fileId); - } - - /** - * Get presigned url to file - * - * @param string $filePath - file path - * - * @return array - * - * @NoAdminRequired - */ - public function url($filePath) { - $this->logger->debug("Request url for: $filePath", ["app" => $this->appName]); - - if (!$this->config->isUserAllowedToUse()) { - return ["error" => $this->trans->t("Not permitted")]; - } - - $user = $this->userSession->getUser(); - $userId = $user->getUID(); - $userFolder = $this->root->getUserFolder($userId); - - $file = $userFolder->get($filePath); - - if ($file === null) { - $this->logger->error("File for generate presigned url was not found: $dir", ["app" => $this->appName]); - return ["error" => $this->trans->t("File not found")]; - } - if (!$file->isReadable()) { - $this->logger->error("File without permission: $dir", ["app" => $this->appName]); - return ["error" => $this->trans->t("You do not have enough permissions to view the file")]; - } - - $fileName = $file->getName(); - $ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION)); - $fileUrl = $this->getUrl($file, $user); - - $result = [ - "fileType" => $ext, - "url" => $fileUrl - ]; - - if (!empty($this->config->GetDocumentServerSecret())) { - $token = \Firebase\JWT\JWT::encode($result, $this->config->GetDocumentServerSecret(), "HS256"); - $result["token"] = $token; - } - - return $result; - } - - /** - * Download method - * - * @param int $fileId - file identifier - * @param string $toExtension - file extension to download - * @param bool $template - file is template - * - * @return DataDownloadResponse|TemplateResponse - * - * @NoAdminRequired - * @NoCSRFRequired - */ - public function download($fileId, $toExtension = null, $template = false) { - $this->logger->debug("Download: $fileId $toExtension", ["app" => $this->appName]); - - if (!$this->config->isUserAllowedToUse()) { - return $this->renderError($this->trans->t("Not permitted")); - } - - if ($template) { - $templateFile = TemplateManager::GetTemplate($fileId); - - if (empty($templateFile)) { - $this->logger->info("Download: template not found: $fileId", ["app" => $this->appName]); - return $this->renderError($this->trans->t("File not found")); - } - - $file = $templateFile; - } else { - $user = $this->userSession->getUser(); - $userId = null; - if (!empty($user)) { - $userId = $user->getUID(); - } - - list($file, $error, $share) = $this->getFile($userId, $fileId); - - if (isset($error)) { - $this->logger->error("Download: $fileId $error", ["app" => $this->appName]); - return $this->renderError($error); - } - } - - $canDownload = $this->fileUtility->hasPermissionAttribute($file); - if (!$canDownload) { - return $this->renderError($this->trans->t("Not permitted")); - } - - $fileName = $file->getName(); - $ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION)); - $toExtension = strtolower($toExtension); - - if ($toExtension === null - || $ext === $toExtension - || $template) { - return new DataDownloadResponse($file->getContent(), $fileName, $file->getMimeType()); - } - - $newFileUri = null; - $documentService = new DocumentService($this->trans, $this->config); - $key = $this->fileUtility->getKey($file); - $fileUrl = $this->getUrl($file, $user); - try { - $newFileUri = $documentService->GetConvertedUri($fileUrl, $ext, $toExtension, $key); - } catch (\Exception $e) { - $this->logger->logException($e, ["message" => "GetConvertedUri: " . $file->getId(), "app" => $this->appName]); - return $this->renderError($e->getMessage()); - } - - try { - $newData = $documentService->Request($newFileUri); - } catch (\Exception $e) { - $this->logger->logException($e, ["message" => "Failed to download converted file", "app" => $this->appName]); - return $this->renderError($this->trans->t("Failed to download converted file")); - } - - $fileNameWithoutExt = substr($fileName, 0, \strlen($fileName) - \strlen($ext) - 1); - $newFileName = $fileNameWithoutExt . "." . $toExtension; - - $formats = $this->config->FormatsSetting(); - - return new DataDownloadResponse($newData, $newFileName, $formats[$toExtension]["mime"]); - } - - /** - * Print editor section - * - * @param integer $fileId - file identifier - * @param string $filePath - file path - * @param string $shareToken - access token - * @param integer $version - file version - * @param bool $inframe - open in frame - * @param bool $template - file is template - * @param string $anchor - anchor for file content - * - * @return TemplateResponse|RedirectResponse - * - * @NoAdminRequired - * @NoCSRFRequired - */ - public function index($fileId, $filePath = null, $shareToken = null, $version = 0, $inframe = false, $template = false, $anchor = null) { - $this->logger->debug("Open: $fileId ($version) $filePath", ["app" => $this->appName]); - - if (empty($shareToken) && !$this->userSession->isLoggedIn()) { - $redirectUrl = $this->urlGenerator->linkToRoute("core.login.showLoginForm", [ - "redirect_url" => $this->request->getRequestUri() - ]); - return new RedirectResponse($redirectUrl); - } - - $shareBy = null; - if (!empty($shareToken) && !$this->userSession->isLoggedIn()) { - list($share, $error) = $this->fileUtility->getShare($shareToken); - if (!empty($share)) { - $shareBy = $share->getSharedBy(); - } - } - - if (!$this->config->isUserAllowedToUse($shareBy)) { - return $this->renderError($this->trans->t("Not permitted")); - } - - $documentServerUrl = $this->config->GetDocumentServerUrl(); - - if (empty($documentServerUrl)) { - $this->logger->error("documentServerUrl is empty", ["app" => $this->appName]); - return $this->renderError($this->trans->t("ONLYOFFICE app is not configured. Please contact admin")); - } - - $params = [ - "documentServerUrl" => $documentServerUrl, - "fileId" => $fileId, - "filePath" => $filePath, - "shareToken" => $shareToken, - "version" => $version, - "template" => $template, - "inframe" => false, - "anchor" => $anchor - ]; - - if ($inframe === true) { - $params["inframe"] = true; - $response = new TemplateResponse($this->appName, "editor", $params, "plain"); - } else { - $response = new TemplateResponse($this->appName, "editor", $params); - } - - $csp = new ContentSecurityPolicy(); - $csp->allowInlineScript(true); - - if (preg_match("/^https?:\/\//i", $documentServerUrl)) { - $csp->addAllowedScriptDomain($documentServerUrl); - $csp->addAllowedFrameDomain($documentServerUrl); - } else { - $csp->addAllowedFrameDomain("'self'"); - } - $response->setContentSecurityPolicy($csp); - - return $response; - } - - /** - * Print public editor section - * - * @param integer $fileId - file identifier - * @param string $shareToken - access token - * @param integer $version - file version - * @param bool $inframe - open in frame - * - * @return TemplateResponse - * - * @NoAdminRequired - * @NoCSRFRequired - * @PublicPage - */ - public function PublicPage($fileId, $shareToken, $version = 0, $inframe = false) { - return $this->index($fileId, null, $shareToken, $version, $inframe); - } - - /** - * Getting file by identifier - * - * @param string $userId - user identifier - * @param integer $fileId - file identifier - * @param string $filePath - file path - * @param bool $template - file is template - * - * @return array - */ - private function getFile($userId, $fileId, $filePath = null, $template = false) { - if (empty($fileId)) { - return [null, $this->trans->t("FileId is empty"), null]; - } - - try { - $folder = !$template ? $this->root->getUserFolder($userId) : TemplateManager::GetGlobalTemplateDir(); - $files = $folder->getById($fileId); - } catch (\Exception $e) { - $this->logger->logException($e, ["message" => "getFile: $fileId", "app" => $this->appName]); - return [null, $this->trans->t("Invalid request"), null]; - } - - if (empty($files)) { - $this->logger->info("Files not found: $fileId", ["app" => $this->appName]); - return [null, $this->trans->t("File not found"), null]; - } - - $file = $files[0]; - - if (\count($files) > 1 && !empty($filePath)) { - $filePath = "/" . $userId . "/files" . $filePath; - foreach ($files as $curFile) { - if ($curFile->getPath() === $filePath) { - $file = $curFile; - break; - } - } - } - - if (!$file->isReadable()) { - return [null, $this->trans->t("You do not have enough permissions to view the file"), null]; - } - - return [$file, null, null]; - } - - /** - * Generate secure link to download document - * - * @param File $file - file - * @param IUser $user - user with access - * @param string $shareToken - access token - * @param integer $version - file version - * @param bool $changes - is required url to file changes - * @param bool $template - file is template - * - * @return string - */ - private function getUrl($file, $user = null, $shareToken = null, $version = 0, $changes = false, $template = false) { - $data = [ - "action" => "download", - "fileId" => $file->getId() - ]; - - $userId = null; - if (!empty($user)) { - $userId = $user->getUID(); - $data["userId"] = $userId; - } - if (!empty($shareToken)) { - $data["shareToken"] = $shareToken; - } - if ($version > 0) { - $data["version"] = $version; - } - if ($changes) { - $data["changes"] = true; - } - if ($template) { - $data["template"] = true; - } - - $hashUrl = $this->crypt->GetHash($data); - - $fileUrl = $this->urlGenerator->linkToRouteAbsolute($this->appName . ".callback.download", ["doc" => $hashUrl]); - - if (!$this->config->UseDemo() && !empty($this->config->GetStorageUrl())) { - $fileUrl = str_replace($this->urlGenerator->getAbsoluteURL("/"), $this->config->GetStorageUrl(), $fileUrl); - } - - return $fileUrl; - } - - /** - * Generate unique user identifier - * - * @param string $userId - current user identifier - * - * @return string - */ - private function buildUserId($userId) { - $instanceId = $this->config->GetSystemValue("instanceid", true); - $userId = $instanceId . "_" . $userId; - return $userId; - } - - /** - * Return list users who has access to file - * - * @param File $file - file - * - * @return array - */ - private function getAccessList($file) { - $result = []; - - foreach ($this->shareManager->getSharesByPath($file) as $share) { - $accessList = []; - $shareWith = $share->getSharedWith(); - if ($share->getShareType() === Share::SHARE_TYPE_GROUP) { - $group = $this->groupManager->get($shareWith); - $accessList = $group->getUsers(); - } elseif ($share->getShareType() === Share::SHARE_TYPE_USER) { - array_push($accessList, $this->userManager->get($shareWith)); - } - - foreach ($accessList as $accessUser) { - if (!\in_array($accessUser, $result)) { - array_push($result, $accessUser); - } - } - } - - if (!\in_array($file->getOwner(), $result)) { - array_push($result, $file->getOwner()); - } - - return $result; - } - - /** - * Return allow autocomplete usernames - * - * @return bool - */ - private function allowEnumeration() { - return \OC::$server->getConfig()->getAppValue("core", "shareapi_allow_share_dialog_user_enumeration", "yes") === "yes"; - } - - /** - * Return allow autocomplete usernames group member only - * - * @return bool - */ - private function limitEnumerationToGroups() { - if ($this->allowEnumeration()) { - return \OC::$server->getConfig()->getAppValue("core", "shareapi_share_dialog_user_enumeration_group_members", "no") === "yes"; - } - - return false; - } - - /** - * Print error page - * - * @param string $error - error message - * @param string $hint - error hint - * - * @return TemplateResponse - */ - private function renderError($error, $hint = "") { - return new TemplateResponse("", "error", [ - "errors" => [ - [ - "error" => $error, - "hint" => $hint - ] - ] - ], "error"); - } + /** + * Current user session + * + * @var IUserSession + */ + private $userSession; + + /** + * Current user manager + * + * @var IUserManager + */ + private $userManager; + + /** + * Root folder + * + * @var IRootFolder + */ + private $root; + + /** + * Url generator service + * + * @var IURLGenerator + */ + private $urlGenerator; + + /** + * l10n service + * + * @var IL10N + */ + private $trans; + + /** + * Logger + * + * @var ILogger + */ + private $logger; + + /** + * Application configuration + * + * @var AppConfig + */ + private $config; + + /** + * Hash generator + * + * @var Crypt + */ + private $crypt; + + /** + * File utility + * + * @var FileUtility + */ + private $fileUtility; + + /** + * File version manager + * + * @var VersionManager + */ + private $versionManager; + + /** + * Share manager + * + * @var IManager + */ + private $shareManager; + + /** + * Group manager + * + * @var IGroupManager + */ + private $groupManager; + + /** + * @param string $AppName - application name + * @param IRequest $request - request object + * @param IRootFolder $root - root folder + * @param IUserSession $userSession - current user session + * @param IUserManager $userManager - current user manager + * @param IURLGenerator $urlGenerator - url generator service + * @param IL10N $trans - l10n service + * @param ILogger $logger - logger + * @param AppConfig $config - application configuration + * @param Crypt $crypt - hash generator + * @param IManager $shareManager - Share manager + * @param ISession $session - Session + * @param IGroupManager $groupManager - Group manager + */ + public function __construct( + $AppName, + IRequest $request, + IRootFolder $root, + IUserSession $userSession, + IUserManager $userManager, + IURLGenerator $urlGenerator, + IL10N $trans, + ILogger $logger, + AppConfig $config, + Crypt $crypt, + IManager $shareManager, + ISession $session, + IGroupManager $groupManager + ) { + parent::__construct($AppName, $request); + + $this->userSession = $userSession; + $this->userManager = $userManager; + $this->root = $root; + $this->urlGenerator = $urlGenerator; + $this->trans = $trans; + $this->logger = $logger; + $this->config = $config; + $this->crypt = $crypt; + $this->shareManager = $shareManager; + $this->groupManager = $groupManager; + + $this->versionManager = new VersionManager($AppName, $root); + + $this->fileUtility = new FileUtility($AppName, $trans, $logger, $config, $shareManager, $session); + } + + /** + * Create new file in folder + * + * @param string $name - file name + * @param string $dir - folder path + * @param string $templateId - file identifier + * @param string $targetPath - file path for using as template for create + * @param string $shareToken - access token + * + * @return array + * + * @NoAdminRequired + * @PublicPage + */ + public function create($name, $dir, $templateId = null, $targetPath = null, $shareToken = null) { + $this->logger->debug("Create: $name", ["app" => $this->appName]); + + if (empty($shareToken) && !$this->config->isUserAllowedToUse()) { + return ["error" => $this->trans->t("Not permitted")]; + } + + if (empty($name)) { + $this->logger->error("File name for creation was not found: $name", ["app" => $this->appName]); + return ["error" => $this->trans->t("Template not found")]; + } + + $user = null; + if (empty($shareToken)) { + $user = $this->userSession->getUser(); + $userId = $user->getUID(); + $userFolder = $this->root->getUserFolder($userId); + } else { + list($userFolder, $error, $share) = $this->fileUtility->getNodeByToken($shareToken); + + if (isset($error)) { + $this->logger->error("Create: $error", ["app" => $this->appName]); + return ["error" => $error]; + } + + if ($userFolder instanceof File) { + return ["error" => $this->trans->t("You don't have enough permission to create")]; + } + + if (!empty($shareToken) && ($share->getPermissions() & Constants::PERMISSION_CREATE) === 0) { + $this->logger->error("Create in public folder without access", ["app" => $this->appName]); + return ["error" => $this->trans->t("You do not have enough permissions to view the file")]; + } + } + + $folder = $userFolder->get($dir); + + if ($folder === null) { + $this->logger->error("Folder for file creation was not found: $dir", ["app" => $this->appName]); + return ["error" => $this->trans->t("The required folder was not found")]; + } + if (!($folder->isCreatable() && $folder->isUpdateable())) { + $this->logger->error("Folder for file creation without permission: $dir", ["app" => $this->appName]); + return ["error" => $this->trans->t("You don't have enough permission to create")]; + } + + if (!empty($templateId)) { + $templateFile = TemplateManager::GetTemplate($templateId); + if ($templateFile) { + $template = $templateFile->getContent(); + } + } elseif (!empty($targetPath)) { + $targetFile = $userFolder->get($targetPath); + + $canDownload = $this->fileUtility->hasPermissionAttribute($targetFile); + if (!$canDownload) { + return ["error" => $this->trans->t("Not permitted")]; + } + + $targetId = $targetFile->getId(); + $targetName = $targetFile->getName(); + $targetExt = strtolower(pathinfo($targetName, PATHINFO_EXTENSION)); + $targetKey = $this->fileUtility->getKey($targetFile); + + $fileUrl = $this->getUrl($targetFile, $user, $shareToken); + + $ext = strtolower(pathinfo($name, PATHINFO_EXTENSION)); + $documentService = new DocumentService($this->trans, $this->config); + try { + $newFileUri = $documentService->GetConvertedUri($fileUrl, $targetExt, $ext, $targetKey); + } catch (\Exception $e) { + $this->logger->logException($e, ["message" => "GetConvertedUri: " . $targetFile->getId(), "app" => $this->appName]); + return ["error" => $e->getMessage()]; + } + $template = $documentService->Request($newFileUri); + } else { + $template = TemplateManager::GetEmptyTemplate($name); + } + + if (!$template) { + $this->logger->error("Template for file creation not found: $name ($templateId)", ["app" => $this->appName]); + return ["error" => $this->trans->t("Template not found")]; + } + + $name = $folder->getNonExistingName($name); + + try { + $file = $folder->newFile($name); + + $file->putContent($template); + } catch (NotPermittedException $e) { + $this->logger->logException($e, ["message" => "Can't create file: $name", "app" => $this->appName]); + return ["error" => $this->trans->t("Can't create file")]; + } catch (ForbiddenException $e) { + $this->logger->logException($e, ["message" => "Can't put file: $name", "app" => $this->appName]); + return ["error" => $this->trans->t("Can't create file")]; + } + + $fileInfo = $file->getFileInfo(); + + $result = Helper::formatFileInfo($fileInfo); + return $result; + } + + /** + * Create new file in folder from editor + * + * @param string $name - file name + * @param string $dir - folder path + * @param string $templateId - file identifier + * + * @return TemplateResponse|RedirectResponse + * + * @NoAdminRequired + * @NoCSRFRequired + */ + public function createNew($name, $dir, $templateId = null) { + $this->logger->debug("Create from editor: $name in $dir", ["app" => $this->appName]); + + $result = $this->create($name, $dir, $templateId); + if (isset($result["error"])) { + return $this->renderError($result["error"]); + } + + $openEditor = $this->urlGenerator->linkToRouteAbsolute($this->appName . ".editor.index", ["fileId" => $result["id"]]); + return new RedirectResponse($openEditor); + } + + /** + * Get users + * + * @param $fileId - file identifier + * + * @return array + * + * @NoAdminRequired + * @NoCSRFRequired + */ + public function users($fileId) { + $this->logger->debug("Search users", ["app" => $this->appName]); + $result = []; + + if (!$this->config->isUserAllowedToUse()) { + return $result; + } + + if (!$this->allowEnumeration()) { + return $result; + } + + $autocompleteMemberGroup = false; + if ($this->limitEnumerationToGroups()) { + $autocompleteMemberGroup = true; + } + + $currentUser = $this->userSession->getUser(); + $currentUserId = $currentUser->getUID(); + + list($file, $error, $share) = $this->getFile($currentUserId, $fileId); + if (isset($error)) { + $this->logger->error("Users: $fileId $error", ["app" => $this->appName]); + return $result; + } + + $canShare = (($file->getPermissions() & Constants::PERMISSION_SHARE) === Constants::PERMISSION_SHARE); + + $shareMemberGroups = $this->shareManager->shareWithGroupMembersOnly(); + + $all = false; + $users = []; + if ($canShare) { + if ($shareMemberGroups || $autocompleteMemberGroup) { + $currentUserGroups = $this->groupManager->getUserGroupIds($currentUser); + foreach ($currentUserGroups as $currentUserGroup) { + $group = $this->groupManager->get($currentUserGroup); + foreach ($group->getUsers() as $user) { + if (!\in_array($user, $users)) { + array_push($users, $user); + } + } + } + } else { + $users = $this->userManager->search(""); + $all = true; + } + } + + if (!$all) { + $accessList = $this->getAccessList($file); + foreach ($accessList as $accessUser) { + if (!\in_array($accessUser, $users)) { + array_push($users, $accessUser); + } + } + } + + foreach ($users as $user) { + $email = $user->getEMailAddress(); + if ($user->getUID() != $currentUserId && !empty($email)) { + array_push($result, [ + "email" => $email, + "name" => $user->getDisplayName() + ]); + } + } + + return $result; + } + + /** + * Send notify about mention + * + * @param int $fileId - file identifier + * @param string $anchor - the anchor on target content + * @param string $comment - comment + * @param array $emails - emails array to whom to send notify + * + * @return array + * + * @NoAdminRequired + * @NoCSRFRequired + */ + public function mention($fileId, $anchor, $comment, $emails) { + $this->logger->debug("mention: from $fileId to " . json_encode($emails), ["app" => $this->appName]); + + if (!$this->config->isUserAllowedToUse()) { + return ["error" => $this->trans->t("Not permitted")]; + } + + if (empty($emails)) { + return ["error" => $this->trans->t("Failed to send notification")]; + } + + $recipientIds = []; + foreach ($emails as $email) { + $recipients = $this->userManager->getByEmail($email); + foreach ($recipients as $recipient) { + $recipientId = $recipient->getUID(); + if (!\in_array($recipientId, $recipientIds)) { + array_push($recipientIds, $recipientId); + } + } + } + + $user = $this->userSession->getUser(); + $userId = null; + if (!empty($user)) { + $userId = $user->getUID(); + } + + list($file, $error, $share) = $this->getFile($userId, $fileId); + if (isset($error)) { + $this->logger->error("Mention: $fileId $error", ["app" => $this->appName]); + return ["error" => $this->trans->t("Failed to send notification")]; + } + + foreach ($emails as $email) { + $substrToDelete = "+" . $email . " "; + $comment = str_replace($substrToDelete, "", $comment); + } + + //Length from ownCloud: + //https://github.com/owncloud/core/blob/master/lib/private/Notification/Notification.php#L181 + $maxLen = 64; + if (\strlen($comment) > $maxLen) { + $ending = "..."; + $comment = substr($comment, 0, ($maxLen - \strlen($ending))) . $ending; + } + + $notificationManager = \OC::$server->getNotificationManager(); + $notification = $notificationManager->createNotification(); + $notification->setApp($this->appName) + ->setDateTime(new \DateTime()) + ->setObject("mention", $comment) + ->setSubject("mention_info", [ + "notifierId" => $userId, + "fileId" => $file->getId(), + "fileName" => $file->getName(), + "anchor" => $anchor + ]); + + $shareMemberGroups = $this->shareManager->shareWithGroupMembersOnly(); + $canShare = ($file->getPermissions() & Constants::PERMISSION_SHARE) === Constants::PERMISSION_SHARE; + + $currentUserGroups = []; + if ($shareMemberGroups) { + $currentUserGroups = $this->groupManager->getUserGroupIds($user); + } + + $accessList = $this->getAccessList($file); + + foreach ($recipientIds as $recipientId) { + $recipient = $this->userManager->get($recipientId); + $isAvailable = \in_array($recipient, $accessList); + + if (!$isAvailable + && $file->getFileInfo()->getMountPoint() instanceof \OCA\Files_External\Config\ExternalMountPoint) { + $recipientFolder = $this->root->getUserFolder($recipientId); + $recipientFile = $recipientFolder->getById($file->getId()); + + $isAvailable = !empty($recipientFile); + } + + if (!$isAvailable) { + if (!$canShare) { + continue; + } + if ($shareMemberGroups) { + $recipientGroups = $this->groupManager->getUserGroupIds($recipient); + if (empty(array_intersect($currentUserGroups, $recipientGroups))) { + continue; + } + } + + $share = $this->shareManager->newShare(); + $share->setNode($file) + ->setShareType(Share::SHARE_TYPE_USER) + ->setSharedBy($userId) + ->setSharedWith($recipientId) + ->setShareOwner($userId) + ->setPermissions(Constants::PERMISSION_READ); + + $this->shareManager->createShare($share); + + $this->logger->debug("mention: share $fileId to $recipientId", ["app" => $this->appName]); + } + + $notification->setUser($recipientId); + + $notificationManager->notify($notification); + } + + return ["message" => $this->trans->t("Notification sent successfully")]; + } + + /** + * Reference data + * + * @param array $referenceData - reference data + * @param string $path - file path + * + * @return array + * + * @NoAdminRequired + * @PublicPage + */ + public function reference($referenceData, $path = null) { + $this->logger->debug("reference: " . json_encode($referenceData) . " $path", ["app" => $this->appName]); + + if (!$this->config->isUserAllowedToUse()) { + return ["error" => $this->trans->t("Not permitted")]; + } + + $user = $this->userSession->getUser(); + if (empty($user)) { + return ["error" => $this->trans->t("Not permitted")]; + } + + $userId = $user->getUID(); + + $file = null; + $fileId = (integer)($referenceData["fileKey"] ?? 0); + if (!empty($fileId) + && $referenceData["instanceId"] === $this->config->GetSystemValue("instanceid", true)) { + list($file, $error, $share) = $this->getFile($userId, $fileId); + } + + $userFolder = $this->root->getUserFolder($userId); + if ($file === null + && $path !== null + && $userFolder->nodeExists($path)) { + $node = $userFolder->get($path); + if ($node instanceof File + && $node->isReadable()) { + $file = $node; + } + } + + if ($file === null) { + $this->logger->error("Reference not found: $fileId $path", ["app" => $this->appName]); + return ["error" => $this->trans->t("File not found")]; + } + + $fileName = $file->getName(); + $ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION)); + + $response = [ + "fileType" => $ext, + "path" => $userFolder->getRelativePath($file->getPath()), + "referenceData" => [ + "fileKey" => $file->getId(), + "instanceId" => $this->config->GetSystemValue("instanceid", true), + ], + "url" => $this->getUrl($file, $user), + ]; + + if (!empty($this->config->GetDocumentServerSecret())) { + $token = \Firebase\JWT\JWT::encode($response, $this->config->GetDocumentServerSecret(), "HS256"); + $response["token"] = $token; + } + + return $response; + } + + /** + * Conversion file to Office Open XML format + * + * @param integer $fileId - file identifier + * @param string $shareToken - access token + * + * @return array + * + * @NoAdminRequired + * @PublicPage + */ + public function convert($fileId, $shareToken = null) { + $this->logger->debug("Convert: $fileId", ["app" => $this->appName]); + + if (empty($shareToken) && !$this->config->isUserAllowedToUse()) { + return ["error" => $this->trans->t("Not permitted")]; + } + + $user = $this->userSession->getUser(); + $userId = null; + if (!empty($user)) { + $userId = $user->getUID(); + } + + list($file, $error, $share) = empty($shareToken) ? $this->getFile($userId, $fileId) : $this->fileUtility->getFileByToken($fileId, $shareToken); + + if (isset($error)) { + $this->logger->error("Convertion: $fileId $error", ["app" => $this->appName]); + return ["error" => $error]; + } + + if (!empty($shareToken) && ($share->getPermissions() & Constants::PERMISSION_CREATE) === 0) { + $this->logger->error("Convertion in public folder without access: $fileId", ["app" => $this->appName]); + return ["error" => $this->trans->t("You do not have enough permissions to view the file")]; + } + + $canDownload = $this->fileUtility->hasPermissionAttribute($file); + if (!$canDownload) { + return ["error" => $this->trans->t("Not permitted")]; + } + + $fileName = $file->getName(); + $ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION)); + $format = $this->config->FormatsSetting()[$ext]; + if (!isset($format)) { + $this->logger->info("Format for convertion not supported: $fileName", ["app" => $this->appName]); + return ["error" => $this->trans->t("Format is not supported")]; + } + + if (!isset($format["conv"]) || $format["conv"] !== true) { + $this->logger->info("Conversion is not required: $fileName", ["app" => $this->appName]); + return ["error" => $this->trans->t("Conversion is not required")]; + } + + $internalExtension = "docx"; + switch ($format["type"]) { + case "cell": + $internalExtension = "xlsx"; + break; + case "slide": + $internalExtension = "pptx"; + break; + } + + $newFileUri = null; + $documentService = new DocumentService($this->trans, $this->config); + $key = $this->fileUtility->getKey($file); + $fileUrl = $this->getUrl($file, $user, $shareToken); + try { + $newFileUri = $documentService->GetConvertedUri($fileUrl, $ext, $internalExtension, $key); + } catch (\Exception $e) { + $this->logger->logException($e, ["message" => "GetConvertedUri: " . $file->getId(), "app" => $this->appName]); + return ["error" => $e->getMessage()]; + } + + $folder = $file->getParent(); + if (!($folder->isCreatable() && $folder->isUpdateable())) { + $folder = $this->root->getUserFolder($userId); + } + + try { + $newData = $documentService->Request($newFileUri); + } catch (\Exception $e) { + $this->logger->logException($e, ["message" => "Failed to download converted file", "app" => $this->appName]); + return ["error" => $this->trans->t("Failed to download converted file")]; + } + + $fileNameWithoutExt = substr($fileName, 0, \strlen($fileName) - \strlen($ext) - 1); + $newFileName = $folder->getNonExistingName($fileNameWithoutExt . "." . $internalExtension); + + try { + $file = $folder->newFile($newFileName); + + $file->putContent($newData); + } catch (NotPermittedException $e) { + $this->logger->logException($e, ["message" => "Can't create file: $newFileName", "app" => $this->appName]); + return ["error" => $this->trans->t("Can't create file")]; + } catch (ForbiddenException $e) { + $this->logger->logException($e, ["message" => "Can't put file: $newFileName", "app" => $this->appName]); + return ["error" => $this->trans->t("Can't create file")]; + } + + $fileInfo = $file->getFileInfo(); + + $result = Helper::formatFileInfo($fileInfo); + return $result; + } + + /** + * Save file to folder + * + * @param string $name - file name + * @param string $dir - folder path + * @param string $url - file url + * + * @return array + * + * @NoAdminRequired + * @PublicPage + */ + public function save($name, $dir, $url) { + $this->logger->debug("Save: $name", ["app" => $this->appName]); + + if (!$this->config->isUserAllowedToUse()) { + return ["error" => $this->trans->t("Not permitted")]; + } + + $userId = $this->userSession->getUser()->getUID(); + $userFolder = $this->root->getUserFolder($userId); + + $folder = $userFolder->get($dir); + + if ($folder === null) { + $this->logger->error("Folder for saving file was not found: $dir", ["app" => $this->appName]); + return ["error" => $this->trans->t("The required folder was not found")]; + } + if (!($folder->isCreatable() && $folder->isUpdateable())) { + $this->logger->error("Folder for saving file without permission: $dir", ["app" => $this->appName]); + return ["error" => $this->trans->t("You don't have enough permission to create")]; + } + + $url = $this->config->ReplaceDocumentServerUrlToInternal($url); + + try { + $documentService = new DocumentService($this->trans, $this->config); + $newData = $documentService->Request($url); + } catch (\Exception $e) { + $this->logger->logException($e, ["message" => "Failed to download file for saving", "app" => $this->appName]); + return ["error" => $this->trans->t("Download failed")]; + } + + $name = $folder->getNonExistingName($name); + + try { + $file = $folder->newFile($name); + + $file->putContent($newData); + } catch (NotPermittedException $e) { + $this->logger->logException($e, ["message" => "Can't save file: $name", "app" => $this->appName]); + return ["error" => $this->trans->t("Can't create file")]; + } catch (ForbiddenException $e) { + $this->logger->logException($e, ["message" => "Can't put file: $name", "app" => $this->appName]); + return ["error" => $this->trans->t("Can't create file")]; + } + + $fileInfo = $file->getFileInfo(); + + $result = Helper::formatFileInfo($fileInfo); + return $result; + } + + /** + * Get versions history for file + * + * @param integer $fileId - file identifier + * + * @return array + * + * @NoAdminRequired + */ + public function history($fileId) { + $this->logger->debug("Request history for: $fileId", ["app" => $this->appName]); + + if (!$this->config->isUserAllowedToUse()) { + return ["error" => $this->trans->t("Not permitted")]; + } + + $history = []; + + $user = $this->userSession->getUser(); + $userId = null; + if (!empty($user)) { + $userId = $user->getUID(); + } + + list($file, $error, $share) = $this->getFile($userId, $fileId); + + if (isset($error)) { + $this->logger->error("History: $fileId $error", ["app" => $this->appName]); + return ["error" => $error]; + } + + if ($fileId === 0) { + $fileId = $file->getId(); + } + + $ownerId = null; + $owner = $file->getFileInfo()->getOwner(); + if ($owner !== null) { + $ownerId = $owner->getUID(); + } + + $versions = []; + if ($this->versionManager->available + && $owner !== null) { + $versions = array_reverse($this->versionManager->getVersionsForFile($owner, $file->getFileInfo())); + } + + $prevVersion = ""; + $versionNum = 0; + foreach ($versions as $version) { + $versionNum = $versionNum + 1; + + $key = $this->fileUtility->getVersionKey($version); + $key = DocumentService::GenerateRevisionId($key); + + $historyItem = [ + "created" => $version->getTimestamp(), + "key" => $key, + "version" => $versionNum + ]; + + $versionId = $version->getRevisionId(); + + $author = FileVersions::getAuthor($ownerId, $fileId, $versionId); + $authorId = $author !== null ? $author["id"] : $ownerId; + $authorName = $author !== null ? $author["name"] : $owner->getDisplayName(); + + $historyItem["user"] = [ + "id" => $this->buildUserId($authorId), + "name" => $authorName + ]; + + $historyData = FileVersions::getHistoryData($ownerId, $fileId, $versionId, $prevVersion); + if ($historyData !== null) { + $historyItem["changes"] = $historyData["changes"]; + $historyItem["serverVersion"] = $historyData["serverVersion"]; + } + + $prevVersion = $versionId; + + array_push($history, $historyItem); + } + + $key = $this->fileUtility->getKey($file, true); + $key = DocumentService::GenerateRevisionId($key); + + $historyItem = [ + "created" => $file->getMTime(), + "key" => $key, + "version" => $versionNum + 1 + ]; + + $versionId = $file->getFileInfo()->getMtime(); + + $author = FileVersions::getAuthor($ownerId, $fileId, $versionId); + if ($author !== null) { + $historyItem["user"] = [ + "id" => $this->buildUserId($author["id"]), + "name" => $author["name"] + ]; + } elseif ($owner !== null) { + $historyItem["user"] = [ + "id" => $this->buildUserId($ownerId), + "name" => $owner->getDisplayName() + ]; + } + + $historyData = FileVersions::getHistoryData($ownerId, $fileId, $versionId, $prevVersion); + if ($historyData !== null) { + $historyItem["changes"] = $historyData["changes"]; + $historyItem["serverVersion"] = $historyData["serverVersion"]; + } + + array_push($history, $historyItem); + + return $history; + } + + /** + * Get file attributes of specific version + * + * @param integer $fileId - file identifier + * @param integer $version - file version + * + * @return array + * + * @NoAdminRequired + */ + public function version($fileId, $version) { + $this->logger->debug("Request version for: $fileId ($version)", ["app" => $this->appName]); + + if (!$this->config->isUserAllowedToUse()) { + return ["error" => $this->trans->t("Not permitted")]; + } + + $version = empty($version) ? null : $version; + + $user = $this->userSession->getUser(); + $userId = null; + if (!empty($user)) { + $userId = $user->getUID(); + } + + list($file, $error, $share) = $this->getFile($userId, $fileId); + + if (isset($error)) { + $this->logger->error("History: $fileId $error", ["app" => $this->appName]); + return ["error" => $error]; + } + + if ($fileId === 0) { + $fileId = $file->getId(); + } + + $owner = null; + $ownerId = null; + $versions = []; + if ($this->versionManager->available) { + $owner = $file->getFileInfo()->getOwner(); + if ($owner !== null) { + $ownerId = $owner->getUID(); + $versions = array_reverse($this->versionManager->getVersionsForFile($owner, $file->getFileInfo())); + } + } + + $key = null; + $fileUrl = null; + $versionId = null; + if ($version > \count($versions)) { + $key = $this->fileUtility->getKey($file, true); + $versionId = $file->getFileInfo()->getMtime(); + + $fileUrl = $this->getUrl($file, $user); + } else { + $fileVersion = array_values($versions)[$version - 1]; + + $key = $this->fileUtility->getVersionKey($fileVersion); + $versionId = $fileVersion->getRevisionId(); + + $fileUrl = $this->getUrl($file, $user, null, $version); + } + $key = DocumentService::GenerateRevisionId($key); + $fileName = $file->getName(); + $ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION)); + + $result = [ + "fileType" => $ext, + "url" => $fileUrl, + "version" => $version, + "key" => $key + ]; + + if ($version > 1 + && \count($versions) >= $version - 1 + && FileVersions::hasChanges($ownerId, $fileId, $versionId)) { + $changesUrl = $this->getUrl($file, $user, null, $version, true); + $result["changesUrl"] = $changesUrl; + + $prevVersion = array_values($versions)[$version - 2]; + $prevVersionKey = $this->fileUtility->getVersionKey($prevVersion); + $prevVersionKey = DocumentService::GenerateRevisionId($prevVersionKey); + + $prevVersionUrl = $this->getUrl($file, $user, null, $version - 1); + + $result["previous"] = [ + "fileType" => $ext, + "key" => $prevVersionKey, + "url" => $prevVersionUrl + ]; + } + + if (!empty($this->config->GetDocumentServerSecret())) { + $token = \Firebase\JWT\JWT::encode($result, $this->config->GetDocumentServerSecret(), "HS256"); + $result["token"] = $token; + } + + return $result; + } + + /** + * Restore file version + * + * @param integer $fileId - file identifier + * @param integer $version - file version + * + * @return array + * + * @NoAdminRequired + * @PublicPage + */ + public function restore($fileId, $version) { + $this->logger->debug("Request restore version for: $fileId ($version)", ["app" => $this->appName]); + + if (!$this->config->isUserAllowedToUse()) { + return ["error" => $this->trans->t("Not permitted")]; + } + + $version = empty($version) ? null : $version; + + $user = $this->userSession->getUser(); + $userId = null; + if (!empty($user)) { + $userId = $user->getUID(); + } + + list($file, $error, $share) = $this->getFile($userId, $fileId); + + if (isset($error)) { + $this->logger->error("Restore: $fileId $error", ["app" => $this->appName]); + return ["error" => $error]; + } + + if ($fileId === 0) { + $fileId = $file->getId(); + } + + $owner = null; + $versions = []; + if ($this->versionManager->available) { + $owner = $file->getFileInfo()->getOwner(); + if ($owner !== null) { + $versions = array_reverse($this->versionManager->getVersionsForFile($owner, $file->getFileInfo())); + } + + if (\count($versions) >= $version) { + $fileVersion = array_values($versions)[$version - 1]; + $this->versionManager->rollback($fileVersion); + } + } + + return $this->history($fileId); + } + + /** + * Get presigned url to file + * + * @param string $filePath - file path + * + * @return array + * + * @NoAdminRequired + */ + public function url($filePath) { + $this->logger->debug("Request url for: $filePath", ["app" => $this->appName]); + + if (!$this->config->isUserAllowedToUse()) { + return ["error" => $this->trans->t("Not permitted")]; + } + + $user = $this->userSession->getUser(); + $userId = $user->getUID(); + $userFolder = $this->root->getUserFolder($userId); + + $file = $userFolder->get($filePath); + + if ($file === null) { + $this->logger->error("File for generate presigned url was not found: $dir", ["app" => $this->appName]); + return ["error" => $this->trans->t("File not found")]; + } + if (!$file->isReadable()) { + $this->logger->error("File without permission: $dir", ["app" => $this->appName]); + return ["error" => $this->trans->t("You do not have enough permissions to view the file")]; + } + + $fileName = $file->getName(); + $ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION)); + $fileUrl = $this->getUrl($file, $user); + + $result = [ + "fileType" => $ext, + "url" => $fileUrl + ]; + + if (!empty($this->config->GetDocumentServerSecret())) { + $token = \Firebase\JWT\JWT::encode($result, $this->config->GetDocumentServerSecret(), "HS256"); + $result["token"] = $token; + } + + return $result; + } + + /** + * Download method + * + * @param int $fileId - file identifier + * @param string $toExtension - file extension to download + * @param bool $template - file is template + * + * @return DataDownloadResponse|TemplateResponse + * + * @NoAdminRequired + * @NoCSRFRequired + */ + public function download($fileId, $toExtension = null, $template = false) { + $this->logger->debug("Download: $fileId $toExtension", ["app" => $this->appName]); + + if (!$this->config->isUserAllowedToUse()) { + return $this->renderError($this->trans->t("Not permitted")); + } + + if ($template) { + $templateFile = TemplateManager::GetTemplate($fileId); + + if (empty($templateFile)) { + $this->logger->info("Download: template not found: $fileId", ["app" => $this->appName]); + return $this->renderError($this->trans->t("File not found")); + } + + $file = $templateFile; + } else { + $user = $this->userSession->getUser(); + $userId = null; + if (!empty($user)) { + $userId = $user->getUID(); + } + + list($file, $error, $share) = $this->getFile($userId, $fileId); + + if (isset($error)) { + $this->logger->error("Download: $fileId $error", ["app" => $this->appName]); + return $this->renderError($error); + } + } + + $canDownload = $this->fileUtility->hasPermissionAttribute($file); + if (!$canDownload) { + return $this->renderError($this->trans->t("Not permitted")); + } + + $fileName = $file->getName(); + $ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION)); + $toExtension = strtolower($toExtension); + + if ($toExtension === null + || $ext === $toExtension + || $template) { + return new DataDownloadResponse($file->getContent(), $fileName, $file->getMimeType()); + } + + $newFileUri = null; + $documentService = new DocumentService($this->trans, $this->config); + $key = $this->fileUtility->getKey($file); + $fileUrl = $this->getUrl($file, $user); + try { + $newFileUri = $documentService->GetConvertedUri($fileUrl, $ext, $toExtension, $key); + } catch (\Exception $e) { + $this->logger->logException($e, ["message" => "GetConvertedUri: " . $file->getId(), "app" => $this->appName]); + return $this->renderError($e->getMessage()); + } + + try { + $newData = $documentService->Request($newFileUri); + } catch (\Exception $e) { + $this->logger->logException($e, ["message" => "Failed to download converted file", "app" => $this->appName]); + return $this->renderError($this->trans->t("Failed to download converted file")); + } + + $fileNameWithoutExt = substr($fileName, 0, \strlen($fileName) - \strlen($ext) - 1); + $newFileName = $fileNameWithoutExt . "." . $toExtension; + + $formats = $this->config->FormatsSetting(); + + return new DataDownloadResponse($newData, $newFileName, $formats[$toExtension]["mime"]); + } + + /** + * Print editor section + * + * @param integer $fileId - file identifier + * @param string $filePath - file path + * @param string $shareToken - access token + * @param integer $version - file version + * @param bool $inframe - open in frame + * @param bool $template - file is template + * @param string $anchor - anchor for file content + * + * @return TemplateResponse|RedirectResponse + * + * @NoAdminRequired + * @NoCSRFRequired + */ + public function index($fileId, $filePath = null, $shareToken = null, $version = 0, $inframe = false, $template = false, $anchor = null) { + $this->logger->debug("Open: $fileId ($version) $filePath", ["app" => $this->appName]); + + if (empty($shareToken) && !$this->userSession->isLoggedIn()) { + $redirectUrl = $this->urlGenerator->linkToRoute("core.login.showLoginForm", [ + "redirect_url" => $this->request->getRequestUri() + ]); + return new RedirectResponse($redirectUrl); + } + + $shareBy = null; + if (!empty($shareToken) && !$this->userSession->isLoggedIn()) { + list($share, $error) = $this->fileUtility->getShare($shareToken); + if (!empty($share)) { + $shareBy = $share->getSharedBy(); + } + } + + if (!$this->config->isUserAllowedToUse($shareBy)) { + return $this->renderError($this->trans->t("Not permitted")); + } + + $documentServerUrl = $this->config->GetDocumentServerUrl(); + + if (empty($documentServerUrl)) { + $this->logger->error("documentServerUrl is empty", ["app" => $this->appName]); + return $this->renderError($this->trans->t("ONLYOFFICE app is not configured. Please contact admin")); + } + + $params = [ + "documentServerUrl" => $documentServerUrl, + "fileId" => $fileId, + "filePath" => $filePath, + "shareToken" => $shareToken, + "version" => $version, + "template" => $template, + "inframe" => false, + "anchor" => $anchor + ]; + + if ($inframe === true) { + $params["inframe"] = true; + $response = new TemplateResponse($this->appName, "editor", $params, "plain"); + } else { + $response = new TemplateResponse($this->appName, "editor", $params); + } + + $csp = new ContentSecurityPolicy(); + $csp->allowInlineScript(true); + + if (preg_match("/^https?:\/\//i", $documentServerUrl)) { + $csp->addAllowedScriptDomain($documentServerUrl); + $csp->addAllowedFrameDomain($documentServerUrl); + } else { + $csp->addAllowedFrameDomain("'self'"); + } + $response->setContentSecurityPolicy($csp); + + return $response; + } + + /** + * Print public editor section + * + * @param integer $fileId - file identifier + * @param string $shareToken - access token + * @param integer $version - file version + * @param bool $inframe - open in frame + * + * @return TemplateResponse + * + * @NoAdminRequired + * @NoCSRFRequired + * @PublicPage + */ + public function PublicPage($fileId, $shareToken, $version = 0, $inframe = false) { + return $this->index($fileId, null, $shareToken, $version, $inframe); + } + + /** + * Getting file by identifier + * + * @param string $userId - user identifier + * @param integer $fileId - file identifier + * @param string $filePath - file path + * @param bool $template - file is template + * + * @return array + */ + private function getFile($userId, $fileId, $filePath = null, $template = false) { + if (empty($fileId)) { + return [null, $this->trans->t("FileId is empty"), null]; + } + + try { + $folder = !$template ? $this->root->getUserFolder($userId) : TemplateManager::GetGlobalTemplateDir(); + $files = $folder->getById($fileId); + } catch (\Exception $e) { + $this->logger->logException($e, ["message" => "getFile: $fileId", "app" => $this->appName]); + return [null, $this->trans->t("Invalid request"), null]; + } + + if (empty($files)) { + $this->logger->info("Files not found: $fileId", ["app" => $this->appName]); + return [null, $this->trans->t("File not found"), null]; + } + + $file = $files[0]; + + if (\count($files) > 1 && !empty($filePath)) { + $filePath = "/" . $userId . "/files" . $filePath; + foreach ($files as $curFile) { + if ($curFile->getPath() === $filePath) { + $file = $curFile; + break; + } + } + } + + if (!$file->isReadable()) { + return [null, $this->trans->t("You do not have enough permissions to view the file"), null]; + } + + return [$file, null, null]; + } + + /** + * Generate secure link to download document + * + * @param File $file - file + * @param IUser $user - user with access + * @param string $shareToken - access token + * @param integer $version - file version + * @param bool $changes - is required url to file changes + * @param bool $template - file is template + * + * @return string + */ + private function getUrl($file, $user = null, $shareToken = null, $version = 0, $changes = false, $template = false) { + $data = [ + "action" => "download", + "fileId" => $file->getId() + ]; + + $userId = null; + if (!empty($user)) { + $userId = $user->getUID(); + $data["userId"] = $userId; + } + if (!empty($shareToken)) { + $data["shareToken"] = $shareToken; + } + if ($version > 0) { + $data["version"] = $version; + } + if ($changes) { + $data["changes"] = true; + } + if ($template) { + $data["template"] = true; + } + + $hashUrl = $this->crypt->GetHash($data); + + $fileUrl = $this->urlGenerator->linkToRouteAbsolute($this->appName . ".callback.download", ["doc" => $hashUrl]); + + if (!$this->config->UseDemo() && !empty($this->config->GetStorageUrl())) { + $fileUrl = str_replace($this->urlGenerator->getAbsoluteURL("/"), $this->config->GetStorageUrl(), $fileUrl); + } + + return $fileUrl; + } + + /** + * Generate unique user identifier + * + * @param string $userId - current user identifier + * + * @return string + */ + private function buildUserId($userId) { + $instanceId = $this->config->GetSystemValue("instanceid", true); + $userId = $instanceId . "_" . $userId; + return $userId; + } + + /** + * Return list users who has access to file + * + * @param File $file - file + * + * @return array + */ + private function getAccessList($file) { + $result = []; + + foreach ($this->shareManager->getSharesByPath($file) as $share) { + $accessList = []; + $shareWith = $share->getSharedWith(); + if ($share->getShareType() === Share::SHARE_TYPE_GROUP) { + $group = $this->groupManager->get($shareWith); + $accessList = $group->getUsers(); + } elseif ($share->getShareType() === Share::SHARE_TYPE_USER) { + array_push($accessList, $this->userManager->get($shareWith)); + } + + foreach ($accessList as $accessUser) { + if (!\in_array($accessUser, $result)) { + array_push($result, $accessUser); + } + } + } + + if (!\in_array($file->getOwner(), $result)) { + array_push($result, $file->getOwner()); + } + + return $result; + } + + /** + * Return allow autocomplete usernames + * + * @return bool + */ + private function allowEnumeration() { + return \OC::$server->getConfig()->getAppValue("core", "shareapi_allow_share_dialog_user_enumeration", "yes") === "yes"; + } + + /** + * Return allow autocomplete usernames group member only + * + * @return bool + */ + private function limitEnumerationToGroups() { + if ($this->allowEnumeration()) { + return \OC::$server->getConfig()->getAppValue("core", "shareapi_share_dialog_user_enumeration_group_members", "no") === "yes"; + } + + return false; + } + + /** + * Print error page + * + * @param string $error - error message + * @param string $hint - error hint + * + * @return TemplateResponse + */ + private function renderError($error, $hint = "") { + return new TemplateResponse("", "error", [ + "errors" => [ + [ + "error" => $error, + "hint" => $hint + ] + ] + ], "error"); + } } diff --git a/controller/federationcontroller.php b/controller/federationcontroller.php index c4858ac0..5070fd5c 100644 --- a/controller/federationcontroller.php +++ b/controller/federationcontroller.php @@ -38,132 +38,132 @@ * OCS handler */ class FederationController extends OCSController { - /** - * Logger - * - * @var ILogger - */ - private $logger; - - /** - * Application configuration - * - * @var AppConfig - */ - public $config; - - /** - * File utility - * - * @var FileUtility - */ - private $fileUtility; - - /** - * @param string $AppName - application name - * @param IRequest $request - request object - * @param IL10N $trans - l10n service - * @param ILogger $logger - logger - * @param IManager $shareManager - Share manager - * @param IManager $ISession - Session - */ - public function __construct( - $AppName, - IRequest $request, - IL10N $trans, - ILogger $logger, - IManager $shareManager, - ISession $session - ) { - parent::__construct($AppName, $request); - - $this->logger = $logger; - - $this->config = new AppConfig($this->appName); - $this->fileUtility = new FileUtility($AppName, $trans, $logger, $this->config, $shareManager, $session); - } - - /** - * Returns the origin document key for editor - * - * @param string $shareToken - access token - * @param string $path - file path - * - * @return Result - * - * @NoAdminRequired - * @NoCSRFRequired - * @PublicPage - */ - public function key($shareToken, $path) { - list($file, $error, $share) = $this->fileUtility->getFileByToken(null, $shareToken, $path); - - if (isset($error)) { - $this->logger->error("Federated getFileByToken: $error", ["app" => $this->appName]); - return new Result(["error" => $error]); - } - - $key = $this->fileUtility->getKey($file, true); - - $key = DocumentService::GenerateRevisionId($key); - - $this->logger->debug("Federated request get for " . $file->getId() . " key $key", ["app" => $this->appName]); - - return new Result(["key" => $key]); - } - - /** - * Lock the origin document key for editor - * - * @param string $shareToken - access token - * @param string $path - file path - * @param bool $lock - status - * @param bool $fs - status - * - * @return Result - * - * @NoAdminRequired - * @NoCSRFRequired - * @PublicPage - */ - public function keylock($shareToken, $path, $lock, $fs) { - list($file, $error, $share) = $this->fileUtility->getFileByToken(null, $shareToken, $path); - - if (isset($error)) { - $this->logger->error("Federated getFileByToken: $error", ["app" => $this->appName]); - return new Result(["error" => $error]); - } - - $fileId = $file->getId(); - - if (RemoteInstance::isRemoteFile($file)) { - $isLock = RemoteInstance::lockRemoteKey($file, $lock, $fs); - if (!$isLock) { - return new Result(["error" => "Failed request"]); - } - } else { - KeyManager::lock($fileId, $lock); - if (!empty($fs)) { - KeyManager::setForcesave($fileId, $fs); - } - } - - $this->logger->debug("Federated request lock for " . $fileId, ["app" => $this->appName]); - return new Result(); - } - - /** - * Health check instance - * - * @return Result - * - * @NoAdminRequired - * @NoCSRFRequired - * @PublicPage - */ - public function healthcheck() { - $this->logger->debug("Federated healthcheck", ["app" => $this->appName]); - - return new Result(["alive" => true]); - } + /** + * Logger + * + * @var ILogger + */ + private $logger; + + /** + * Application configuration + * + * @var AppConfig + */ + public $config; + + /** + * File utility + * + * @var FileUtility + */ + private $fileUtility; + + /** + * @param string $AppName - application name + * @param IRequest $request - request object + * @param IL10N $trans - l10n service + * @param ILogger $logger - logger + * @param IManager $shareManager - Share manager + * @param IManager $ISession - Session + */ + public function __construct( + $AppName, + IRequest $request, + IL10N $trans, + ILogger $logger, + IManager $shareManager, + ISession $session + ) { + parent::__construct($AppName, $request); + + $this->logger = $logger; + + $this->config = new AppConfig($this->appName); + $this->fileUtility = new FileUtility($AppName, $trans, $logger, $this->config, $shareManager, $session); + } + + /** + * Returns the origin document key for editor + * + * @param string $shareToken - access token + * @param string $path - file path + * + * @return Result + * + * @NoAdminRequired + * @NoCSRFRequired + * @PublicPage + */ + public function key($shareToken, $path) { + list($file, $error, $share) = $this->fileUtility->getFileByToken(null, $shareToken, $path); + + if (isset($error)) { + $this->logger->error("Federated getFileByToken: $error", ["app" => $this->appName]); + return new Result(["error" => $error]); + } + + $key = $this->fileUtility->getKey($file, true); + + $key = DocumentService::GenerateRevisionId($key); + + $this->logger->debug("Federated request get for " . $file->getId() . " key $key", ["app" => $this->appName]); + + return new Result(["key" => $key]); + } + + /** + * Lock the origin document key for editor + * + * @param string $shareToken - access token + * @param string $path - file path + * @param bool $lock - status + * @param bool $fs - status + * + * @return Result + * + * @NoAdminRequired + * @NoCSRFRequired + * @PublicPage + */ + public function keylock($shareToken, $path, $lock, $fs) { + list($file, $error, $share) = $this->fileUtility->getFileByToken(null, $shareToken, $path); + + if (isset($error)) { + $this->logger->error("Federated getFileByToken: $error", ["app" => $this->appName]); + return new Result(["error" => $error]); + } + + $fileId = $file->getId(); + + if (RemoteInstance::isRemoteFile($file)) { + $isLock = RemoteInstance::lockRemoteKey($file, $lock, $fs); + if (!$isLock) { + return new Result(["error" => "Failed request"]); + } + } else { + KeyManager::lock($fileId, $lock); + if (!empty($fs)) { + KeyManager::setForcesave($fileId, $fs); + } + } + + $this->logger->debug("Federated request lock for " . $fileId, ["app" => $this->appName]); + return new Result(); + } + + /** + * Health check instance + * + * @return Result + * + * @NoAdminRequired + * @NoCSRFRequired + * @PublicPage + */ + public function healthcheck() { + $this->logger->debug("Federated healthcheck", ["app" => $this->appName]); + + return new Result(["alive" => true]); + } } diff --git a/controller/joblistcontroller.php b/controller/joblistcontroller.php index a1138043..562eecdf 100644 --- a/controller/joblistcontroller.php +++ b/controller/joblistcontroller.php @@ -39,84 +39,84 @@ * @package OCA\Onlyoffice\Controller */ class JobListController extends Controller { - /** - * Logger - * - * @var ILogger - */ - private $logger; + /** + * Logger + * + * @var ILogger + */ + private $logger; - /** - * Job list - * - * @var IJobList - */ - private $jobList; + /** + * Job list + * + * @var IJobList + */ + private $jobList; - /** - * Application configuration - * - * @var AppConfig - */ - private $config; + /** + * Application configuration + * + * @var AppConfig + */ + private $config; - /** - * JobListController constructor. - * - * @param string $AppName - application name - * @param IRequest $request - request object - * @param ILogger $logger - * @param AppConfig $config - application configuration - * @param IJobList $jobList - job list - */ - public function __construct($AppName, IRequest $request, ILogger $logger, AppConfig $config, IJobList $jobList) { - parent::__construct($AppName, $request); - $this->logger = $logger; - $this->config = $config; - $this->jobList = $jobList; - } + /** + * JobListController constructor. + * + * @param string $AppName - application name + * @param IRequest $request - request object + * @param ILogger $logger + * @param AppConfig $config - application configuration + * @param IJobList $jobList - job list + */ + public function __construct($AppName, IRequest $request, ILogger $logger, AppConfig $config, IJobList $jobList) { + parent::__construct($AppName, $request); + $this->logger = $logger; + $this->config = $config; + $this->jobList = $jobList; + } - /** - * Add a job to list - * - * @param IJob|string $job - */ - private function addJob($job) { - if (!$this->jobList->has($job, null)) { - $this->jobList->add($job); - $this->logger->debug("Job '".$job."' added to JobList.", ["app" => $this->appName]); - } - } + /** + * Add a job to list + * + * @param IJob|string $job + */ + private function addJob($job) { + if (!$this->jobList->has($job, null)) { + $this->jobList->add($job); + $this->logger->debug("Job '".$job."' added to JobList.", ["app" => $this->appName]); + } + } - /** - * Remove a job from list - * - * @param IJob|string $job - */ - private function removeJob($job) { - if ($this->jobList->has($job, null)) { - $this->jobList->remove($job); - $this->logger->debug("Job '".$job."' removed from JobList.", ["app" => $this->appName]); - } - } + /** + * Remove a job from list + * + * @param IJob|string $job + */ + private function removeJob($job) { + if ($this->jobList->has($job, null)) { + $this->jobList->remove($job); + $this->logger->debug("Job '".$job."' removed from JobList.", ["app" => $this->appName]); + } + } - /** - * Add or remove EditorsCheck job depending on the value of _editors_check_interval - * - */ - private function checkEditorsCheckJob() { - if ($this->config->GetEditorsCheckInterval() > 0) { - $this->addJob(EditorsCheck::class); - } else { - $this->removeJob(EditorsCheck::class); - } - } + /** + * Add or remove EditorsCheck job depending on the value of _editors_check_interval + * + */ + private function checkEditorsCheckJob() { + if ($this->config->GetEditorsCheckInterval() > 0) { + $this->addJob(EditorsCheck::class); + } else { + $this->removeJob(EditorsCheck::class); + } + } - /** - * Method for sequentially calling checks of all jobs - * - */ - public function checkAllJobs() { - $this->checkEditorsCheckJob(); - } + /** + * Method for sequentially calling checks of all jobs + * + */ + public function checkAllJobs() { + $this->checkEditorsCheckJob(); + } } diff --git a/controller/settingsapicontroller.php b/controller/settingsapicontroller.php index 83e2f6e8..45369859 100644 --- a/controller/settingsapicontroller.php +++ b/controller/settingsapicontroller.php @@ -30,54 +30,54 @@ * Settings controller for the administration page */ class SettingsApiController extends OCSController { - /** - * Url generator service - * - * @var IURLGenerator - */ - private $urlGenerator; + /** + * Url generator service + * + * @var IURLGenerator + */ + private $urlGenerator; - /** - * Application configuration - * - * @var AppConfig - */ - private $config; + /** + * Application configuration + * + * @var AppConfig + */ + private $config; - /** - * @param string $AppName - application name - * @param IRequest $request - request object - * @param IURLGenerator $urlGenerator - url generator service - * @param AppConfig $config - application configuration - */ - public function __construct( - $AppName, - IRequest $request, - IURLGenerator $urlGenerator, - AppConfig $config - ) { - parent::__construct($AppName, $request); + /** + * @param string $AppName - application name + * @param IRequest $request - request object + * @param IURLGenerator $urlGenerator - url generator service + * @param AppConfig $config - application configuration + */ + public function __construct( + $AppName, + IRequest $request, + IURLGenerator $urlGenerator, + AppConfig $config + ) { + parent::__construct($AppName, $request); - $this->urlGenerator = $urlGenerator; - $this->config = $config; - } + $this->urlGenerator = $urlGenerator; + $this->config = $config; + } - /** - * Get document server url - * - * @return JSONResponse - * - * @NoAdminRequired - * @CORS - */ - public function GetDocServerUrl() { - $url = $this->config->GetDocumentServerUrl(); - if (!$this->config->SettingsAreSuccessful()) { - $url = ""; - } elseif (!preg_match("/^https?:\/\//i", $url)) { - $url = $this->urlGenerator->getAbsoluteURL($url); - } + /** + * Get document server url + * + * @return JSONResponse + * + * @NoAdminRequired + * @CORS + */ + public function GetDocServerUrl() { + $url = $this->config->GetDocumentServerUrl(); + if (!$this->config->SettingsAreSuccessful()) { + $url = ""; + } elseif (!preg_match("/^https?:\/\//i", $url)) { + $url = $this->urlGenerator->getAbsoluteURL($url); + } - return new JSONResponse(["documentServerUrl" => $url]); - } + return new JSONResponse(["documentServerUrl" => $url]); + } } diff --git a/controller/settingscontroller.php b/controller/settingscontroller.php index 4d3ba471..870b8675 100644 --- a/controller/settingscontroller.php +++ b/controller/settingscontroller.php @@ -36,292 +36,292 @@ * Settings controller for the administration page */ class SettingsController extends Controller { - /** - * l10n service - * - * @var IL10N - */ - private $trans; + /** + * l10n service + * + * @var IL10N + */ + private $trans; - /** - * Logger - * - * @var ILogger - */ - private $logger; + /** + * Logger + * + * @var ILogger + */ + private $logger; - /** - * Application configuration - * - * @var AppConfig - */ - private $config; + /** + * Application configuration + * + * @var AppConfig + */ + private $config; - /** - * Url generator service - * - * @var IURLGenerator - */ - private $urlGenerator; + /** + * Url generator service + * + * @var IURLGenerator + */ + private $urlGenerator; - /** - * Hash generator - * - * @var Crypt - */ - private $crypt; + /** + * Hash generator + * + * @var Crypt + */ + private $crypt; - /** - * @param string $AppName - application name - * @param IRequest $request - request object - * @param IURLGenerator $urlGenerator - url generator service - * @param IL10N $trans - l10n service - * @param ILogger $logger - logger - * @param AppConfig $config - application configuration - * @param Crypt $crypt - hash generator - */ - public function __construct( - $AppName, - IRequest $request, - IURLGenerator $urlGenerator, - IL10N $trans, - ILogger $logger, - AppConfig $config, - Crypt $crypt - ) { - parent::__construct($AppName, $request); + /** + * @param string $AppName - application name + * @param IRequest $request - request object + * @param IURLGenerator $urlGenerator - url generator service + * @param IL10N $trans - l10n service + * @param ILogger $logger - logger + * @param AppConfig $config - application configuration + * @param Crypt $crypt - hash generator + */ + public function __construct( + $AppName, + IRequest $request, + IURLGenerator $urlGenerator, + IL10N $trans, + ILogger $logger, + AppConfig $config, + Crypt $crypt + ) { + parent::__construct($AppName, $request); - $this->urlGenerator = $urlGenerator; - $this->trans = $trans; - $this->logger = $logger; - $this->config = $config; - $this->crypt = $crypt; - } + $this->urlGenerator = $urlGenerator; + $this->trans = $trans; + $this->logger = $logger; + $this->config = $config; + $this->crypt = $crypt; + } - /** - * Print config section - * - * @return TemplateResponse - */ - public function index() { - $data = [ - "documentserver" => $this->config->GetDocumentServerUrl(true), - "documentserverInternal" => $this->config->GetDocumentServerInternalUrl(true), - "storageUrl" => $this->config->GetStorageUrl(), - "verifyPeerOff" => $this->config->GetVerifyPeerOff(), - "secret" => $this->config->GetDocumentServerSecret(true), - "jwtHeader" => $this->config->JwtHeader(true), - "demo" => $this->config->GetDemoData(), - "currentServer" => $this->urlGenerator->getAbsoluteURL("/"), - "formats" => $this->config->FormatsSetting(), - "sameTab" => $this->config->GetSameTab(), - "preview" => $this->config->GetPreview(), - "versionHistory" => $this->config->GetVersionHistory(), - "protection" => $this->config->GetProtection(), - "encryption" => $this->config->checkEncryptionModule(), - "limitGroups" => $this->config->GetLimitGroups(), - "chat" => $this->config->GetCustomizationChat(), - "compactHeader" => $this->config->GetCustomizationCompactHeader(), - "feedback" => $this->config->GetCustomizationFeedback(), - "forcesave" => $this->config->GetCustomizationForcesave(), - "help" => $this->config->GetCustomizationHelp(), - "toolbarNoTabs" => $this->config->GetCustomizationToolbarNoTabs(), - "successful" => $this->config->SettingsAreSuccessful(), - "plugins" => $this->config->GetCustomizationPlugins(), - "macros" => $this->config->GetCustomizationMacros(), - "reviewDisplay" => $this->config->GetCustomizationReviewDisplay(), - "theme" => $this->config->GetCustomizationTheme(), - "templates" => $this->GetGlobalTemplates(), - "linkToDocs" => $this->config->GetLinkToDocs() - ]; - return new TemplateResponse($this->appName, "settings", $data, "blank"); - } + /** + * Print config section + * + * @return TemplateResponse + */ + public function index() { + $data = [ + "documentserver" => $this->config->GetDocumentServerUrl(true), + "documentserverInternal" => $this->config->GetDocumentServerInternalUrl(true), + "storageUrl" => $this->config->GetStorageUrl(), + "verifyPeerOff" => $this->config->GetVerifyPeerOff(), + "secret" => $this->config->GetDocumentServerSecret(true), + "jwtHeader" => $this->config->JwtHeader(true), + "demo" => $this->config->GetDemoData(), + "currentServer" => $this->urlGenerator->getAbsoluteURL("/"), + "formats" => $this->config->FormatsSetting(), + "sameTab" => $this->config->GetSameTab(), + "preview" => $this->config->GetPreview(), + "versionHistory" => $this->config->GetVersionHistory(), + "protection" => $this->config->GetProtection(), + "encryption" => $this->config->checkEncryptionModule(), + "limitGroups" => $this->config->GetLimitGroups(), + "chat" => $this->config->GetCustomizationChat(), + "compactHeader" => $this->config->GetCustomizationCompactHeader(), + "feedback" => $this->config->GetCustomizationFeedback(), + "forcesave" => $this->config->GetCustomizationForcesave(), + "help" => $this->config->GetCustomizationHelp(), + "toolbarNoTabs" => $this->config->GetCustomizationToolbarNoTabs(), + "successful" => $this->config->SettingsAreSuccessful(), + "plugins" => $this->config->GetCustomizationPlugins(), + "macros" => $this->config->GetCustomizationMacros(), + "reviewDisplay" => $this->config->GetCustomizationReviewDisplay(), + "theme" => $this->config->GetCustomizationTheme(), + "templates" => $this->GetGlobalTemplates(), + "linkToDocs" => $this->config->GetLinkToDocs() + ]; + return new TemplateResponse($this->appName, "settings", $data, "blank"); + } - /** - * Save address settings - * - * @param string $jwtHeader - jwt header - * @param string $documentserver - document service address - * @param string $documentserverInternal - document service address available from ownCloud - * @param string $storageUrl - ownCloud address available from document server - * @param bool $verifyPeerOff - parameter verification setting - * @param string $secret - secret key for signature - * @param bool $demo - use demo server - * - * @return array - */ - public function SaveAddress( - $documentserver, - $documentserverInternal, - $storageUrl, - $verifyPeerOff, - $secret, - $jwtHeader, - $demo - ) { - $error = null; - if (!$this->config->SelectDemo($demo === true)) { - $error = $this->trans->t("The 30-day test period is over, you can no longer connect to demo ONLYOFFICE Docs server."); - } - if ($demo !== true) { - $this->config->SetDocumentServerUrl($documentserver); - $this->config->SetVerifyPeerOff($verifyPeerOff); - $this->config->SetDocumentServerInternalUrl($documentserverInternal); - $this->config->SetDocumentServerSecret($secret); - $this->config->SetJwtHeader($jwtHeader); - } - $this->config->SetStorageUrl($storageUrl); + /** + * Save address settings + * + * @param string $jwtHeader - jwt header + * @param string $documentserver - document service address + * @param string $documentserverInternal - document service address available from ownCloud + * @param string $storageUrl - ownCloud address available from document server + * @param bool $verifyPeerOff - parameter verification setting + * @param string $secret - secret key for signature + * @param bool $demo - use demo server + * + * @return array + */ + public function SaveAddress( + $documentserver, + $documentserverInternal, + $storageUrl, + $verifyPeerOff, + $secret, + $jwtHeader, + $demo + ) { + $error = null; + if (!$this->config->SelectDemo($demo === true)) { + $error = $this->trans->t("The 30-day test period is over, you can no longer connect to demo ONLYOFFICE Docs server."); + } + if ($demo !== true) { + $this->config->SetDocumentServerUrl($documentserver); + $this->config->SetVerifyPeerOff($verifyPeerOff); + $this->config->SetDocumentServerInternalUrl($documentserverInternal); + $this->config->SetDocumentServerSecret($secret); + $this->config->SetJwtHeader($jwtHeader); + } + $this->config->SetStorageUrl($storageUrl); - $version = null; - if (empty($error)) { - $documentserver = $this->config->GetDocumentServerUrl(); - if (!empty($documentserver)) { - $documentService = new DocumentService($this->trans, $this->config); - list($error, $version) = $documentService->checkDocServiceUrl($this->urlGenerator, $this->crypt); - $this->config->SetSettingsError($error); - } + $version = null; + if (empty($error)) { + $documentserver = $this->config->GetDocumentServerUrl(); + if (!empty($documentserver)) { + $documentService = new DocumentService($this->trans, $this->config); + list($error, $version) = $documentService->checkDocServiceUrl($this->urlGenerator, $this->crypt); + $this->config->SetSettingsError($error); + } - if ($this->config->checkEncryptionModule() === true) { - $this->logger->info("SaveSettings when encryption is enabled", ["app" => $this->appName]); - } - } + if ($this->config->checkEncryptionModule() === true) { + $this->logger->info("SaveSettings when encryption is enabled", ["app" => $this->appName]); + } + } - return [ - "documentserver" => $this->config->GetDocumentServerUrl(true), - "verifyPeerOff" => $this->config->GetVerifyPeerOff(), - "documentserverInternal" => $this->config->GetDocumentServerInternalUrl(true), - "storageUrl" => $this->config->GetStorageUrl(), - "secret" => $this->config->GetDocumentServerSecret(true), - "jwtHeader" => $this->config->JwtHeader(true), - "error" => $error, - "version" => $version, - ]; - } + return [ + "documentserver" => $this->config->GetDocumentServerUrl(true), + "verifyPeerOff" => $this->config->GetVerifyPeerOff(), + "documentserverInternal" => $this->config->GetDocumentServerInternalUrl(true), + "storageUrl" => $this->config->GetStorageUrl(), + "secret" => $this->config->GetDocumentServerSecret(true), + "jwtHeader" => $this->config->JwtHeader(true), + "error" => $error, + "version" => $version, + ]; + } - /** - * Save common settings - * - * @param array $defFormats - formats array with default action - * @param array $editFormats - editable formats array - * @param bool $sameTab - open in the same tab - * @param bool $preview - generate preview files - * @param bool $versionHistory - keep version history - * @param array $limitGroups - list of groups - * @param bool $chat - display chat - * @param bool $compactHeader - display compact header - * @param bool $feedback - display feedback - * @param bool $forcesave - forcesave - * @param bool $help - display help - * @param bool $toolbarNoTabs - display toolbar tab - * @param string $reviewDisplay - review viewing mode - * @param string $theme - default theme mode - * - * @return array - */ - public function SaveCommon( - $defFormats, - $editFormats, - $sameTab, - $preview, - $versionHistory, - $limitGroups, - $chat, - $compactHeader, - $feedback, - $forcesave, - $help, - $toolbarNoTabs, - $reviewDisplay, - $theme - ) { - $this->config->SetDefaultFormats($defFormats); - $this->config->SetEditableFormats($editFormats); - $this->config->SetSameTab($sameTab); - $this->config->SetPreview($preview); - $this->config->SetVersionHistory($versionHistory); - $this->config->SetLimitGroups($limitGroups); - $this->config->SetCustomizationChat($chat); - $this->config->SetCustomizationCompactHeader($compactHeader); - $this->config->SetCustomizationFeedback($feedback); - $this->config->SetCustomizationForcesave($forcesave); - $this->config->SetCustomizationHelp($help); - $this->config->SetCustomizationToolbarNoTabs($toolbarNoTabs); - $this->config->SetCustomizationReviewDisplay($reviewDisplay); - $this->config->SetCustomizationTheme($theme); + /** + * Save common settings + * + * @param array $defFormats - formats array with default action + * @param array $editFormats - editable formats array + * @param bool $sameTab - open in the same tab + * @param bool $preview - generate preview files + * @param bool $versionHistory - keep version history + * @param array $limitGroups - list of groups + * @param bool $chat - display chat + * @param bool $compactHeader - display compact header + * @param bool $feedback - display feedback + * @param bool $forcesave - forcesave + * @param bool $help - display help + * @param bool $toolbarNoTabs - display toolbar tab + * @param string $reviewDisplay - review viewing mode + * @param string $theme - default theme mode + * + * @return array + */ + public function SaveCommon( + $defFormats, + $editFormats, + $sameTab, + $preview, + $versionHistory, + $limitGroups, + $chat, + $compactHeader, + $feedback, + $forcesave, + $help, + $toolbarNoTabs, + $reviewDisplay, + $theme + ) { + $this->config->SetDefaultFormats($defFormats); + $this->config->SetEditableFormats($editFormats); + $this->config->SetSameTab($sameTab); + $this->config->SetPreview($preview); + $this->config->SetVersionHistory($versionHistory); + $this->config->SetLimitGroups($limitGroups); + $this->config->SetCustomizationChat($chat); + $this->config->SetCustomizationCompactHeader($compactHeader); + $this->config->SetCustomizationFeedback($feedback); + $this->config->SetCustomizationForcesave($forcesave); + $this->config->SetCustomizationHelp($help); + $this->config->SetCustomizationToolbarNoTabs($toolbarNoTabs); + $this->config->SetCustomizationReviewDisplay($reviewDisplay); + $this->config->SetCustomizationTheme($theme); - return [ - ]; - } + return [ + ]; + } - /** - * Save security settings - * - * @param bool $plugins - enable plugins - * @param bool $macros - run document macros - * @param string $protection - protection - * - * @return array - */ - public function SaveSecurity( - $plugins, - $macros, - $protection - ) { - $this->config->SetCustomizationPlugins($plugins); - $this->config->SetCustomizationMacros($macros); - $this->config->SetProtection($protection); + /** + * Save security settings + * + * @param bool $plugins - enable plugins + * @param bool $macros - run document macros + * @param string $protection - protection + * + * @return array + */ + public function SaveSecurity( + $plugins, + $macros, + $protection + ) { + $this->config->SetCustomizationPlugins($plugins); + $this->config->SetCustomizationMacros($macros); + $this->config->SetProtection($protection); - return [ - ]; - } + return [ + ]; + } - /** - * Clear all version history - * - * @return array - */ - public function ClearHistory() { - FileVersions::clearHistory(); + /** + * Clear all version history + * + * @return array + */ + public function ClearHistory() { + FileVersions::clearHistory(); - return [ - ]; - } + return [ + ]; + } - /** - * Get app settings - * - * @return array - * - * @NoAdminRequired - * @PublicPage - */ - public function GetSettings() { - $result = [ - "formats" => $this->config->FormatsSetting(), - "sameTab" => $this->config->GetSameTab(), - "shareAttributesVersion" => $this->config->ShareAttributesVersion() - ]; - return $result; - } + /** + * Get app settings + * + * @return array + * + * @NoAdminRequired + * @PublicPage + */ + public function GetSettings() { + $result = [ + "formats" => $this->config->FormatsSetting(), + "sameTab" => $this->config->GetSameTab(), + "shareAttributesVersion" => $this->config->ShareAttributesVersion() + ]; + return $result; + } - /** - * Get global templates - * - * @return array - */ - private function GetGlobalTemplates() { - $templates = []; - $templatesList = TemplateManager::GetGlobalTemplates(); + /** + * Get global templates + * + * @return array + */ + private function GetGlobalTemplates() { + $templates = []; + $templatesList = TemplateManager::GetGlobalTemplates(); - foreach ($templatesList as $templateItem) { - $template = [ - "id" => $templateItem->getId(), - "name" => $templateItem->getName(), - "type" => TemplateManager::GetTypeTemplate($templateItem->getMimeType()) - ]; - array_push($templates, $template); - } + foreach ($templatesList as $templateItem) { + $template = [ + "id" => $templateItem->getId(), + "name" => $templateItem->getName(), + "type" => TemplateManager::GetTypeTemplate($templateItem->getMimeType()) + ]; + array_push($templates, $template); + } - return $templates; - } + return $templates; + } } diff --git a/controller/templatecontroller.php b/controller/templatecontroller.php index 98aa3da3..4dfc1317 100644 --- a/controller/templatecontroller.php +++ b/controller/templatecontroller.php @@ -30,132 +30,132 @@ * Template controller for template manage */ class TemplateController extends Controller { - /** - * l10n service - * - * @var IL10N - */ - private $trans; - - /** - * Logger - * - * @var ILogger - */ - private $logger; - - /** - * @param string $AppName - application name - * @param IRequest $request - request object - * @param IL10N $trans - l10n service - */ - public function __construct( - $AppName, - IRequest $request, - IL10N $trans, - ILogger $logger - ) { - parent::__construct($AppName, $request); - - $this->trans = $trans; - $this->logger = $logger; - } - - /** - * Get templates - * - * @return array - * - * @NoAdminRequired - */ - public function GetTemplates() { - $templatesList = TemplateManager::GetGlobalTemplates(); - - $templates = []; - foreach ($templatesList as $templatesItem) { - $template = [ - "id" => $templatesItem->getId(), - "name" => $templatesItem->getName(), - "type" => TemplateManager::GetTypeTemplate($templatesItem->getMimeType()) - ]; - array_push($templates, $template); - } - - return $templates; - } - - /** - * Add global template - * - * @return array - */ - public function AddTemplate() { - $file = $this->request->getUploadedFile("file"); - - if ($file !== null) { - if (is_uploaded_file($file["tmp_name"]) && $file["error"] === 0) { - if (!TemplateManager::IsTemplateType($file["name"])) { - return [ - "error" => $this->trans->t("Template must be in OOXML format") - ]; - } - - $templateDir = TemplateManager::GetGlobalTemplateDir(); - if ($templateDir->nodeExists($file["name"])) { - return [ - "error" => $this->trans->t("Template already exists") - ]; - } - - $templateContent = file_get_contents($file["tmp_name"]); - $template = $templateDir->newFile($file["name"]); - $template->putContent($templateContent); - - $fileInfo = $template->getFileInfo(); - $result = [ - "id" => $fileInfo->getId(), - "name" => $fileInfo->getName(), - "type" => TemplateManager::GetTypeTemplate($fileInfo->getMimeType()) - ]; - - $this->logger->debug("Template: added " . $fileInfo->getName(), ["app" => $this->appName]); - - return $result; - } - } - - return [ - "error" => $this->trans->t("Invalid file provided") - ]; - } - - /** - * Delete template - * - * @param string $templateId - file identifier - */ - public function DeleteTemplate($templateId) { - $templateDir = TemplateManager::GetGlobalTemplateDir(); - - try { - $templates = $templateDir->getById($templateId); - } catch(\Exception $e) { - $this->logger->logException($e, ["message" => "DeleteTemplate: $templateId", "app" => $this->AppName]); - return [ - "error" => $this->trans->t("Failed to delete template") - ]; - } - - if (empty($templates)) { - $this->logger->info("Template not found: $templateId", ["app" => $this->AppName]); - return [ - "error" => $this->trans->t("Failed to delete template") - ]; - } - - $templates[0]->delete(); - - $this->logger->debug("Template: deleted " . $templates[0]->getName(), ["app" => $this->appName]); - return []; - } + /** + * l10n service + * + * @var IL10N + */ + private $trans; + + /** + * Logger + * + * @var ILogger + */ + private $logger; + + /** + * @param string $AppName - application name + * @param IRequest $request - request object + * @param IL10N $trans - l10n service + */ + public function __construct( + $AppName, + IRequest $request, + IL10N $trans, + ILogger $logger + ) { + parent::__construct($AppName, $request); + + $this->trans = $trans; + $this->logger = $logger; + } + + /** + * Get templates + * + * @return array + * + * @NoAdminRequired + */ + public function GetTemplates() { + $templatesList = TemplateManager::GetGlobalTemplates(); + + $templates = []; + foreach ($templatesList as $templatesItem) { + $template = [ + "id" => $templatesItem->getId(), + "name" => $templatesItem->getName(), + "type" => TemplateManager::GetTypeTemplate($templatesItem->getMimeType()) + ]; + array_push($templates, $template); + } + + return $templates; + } + + /** + * Add global template + * + * @return array + */ + public function AddTemplate() { + $file = $this->request->getUploadedFile("file"); + + if ($file !== null) { + if (is_uploaded_file($file["tmp_name"]) && $file["error"] === 0) { + if (!TemplateManager::IsTemplateType($file["name"])) { + return [ + "error" => $this->trans->t("Template must be in OOXML format") + ]; + } + + $templateDir = TemplateManager::GetGlobalTemplateDir(); + if ($templateDir->nodeExists($file["name"])) { + return [ + "error" => $this->trans->t("Template already exists") + ]; + } + + $templateContent = file_get_contents($file["tmp_name"]); + $template = $templateDir->newFile($file["name"]); + $template->putContent($templateContent); + + $fileInfo = $template->getFileInfo(); + $result = [ + "id" => $fileInfo->getId(), + "name" => $fileInfo->getName(), + "type" => TemplateManager::GetTypeTemplate($fileInfo->getMimeType()) + ]; + + $this->logger->debug("Template: added " . $fileInfo->getName(), ["app" => $this->appName]); + + return $result; + } + } + + return [ + "error" => $this->trans->t("Invalid file provided") + ]; + } + + /** + * Delete template + * + * @param string $templateId - file identifier + */ + public function DeleteTemplate($templateId) { + $templateDir = TemplateManager::GetGlobalTemplateDir(); + + try { + $templates = $templateDir->getById($templateId); + } catch(\Exception $e) { + $this->logger->logException($e, ["message" => "DeleteTemplate: $templateId", "app" => $this->AppName]); + return [ + "error" => $this->trans->t("Failed to delete template") + ]; + } + + if (empty($templates)) { + $this->logger->info("Template not found: $templateId", ["app" => $this->AppName]); + return [ + "error" => $this->trans->t("Failed to delete template") + ]; + } + + $templates[0]->delete(); + + $this->logger->debug("Template: deleted " . $templates[0]->getName(), ["app" => $this->appName]); + return []; + } } diff --git a/controller/webassetcontroller.php b/controller/webassetcontroller.php index 3e03ab7f..c904fbb2 100644 --- a/controller/webassetcontroller.php +++ b/controller/webassetcontroller.php @@ -33,46 +33,46 @@ * @package OCA\Onlyoffice\Controller */ class WebAssetController extends Controller { - /** - * @var ILogger - */ - private $logger; + /** + * @var ILogger + */ + private $logger; - /** - * WebAssetController constructor. - * - * @param string $AppName - application name - * @param IRequest $request - request object - * @param ILogger $logger - */ - public function __construct($AppName, IRequest $request, ILogger $logger) { - parent::__construct($AppName, $request); - $this->logger = $logger; - } + /** + * WebAssetController constructor. + * + * @param string $AppName - application name + * @param IRequest $request - request object + * @param ILogger $logger + */ + public function __construct($AppName, IRequest $request, ILogger $logger) { + parent::__construct($AppName, $request); + $this->logger = $logger; + } - /** - * Loads the onlyoffice.js file for integration into ownCloud Web - * - * @PublicPage - * @NoCSRFRequired - * - * @return Response - */ - public function get(): Response { - $basePath = \dirname(__DIR__, 1); - $filePath = \realpath($basePath . '/js/web/onlyoffice.js'); - try { - return new DataDisplayResponse(\file_get_contents($filePath), Http::STATUS_OK, [ - 'Content-Type' => "text/javascript", - 'Content-Length' => \filesize($filePath), - 'Cache-Control' => 'max-age=0, no-cache, no-store, must-revalidate', - 'Pragma' => 'no-cache', - 'Expires' => 'Tue, 24 Sep 1985 22:15:00 GMT', - 'X-Frame-Options' => 'DENY' - ]); - } catch(\Exception $e) { - $this->logger->logException($e, ['app' => $this->appName]); - return new DataResponse(["message" => $e->getMessage()], Http::STATUS_NOT_FOUND); - } - } + /** + * Loads the onlyoffice.js file for integration into ownCloud Web + * + * @PublicPage + * @NoCSRFRequired + * + * @return Response + */ + public function get(): Response { + $basePath = \dirname(__DIR__, 1); + $filePath = \realpath($basePath . '/js/web/onlyoffice.js'); + try { + return new DataDisplayResponse(\file_get_contents($filePath), Http::STATUS_OK, [ + 'Content-Type' => "text/javascript", + 'Content-Length' => \filesize($filePath), + 'Cache-Control' => 'max-age=0, no-cache, no-store, must-revalidate', + 'Pragma' => 'no-cache', + 'Expires' => 'Tue, 24 Sep 1985 22:15:00 GMT', + 'X-Frame-Options' => 'DENY' + ]); + } catch(\Exception $e) { + $this->logger->logException($e, ['app' => $this->appName]); + return new DataResponse(["message" => $e->getMessage()], Http::STATUS_NOT_FOUND); + } + } } diff --git a/lib/adminsettings.php b/lib/adminsettings.php index 79b68135..14171bc4 100644 --- a/lib/adminsettings.php +++ b/lib/adminsettings.php @@ -25,33 +25,33 @@ * Settings controller for the administration page */ class AdminSettings implements ISettings { - public function __construct() { - } + public function __construct() { + } - /** - * Print config section - * - * @return TemplateResponse - */ - public function getPanel() { - return $this->getForm(); - } + /** + * Print config section + * + * @return TemplateResponse + */ + public function getPanel() { + return $this->getForm(); + } - /** - * Get section ID - * - * @return string - */ - public function getSectionID() { - return "general"; - } + /** + * Get section ID + * + * @return string + */ + public function getSectionID() { + return "general"; + } - /** - * Get priority order - * - * @return int - */ - public function getPriority() { - return 50; - } + /** + * Get priority order + * + * @return int + */ + public function getPriority() { + return 50; + } } diff --git a/lib/appconfig.php b/lib/appconfig.php index ddbe49f1..8dac94f2 100644 --- a/lib/appconfig.php +++ b/lib/appconfig.php @@ -31,1231 +31,1231 @@ * @package OCA\Onlyoffice */ class AppConfig { - /** - * Application name - * - * @var string - */ - private $appName; - - /** - * Config service - * - * @var IConfig - */ - private $config; - - /** - * Logger - * - * @var ILogger - */ - private $logger; - - /** - * The config key for the demo server - * - * @var string - */ - private $_demo = "demo"; - - /** - * The config key for the document server address - * - * @var string - */ - private $_documentserver = "DocumentServerUrl"; - - /** - * The config key for the document server address available from ownCloud - * - * @var string - */ - private $_documentserverInternal = "DocumentServerInternalUrl"; - - /** - * The config key for the ownCloud address available from document server - * - * @var string - */ - private $_storageUrl = "StorageUrl"; - - /** - * The config key for the secret key - * - * @var string - */ - private $_cryptSecret = "secret"; - - /** - * The config key for the default formats - * - * @var string - */ - private $_defFormats = "defFormats"; - - /** - * The config key for the editable formats - * - * @var string - */ - private $_editFormats = "editFormats"; - - /** - * The config key for the setting same tab - * - * @var string - */ - private $_sameTab = "sameTab"; - - /** - * The config key for the generate preview - * - * @var string - */ - private $_preview = "preview"; - - /** - * The config key for the keep versions history - * - * @var string - */ - private $_versionHistory = "versionHistory"; - - /** - * The config key for the protection - * - * @var string - */ - private $_protection = "protection"; - - /** - * The config key for the chat display setting - * - * @var string - */ - private $_customizationChat = "customizationChat"; - - /** - * The config key for display the header more compact setting - * - * @var string - */ - private $_customizationCompactHeader = "customizationCompactHeader"; - - /** - * The config key for the feedback display setting - * - * @var string - */ - private $_customizationFeedback = "customizationFeedback"; - - /** - * The config key for the forcesave setting - * - * @var string - */ - private $_customizationForcesave = "customizationForcesave"; - - /** - * The config key for the help display setting - * - * @var string - */ - private $_customizationHelp = "customizationHelp"; - - /** - * The config key for the no tabs setting - * - * @var string - */ - private $_customizationToolbarNoTabs = "customizationToolbarNoTabs"; - - /** - * The config key for the review mode setting - * - * @var string - */ - private $_customizationReviewDisplay = "customizationReviewDisplay"; - - /** - * The config key for the theme setting - * - * @var string - */ - private $_customizationTheme = "customizationTheme"; - - /** - * The config key for the setting limit groups - * - * @var string - */ - private $_groups = "groups"; - - /** - * The config key for the verification - * - * @var string - */ - private $_verification = "verify_peer_off"; - - /** - * The config key for the secret key in jwt - * - * @var string - */ - private $_jwtSecret = "jwt_secret"; - - /** - * The config key for the jwt header - * - * @var string - */ - private $_jwtHeader = "jwt_header"; - - /** - * The config key for the allowable leeway in Jwt checks - * - * @var string - */ - private $_jwtLeeway = "jwt_leeway"; - - /** - * The config key for the settings error - * - * @var string - */ - private $_settingsError = "settings_error"; - - /** - * The config key for limit thumbnail size - * - * @var string - */ - public $_limitThumbSize = "limit_thumb_size"; - - /** - * The config key for the customer - * - * @var string - */ - public $_customization_customer = "customization_customer"; - - /** - * The config key for the loaderLogo - * - * @var string - */ - public $_customization_loaderLogo = "customization_loaderLogo"; - - /** - * The config key for the loaderName - * - * @var string - */ - public $_customization_loaderName = "customization_loaderName"; - - /** - * The config key for the logo - * - * @var string - */ - public $_customization_logo = "customization_logo"; - - /** - * The config key for the zoom - * - * @var string - */ - public $_customization_zoom = "customization_zoom"; - - /** - * The config key for the autosave - * - * @var string - */ - public $_customization_autosave = "customization_autosave"; - - /** - * The config key for the goback - * - * @var string - */ - public $_customization_goback = "customization_goback"; - - /** - * The config key for the macros - * - * @var string - */ - public $_customization_macros = "customization_macros"; - - /** - * The config key for the plugins - * - * @var string - */ - public $_customizationPlugins = "customization_plugins"; - - /** - * The config key for the interval of editors availability check by cron - * - * @var string - */ - private $_editors_check_interval = "editors_check_interval"; - - /** - * @param string $AppName - application name - */ - public function __construct($AppName) { - $this->appName = $AppName; - - $this->config = \OC::$server->getConfig(); - $this->logger = \OC::$server->getLogger(); - } - - /** - * Get value from the system configuration - * - * @param string $key - key configuration - * @param bool $system - get from root or from app section - * - * @return string - */ - public function GetSystemValue($key, $system = false) { - if ($system) { - return $this->config->getSystemValue($key); - } - if (!empty($this->config->getSystemValue($this->appName)) - && \array_key_exists($key, $this->config->getSystemValue($this->appName))) { - return $this->config->getSystemValue($this->appName)[$key]; - } - return null; - } - - /** - * Switch on demo server - * - * @param bool $value - select demo - * - * @return bool - */ - public function SelectDemo($value) { - $this->logger->info("Select demo: " . json_encode($value), ["app" => $this->appName]); - - $data = $this->GetDemoData(); - - if ($value === true && !$data["available"]) { - $this->logger->info("Trial demo is overdue: " . json_encode($data), ["app" => $this->appName]); - return false; - } - - $data["enabled"] = $value === true; - if (!isset($data["start"])) { - $data["start"] = new DateTime(); - } - - $this->config->setAppValue($this->appName, $this->_demo, json_encode($data)); - return true; - } - - /** - * Get demo data - * - * @return array - */ - public function GetDemoData() { - $data = $this->config->getAppValue($this->appName, $this->_demo, ""); - - if (empty($data)) { - return [ - "available" => true, - "enabled" => false - ]; - } - $data = json_decode($data, true); - - $overdue = new DateTime(isset($data["start"]) ? $data["start"]["date"] : null); - $overdue->add(new DateInterval("P" . $this->DEMO_PARAM["TRIAL"] . "D")); - if ($overdue > new DateTime()) { - $data["available"] = true; - $data["enabled"] = $data["enabled"] === true; - } else { - $data["available"] = false; - $data["enabled"] = false; - } - - return $data; - } - - /** - * Get status of demo server - * - * @return bool - */ - public function UseDemo() { - return $this->GetDemoData()["enabled"] === true; - } - - /** - * Save the document service address to the application configuration - * - * @param string $documentServer - document service address - */ - public function SetDocumentServerUrl($documentServer) { - $documentServer = trim($documentServer); - if (\strlen($documentServer) > 0) { - $documentServer = rtrim($documentServer, "/") . "/"; - if (!preg_match("/(^https?:\/\/)|^\//i", $documentServer)) { - $documentServer = "http://" . $documentServer; - } - } - - $this->logger->info("SetDocumentServerUrl: $documentServer", ["app" => $this->appName]); - - $this->config->setAppValue($this->appName, $this->_documentserver, $documentServer); - } - - /** - * Get the document service address from the application configuration - * - * @param bool $origin - take origin - * - * @return string - */ - public function GetDocumentServerUrl($origin = false) { - if (!$origin && $this->UseDemo()) { - return $this->DEMO_PARAM["ADDR"]; - } - - $url = $this->config->getAppValue($this->appName, $this->_documentserver, ""); - if (empty($url)) { - $url = $this->GetSystemValue($this->_documentserver); - } - if ($url !== "/") { - $url = rtrim($url, "/"); - if (\strlen($url) > 0) { - $url = $url . "/"; - } - } - return $url; - } - - /** - * Save the document service address available from ownCloud to the application configuration - * - * @param string $documentServerInternal - document service address - */ - public function SetDocumentServerInternalUrl($documentServerInternal) { - $documentServerInternal = rtrim(trim($documentServerInternal), "/"); - if (\strlen($documentServerInternal) > 0) { - $documentServerInternal = $documentServerInternal . "/"; - if (!preg_match("/^https?:\/\//i", $documentServerInternal)) { - $documentServerInternal = "http://" . $documentServerInternal; - } - } - - $this->logger->info("SetDocumentServerInternalUrl: $documentServerInternal", ["app" => $this->appName]); - - $this->config->setAppValue($this->appName, $this->_documentserverInternal, $documentServerInternal); - } - - /** - * Get the document service address available from ownCloud from the application configuration - * - * @param bool $origin - take origin - * - * @return string - */ - public function GetDocumentServerInternalUrl($origin = false) { - if (!$origin && $this->UseDemo()) { - return $this->GetDocumentServerUrl(); - } - - $url = $this->config->getAppValue($this->appName, $this->_documentserverInternal, ""); - if (empty($url)) { - $url = $this->GetSystemValue($this->_documentserverInternal); - } - if (!$origin && empty($url)) { - $url = $this->GetDocumentServerUrl(); - } - return $url; - } - - /** - * Replace domain in document server url with internal address from configuration - * - * @param string $url - document server url - * - * @return string - */ - public function ReplaceDocumentServerUrlToInternal($url) { - $documentServerUrl = $this->GetDocumentServerInternalUrl(); - if (!empty($documentServerUrl)) { - $from = $this->GetDocumentServerUrl(); - - if (!preg_match("/^https?:\/\//i", $from)) { - $parsedUrl = parse_url($url); - $from = $parsedUrl["scheme"] . "://" . $parsedUrl["host"] . (\array_key_exists("port", $parsedUrl) ? (":" . $parsedUrl["port"]) : "") . $from; - } - - if ($from !== $documentServerUrl) { - $this->logger->debug("Replace url from $from to $documentServerUrl", ["app" => $this->appName]); - $url = str_replace($from, $documentServerUrl, $url); - } - } - - return $url; - } - - /** - * Save the ownCloud address available from document server to the application configuration - * - * @param string $documentServer - document service address - */ - public function SetStorageUrl($storageUrl) { - $storageUrl = rtrim(trim($storageUrl), "/"); - if (\strlen($storageUrl) > 0) { - $storageUrl = $storageUrl . "/"; - if (!preg_match("/^https?:\/\//i", $storageUrl)) { - $storageUrl = "http://" . $storageUrl; - } - } - - $this->logger->info("SetStorageUrl: $storageUrl", ["app" => $this->appName]); - - $this->config->setAppValue($this->appName, $this->_storageUrl, $storageUrl); - } - - /** - * Get the ownCloud address available from document server from the application configuration - * - * @return string - */ - public function GetStorageUrl() { - $url = $this->config->getAppValue($this->appName, $this->_storageUrl, ""); - if (empty($url)) { - $url = $this->GetSystemValue($this->_storageUrl); - } - return $url; - } - - /** - * Save the document service secret key to the application configuration - * - * @param string $secret - secret key - */ - public function SetDocumentServerSecret($secret) { - $secret = trim($secret); - if (empty($secret)) { - $this->logger->info("Clear secret key", ["app" => $this->appName]); - } else { - $this->logger->info("Set secret key", ["app" => $this->appName]); - } - - $this->config->setAppValue($this->appName, $this->_jwtSecret, $secret); - } - - /** - * Get the document service secret key from the application configuration - * - * @param bool $origin - take origin - * - * @return string - */ - public function GetDocumentServerSecret($origin = false) { - if (!$origin && $this->UseDemo()) { - return $this->DEMO_PARAM["SECRET"]; - } - - $secret = $this->config->getAppValue($this->appName, $this->_jwtSecret, ""); - if (empty($secret)) { - $secret = $this->GetSystemValue($this->_jwtSecret); - } - return $secret; - } - - /** - * Get the secret key from the application configuration - * - * @return string - */ - public function GetSKey() { - $secret = $this->GetDocumentServerSecret(); - if (empty($secret)) { - $secret = $this->GetSystemValue($this->_cryptSecret, true); - } - return $secret; - } - - /** - * Save an array of formats with default action - * - * @param array $formats - formats with status - */ - public function SetDefaultFormats($formats) { - $value = json_encode($formats); - $this->logger->info("Set default formats: $value", ["app" => $this->appName]); - - $this->config->setAppValue($this->appName, $this->_defFormats, $value); - } - - /** - * Get an array of formats with default action - * - * @return array - */ - private function GetDefaultFormats() { - $value = $this->config->getAppValue($this->appName, $this->_defFormats, ""); - if (empty($value)) { - return []; - } - return json_decode($value, true); - } - - /** - * Save an array of formats that is opened for editing - * - * @param array $formats - formats with status - */ - public function SetEditableFormats($formats) { - $value = json_encode($formats); - $this->logger->info("Set editing formats: $value", ["app" => $this->appName]); - - $this->config->setAppValue($this->appName, $this->_editFormats, $value); - } - - /** - * Get an array of formats opening for editing - * - * @return array - */ - private function GetEditableFormats() { - $value = $this->config->getAppValue($this->appName, $this->_editFormats, ""); - if (empty($value)) { - return []; - } - return json_decode($value, true); - } - - /** - * Save the opening setting in a same tab - * - * @param bool $value - same tab - */ - public function SetSameTab($value) { - $this->logger->info("Set opening in a same tab: " . json_encode($value), ["app" => $this->appName]); - - $this->config->setAppValue($this->appName, $this->_sameTab, json_encode($value)); - } - - /** - * Get the opening setting in a same tab - * - * @return bool - */ - public function GetSameTab() { - return $this->config->getAppValue($this->appName, $this->_sameTab, "false") === "true"; - } - - /** - * Save generate preview setting - * - * @param bool $value - preview - */ - public function SetPreview($value) { - $this->logger->info("Set generate preview: " . json_encode($value), ["app" => $this->appName]); - - $this->config->setAppValue($this->appName, $this->_preview, json_encode($value)); - } - - /** - * Get generate preview setting - * - * @return bool - */ - public function GetPreview() { - return $this->config->getAppValue($this->appName, $this->_preview, "true") === "true"; - } - - /** - * Save keep versions history - * - * @param bool $value - version history - */ - public function SetVersionHistory($value) { - $this->logger->info("Set keep versions history: " . json_encode($value), ["app" => $this->appName]); - - $this->config->setAppValue($this->appName, $this->_versionHistory, json_encode($value)); - } - - /** - * Get keep versions history - * - * @return bool - */ - public function GetVersionHistory() { - return $this->config->getAppValue($this->appName, $this->_versionHistory, "true") === "true"; - } - - /** - * Save protection - * - * @param bool $value - version history - */ - public function SetProtection($value) { - $this->logger->info("Set protection: " . $value, ["app" => $this->appName]); - - $this->config->setAppValue($this->appName, $this->_protection, $value); - } - - /** - * Get protection - * - * @return bool - */ - public function GetProtection() { - $value = $this->config->getAppValue($this->appName, $this->_protection, "owner"); - if ($value === "all") { - return "all"; - } - return "owner"; - } - - /** - * Save chat display setting - * - * @param bool $value - display chat - */ - public function SetCustomizationChat($value) { - $this->logger->info("Set chat display: " . json_encode($value), ["app" => $this->appName]); - - $this->config->setAppValue($this->appName, $this->_customizationChat, json_encode($value)); - } - - /** - * Get chat display setting - * - * @return bool - */ - public function GetCustomizationChat() { - return $this->config->getAppValue($this->appName, $this->_customizationChat, "true") === "true"; - } - - /** - * Save compact header setting - * - * @param bool $value - display compact header - */ - public function SetCustomizationCompactHeader($value) { - $this->logger->info("Set compact header display: " . json_encode($value), ["app" => $this->appName]); - - $this->config->setAppValue($this->appName, $this->_customizationCompactHeader, json_encode($value)); - } - - /** - * Get compact header setting - * - * @return bool - */ - public function GetCustomizationCompactHeader() { - return $this->config->getAppValue($this->appName, $this->_customizationCompactHeader, "true") === "true"; - } - - /** - * Save feedback display setting - * - * @param bool $value - display feedback - */ - public function SetCustomizationFeedback($value) { - $this->logger->info("Set feedback display: " . json_encode($value), ["app" => $this->appName]); - - $this->config->setAppValue($this->appName, $this->_customizationFeedback, json_encode($value)); - } - - /** - * Get feedback display setting - * - * @return bool - */ - public function GetCustomizationFeedback() { - return $this->config->getAppValue($this->appName, $this->_customizationFeedback, "true") === "true"; - } - - /** - * Save forcesave setting - * - * @param bool $value - forcesave - */ - public function SetCustomizationForcesave($value) { - $this->logger->info("Set forcesave: " . json_encode($value), ["app" => $this->appName]); - - $this->config->setAppValue($this->appName, $this->_customizationForcesave, json_encode($value)); - } - - /** - * Get forcesave setting - * - * @return bool - */ - public function GetCustomizationForcesave() { - $value = $this->config->getAppValue($this->appName, $this->_customizationForcesave, "false") === "true"; - - return $value && ($this->checkEncryptionModule() === false); - } - - /** - * Save help display setting - * - * @param bool $value - display help - */ - public function SetCustomizationHelp($value) { - $this->logger->info("Set help display: " . json_encode($value), ["app" => $this->appName]); - - $this->config->setAppValue($this->appName, $this->_customizationHelp, json_encode($value)); - } - - /** - * Get help display setting - * - * @return bool - */ - public function GetCustomizationHelp() { - return $this->config->getAppValue($this->appName, $this->_customizationHelp, "true") === "true"; - } - - /** - * Save without tabs setting - * - * @param bool $value - without tabs - */ - public function SetCustomizationToolbarNoTabs($value) { - $this->logger->info("Set without tabs: " . json_encode($value), ["app" => $this->appName]); - - $this->config->setAppValue($this->appName, $this->_customizationToolbarNoTabs, json_encode($value)); - } - - /** - * Get without tabs setting - * - * @return bool - */ - public function GetCustomizationToolbarNoTabs() { - return $this->config->getAppValue($this->appName, $this->_customizationToolbarNoTabs, "true") === "true"; - } - - /** - * Save review viewing mode setting - * - * @param string $value - review mode - */ - public function SetCustomizationReviewDisplay($value) { - $this->logger->info("Set review mode: " . $value, ["app" => $this->appName]); - - $this->config->setAppValue($this->appName, $this->_customizationReviewDisplay, $value); - } - - /** - * Get review viewing mode setting - * - * @return string - */ - public function GetCustomizationReviewDisplay() { - $value = $this->config->getAppValue($this->appName, $this->_customizationReviewDisplay, "original"); - if ($value === "markup") { - return "markup"; - } - if ($value === "final") { - return "final"; - } - return "original"; - } - - /** - * Save theme setting - * - * @param string $value - theme - */ - public function SetCustomizationTheme($value) { - $this->logger->info("Set theme: " . $value, ["app" => $this->appName]); - - $this->config->setAppValue($this->appName, $this->_customizationTheme, $value); - } - - /** - * Get theme setting - * - * @return string - */ - public function GetCustomizationTheme() { - $value = $this->config->getAppValue($this->appName, $this->_customizationTheme, "theme-classic-light"); - if ($value === "theme-light") { - return "theme-light"; - } - if ($value === "theme-dark") { - return "theme-dark"; - } - return "theme-classic-light"; - } - - /** - * Save macros setting - * - * @param bool $value - enable macros - */ - public function SetCustomizationMacros($value) { - $this->logger->info("Set macros enabled: " . json_encode($value), ["app" => $this->appName]); - - $this->config->setAppValue($this->appName, $this->_customization_macros, json_encode($value)); - } - - /** - * Get macros setting - * - * @return bool - */ - public function GetCustomizationMacros() { - return $this->config->getAppValue($this->appName, $this->_customization_macros, "true") === "true"; - } - - /** - * Save plugins setting - * - * @param bool $value - enable macros - */ - public function SetCustomizationPlugins($value) { - $this->logger->info("Set plugins enabled: " . json_encode($value), ["app" => $this->appName]); - - $this->config->setAppValue($this->appName, $this->_customizationPlugins, json_encode($value)); - } - - /** - * Get plugins setting - * - * @return bool - */ - public function GetCustomizationPlugins() { - return $this->config->getAppValue($this->appName, $this->_customizationPlugins, "true") === "true"; - } - - /** - * Save the list of groups - * - * @param array $groups - the list of groups - */ - public function SetLimitGroups($groups) { - if (!\is_array($groups)) { - $groups = []; - } - $value = json_encode($groups); - $this->logger->info("Set groups: $value", ["app" => $this->appName]); - - $this->config->setAppValue($this->appName, $this->_groups, $value); - } - - /** - * Get the list of groups - * - * @return array - */ - public function GetLimitGroups() { - $value = $this->config->getAppValue($this->appName, $this->_groups, ""); - if (empty($value)) { - return []; - } - $groups = json_decode($value, true); - if (!\is_array($groups)) { - $groups = []; - } - return $groups; - } - - /** - * Check access for group - * - * @param string $userId - user identifier - * - * @return bool - */ - public function isUserAllowedToUse($userId = null) { - // no user -> no - $userSession = \OC::$server->getUserSession(); - if ($userId === null && ($userSession === null || !$userSession->isLoggedIn())) { - return false; - } - - $groups = $this->GetLimitGroups(); - // no group set -> all users are allowed - if (\count($groups) === 0) { - return true; - } - - if ($userId === null) { - $user = $userSession->getUser(); - } else { - $user = \OC::$server->getUserManager()->get($userId); - if (empty($user)) { - return false; - } - } - - foreach ($groups as $groupName) { - // group unknown -> error and allow nobody - $group = \OC::$server->getGroupManager()->get($groupName); - if ($group === null) { - \OC::$server->getLogger()->error("Group is unknown $groupName", ["app" => $this->appName]); - $this->SetLimitGroups(array_diff($groups, [$groupName])); - } else { - if ($group->inGroup($user)) { - return true; - } - } - } - - return false; - } - - /** - * Save the document service verification setting to the application configuration - * - * @param bool $verifyPeerOff - parameter verification setting - */ - public function SetVerifyPeerOff($verifyPeerOff) { - $this->logger->info("SetVerifyPeerOff " . json_encode($verifyPeerOff), ["app" => $this->appName]); - - $this->config->setAppValue($this->appName, $this->_verification, json_encode($verifyPeerOff)); - } - - /** - * Get the document service verification setting to the application configuration - * - * @return bool - */ - public function GetVerifyPeerOff() { - $turnOff = $this->config->getAppValue($this->appName, $this->_verification, ""); - - if (!empty($turnOff)) { - return $turnOff === "true"; - } - - return $this->GetSystemValue($this->_verification); - } - - /** - * Get the limit on size document when generating thumbnails - * - * @return int - */ - public function GetLimitThumbSize() { - $limitSize = (integer)$this->GetSystemValue($this->_limitThumbSize); - - if (!empty($limitSize)) { - return $limitSize; - } - - return 100*1024*1024; - } - - /** - * Get the jwt header setting - * - * @param bool $origin - take origin - * - * @return string - */ - public function JwtHeader($origin = false) { - if (!$origin && $this->UseDemo()) { - return $this->DEMO_PARAM["HEADER"]; - } - - $header = $this->config->getAppValue($this->appName, $this->_jwtHeader, ""); - if (empty($header)) { - $header = $this->GetSystemValue($this->_jwtHeader); - } - if (!$origin && empty($header)) { - $header = "Authorization"; - } - return $header; - } - - /** - * Save the jwtHeader setting - * - * @param string $value - jwtHeader - */ - public function SetJwtHeader($value) { - $value = trim($value); - if (empty($value)) { - $this->logger->info("Clear header key", ["app" => $this->appName]); - } else { - $this->logger->info("Set header key " . $value, ["app" => $this->appName]); - } - - $this->config->setAppValue($this->appName, $this->_jwtHeader, $value); - } - - /** - * Get the Jwt Leeway - * - * @return int - */ - public function GetJwtLeeway() { - $jwtLeeway = (integer)$this->GetSystemValue($this->_jwtLeeway); - - return $jwtLeeway; - } - - /** - * Save the status settings - * - * @param string $value - error - */ - public function SetSettingsError($value) { - $this->config->setAppValue($this->appName, $this->_settingsError, $value); - } - - /** - * Get the status settings - * - * @return bool - */ - public function SettingsAreSuccessful() { - return empty($this->config->getAppValue($this->appName, $this->_settingsError, "")); - } - - /** - * Checking encryption enabled - * - * @return string|bool - */ - public function checkEncryptionModule() { - if (!\OC::$server->getAppManager()->isInstalled("encryption")) { - return false; - } - if (!\OC::$server->getEncryptionManager()->isEnabled()) { - return false; - } - - $crypt = new \OCA\Encryption\Crypto\Crypt(\OC::$server->getLogger(), \OC::$server->getUserSession(), \OC::$server->getConfig(), \OC::$server->getL10N("encryption")); - $util = new \OCA\Encryption\Util(new \OC\Files\View(), $crypt, \OC::$server->getLogger(), \OC::$server->getUserSession(), \OC::$server->getConfig(), \OC::$server->getUserManager()); - if ($util->isMasterKeyEnabled()) { - return "master"; - } - - return true; - } - - /** - * Get supported formats - * - * @return array - * - * @NoAdminRequired - */ - public function FormatsSetting() { - $result = $this->formats; - - $defFormats = $this->GetDefaultFormats(); - foreach ($defFormats as $format => $setting) { - if (\array_key_exists($format, $result)) { - $result[$format]["def"] = ($setting === true || $setting === "true"); - } - } - - $editFormats = $this->GetEditableFormats(); - foreach ($editFormats as $format => $setting) { - if (\array_key_exists($format, $result)) { - $result[$format]["edit"] = ($setting === true || $setting === "true"); - } - } - - return $result; - } - - public function ShareAttributesVersion() { - if (\version_compare(\implode(".", \OCP\Util::getVersion()), "10.3.0", ">=")) { - return "v2"; - } elseif (\version_compare(\implode(".", \OCP\Util::getVersion()), "10.2.0", ">=")) { - return "v1"; - } - return ""; - } - - /** - * Get the editors check interval - * - * @return int - */ - public function GetEditorsCheckInterval() { - $interval = $this->GetSystemValue($this->_editors_check_interval); - - if (empty($interval) && $interval !== 0) { - $interval = 60*60*24; - } - return (integer)$interval; - } - - /** - * Additional data about formats - * - * @var array - */ - private $formats = [ - "csv" => [ "mime" => "text/csv", "type" => "cell", "edit" => true, "editable" => true, "saveas" => ["ods", "pdf", "xlsx"] ], - "doc" => [ "mime" => "application/msword", "type" => "word", "conv" => true, "saveas" => ["docx", "odt", "pdf", "rtf", "txt"] ], - "docm" => [ "mime" => "application/vnd.ms-word.document.macroEnabled.12", "type" => "word", "conv" => true, "saveas" => ["docx", "odt", "pdf", "rtf", "txt"] ], - "docx" => [ "mime" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "type" => "word", "edit" => true, "def" => true, "review" => true, "comment" => true, "saveas" => ["odt", "pdf", "rtf", "txt"] ], - "docxf" => [ "mime" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document.docxf", "type" => "word", "edit" => true, "def" => true, "review" => true, "comment" => true, "saveas" => ["odt", "pdf", "rtf", "txt"], "createForm" => true ], - "oform" => [ "mime" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document.oform", "type" => "word", "fillForms" => true, "def" => true ], - "dot" => [ "type" => "word", "conv" => true, "saveas" => ["docx", "odt", "pdf", "rtf", "txt"] ], - "dotx" => [ "mime" => "application/vnd.openxmlformats-officedocument.wordprocessingml.template", "type" => "word", "conv" => true, "saveas" => ["docx", "odt", "pdf", "rtf", "txt"] ], - "epub" => [ "mime" => "application/epub+zip", "type" => "word", "conv" => true, "saveas" => ["docx", "odt", "pdf", "rtf", "txt"] ], - "htm" => [ "type" => "word", "conv" => true ], - "html" => [ "mime" => "text/html", "type" => "word", "conv" => true, "saveas" => ["docx", "odt", "pdf", "rtf", "txt"] ], - "odp" => [ "mime" => "application/vnd.oasis.opendocument.presentation", "type" => "slide", "conv" => true, "editable" => true, "saveas" => ["pdf", "pptx"] ], - "ods" => [ "mime" => "application/vnd.oasis.opendocument.spreadsheet", "type" => "cell", "conv" => true, "editable" => true, "saveas" => ["csv", "pdf", "xlsx"] ], - "odt" => [ "mime" => "application/vnd.oasis.opendocument.text", "type" => "word", "conv" => true, "editable" => true, "saveas" => ["docx", "pdf", "rtf", "txt"] ], - "otp" => [ "mime" => "application/vnd.oasis.opendocument.presentation-template", "type" => "slide", "conv" => true, "saveas" => ["pdf", "pptx", "odp"] ], - "ots" => [ "mime" => "application/vnd.oasis.opendocument.spreadsheet-template", "type" => "cell", "conv" => true, "saveas" => ["csv", "ods", "pdf", "xlsx"] ], - "ott" => [ "mime" => "application/vnd.oasis.opendocument.text-template", "type" => "word", "conv" => true, "saveas" => ["docx", "odt", "pdf", "rtf", "txt"] ], - "pdf" => [ "mime" => "application/pdf", "type" => "word" ], - "pot" => [ "type" => "slide", "conv" => true, "saveas" => ["pdf", "pptx", "odp"] ], - "potm" => [ "mime" => "application/vnd.ms-powerpoint.template.macroEnabled.12", "type" => "slide", "conv" => true, "saveas" => ["pdf", "pptx", "odp"] ], - "potx" => [ "mime" => "application/vnd.openxmlformats-officedocument.presentationml.template", "type" => "slide", "conv" => true, "saveas" => ["pdf", "pptx", "odp"] ], - "pps" => [ "type" => "slide", "conv" => true, "saveas" => ["pdf", "pptx", "odp"] ], - "ppsm" => [ "mime" => "application/vnd.ms-powerpoint.slideshow.macroEnabled.12", "type" => "slide", "conv" => true, "saveas" => ["pdf", "pptx", "odp"] ], - "ppsx" => [ "mime" => "application/vnd.openxmlformats-officedocument.presentationml.slideshow", "type" => "slide", "conv" => true, "saveas" => ["pdf", "pptx", "odp"] ], - "ppt" => [ "mime" => "application/vnd.ms-powerpoint", "type" => "slide", "conv" => true, "saveas" => ["pdf", "pptx", "odp"] ], - "pptm" => [ "mime" => "application/vnd.ms-powerpoint.presentation.macroEnabled.12", "type" => "slide", "conv" => true, "saveas" => ["pdf", "pptx", "odp"] ], - "pptx" => [ "mime" => "application/vnd.openxmlformats-officedocument.presentationml.presentation", "type" => "slide", "edit" => true, "def" => true, "comment" => true, "saveas" => ["pdf", "odp"] ], - "rtf" => [ "mime" => "text/rtf", "type" => "word", "conv" => true, "editable" => true, "saveas" => ["docx", "odt", "pdf", "txt"] ], - "txt" => [ "mime" => "text/plain", "type" => "word", "edit" => true, "editable" => true, "saveas" => ["docx", "odt", "pdf", "rtf"] ], - "xls" => [ "mime" => "application/vnd.ms-excel", "type" => "cell", "conv" => true, "saveas" => ["csv", "ods", "pdf", "xlsx"] ], - "xlsm" => [ "mime" => "application/vnd.ms-excel.sheet.macroEnabled.12", "type" => "cell", "conv" => true, "saveas" => ["csv", "ods", "pdf", "xlsx"] ], - "xlsx" => [ "mime" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "type" => "cell", "edit" => true, "def" => true, "comment" => true, "modifyFilter" => true, "saveas" => ["csv", "ods", "pdf"] ], - "xlt" => [ "type" => "cell", "conv" => true, "saveas" => ["csv", "ods", "pdf", "xlsx"] ], - "xltm" => [ "mime" => "application/vnd.ms-excel.template.macroEnabled.12", "type" => "cell", "conv" => true, "saveas" => ["csv", "ods", "pdf", "xlsx"] ], - "xltx" => [ "mime" => "application/vnd.openxmlformats-officedocument.spreadsheetml.template", "type" => "cell", "conv" => true, "saveas" => ["csv", "ods", "pdf", "xlsx"] ] - ]; - - /** - * DEMO DATA - */ - private $DEMO_PARAM = [ - "ADDR" => "https://onlinedocs.onlyoffice.com/", - "HEADER" => "AuthorizationJWT", - "SECRET" => "sn2puSUF7muF5Jas", - "TRIAL" => 30 - ]; - - private $linkToDocs = "https://www.onlyoffice.com/docs-registration.aspx?referer=owncloud"; - - /** - * Get link to Docs Cloud - * - * @return string - */ - public function GetLinkToDocs() { - return $this->linkToDocs; - } + /** + * Application name + * + * @var string + */ + private $appName; + + /** + * Config service + * + * @var IConfig + */ + private $config; + + /** + * Logger + * + * @var ILogger + */ + private $logger; + + /** + * The config key for the demo server + * + * @var string + */ + private $_demo = "demo"; + + /** + * The config key for the document server address + * + * @var string + */ + private $_documentserver = "DocumentServerUrl"; + + /** + * The config key for the document server address available from ownCloud + * + * @var string + */ + private $_documentserverInternal = "DocumentServerInternalUrl"; + + /** + * The config key for the ownCloud address available from document server + * + * @var string + */ + private $_storageUrl = "StorageUrl"; + + /** + * The config key for the secret key + * + * @var string + */ + private $_cryptSecret = "secret"; + + /** + * The config key for the default formats + * + * @var string + */ + private $_defFormats = "defFormats"; + + /** + * The config key for the editable formats + * + * @var string + */ + private $_editFormats = "editFormats"; + + /** + * The config key for the setting same tab + * + * @var string + */ + private $_sameTab = "sameTab"; + + /** + * The config key for the generate preview + * + * @var string + */ + private $_preview = "preview"; + + /** + * The config key for the keep versions history + * + * @var string + */ + private $_versionHistory = "versionHistory"; + + /** + * The config key for the protection + * + * @var string + */ + private $_protection = "protection"; + + /** + * The config key for the chat display setting + * + * @var string + */ + private $_customizationChat = "customizationChat"; + + /** + * The config key for display the header more compact setting + * + * @var string + */ + private $_customizationCompactHeader = "customizationCompactHeader"; + + /** + * The config key for the feedback display setting + * + * @var string + */ + private $_customizationFeedback = "customizationFeedback"; + + /** + * The config key for the forcesave setting + * + * @var string + */ + private $_customizationForcesave = "customizationForcesave"; + + /** + * The config key for the help display setting + * + * @var string + */ + private $_customizationHelp = "customizationHelp"; + + /** + * The config key for the no tabs setting + * + * @var string + */ + private $_customizationToolbarNoTabs = "customizationToolbarNoTabs"; + + /** + * The config key for the review mode setting + * + * @var string + */ + private $_customizationReviewDisplay = "customizationReviewDisplay"; + + /** + * The config key for the theme setting + * + * @var string + */ + private $_customizationTheme = "customizationTheme"; + + /** + * The config key for the setting limit groups + * + * @var string + */ + private $_groups = "groups"; + + /** + * The config key for the verification + * + * @var string + */ + private $_verification = "verify_peer_off"; + + /** + * The config key for the secret key in jwt + * + * @var string + */ + private $_jwtSecret = "jwt_secret"; + + /** + * The config key for the jwt header + * + * @var string + */ + private $_jwtHeader = "jwt_header"; + + /** + * The config key for the allowable leeway in Jwt checks + * + * @var string + */ + private $_jwtLeeway = "jwt_leeway"; + + /** + * The config key for the settings error + * + * @var string + */ + private $_settingsError = "settings_error"; + + /** + * The config key for limit thumbnail size + * + * @var string + */ + public $_limitThumbSize = "limit_thumb_size"; + + /** + * The config key for the customer + * + * @var string + */ + public $_customization_customer = "customization_customer"; + + /** + * The config key for the loaderLogo + * + * @var string + */ + public $_customization_loaderLogo = "customization_loaderLogo"; + + /** + * The config key for the loaderName + * + * @var string + */ + public $_customization_loaderName = "customization_loaderName"; + + /** + * The config key for the logo + * + * @var string + */ + public $_customization_logo = "customization_logo"; + + /** + * The config key for the zoom + * + * @var string + */ + public $_customization_zoom = "customization_zoom"; + + /** + * The config key for the autosave + * + * @var string + */ + public $_customization_autosave = "customization_autosave"; + + /** + * The config key for the goback + * + * @var string + */ + public $_customization_goback = "customization_goback"; + + /** + * The config key for the macros + * + * @var string + */ + public $_customization_macros = "customization_macros"; + + /** + * The config key for the plugins + * + * @var string + */ + public $_customizationPlugins = "customization_plugins"; + + /** + * The config key for the interval of editors availability check by cron + * + * @var string + */ + private $_editors_check_interval = "editors_check_interval"; + + /** + * @param string $AppName - application name + */ + public function __construct($AppName) { + $this->appName = $AppName; + + $this->config = \OC::$server->getConfig(); + $this->logger = \OC::$server->getLogger(); + } + + /** + * Get value from the system configuration + * + * @param string $key - key configuration + * @param bool $system - get from root or from app section + * + * @return string + */ + public function GetSystemValue($key, $system = false) { + if ($system) { + return $this->config->getSystemValue($key); + } + if (!empty($this->config->getSystemValue($this->appName)) + && \array_key_exists($key, $this->config->getSystemValue($this->appName))) { + return $this->config->getSystemValue($this->appName)[$key]; + } + return null; + } + + /** + * Switch on demo server + * + * @param bool $value - select demo + * + * @return bool + */ + public function SelectDemo($value) { + $this->logger->info("Select demo: " . json_encode($value), ["app" => $this->appName]); + + $data = $this->GetDemoData(); + + if ($value === true && !$data["available"]) { + $this->logger->info("Trial demo is overdue: " . json_encode($data), ["app" => $this->appName]); + return false; + } + + $data["enabled"] = $value === true; + if (!isset($data["start"])) { + $data["start"] = new DateTime(); + } + + $this->config->setAppValue($this->appName, $this->_demo, json_encode($data)); + return true; + } + + /** + * Get demo data + * + * @return array + */ + public function GetDemoData() { + $data = $this->config->getAppValue($this->appName, $this->_demo, ""); + + if (empty($data)) { + return [ + "available" => true, + "enabled" => false + ]; + } + $data = json_decode($data, true); + + $overdue = new DateTime(isset($data["start"]) ? $data["start"]["date"] : null); + $overdue->add(new DateInterval("P" . $this->DEMO_PARAM["TRIAL"] . "D")); + if ($overdue > new DateTime()) { + $data["available"] = true; + $data["enabled"] = $data["enabled"] === true; + } else { + $data["available"] = false; + $data["enabled"] = false; + } + + return $data; + } + + /** + * Get status of demo server + * + * @return bool + */ + public function UseDemo() { + return $this->GetDemoData()["enabled"] === true; + } + + /** + * Save the document service address to the application configuration + * + * @param string $documentServer - document service address + */ + public function SetDocumentServerUrl($documentServer) { + $documentServer = trim($documentServer); + if (\strlen($documentServer) > 0) { + $documentServer = rtrim($documentServer, "/") . "/"; + if (!preg_match("/(^https?:\/\/)|^\//i", $documentServer)) { + $documentServer = "http://" . $documentServer; + } + } + + $this->logger->info("SetDocumentServerUrl: $documentServer", ["app" => $this->appName]); + + $this->config->setAppValue($this->appName, $this->_documentserver, $documentServer); + } + + /** + * Get the document service address from the application configuration + * + * @param bool $origin - take origin + * + * @return string + */ + public function GetDocumentServerUrl($origin = false) { + if (!$origin && $this->UseDemo()) { + return $this->DEMO_PARAM["ADDR"]; + } + + $url = $this->config->getAppValue($this->appName, $this->_documentserver, ""); + if (empty($url)) { + $url = $this->GetSystemValue($this->_documentserver); + } + if ($url !== "/") { + $url = rtrim($url, "/"); + if (\strlen($url) > 0) { + $url = $url . "/"; + } + } + return $url; + } + + /** + * Save the document service address available from ownCloud to the application configuration + * + * @param string $documentServerInternal - document service address + */ + public function SetDocumentServerInternalUrl($documentServerInternal) { + $documentServerInternal = rtrim(trim($documentServerInternal), "/"); + if (\strlen($documentServerInternal) > 0) { + $documentServerInternal = $documentServerInternal . "/"; + if (!preg_match("/^https?:\/\//i", $documentServerInternal)) { + $documentServerInternal = "http://" . $documentServerInternal; + } + } + + $this->logger->info("SetDocumentServerInternalUrl: $documentServerInternal", ["app" => $this->appName]); + + $this->config->setAppValue($this->appName, $this->_documentserverInternal, $documentServerInternal); + } + + /** + * Get the document service address available from ownCloud from the application configuration + * + * @param bool $origin - take origin + * + * @return string + */ + public function GetDocumentServerInternalUrl($origin = false) { + if (!$origin && $this->UseDemo()) { + return $this->GetDocumentServerUrl(); + } + + $url = $this->config->getAppValue($this->appName, $this->_documentserverInternal, ""); + if (empty($url)) { + $url = $this->GetSystemValue($this->_documentserverInternal); + } + if (!$origin && empty($url)) { + $url = $this->GetDocumentServerUrl(); + } + return $url; + } + + /** + * Replace domain in document server url with internal address from configuration + * + * @param string $url - document server url + * + * @return string + */ + public function ReplaceDocumentServerUrlToInternal($url) { + $documentServerUrl = $this->GetDocumentServerInternalUrl(); + if (!empty($documentServerUrl)) { + $from = $this->GetDocumentServerUrl(); + + if (!preg_match("/^https?:\/\//i", $from)) { + $parsedUrl = parse_url($url); + $from = $parsedUrl["scheme"] . "://" . $parsedUrl["host"] . (\array_key_exists("port", $parsedUrl) ? (":" . $parsedUrl["port"]) : "") . $from; + } + + if ($from !== $documentServerUrl) { + $this->logger->debug("Replace url from $from to $documentServerUrl", ["app" => $this->appName]); + $url = str_replace($from, $documentServerUrl, $url); + } + } + + return $url; + } + + /** + * Save the ownCloud address available from document server to the application configuration + * + * @param string $documentServer - document service address + */ + public function SetStorageUrl($storageUrl) { + $storageUrl = rtrim(trim($storageUrl), "/"); + if (\strlen($storageUrl) > 0) { + $storageUrl = $storageUrl . "/"; + if (!preg_match("/^https?:\/\//i", $storageUrl)) { + $storageUrl = "http://" . $storageUrl; + } + } + + $this->logger->info("SetStorageUrl: $storageUrl", ["app" => $this->appName]); + + $this->config->setAppValue($this->appName, $this->_storageUrl, $storageUrl); + } + + /** + * Get the ownCloud address available from document server from the application configuration + * + * @return string + */ + public function GetStorageUrl() { + $url = $this->config->getAppValue($this->appName, $this->_storageUrl, ""); + if (empty($url)) { + $url = $this->GetSystemValue($this->_storageUrl); + } + return $url; + } + + /** + * Save the document service secret key to the application configuration + * + * @param string $secret - secret key + */ + public function SetDocumentServerSecret($secret) { + $secret = trim($secret); + if (empty($secret)) { + $this->logger->info("Clear secret key", ["app" => $this->appName]); + } else { + $this->logger->info("Set secret key", ["app" => $this->appName]); + } + + $this->config->setAppValue($this->appName, $this->_jwtSecret, $secret); + } + + /** + * Get the document service secret key from the application configuration + * + * @param bool $origin - take origin + * + * @return string + */ + public function GetDocumentServerSecret($origin = false) { + if (!$origin && $this->UseDemo()) { + return $this->DEMO_PARAM["SECRET"]; + } + + $secret = $this->config->getAppValue($this->appName, $this->_jwtSecret, ""); + if (empty($secret)) { + $secret = $this->GetSystemValue($this->_jwtSecret); + } + return $secret; + } + + /** + * Get the secret key from the application configuration + * + * @return string + */ + public function GetSKey() { + $secret = $this->GetDocumentServerSecret(); + if (empty($secret)) { + $secret = $this->GetSystemValue($this->_cryptSecret, true); + } + return $secret; + } + + /** + * Save an array of formats with default action + * + * @param array $formats - formats with status + */ + public function SetDefaultFormats($formats) { + $value = json_encode($formats); + $this->logger->info("Set default formats: $value", ["app" => $this->appName]); + + $this->config->setAppValue($this->appName, $this->_defFormats, $value); + } + + /** + * Get an array of formats with default action + * + * @return array + */ + private function GetDefaultFormats() { + $value = $this->config->getAppValue($this->appName, $this->_defFormats, ""); + if (empty($value)) { + return []; + } + return json_decode($value, true); + } + + /** + * Save an array of formats that is opened for editing + * + * @param array $formats - formats with status + */ + public function SetEditableFormats($formats) { + $value = json_encode($formats); + $this->logger->info("Set editing formats: $value", ["app" => $this->appName]); + + $this->config->setAppValue($this->appName, $this->_editFormats, $value); + } + + /** + * Get an array of formats opening for editing + * + * @return array + */ + private function GetEditableFormats() { + $value = $this->config->getAppValue($this->appName, $this->_editFormats, ""); + if (empty($value)) { + return []; + } + return json_decode($value, true); + } + + /** + * Save the opening setting in a same tab + * + * @param bool $value - same tab + */ + public function SetSameTab($value) { + $this->logger->info("Set opening in a same tab: " . json_encode($value), ["app" => $this->appName]); + + $this->config->setAppValue($this->appName, $this->_sameTab, json_encode($value)); + } + + /** + * Get the opening setting in a same tab + * + * @return bool + */ + public function GetSameTab() { + return $this->config->getAppValue($this->appName, $this->_sameTab, "false") === "true"; + } + + /** + * Save generate preview setting + * + * @param bool $value - preview + */ + public function SetPreview($value) { + $this->logger->info("Set generate preview: " . json_encode($value), ["app" => $this->appName]); + + $this->config->setAppValue($this->appName, $this->_preview, json_encode($value)); + } + + /** + * Get generate preview setting + * + * @return bool + */ + public function GetPreview() { + return $this->config->getAppValue($this->appName, $this->_preview, "true") === "true"; + } + + /** + * Save keep versions history + * + * @param bool $value - version history + */ + public function SetVersionHistory($value) { + $this->logger->info("Set keep versions history: " . json_encode($value), ["app" => $this->appName]); + + $this->config->setAppValue($this->appName, $this->_versionHistory, json_encode($value)); + } + + /** + * Get keep versions history + * + * @return bool + */ + public function GetVersionHistory() { + return $this->config->getAppValue($this->appName, $this->_versionHistory, "true") === "true"; + } + + /** + * Save protection + * + * @param bool $value - version history + */ + public function SetProtection($value) { + $this->logger->info("Set protection: " . $value, ["app" => $this->appName]); + + $this->config->setAppValue($this->appName, $this->_protection, $value); + } + + /** + * Get protection + * + * @return bool + */ + public function GetProtection() { + $value = $this->config->getAppValue($this->appName, $this->_protection, "owner"); + if ($value === "all") { + return "all"; + } + return "owner"; + } + + /** + * Save chat display setting + * + * @param bool $value - display chat + */ + public function SetCustomizationChat($value) { + $this->logger->info("Set chat display: " . json_encode($value), ["app" => $this->appName]); + + $this->config->setAppValue($this->appName, $this->_customizationChat, json_encode($value)); + } + + /** + * Get chat display setting + * + * @return bool + */ + public function GetCustomizationChat() { + return $this->config->getAppValue($this->appName, $this->_customizationChat, "true") === "true"; + } + + /** + * Save compact header setting + * + * @param bool $value - display compact header + */ + public function SetCustomizationCompactHeader($value) { + $this->logger->info("Set compact header display: " . json_encode($value), ["app" => $this->appName]); + + $this->config->setAppValue($this->appName, $this->_customizationCompactHeader, json_encode($value)); + } + + /** + * Get compact header setting + * + * @return bool + */ + public function GetCustomizationCompactHeader() { + return $this->config->getAppValue($this->appName, $this->_customizationCompactHeader, "true") === "true"; + } + + /** + * Save feedback display setting + * + * @param bool $value - display feedback + */ + public function SetCustomizationFeedback($value) { + $this->logger->info("Set feedback display: " . json_encode($value), ["app" => $this->appName]); + + $this->config->setAppValue($this->appName, $this->_customizationFeedback, json_encode($value)); + } + + /** + * Get feedback display setting + * + * @return bool + */ + public function GetCustomizationFeedback() { + return $this->config->getAppValue($this->appName, $this->_customizationFeedback, "true") === "true"; + } + + /** + * Save forcesave setting + * + * @param bool $value - forcesave + */ + public function SetCustomizationForcesave($value) { + $this->logger->info("Set forcesave: " . json_encode($value), ["app" => $this->appName]); + + $this->config->setAppValue($this->appName, $this->_customizationForcesave, json_encode($value)); + } + + /** + * Get forcesave setting + * + * @return bool + */ + public function GetCustomizationForcesave() { + $value = $this->config->getAppValue($this->appName, $this->_customizationForcesave, "false") === "true"; + + return $value && ($this->checkEncryptionModule() === false); + } + + /** + * Save help display setting + * + * @param bool $value - display help + */ + public function SetCustomizationHelp($value) { + $this->logger->info("Set help display: " . json_encode($value), ["app" => $this->appName]); + + $this->config->setAppValue($this->appName, $this->_customizationHelp, json_encode($value)); + } + + /** + * Get help display setting + * + * @return bool + */ + public function GetCustomizationHelp() { + return $this->config->getAppValue($this->appName, $this->_customizationHelp, "true") === "true"; + } + + /** + * Save without tabs setting + * + * @param bool $value - without tabs + */ + public function SetCustomizationToolbarNoTabs($value) { + $this->logger->info("Set without tabs: " . json_encode($value), ["app" => $this->appName]); + + $this->config->setAppValue($this->appName, $this->_customizationToolbarNoTabs, json_encode($value)); + } + + /** + * Get without tabs setting + * + * @return bool + */ + public function GetCustomizationToolbarNoTabs() { + return $this->config->getAppValue($this->appName, $this->_customizationToolbarNoTabs, "true") === "true"; + } + + /** + * Save review viewing mode setting + * + * @param string $value - review mode + */ + public function SetCustomizationReviewDisplay($value) { + $this->logger->info("Set review mode: " . $value, ["app" => $this->appName]); + + $this->config->setAppValue($this->appName, $this->_customizationReviewDisplay, $value); + } + + /** + * Get review viewing mode setting + * + * @return string + */ + public function GetCustomizationReviewDisplay() { + $value = $this->config->getAppValue($this->appName, $this->_customizationReviewDisplay, "original"); + if ($value === "markup") { + return "markup"; + } + if ($value === "final") { + return "final"; + } + return "original"; + } + + /** + * Save theme setting + * + * @param string $value - theme + */ + public function SetCustomizationTheme($value) { + $this->logger->info("Set theme: " . $value, ["app" => $this->appName]); + + $this->config->setAppValue($this->appName, $this->_customizationTheme, $value); + } + + /** + * Get theme setting + * + * @return string + */ + public function GetCustomizationTheme() { + $value = $this->config->getAppValue($this->appName, $this->_customizationTheme, "theme-classic-light"); + if ($value === "theme-light") { + return "theme-light"; + } + if ($value === "theme-dark") { + return "theme-dark"; + } + return "theme-classic-light"; + } + + /** + * Save macros setting + * + * @param bool $value - enable macros + */ + public function SetCustomizationMacros($value) { + $this->logger->info("Set macros enabled: " . json_encode($value), ["app" => $this->appName]); + + $this->config->setAppValue($this->appName, $this->_customization_macros, json_encode($value)); + } + + /** + * Get macros setting + * + * @return bool + */ + public function GetCustomizationMacros() { + return $this->config->getAppValue($this->appName, $this->_customization_macros, "true") === "true"; + } + + /** + * Save plugins setting + * + * @param bool $value - enable macros + */ + public function SetCustomizationPlugins($value) { + $this->logger->info("Set plugins enabled: " . json_encode($value), ["app" => $this->appName]); + + $this->config->setAppValue($this->appName, $this->_customizationPlugins, json_encode($value)); + } + + /** + * Get plugins setting + * + * @return bool + */ + public function GetCustomizationPlugins() { + return $this->config->getAppValue($this->appName, $this->_customizationPlugins, "true") === "true"; + } + + /** + * Save the list of groups + * + * @param array $groups - the list of groups + */ + public function SetLimitGroups($groups) { + if (!\is_array($groups)) { + $groups = []; + } + $value = json_encode($groups); + $this->logger->info("Set groups: $value", ["app" => $this->appName]); + + $this->config->setAppValue($this->appName, $this->_groups, $value); + } + + /** + * Get the list of groups + * + * @return array + */ + public function GetLimitGroups() { + $value = $this->config->getAppValue($this->appName, $this->_groups, ""); + if (empty($value)) { + return []; + } + $groups = json_decode($value, true); + if (!\is_array($groups)) { + $groups = []; + } + return $groups; + } + + /** + * Check access for group + * + * @param string $userId - user identifier + * + * @return bool + */ + public function isUserAllowedToUse($userId = null) { + // no user -> no + $userSession = \OC::$server->getUserSession(); + if ($userId === null && ($userSession === null || !$userSession->isLoggedIn())) { + return false; + } + + $groups = $this->GetLimitGroups(); + // no group set -> all users are allowed + if (\count($groups) === 0) { + return true; + } + + if ($userId === null) { + $user = $userSession->getUser(); + } else { + $user = \OC::$server->getUserManager()->get($userId); + if (empty($user)) { + return false; + } + } + + foreach ($groups as $groupName) { + // group unknown -> error and allow nobody + $group = \OC::$server->getGroupManager()->get($groupName); + if ($group === null) { + \OC::$server->getLogger()->error("Group is unknown $groupName", ["app" => $this->appName]); + $this->SetLimitGroups(array_diff($groups, [$groupName])); + } else { + if ($group->inGroup($user)) { + return true; + } + } + } + + return false; + } + + /** + * Save the document service verification setting to the application configuration + * + * @param bool $verifyPeerOff - parameter verification setting + */ + public function SetVerifyPeerOff($verifyPeerOff) { + $this->logger->info("SetVerifyPeerOff " . json_encode($verifyPeerOff), ["app" => $this->appName]); + + $this->config->setAppValue($this->appName, $this->_verification, json_encode($verifyPeerOff)); + } + + /** + * Get the document service verification setting to the application configuration + * + * @return bool + */ + public function GetVerifyPeerOff() { + $turnOff = $this->config->getAppValue($this->appName, $this->_verification, ""); + + if (!empty($turnOff)) { + return $turnOff === "true"; + } + + return $this->GetSystemValue($this->_verification); + } + + /** + * Get the limit on size document when generating thumbnails + * + * @return int + */ + public function GetLimitThumbSize() { + $limitSize = (integer)$this->GetSystemValue($this->_limitThumbSize); + + if (!empty($limitSize)) { + return $limitSize; + } + + return 100*1024*1024; + } + + /** + * Get the jwt header setting + * + * @param bool $origin - take origin + * + * @return string + */ + public function JwtHeader($origin = false) { + if (!$origin && $this->UseDemo()) { + return $this->DEMO_PARAM["HEADER"]; + } + + $header = $this->config->getAppValue($this->appName, $this->_jwtHeader, ""); + if (empty($header)) { + $header = $this->GetSystemValue($this->_jwtHeader); + } + if (!$origin && empty($header)) { + $header = "Authorization"; + } + return $header; + } + + /** + * Save the jwtHeader setting + * + * @param string $value - jwtHeader + */ + public function SetJwtHeader($value) { + $value = trim($value); + if (empty($value)) { + $this->logger->info("Clear header key", ["app" => $this->appName]); + } else { + $this->logger->info("Set header key " . $value, ["app" => $this->appName]); + } + + $this->config->setAppValue($this->appName, $this->_jwtHeader, $value); + } + + /** + * Get the Jwt Leeway + * + * @return int + */ + public function GetJwtLeeway() { + $jwtLeeway = (integer)$this->GetSystemValue($this->_jwtLeeway); + + return $jwtLeeway; + } + + /** + * Save the status settings + * + * @param string $value - error + */ + public function SetSettingsError($value) { + $this->config->setAppValue($this->appName, $this->_settingsError, $value); + } + + /** + * Get the status settings + * + * @return bool + */ + public function SettingsAreSuccessful() { + return empty($this->config->getAppValue($this->appName, $this->_settingsError, "")); + } + + /** + * Checking encryption enabled + * + * @return string|bool + */ + public function checkEncryptionModule() { + if (!\OC::$server->getAppManager()->isInstalled("encryption")) { + return false; + } + if (!\OC::$server->getEncryptionManager()->isEnabled()) { + return false; + } + + $crypt = new \OCA\Encryption\Crypto\Crypt(\OC::$server->getLogger(), \OC::$server->getUserSession(), \OC::$server->getConfig(), \OC::$server->getL10N("encryption")); + $util = new \OCA\Encryption\Util(new \OC\Files\View(), $crypt, \OC::$server->getLogger(), \OC::$server->getUserSession(), \OC::$server->getConfig(), \OC::$server->getUserManager()); + if ($util->isMasterKeyEnabled()) { + return "master"; + } + + return true; + } + + /** + * Get supported formats + * + * @return array + * + * @NoAdminRequired + */ + public function FormatsSetting() { + $result = $this->formats; + + $defFormats = $this->GetDefaultFormats(); + foreach ($defFormats as $format => $setting) { + if (\array_key_exists($format, $result)) { + $result[$format]["def"] = ($setting === true || $setting === "true"); + } + } + + $editFormats = $this->GetEditableFormats(); + foreach ($editFormats as $format => $setting) { + if (\array_key_exists($format, $result)) { + $result[$format]["edit"] = ($setting === true || $setting === "true"); + } + } + + return $result; + } + + public function ShareAttributesVersion() { + if (\version_compare(\implode(".", \OCP\Util::getVersion()), "10.3.0", ">=")) { + return "v2"; + } elseif (\version_compare(\implode(".", \OCP\Util::getVersion()), "10.2.0", ">=")) { + return "v1"; + } + return ""; + } + + /** + * Get the editors check interval + * + * @return int + */ + public function GetEditorsCheckInterval() { + $interval = $this->GetSystemValue($this->_editors_check_interval); + + if (empty($interval) && $interval !== 0) { + $interval = 60*60*24; + } + return (integer)$interval; + } + + /** + * Additional data about formats + * + * @var array + */ + private $formats = [ + "csv" => [ "mime" => "text/csv", "type" => "cell", "edit" => true, "editable" => true, "saveas" => ["ods", "pdf", "xlsx"] ], + "doc" => [ "mime" => "application/msword", "type" => "word", "conv" => true, "saveas" => ["docx", "odt", "pdf", "rtf", "txt"] ], + "docm" => [ "mime" => "application/vnd.ms-word.document.macroEnabled.12", "type" => "word", "conv" => true, "saveas" => ["docx", "odt", "pdf", "rtf", "txt"] ], + "docx" => [ "mime" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "type" => "word", "edit" => true, "def" => true, "review" => true, "comment" => true, "saveas" => ["odt", "pdf", "rtf", "txt"] ], + "docxf" => [ "mime" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document.docxf", "type" => "word", "edit" => true, "def" => true, "review" => true, "comment" => true, "saveas" => ["odt", "pdf", "rtf", "txt"], "createForm" => true ], + "oform" => [ "mime" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document.oform", "type" => "word", "fillForms" => true, "def" => true ], + "dot" => [ "type" => "word", "conv" => true, "saveas" => ["docx", "odt", "pdf", "rtf", "txt"] ], + "dotx" => [ "mime" => "application/vnd.openxmlformats-officedocument.wordprocessingml.template", "type" => "word", "conv" => true, "saveas" => ["docx", "odt", "pdf", "rtf", "txt"] ], + "epub" => [ "mime" => "application/epub+zip", "type" => "word", "conv" => true, "saveas" => ["docx", "odt", "pdf", "rtf", "txt"] ], + "htm" => [ "type" => "word", "conv" => true ], + "html" => [ "mime" => "text/html", "type" => "word", "conv" => true, "saveas" => ["docx", "odt", "pdf", "rtf", "txt"] ], + "odp" => [ "mime" => "application/vnd.oasis.opendocument.presentation", "type" => "slide", "conv" => true, "editable" => true, "saveas" => ["pdf", "pptx"] ], + "ods" => [ "mime" => "application/vnd.oasis.opendocument.spreadsheet", "type" => "cell", "conv" => true, "editable" => true, "saveas" => ["csv", "pdf", "xlsx"] ], + "odt" => [ "mime" => "application/vnd.oasis.opendocument.text", "type" => "word", "conv" => true, "editable" => true, "saveas" => ["docx", "pdf", "rtf", "txt"] ], + "otp" => [ "mime" => "application/vnd.oasis.opendocument.presentation-template", "type" => "slide", "conv" => true, "saveas" => ["pdf", "pptx", "odp"] ], + "ots" => [ "mime" => "application/vnd.oasis.opendocument.spreadsheet-template", "type" => "cell", "conv" => true, "saveas" => ["csv", "ods", "pdf", "xlsx"] ], + "ott" => [ "mime" => "application/vnd.oasis.opendocument.text-template", "type" => "word", "conv" => true, "saveas" => ["docx", "odt", "pdf", "rtf", "txt"] ], + "pdf" => [ "mime" => "application/pdf", "type" => "word" ], + "pot" => [ "type" => "slide", "conv" => true, "saveas" => ["pdf", "pptx", "odp"] ], + "potm" => [ "mime" => "application/vnd.ms-powerpoint.template.macroEnabled.12", "type" => "slide", "conv" => true, "saveas" => ["pdf", "pptx", "odp"] ], + "potx" => [ "mime" => "application/vnd.openxmlformats-officedocument.presentationml.template", "type" => "slide", "conv" => true, "saveas" => ["pdf", "pptx", "odp"] ], + "pps" => [ "type" => "slide", "conv" => true, "saveas" => ["pdf", "pptx", "odp"] ], + "ppsm" => [ "mime" => "application/vnd.ms-powerpoint.slideshow.macroEnabled.12", "type" => "slide", "conv" => true, "saveas" => ["pdf", "pptx", "odp"] ], + "ppsx" => [ "mime" => "application/vnd.openxmlformats-officedocument.presentationml.slideshow", "type" => "slide", "conv" => true, "saveas" => ["pdf", "pptx", "odp"] ], + "ppt" => [ "mime" => "application/vnd.ms-powerpoint", "type" => "slide", "conv" => true, "saveas" => ["pdf", "pptx", "odp"] ], + "pptm" => [ "mime" => "application/vnd.ms-powerpoint.presentation.macroEnabled.12", "type" => "slide", "conv" => true, "saveas" => ["pdf", "pptx", "odp"] ], + "pptx" => [ "mime" => "application/vnd.openxmlformats-officedocument.presentationml.presentation", "type" => "slide", "edit" => true, "def" => true, "comment" => true, "saveas" => ["pdf", "odp"] ], + "rtf" => [ "mime" => "text/rtf", "type" => "word", "conv" => true, "editable" => true, "saveas" => ["docx", "odt", "pdf", "txt"] ], + "txt" => [ "mime" => "text/plain", "type" => "word", "edit" => true, "editable" => true, "saveas" => ["docx", "odt", "pdf", "rtf"] ], + "xls" => [ "mime" => "application/vnd.ms-excel", "type" => "cell", "conv" => true, "saveas" => ["csv", "ods", "pdf", "xlsx"] ], + "xlsm" => [ "mime" => "application/vnd.ms-excel.sheet.macroEnabled.12", "type" => "cell", "conv" => true, "saveas" => ["csv", "ods", "pdf", "xlsx"] ], + "xlsx" => [ "mime" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "type" => "cell", "edit" => true, "def" => true, "comment" => true, "modifyFilter" => true, "saveas" => ["csv", "ods", "pdf"] ], + "xlt" => [ "type" => "cell", "conv" => true, "saveas" => ["csv", "ods", "pdf", "xlsx"] ], + "xltm" => [ "mime" => "application/vnd.ms-excel.template.macroEnabled.12", "type" => "cell", "conv" => true, "saveas" => ["csv", "ods", "pdf", "xlsx"] ], + "xltx" => [ "mime" => "application/vnd.openxmlformats-officedocument.spreadsheetml.template", "type" => "cell", "conv" => true, "saveas" => ["csv", "ods", "pdf", "xlsx"] ] + ]; + + /** + * DEMO DATA + */ + private $DEMO_PARAM = [ + "ADDR" => "https://onlinedocs.onlyoffice.com/", + "HEADER" => "AuthorizationJWT", + "SECRET" => "sn2puSUF7muF5Jas", + "TRIAL" => 30 + ]; + + private $linkToDocs = "https://www.onlyoffice.com/docs-registration.aspx?referer=owncloud"; + + /** + * Get link to Docs Cloud + * + * @return string + */ + public function GetLinkToDocs() { + return $this->linkToDocs; + } } diff --git a/lib/command/documentserver.php b/lib/command/documentserver.php index 33c589f2..adda3514 100644 --- a/lib/command/documentserver.php +++ b/lib/command/documentserver.php @@ -32,101 +32,101 @@ use OCA\Onlyoffice\Crypt; class DocumentServer extends Command { - /** - * Application configuration - * - * @var AppConfig - */ - private $config; - - /** - * l10n service - * - * @var IL10N - */ - private $trans; - - /** - * Url generator service - * - * @var IURLGenerator - */ - private $urlGenerator; - - /** - * Hash generator - * - * @var Crypt - */ - private $crypt; - - /** - * @param AppConfig $config - application configuration - * @param IL10N $trans - l10n service - * @param IURLGenerator $urlGenerator - url generator service - * @param Crypt $crypt - hash generator - */ - public function __construct( - AppConfig $config, - IL10N $trans, - IURLGenerator $urlGenerator, - Crypt $crypt - ) { - parent::__construct(); - $this->config = $config; - $this->trans = $trans; - $this->urlGenerator = $urlGenerator; - $this->crypt = $crypt; - } - - /** - * Configures the current command. - */ - protected function configure() { - $this - ->setName("onlyoffice:documentserver") - ->setDescription("Manage document server") - ->addOption( - "check", - null, - InputOption::VALUE_NONE, - "Check connection document server" - ); - } - - /** - * Executes the current command. - * - * @param InputInterface $input - input data - * @param OutputInterface $output - output data - * - * @return int 0 if everything went fine, or an exit code - */ - protected function execute(InputInterface $input, OutputInterface $output) { - $check = $input->getOption("check"); - - $documentserver = $this->config->GetDocumentServerUrl(true); - if (empty($documentserver)) { - $output->writeln("Document server is not configured"); - return 1; - } - - if ($check) { - $documentService = new DocumentService($this->trans, $this->config); - - list($error, $version) = $documentService->checkDocServiceUrl($this->urlGenerator, $this->crypt); - $this->config->SetSettingsError($error); - - if (!empty($error)) { - $output->writeln("Error connection: $error"); - return 1; - } else { - $output->writeln("Document server $documentserver version $version is successfully connected"); - return 0; - } - } - - $output->writeln("The current document server: $documentserver"); - return 0; - } + /** + * Application configuration + * + * @var AppConfig + */ + private $config; + + /** + * l10n service + * + * @var IL10N + */ + private $trans; + + /** + * Url generator service + * + * @var IURLGenerator + */ + private $urlGenerator; + + /** + * Hash generator + * + * @var Crypt + */ + private $crypt; + + /** + * @param AppConfig $config - application configuration + * @param IL10N $trans - l10n service + * @param IURLGenerator $urlGenerator - url generator service + * @param Crypt $crypt - hash generator + */ + public function __construct( + AppConfig $config, + IL10N $trans, + IURLGenerator $urlGenerator, + Crypt $crypt + ) { + parent::__construct(); + $this->config = $config; + $this->trans = $trans; + $this->urlGenerator = $urlGenerator; + $this->crypt = $crypt; + } + + /** + * Configures the current command. + */ + protected function configure() { + $this + ->setName("onlyoffice:documentserver") + ->setDescription("Manage document server") + ->addOption( + "check", + null, + InputOption::VALUE_NONE, + "Check connection document server" + ); + } + + /** + * Executes the current command. + * + * @param InputInterface $input - input data + * @param OutputInterface $output - output data + * + * @return int 0 if everything went fine, or an exit code + */ + protected function execute(InputInterface $input, OutputInterface $output) { + $check = $input->getOption("check"); + + $documentserver = $this->config->GetDocumentServerUrl(true); + if (empty($documentserver)) { + $output->writeln("Document server is not configured"); + return 1; + } + + if ($check) { + $documentService = new DocumentService($this->trans, $this->config); + + list($error, $version) = $documentService->checkDocServiceUrl($this->urlGenerator, $this->crypt); + $this->config->SetSettingsError($error); + + if (!empty($error)) { + $output->writeln("Error connection: $error"); + return 1; + } else { + $output->writeln("Document server $documentserver version $version is successfully connected"); + return 0; + } + } + + $output->writeln("The current document server: $documentserver"); + return 0; + } } diff --git a/lib/cron/editorscheck.php b/lib/cron/editorscheck.php index 69065c4f..e9aa5054 100644 --- a/lib/cron/editorscheck.php +++ b/lib/cron/editorscheck.php @@ -37,156 +37,156 @@ * */ class EditorsCheck extends TimedJob { - /** - * Application name - * - * @var string - */ - private $appName; - - /** - * Url generator service - * - * @var IURLGenerator - */ - private $urlGenerator; - - /** - * Logger - * - * @var OCP\ILogger - */ - private $logger; - - /** - * Application configuration - * - * @var AppConfig - */ - private $config; - - /** - * l10n service - * - * @var IL10N - */ - private $trans; - - /** - * Hash generator - * - * @var Crypt - */ - private $crypt; - - /** - * Group manager - * - * @var IGroupManager - */ - private $groupManager; - - /** - * @param string $AppName - application name - * @param IURLGenerator $urlGenerator - url generator service - * @param ITimeFactory $time - time - * @param AppConfig $config - application configuration - * @param IL10N $trans - l10n service - * @param Crypt $crypt - crypt service - */ - public function __construct( - string $AppName, - IURLGenerator $urlGenerator, - ITimeFactory $time, - AppConfig $config, - IL10N $trans, - Crypt $crypt, - IGroupManager $groupManager - ) { - $this->appName = $AppName; - $this->urlGenerator = $urlGenerator; - - $this->logger = \OC::$server->getLogger(); - $this->config = $config; - $this->trans = $trans; - $this->crypt = $crypt; - $this->groupManager = $groupManager; - $this->setInterval($this->config->GetEditorsCheckInterval()); - } - - /** - * Makes the background check - * - * @param array $argument unused argument - */ - protected function run($argument) { - if (empty($this->config->GetDocumentServerUrl())) { - $this->logger->debug("Settings are empty", ["app" => $this->appName]); - return; - } - if (!$this->config->SettingsAreSuccessful()) { - $this->logger->debug("Settings are not correct", ["app" => $this->appName]); - return; - } - $fileUrl = $this->urlGenerator->linkToRouteAbsolute($this->appName . ".callback.emptyfile"); - if (!$this->config->UseDemo() && !empty($this->config->GetStorageUrl())) { - $fileUrl = str_replace($this->urlGenerator->getAbsoluteURL("/"), $this->config->GetStorageUrl(), $fileUrl); - } - $host = parse_url($fileUrl)["host"]; - if ($host === "localhost" || $host === "127.0.0.1") { - $this->logger->debug("Localhost is not alowed for cron editors availability check. Please provide server address for internal requests from ONLYOFFICE Docs", ["app" => $this->appName]); - return; - } - - $this->logger->debug("ONLYOFFICE check started by cron", ["app" => $this->appName]); - - $documentService = new DocumentService($this->trans, $this->config); - list($error, $version) = $documentService->checkDocServiceUrl($this->urlGenerator, $this->crypt); - if (!empty($error)) { - $this->logger->info("ONLYOFFICE server is not available", ["app" => $this->appName]); - $this->config->SetSettingsError($error); - $this->notifyAdmins(); - } else { - $this->logger->debug("ONLYOFFICE server availability check is finished successfully", ["app" => $this->appName]); - } - } - - /** - * Get the list of users to notify - * - * @return string[] - */ - private function getUsersToNotify() { - $notifyGroups = ["admin"]; - $notifyUsers = []; - - foreach ($notifyGroups as $notifyGroup) { - $group = $this->groupManager->get($notifyGroup); - if ($group === null || !($group instanceof IGroup)) { - continue; - } - $users = $group->getUsers(); - foreach ($users as $user) { - $notifyUsers[] = $user->getUID(); - } - } - return $notifyUsers; - } - - /** - * Send notification to admins - * @return void - */ - private function notifyAdmins() { - $notificationManager = \OC::$server->getNotificationManager(); - $notification = $notificationManager->createNotification(); - $notification->setApp($this->appName) - ->setDateTime(new \DateTime()) - ->setObject("editorsCheck", $this->trans->t("ONLYOFFICE server is not available")) - ->setSubject("editorscheck_info"); - foreach ($this->getUsersToNotify() as $uid) { - $notification->setUser($uid); - $notificationManager->notify($notification); - } - } + /** + * Application name + * + * @var string + */ + private $appName; + + /** + * Url generator service + * + * @var IURLGenerator + */ + private $urlGenerator; + + /** + * Logger + * + * @var OCP\ILogger + */ + private $logger; + + /** + * Application configuration + * + * @var AppConfig + */ + private $config; + + /** + * l10n service + * + * @var IL10N + */ + private $trans; + + /** + * Hash generator + * + * @var Crypt + */ + private $crypt; + + /** + * Group manager + * + * @var IGroupManager + */ + private $groupManager; + + /** + * @param string $AppName - application name + * @param IURLGenerator $urlGenerator - url generator service + * @param ITimeFactory $time - time + * @param AppConfig $config - application configuration + * @param IL10N $trans - l10n service + * @param Crypt $crypt - crypt service + */ + public function __construct( + string $AppName, + IURLGenerator $urlGenerator, + ITimeFactory $time, + AppConfig $config, + IL10N $trans, + Crypt $crypt, + IGroupManager $groupManager + ) { + $this->appName = $AppName; + $this->urlGenerator = $urlGenerator; + + $this->logger = \OC::$server->getLogger(); + $this->config = $config; + $this->trans = $trans; + $this->crypt = $crypt; + $this->groupManager = $groupManager; + $this->setInterval($this->config->GetEditorsCheckInterval()); + } + + /** + * Makes the background check + * + * @param array $argument unused argument + */ + protected function run($argument) { + if (empty($this->config->GetDocumentServerUrl())) { + $this->logger->debug("Settings are empty", ["app" => $this->appName]); + return; + } + if (!$this->config->SettingsAreSuccessful()) { + $this->logger->debug("Settings are not correct", ["app" => $this->appName]); + return; + } + $fileUrl = $this->urlGenerator->linkToRouteAbsolute($this->appName . ".callback.emptyfile"); + if (!$this->config->UseDemo() && !empty($this->config->GetStorageUrl())) { + $fileUrl = str_replace($this->urlGenerator->getAbsoluteURL("/"), $this->config->GetStorageUrl(), $fileUrl); + } + $host = parse_url($fileUrl)["host"]; + if ($host === "localhost" || $host === "127.0.0.1") { + $this->logger->debug("Localhost is not alowed for cron editors availability check. Please provide server address for internal requests from ONLYOFFICE Docs", ["app" => $this->appName]); + return; + } + + $this->logger->debug("ONLYOFFICE check started by cron", ["app" => $this->appName]); + + $documentService = new DocumentService($this->trans, $this->config); + list($error, $version) = $documentService->checkDocServiceUrl($this->urlGenerator, $this->crypt); + if (!empty($error)) { + $this->logger->info("ONLYOFFICE server is not available", ["app" => $this->appName]); + $this->config->SetSettingsError($error); + $this->notifyAdmins(); + } else { + $this->logger->debug("ONLYOFFICE server availability check is finished successfully", ["app" => $this->appName]); + } + } + + /** + * Get the list of users to notify + * + * @return string[] + */ + private function getUsersToNotify() { + $notifyGroups = ["admin"]; + $notifyUsers = []; + + foreach ($notifyGroups as $notifyGroup) { + $group = $this->groupManager->get($notifyGroup); + if ($group === null || !($group instanceof IGroup)) { + continue; + } + $users = $group->getUsers(); + foreach ($users as $user) { + $notifyUsers[] = $user->getUID(); + } + } + return $notifyUsers; + } + + /** + * Send notification to admins + * @return void + */ + private function notifyAdmins() { + $notificationManager = \OC::$server->getNotificationManager(); + $notification = $notificationManager->createNotification(); + $notification->setApp($this->appName) + ->setDateTime(new \DateTime()) + ->setObject("editorsCheck", $this->trans->t("ONLYOFFICE server is not available")) + ->setSubject("editorscheck_info"); + foreach ($this->getUsersToNotify() as $uid) { + $notification->setUser($uid); + $notificationManager->notify($notification); + } + } } diff --git a/lib/crypt.php b/lib/crypt.php index 730b2932..692064c5 100644 --- a/lib/crypt.php +++ b/lib/crypt.php @@ -27,49 +27,49 @@ * @package OCA\Onlyoffice */ class Crypt { - /** - * Application configuration - * - * @var AppConfig - */ - private $config; + /** + * Application configuration + * + * @var AppConfig + */ + private $config; - /** - * @param AppConfig $config - application configutarion - */ - public function __construct(AppConfig $appConfig) { - $this->config = $appConfig; - } + /** + * @param AppConfig $config - application configutarion + */ + public function __construct(AppConfig $appConfig) { + $this->config = $appConfig; + } - /** - * Generate token for the object - * - * @param array $object - object to signature - * - * @return string - */ - public function GetHash($object) { - return \Firebase\JWT\JWT::encode($object, $this->config->GetSKey(), "HS256"); - } + /** + * Generate token for the object + * + * @param array $object - object to signature + * + * @return string + */ + public function GetHash($object) { + return \Firebase\JWT\JWT::encode($object, $this->config->GetSKey(), "HS256"); + } - /** - * Create an object from the token - * - * @param string $token - token - * - * @return array - */ - public function ReadHash($token) { - $result = null; - $error = null; - if ($token === null) { - return [$result, "token is empty"]; - } - try { - $result = \Firebase\JWT\JWT::decode($token, new \Firebase\JWT\Key($this->config->GetSKey(), "HS256")); - } catch (\UnexpectedValueException $e) { - $error = $e->getMessage(); - } - return [$result, $error]; - } + /** + * Create an object from the token + * + * @param string $token - token + * + * @return array + */ + public function ReadHash($token) { + $result = null; + $error = null; + if ($token === null) { + return [$result, "token is empty"]; + } + try { + $result = \Firebase\JWT\JWT::decode($token, new \Firebase\JWT\Key($this->config->GetSKey(), "HS256")); + } catch (\UnexpectedValueException $e) { + $error = $e->getMessage(); + } + return [$result, $error]; + } } diff --git a/lib/documentservice.php b/lib/documentservice.php index 73828716..88e59f8c 100644 --- a/lib/documentservice.php +++ b/lib/documentservice.php @@ -29,414 +29,414 @@ * @package OCA\Onlyoffice */ class DocumentService { - /** - * Application name - * - * @var string - */ - private static $appName = "onlyoffice"; - - /** - * l10n service - * - * @var IL10N - */ - private $trans; - - /** - * Application configuration - * - * @var AppConfig - */ - private $config; - - /** - * @param IL10N $trans - l10n service - * @param AppConfig $config - application configutarion - */ - public function __construct(IL10N $trans, AppConfig $appConfig) { - $this->trans = $trans; - $this->config = $appConfig; - } - - /** - * Translation key to a supported form. - * - * @param string $expected_key - Expected key - * - * @return string - */ - public static function GenerateRevisionId($expected_key) { - if (\strlen($expected_key) > 20) { - $expected_key = crc32($expected_key); - } - $key = preg_replace("[^0-9-.a-zA-Z_=]", "_", $expected_key); - $key = substr($key, 0, min([\strlen($key), 20])); - return $key; - } - - /** - * The method is to convert the file to the required format and return the result url - * - * @param string $document_uri - Uri for the document to convert - * @param string $from_extension - Document extension - * @param string $to_extension - Extension to which to convert - * @param string $document_revision_id - Key for caching on service - * - * @return string - */ - public function GetConvertedUri($document_uri, $from_extension, $to_extension, $document_revision_id) { - $responceFromConvertService = $this->SendRequestToConvertService($document_uri, $from_extension, $to_extension, $document_revision_id, false); - - $errorElement = $responceFromConvertService->Error; - if ($errorElement->count() > 0) { - $this->ProcessConvServResponceError($errorElement . ""); - } - - $isEndConvert = $responceFromConvertService->EndConvert; - - if ($isEndConvert !== null && strtolower($isEndConvert) === "true") { - return (string)$responceFromConvertService->FileUrl; - } - - return ""; - } - - /** - * Request for conversion to a service - * - * @param string $document_uri - Uri for the document to convert - * @param string $from_extension - Document extension - * @param string $to_extension - Extension to which to convert - * @param string $document_revision_id - Key for caching on service - * @param bool - $is_async - Perform conversions asynchronously - * - * @return array - */ - public function SendRequestToConvertService($document_uri, $from_extension, $to_extension, $document_revision_id, $is_async) { - $documentServerUrl = $this->config->GetDocumentServerInternalUrl(); - - if (empty($documentServerUrl)) { - throw new \Exception($this->trans->t("ONLYOFFICE app is not configured. Please contact admin")); - } - - $urlToConverter = $documentServerUrl . "ConvertService.ashx"; - - if (empty($document_revision_id)) { - $document_revision_id = $document_uri; - } - - $document_revision_id = self::GenerateRevisionId($document_revision_id); - - if (empty($from_extension)) { - $from_extension = pathinfo($document_uri)["extension"]; - } else { - $from_extension = trim($from_extension, "."); - } - - $data = [ - "async" => $is_async, - "url" => $document_uri, - "outputtype" => trim($to_extension, "."), - "filetype" => $from_extension, - "title" => $document_revision_id . "." . $from_extension, - "key" => $document_revision_id, - "region" => str_replace("_", "-", \OC::$server->getL10NFactory("")->get("")->getLanguageCode()) - ]; - - if ($this->config->UseDemo()) { - $data["tenant"] = $this->config->GetSystemValue("instanceid", true); - } - - $opts = [ - "timeout" => "120", - "headers" => [ - "Content-type" => "application/json" - ], - "body" => json_encode($data) - ]; - - if (!empty($this->config->GetDocumentServerSecret())) { - $params = [ - "payload" => $data - ]; - $token = \Firebase\JWT\JWT::encode($params, $this->config->GetDocumentServerSecret(), "HS256"); - $opts["headers"][$this->config->JwtHeader()] = "Bearer " . $token; - - $token = \Firebase\JWT\JWT::encode($data, $this->config->GetDocumentServerSecret(), "HS256"); - $data["token"] = $token; - $opts["body"] = json_encode($data); - } - - $response_xml_data = $this->Request($urlToConverter, "post", $opts); - - libxml_use_internal_errors(true); - if (!\function_exists("simplexml_load_file")) { - throw new \Exception($this->trans->t("Server can't read xml")); - } - $response_data = simplexml_load_string($response_xml_data); - if (!$response_data) { - $exc = $this->trans->t("Bad Response. Errors: "); - foreach (libxml_get_errors() as $error) { - $exc = $exc . "\t" . $error->message; - } - throw new \Exception($exc); - } - - return $response_data; - } - - /** - * Generate an error code table of convertion - * - * @param string $errorCode - Error code - * - * @return null - */ - public function ProcessConvServResponceError($errorCode) { - $errorMessageTemplate = $this->trans->t("Error occurred in the document service"); - $errorMessage = ""; - - switch ($errorCode) { - case -20: - $errorMessage = $errorMessageTemplate . ": Error encrypt signature"; - break; - case -8: - $errorMessage = $errorMessageTemplate . ": Invalid token"; - break; - case -7: - $errorMessage = $errorMessageTemplate . ": Error document request"; - break; - case -6: - $errorMessage = $errorMessageTemplate . ": Error while accessing the conversion result database"; - break; - case -5: - $errorMessage = $errorMessageTemplate . ": Incorrect password"; - break; - case -4: - $errorMessage = $errorMessageTemplate . ": Error while downloading the document file to be converted."; - break; - case -3: - $errorMessage = $errorMessageTemplate . ": Conversion error"; - break; - case -2: - $errorMessage = $errorMessageTemplate . ": Timeout conversion error"; - break; - case -1: - $errorMessage = $errorMessageTemplate . ": Unknown error"; - break; - case 0: - break; - default: - $errorMessage = $errorMessageTemplate . ": ErrorCode = " . $errorCode; - break; - } - - throw new \Exception($errorMessage); - } - - /** - * Request health status - * - * @return bool - */ - public function HealthcheckRequest() { - $documentServerUrl = $this->config->GetDocumentServerInternalUrl(); - - if (empty($documentServerUrl)) { - throw new \Exception($this->trans->t("ONLYOFFICE app is not configured. Please contact admin")); - } - - $urlHealthcheck = $documentServerUrl . "healthcheck"; - - $response = $this->Request($urlHealthcheck); - - return $response === "true"; - } - - /** - * Send command - * - * @param string $method - type of command - * - * @return array - */ - public function CommandRequest($method) { - $documentServerUrl = $this->config->GetDocumentServerInternalUrl(); - - if (empty($documentServerUrl)) { - throw new \Exception($this->trans->t("ONLYOFFICE app is not configured. Please contact admin")); - } - - $urlCommand = $documentServerUrl . "coauthoring/CommandService.ashx"; - - $data = [ - "c" => $method - ]; - - $opts = [ - "headers" => [ - "Content-type" => "application/json" - ], - "body" => json_encode($data) - ]; - - if (!empty($this->config->GetDocumentServerSecret())) { - $params = [ - "payload" => $data - ]; - $token = \Firebase\JWT\JWT::encode($params, $this->config->GetDocumentServerSecret(), "HS256"); - $opts["headers"][$this->config->JwtHeader()] = "Bearer " . $token; - - $token = \Firebase\JWT\JWT::encode($data, $this->config->GetDocumentServerSecret(), "HS256"); - $data["token"] = $token; - $opts["body"] = json_encode($data); - } - - $response = $this->Request($urlCommand, "post", $opts); - - $data = json_decode($response); - - $this->ProcessCommandServResponceError($data->error); - - return $data; - } - - /** - * Generate an error code table of command - * - * @param string $errorCode - Error code - * - * @return null - */ - public function ProcessCommandServResponceError($errorCode) { - $errorMessageTemplate = $this->trans->t("Error occurred in the document service"); - $errorMessage = ""; - - switch ($errorCode) { - case 6: - $errorMessage = $errorMessageTemplate . ": Invalid token"; - break; - case 5: - $errorMessage = $errorMessageTemplate . ": Command not correсt"; - break; - case 3: - $errorMessage = $errorMessageTemplate . ": Internal server error"; - break; - case 0: - return; - default: - $errorMessage = $errorMessageTemplate . ": ErrorCode = " . $errorCode; - break; - } - - throw new \Exception($errorMessage); - } - - /** - * Request to Document Server with turn off verification - * - * @param string $url - request address - * @param array $method - request method - * @param array $opts - request options - * - * @return string - */ - public function Request($url, $method = "get", $opts = null) { - $httpClientService = \OC::$server->getHTTPClientService(); - $client = $httpClientService->newClient(); - - if ($opts === null) { - $opts = []; - } - if (substr($url, 0, \strlen("https")) === "https" && $this->config->GetVerifyPeerOff()) { - $opts["verify"] = false; - } - if (!\array_key_exists("timeout", $opts)) { - $opts["timeout"] = 60; - } - - if ($method === "post") { - $response = $client->post($url, $opts); - } else { - $response = $client->get($url, $opts); - } - - return $response->getBody(); - } - - /** - * Checking document service location - * - * @param OCP\IURLGenerator $urlGenerator - url generator - * @param OCA\Onlyoffice\Crypt $crypt -crypt - * - * @return array - */ - public function checkDocServiceUrl($urlGenerator, $crypt) { - $logger = \OC::$server->getLogger(); - $version = null; - - try { - if (preg_match("/^https:\/\//i", $urlGenerator->getAbsoluteURL("/")) - && preg_match("/^http:\/\//i", $this->config->GetDocumentServerUrl())) { - throw new \Exception($this->trans->t("Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required.")); - } - } catch (\Exception $e) { - $logger->logException($e, ["message" => "Protocol on check error", "app" => self::$appName]); - return [$e->getMessage(), $version]; - } - - try { - $healthcheckResponse = $this->HealthcheckRequest(); - if (!$healthcheckResponse) { - throw new \Exception($this->trans->t("Bad healthcheck status")); - } - } catch (\Exception $e) { - $logger->logException($e, ["message" => "HealthcheckRequest on check error", "app" => self::$appName]); - return [$e->getMessage(), $version]; - } - - try { - $commandResponse = $this->CommandRequest("version"); - - $logger->debug("CommandRequest on check: " . json_encode($commandResponse), ["app" => self::$appName]); - - if (empty($commandResponse)) { - throw new \Exception($this->trans->t("Error occurred in the document service")); - } - - $version = $commandResponse->version; - $versionF = \floatval($version); - if ($versionF > 0.0 && $versionF <= 6.0) { - throw new \Exception($this->trans->t("Not supported version")); - } - } catch (\Exception $e) { - $logger->logException($e, ["message" => "CommandRequest on check error", "app" => self::$appName]); - return [$e->getMessage(), $version]; - } - - $convertedFileUri = null; - try { - $hashUrl = $crypt->GetHash(["action" => "empty"]); - $fileUrl = $urlGenerator->linkToRouteAbsolute(self::$appName . ".callback.emptyfile", ["doc" => $hashUrl]); - if (!$this->config->UseDemo() && !empty($this->config->GetStorageUrl())) { - $fileUrl = str_replace($urlGenerator->getAbsoluteURL("/"), $this->config->GetStorageUrl(), $fileUrl); - } - - $convertedFileUri = $this->GetConvertedUri($fileUrl, "docx", "docx", "check_" . rand()); - } catch (\Exception $e) { - $logger->logException($e, ["message" => "GetConvertedUri on check error", "app" => self::$appName]); - return [$e->getMessage(), $version]; - } - - try { - $this->Request($convertedFileUri); - } catch (\Exception $e) { - $logger->logException($e, ["message" => "Request converted file on check error", "app" => self::$appName]); - return [$e->getMessage(), $version]; - } - - return ["", $version]; - } + /** + * Application name + * + * @var string + */ + private static $appName = "onlyoffice"; + + /** + * l10n service + * + * @var IL10N + */ + private $trans; + + /** + * Application configuration + * + * @var AppConfig + */ + private $config; + + /** + * @param IL10N $trans - l10n service + * @param AppConfig $config - application configutarion + */ + public function __construct(IL10N $trans, AppConfig $appConfig) { + $this->trans = $trans; + $this->config = $appConfig; + } + + /** + * Translation key to a supported form. + * + * @param string $expected_key - Expected key + * + * @return string + */ + public static function GenerateRevisionId($expected_key) { + if (\strlen($expected_key) > 20) { + $expected_key = crc32($expected_key); + } + $key = preg_replace("[^0-9-.a-zA-Z_=]", "_", $expected_key); + $key = substr($key, 0, min([\strlen($key), 20])); + return $key; + } + + /** + * The method is to convert the file to the required format and return the result url + * + * @param string $document_uri - Uri for the document to convert + * @param string $from_extension - Document extension + * @param string $to_extension - Extension to which to convert + * @param string $document_revision_id - Key for caching on service + * + * @return string + */ + public function GetConvertedUri($document_uri, $from_extension, $to_extension, $document_revision_id) { + $responceFromConvertService = $this->SendRequestToConvertService($document_uri, $from_extension, $to_extension, $document_revision_id, false); + + $errorElement = $responceFromConvertService->Error; + if ($errorElement->count() > 0) { + $this->ProcessConvServResponceError($errorElement . ""); + } + + $isEndConvert = $responceFromConvertService->EndConvert; + + if ($isEndConvert !== null && strtolower($isEndConvert) === "true") { + return (string)$responceFromConvertService->FileUrl; + } + + return ""; + } + + /** + * Request for conversion to a service + * + * @param string $document_uri - Uri for the document to convert + * @param string $from_extension - Document extension + * @param string $to_extension - Extension to which to convert + * @param string $document_revision_id - Key for caching on service + * @param bool - $is_async - Perform conversions asynchronously + * + * @return array + */ + public function SendRequestToConvertService($document_uri, $from_extension, $to_extension, $document_revision_id, $is_async) { + $documentServerUrl = $this->config->GetDocumentServerInternalUrl(); + + if (empty($documentServerUrl)) { + throw new \Exception($this->trans->t("ONLYOFFICE app is not configured. Please contact admin")); + } + + $urlToConverter = $documentServerUrl . "ConvertService.ashx"; + + if (empty($document_revision_id)) { + $document_revision_id = $document_uri; + } + + $document_revision_id = self::GenerateRevisionId($document_revision_id); + + if (empty($from_extension)) { + $from_extension = pathinfo($document_uri)["extension"]; + } else { + $from_extension = trim($from_extension, "."); + } + + $data = [ + "async" => $is_async, + "url" => $document_uri, + "outputtype" => trim($to_extension, "."), + "filetype" => $from_extension, + "title" => $document_revision_id . "." . $from_extension, + "key" => $document_revision_id, + "region" => str_replace("_", "-", \OC::$server->getL10NFactory("")->get("")->getLanguageCode()) + ]; + + if ($this->config->UseDemo()) { + $data["tenant"] = $this->config->GetSystemValue("instanceid", true); + } + + $opts = [ + "timeout" => "120", + "headers" => [ + "Content-type" => "application/json" + ], + "body" => json_encode($data) + ]; + + if (!empty($this->config->GetDocumentServerSecret())) { + $params = [ + "payload" => $data + ]; + $token = \Firebase\JWT\JWT::encode($params, $this->config->GetDocumentServerSecret(), "HS256"); + $opts["headers"][$this->config->JwtHeader()] = "Bearer " . $token; + + $token = \Firebase\JWT\JWT::encode($data, $this->config->GetDocumentServerSecret(), "HS256"); + $data["token"] = $token; + $opts["body"] = json_encode($data); + } + + $response_xml_data = $this->Request($urlToConverter, "post", $opts); + + libxml_use_internal_errors(true); + if (!\function_exists("simplexml_load_file")) { + throw new \Exception($this->trans->t("Server can't read xml")); + } + $response_data = simplexml_load_string($response_xml_data); + if (!$response_data) { + $exc = $this->trans->t("Bad Response. Errors: "); + foreach (libxml_get_errors() as $error) { + $exc = $exc . "\t" . $error->message; + } + throw new \Exception($exc); + } + + return $response_data; + } + + /** + * Generate an error code table of convertion + * + * @param string $errorCode - Error code + * + * @return null + */ + public function ProcessConvServResponceError($errorCode) { + $errorMessageTemplate = $this->trans->t("Error occurred in the document service"); + $errorMessage = ""; + + switch ($errorCode) { + case -20: + $errorMessage = $errorMessageTemplate . ": Error encrypt signature"; + break; + case -8: + $errorMessage = $errorMessageTemplate . ": Invalid token"; + break; + case -7: + $errorMessage = $errorMessageTemplate . ": Error document request"; + break; + case -6: + $errorMessage = $errorMessageTemplate . ": Error while accessing the conversion result database"; + break; + case -5: + $errorMessage = $errorMessageTemplate . ": Incorrect password"; + break; + case -4: + $errorMessage = $errorMessageTemplate . ": Error while downloading the document file to be converted."; + break; + case -3: + $errorMessage = $errorMessageTemplate . ": Conversion error"; + break; + case -2: + $errorMessage = $errorMessageTemplate . ": Timeout conversion error"; + break; + case -1: + $errorMessage = $errorMessageTemplate . ": Unknown error"; + break; + case 0: + break; + default: + $errorMessage = $errorMessageTemplate . ": ErrorCode = " . $errorCode; + break; + } + + throw new \Exception($errorMessage); + } + + /** + * Request health status + * + * @return bool + */ + public function HealthcheckRequest() { + $documentServerUrl = $this->config->GetDocumentServerInternalUrl(); + + if (empty($documentServerUrl)) { + throw new \Exception($this->trans->t("ONLYOFFICE app is not configured. Please contact admin")); + } + + $urlHealthcheck = $documentServerUrl . "healthcheck"; + + $response = $this->Request($urlHealthcheck); + + return $response === "true"; + } + + /** + * Send command + * + * @param string $method - type of command + * + * @return array + */ + public function CommandRequest($method) { + $documentServerUrl = $this->config->GetDocumentServerInternalUrl(); + + if (empty($documentServerUrl)) { + throw new \Exception($this->trans->t("ONLYOFFICE app is not configured. Please contact admin")); + } + + $urlCommand = $documentServerUrl . "coauthoring/CommandService.ashx"; + + $data = [ + "c" => $method + ]; + + $opts = [ + "headers" => [ + "Content-type" => "application/json" + ], + "body" => json_encode($data) + ]; + + if (!empty($this->config->GetDocumentServerSecret())) { + $params = [ + "payload" => $data + ]; + $token = \Firebase\JWT\JWT::encode($params, $this->config->GetDocumentServerSecret(), "HS256"); + $opts["headers"][$this->config->JwtHeader()] = "Bearer " . $token; + + $token = \Firebase\JWT\JWT::encode($data, $this->config->GetDocumentServerSecret(), "HS256"); + $data["token"] = $token; + $opts["body"] = json_encode($data); + } + + $response = $this->Request($urlCommand, "post", $opts); + + $data = json_decode($response); + + $this->ProcessCommandServResponceError($data->error); + + return $data; + } + + /** + * Generate an error code table of command + * + * @param string $errorCode - Error code + * + * @return null + */ + public function ProcessCommandServResponceError($errorCode) { + $errorMessageTemplate = $this->trans->t("Error occurred in the document service"); + $errorMessage = ""; + + switch ($errorCode) { + case 6: + $errorMessage = $errorMessageTemplate . ": Invalid token"; + break; + case 5: + $errorMessage = $errorMessageTemplate . ": Command not correсt"; + break; + case 3: + $errorMessage = $errorMessageTemplate . ": Internal server error"; + break; + case 0: + return; + default: + $errorMessage = $errorMessageTemplate . ": ErrorCode = " . $errorCode; + break; + } + + throw new \Exception($errorMessage); + } + + /** + * Request to Document Server with turn off verification + * + * @param string $url - request address + * @param array $method - request method + * @param array $opts - request options + * + * @return string + */ + public function Request($url, $method = "get", $opts = null) { + $httpClientService = \OC::$server->getHTTPClientService(); + $client = $httpClientService->newClient(); + + if ($opts === null) { + $opts = []; + } + if (substr($url, 0, \strlen("https")) === "https" && $this->config->GetVerifyPeerOff()) { + $opts["verify"] = false; + } + if (!\array_key_exists("timeout", $opts)) { + $opts["timeout"] = 60; + } + + if ($method === "post") { + $response = $client->post($url, $opts); + } else { + $response = $client->get($url, $opts); + } + + return $response->getBody(); + } + + /** + * Checking document service location + * + * @param OCP\IURLGenerator $urlGenerator - url generator + * @param OCA\Onlyoffice\Crypt $crypt -crypt + * + * @return array + */ + public function checkDocServiceUrl($urlGenerator, $crypt) { + $logger = \OC::$server->getLogger(); + $version = null; + + try { + if (preg_match("/^https:\/\//i", $urlGenerator->getAbsoluteURL("/")) + && preg_match("/^http:\/\//i", $this->config->GetDocumentServerUrl())) { + throw new \Exception($this->trans->t("Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required.")); + } + } catch (\Exception $e) { + $logger->logException($e, ["message" => "Protocol on check error", "app" => self::$appName]); + return [$e->getMessage(), $version]; + } + + try { + $healthcheckResponse = $this->HealthcheckRequest(); + if (!$healthcheckResponse) { + throw new \Exception($this->trans->t("Bad healthcheck status")); + } + } catch (\Exception $e) { + $logger->logException($e, ["message" => "HealthcheckRequest on check error", "app" => self::$appName]); + return [$e->getMessage(), $version]; + } + + try { + $commandResponse = $this->CommandRequest("version"); + + $logger->debug("CommandRequest on check: " . json_encode($commandResponse), ["app" => self::$appName]); + + if (empty($commandResponse)) { + throw new \Exception($this->trans->t("Error occurred in the document service")); + } + + $version = $commandResponse->version; + $versionF = \floatval($version); + if ($versionF > 0.0 && $versionF <= 6.0) { + throw new \Exception($this->trans->t("Not supported version")); + } + } catch (\Exception $e) { + $logger->logException($e, ["message" => "CommandRequest on check error", "app" => self::$appName]); + return [$e->getMessage(), $version]; + } + + $convertedFileUri = null; + try { + $hashUrl = $crypt->GetHash(["action" => "empty"]); + $fileUrl = $urlGenerator->linkToRouteAbsolute(self::$appName . ".callback.emptyfile", ["doc" => $hashUrl]); + if (!$this->config->UseDemo() && !empty($this->config->GetStorageUrl())) { + $fileUrl = str_replace($urlGenerator->getAbsoluteURL("/"), $this->config->GetStorageUrl(), $fileUrl); + } + + $convertedFileUri = $this->GetConvertedUri($fileUrl, "docx", "docx", "check_" . rand()); + } catch (\Exception $e) { + $logger->logException($e, ["message" => "GetConvertedUri on check error", "app" => self::$appName]); + return [$e->getMessage(), $version]; + } + + try { + $this->Request($convertedFileUri); + } catch (\Exception $e) { + $logger->logException($e, ["message" => "Request converted file on check error", "app" => self::$appName]); + return [$e->getMessage(), $version]; + } + + return ["", $version]; + } } diff --git a/lib/fileutility.php b/lib/fileutility.php index 3233511e..d413484a 100644 --- a/lib/fileutility.php +++ b/lib/fileutility.php @@ -38,260 +38,260 @@ * @package OCA\Onlyoffice */ class FileUtility { - /** - * Application name - * - * @var string - */ - private $appName; - - /** - * l10n service - * - * @var IL10N - */ - private $trans; - - /** - * Logger - * - * @var ILogger - */ - private $logger; - - /** - * Share manager - * - * @var IManager - */ - private $shareManager; - - /** - * Session - * - * @var ISession - */ - private $session; - - /** - * Application configuration - * - * @var AppConfig - */ - private $config; - - /** - * @param string $AppName - application name - * @param IL10N $trans - l10n service - * @param ILogger $logger - logger - * @param AppConfig $config - application configuration - * @param IManager $shareManager - Share manager - * @param IManager $ISession - Session - */ - public function __construct( - $AppName, - IL10N $trans, - ILogger $logger, - AppConfig $config, - IManager $shareManager, - ISession $session - ) { - $this->appName = $AppName; - $this->trans = $trans; - $this->logger = $logger; - $this->config = $config; - $this->shareManager = $shareManager; - $this->session = $session; - } - - /** - * Getting file by token - * - * @param integer $fileId - file identifier - * @param string $shareToken - access token - * @param string $path - file path - * - * @return array - */ - public function getFileByToken($fileId, $shareToken, $path = null) { - list($node, $error, $share) = $this->getNodeByToken($shareToken); - - if (isset($error)) { - return [null, $error, null]; - } - - if ($node instanceof Folder) { - if ($fileId !== null && $fileId !== 0) { - try { - $files = $node->getById($fileId); - } catch (\Exception $e) { - $this->logger->logException($e, ["message" => "getFileByToken: $fileId", "app" => $this->appName]); - return [null, $this->trans->t("Invalid request"), null]; - } - - if (empty($files)) { - $this->logger->info("Files not found: $fileId", ["app" => $this->appName]); - return [null, $this->trans->t("File not found"), null]; - } - $file = $files[0]; - } else { - try { - $file = $node->get($path); - } catch (\Exception $e) { - $this->logger->logException($e, ["message" => "getFileByToken for path: $path", "app" => $this->appName]); - return [null, $this->trans->t("Invalid request"), null]; - } - } - } else { - $file = $node; - } - - return [$file, null, $share]; - } - - /** - * Getting file by token - * - * @param string $shareToken - access token - * - * @return array - */ - public function getNodeByToken($shareToken) { - list($share, $error) = $this->getShare($shareToken); - - if (isset($error)) { - return [null, $error, null]; - } - - if (($share->getPermissions() & Constants::PERMISSION_READ) === 0) { - return [null, $this->trans->t("You do not have enough permissions to view the file"), null]; - } - - try { - $node = $share->getNode(); - } catch (NotFoundException $e) { - $this->logger->logException($e, ["message" => "getNodeByToken error", "app" => $this->appName]); - return [null, $this->trans->t("File not found"), null]; - } - - return [$node, null, $share]; - } - - /** - * Getting share by token - * - * @param string $shareToken - access token - * - * @return array - */ - public function getShare($shareToken) { - if (empty($shareToken)) { - return [null, $this->trans->t("FileId is empty")]; - } - - $share = null; - try { - $share = $this->shareManager->getShareByToken($shareToken); - } catch (ShareNotFound $e) { - $this->logger->logException($e, ["message" => "getShare error", "app" => $this->appName]); - $share = null; - } - - if ($share === null || $share === false) { - return [null, $this->trans->t("You do not have enough permissions to view the file")]; - } - - if ($share->getPassword() - && (!$this->session->exists("public_link_authenticated") - || $this->session->get("public_link_authenticated") !== (string) $share->getId())) { - return [null, $this->trans->t("You do not have enough permissions to view the file")]; - } - - return [$share, null]; - } - - /** - * Generate unique document identifier - * - * @param File $file - file - * @param bool $origin - request from federated store - * - * @return string - */ - public function getKey($file, $origin = false) { - $fileId = $file->getId(); - - if ($origin - && RemoteInstance::isRemoteFile($file)) { - $key = RemoteInstance::getRemoteKey($file); - if (!empty($key)) { - return $key; - } - } - - $key = KeyManager::get($fileId); - - if (empty($key)) { - $instanceId = $this->config->GetSystemValue("instanceid", true); - - $key = $instanceId . "_" . $this->GUID(); - - KeyManager::set($fileId, $key); - } - - return $key; - } - - /** - * Detected attribute permission for shared file - * - * @param File $file - file - * @param string $attribute - request from federated store - * - * @return bool - */ - public function hasPermissionAttribute($file, $attribute = "download") { - $fileStorage = $file->getStorage(); - if ($fileStorage->instanceOfStorage("\OCA\Files_Sharing\SharedStorage")) { - $storageShare = $fileStorage->getShare(); - if (method_exists($storageShare, "getAttributes")) { - $attributes = $storageShare->getAttributes(); - - $permissionsDownload = $attributes->getAttribute("permissions", "download"); - if ($permissionsDownload !== null && $permissionsDownload !== true) { - return false; - } - } - } - - return true; - } - - /** - * Generate unique identifier - * - * @return string - */ - private function GUID() { - if (\function_exists("com_create_guid") === true) { - return trim(com_create_guid(), "{}"); - } - - return sprintf('%04X%04X-%04X-%04X-%04X-%04X%04X%04X', mt_rand(0, 65535), mt_rand(0, 65535), mt_rand(0, 65535), mt_rand(16384, 20479), mt_rand(32768, 49151), mt_rand(0, 65535), mt_rand(0, 65535), mt_rand(0, 65535)); - } - - /** - * Generate unique file version key - * - * @param Version $version - file version - * - * @return string - */ - public function getVersionKey($version) { - $instanceId = $this->config->GetSystemValue("instanceid", true); - - $key = $instanceId . "_" . $version->getSourceFile()->getEtag() . "_" . $version->getRevisionId(); - - return $key; - } + /** + * Application name + * + * @var string + */ + private $appName; + + /** + * l10n service + * + * @var IL10N + */ + private $trans; + + /** + * Logger + * + * @var ILogger + */ + private $logger; + + /** + * Share manager + * + * @var IManager + */ + private $shareManager; + + /** + * Session + * + * @var ISession + */ + private $session; + + /** + * Application configuration + * + * @var AppConfig + */ + private $config; + + /** + * @param string $AppName - application name + * @param IL10N $trans - l10n service + * @param ILogger $logger - logger + * @param AppConfig $config - application configuration + * @param IManager $shareManager - Share manager + * @param IManager $ISession - Session + */ + public function __construct( + $AppName, + IL10N $trans, + ILogger $logger, + AppConfig $config, + IManager $shareManager, + ISession $session + ) { + $this->appName = $AppName; + $this->trans = $trans; + $this->logger = $logger; + $this->config = $config; + $this->shareManager = $shareManager; + $this->session = $session; + } + + /** + * Getting file by token + * + * @param integer $fileId - file identifier + * @param string $shareToken - access token + * @param string $path - file path + * + * @return array + */ + public function getFileByToken($fileId, $shareToken, $path = null) { + list($node, $error, $share) = $this->getNodeByToken($shareToken); + + if (isset($error)) { + return [null, $error, null]; + } + + if ($node instanceof Folder) { + if ($fileId !== null && $fileId !== 0) { + try { + $files = $node->getById($fileId); + } catch (\Exception $e) { + $this->logger->logException($e, ["message" => "getFileByToken: $fileId", "app" => $this->appName]); + return [null, $this->trans->t("Invalid request"), null]; + } + + if (empty($files)) { + $this->logger->info("Files not found: $fileId", ["app" => $this->appName]); + return [null, $this->trans->t("File not found"), null]; + } + $file = $files[0]; + } else { + try { + $file = $node->get($path); + } catch (\Exception $e) { + $this->logger->logException($e, ["message" => "getFileByToken for path: $path", "app" => $this->appName]); + return [null, $this->trans->t("Invalid request"), null]; + } + } + } else { + $file = $node; + } + + return [$file, null, $share]; + } + + /** + * Getting file by token + * + * @param string $shareToken - access token + * + * @return array + */ + public function getNodeByToken($shareToken) { + list($share, $error) = $this->getShare($shareToken); + + if (isset($error)) { + return [null, $error, null]; + } + + if (($share->getPermissions() & Constants::PERMISSION_READ) === 0) { + return [null, $this->trans->t("You do not have enough permissions to view the file"), null]; + } + + try { + $node = $share->getNode(); + } catch (NotFoundException $e) { + $this->logger->logException($e, ["message" => "getNodeByToken error", "app" => $this->appName]); + return [null, $this->trans->t("File not found"), null]; + } + + return [$node, null, $share]; + } + + /** + * Getting share by token + * + * @param string $shareToken - access token + * + * @return array + */ + public function getShare($shareToken) { + if (empty($shareToken)) { + return [null, $this->trans->t("FileId is empty")]; + } + + $share = null; + try { + $share = $this->shareManager->getShareByToken($shareToken); + } catch (ShareNotFound $e) { + $this->logger->logException($e, ["message" => "getShare error", "app" => $this->appName]); + $share = null; + } + + if ($share === null || $share === false) { + return [null, $this->trans->t("You do not have enough permissions to view the file")]; + } + + if ($share->getPassword() + && (!$this->session->exists("public_link_authenticated") + || $this->session->get("public_link_authenticated") !== (string) $share->getId())) { + return [null, $this->trans->t("You do not have enough permissions to view the file")]; + } + + return [$share, null]; + } + + /** + * Generate unique document identifier + * + * @param File $file - file + * @param bool $origin - request from federated store + * + * @return string + */ + public function getKey($file, $origin = false) { + $fileId = $file->getId(); + + if ($origin + && RemoteInstance::isRemoteFile($file)) { + $key = RemoteInstance::getRemoteKey($file); + if (!empty($key)) { + return $key; + } + } + + $key = KeyManager::get($fileId); + + if (empty($key)) { + $instanceId = $this->config->GetSystemValue("instanceid", true); + + $key = $instanceId . "_" . $this->GUID(); + + KeyManager::set($fileId, $key); + } + + return $key; + } + + /** + * Detected attribute permission for shared file + * + * @param File $file - file + * @param string $attribute - request from federated store + * + * @return bool + */ + public function hasPermissionAttribute($file, $attribute = "download") { + $fileStorage = $file->getStorage(); + if ($fileStorage->instanceOfStorage("\OCA\Files_Sharing\SharedStorage")) { + $storageShare = $fileStorage->getShare(); + if (method_exists($storageShare, "getAttributes")) { + $attributes = $storageShare->getAttributes(); + + $permissionsDownload = $attributes->getAttribute("permissions", "download"); + if ($permissionsDownload !== null && $permissionsDownload !== true) { + return false; + } + } + } + + return true; + } + + /** + * Generate unique identifier + * + * @return string + */ + private function GUID() { + if (\function_exists("com_create_guid") === true) { + return trim(com_create_guid(), "{}"); + } + + return sprintf('%04X%04X-%04X-%04X-%04X-%04X%04X%04X', mt_rand(0, 65535), mt_rand(0, 65535), mt_rand(0, 65535), mt_rand(16384, 20479), mt_rand(32768, 49151), mt_rand(0, 65535), mt_rand(0, 65535), mt_rand(0, 65535)); + } + + /** + * Generate unique file version key + * + * @param Version $version - file version + * + * @return string + */ + public function getVersionKey($version) { + $instanceId = $this->config->GetSystemValue("instanceid", true); + + $key = $instanceId . "_" . $version->getSourceFile()->getEtag() . "_" . $version->getRevisionId(); + + return $key; + } } diff --git a/lib/fileversions.php b/lib/fileversions.php index e690f1f3..957271c1 100644 --- a/lib/fileversions.php +++ b/lib/fileversions.php @@ -34,444 +34,444 @@ * @package OCA\Onlyoffice */ class FileVersions { - /** - * Application name - * - * @var string - */ - private static $appName = "onlyoffice"; - - /** - * Changes file extension - * - * @var string - */ - private static $changesExt = ".zip"; - - /** - * History file extension - * - * @var string - */ - private static $historyExt = ".json"; - - /** - * File name contain author - * - * @var string - */ - private static $authorExt = "_author.json"; - - /** - * Split file path and version id - * - * @param string $pathVersion - version path - * - * @return array - */ - public static function splitPathVersion($pathVersion) { - $pos = strrpos($pathVersion, ".v"); - if ($pos === false) { - return false; - } - $filePath = substr($pathVersion, 0, $pos); - $versionId = substr($pathVersion, 2 + $pos - \strlen($pathVersion)); - return [$filePath, $versionId]; - } - - /** - * Check if folder is not exist - * - * @param View $view - view - * @param string $path - folder path - * @param bool $createIfNotExist - create folder if not exist - * - * @return bool - */ - private static function checkFolderExist($view, $path, $createIfNotExist = false) { - if ($view->is_dir($path)) { - return true; - } - if (!$createIfNotExist) { - return false; - } - $view->mkdir($path); - return true; - } - - /** - * Get view and path for changes - * - * @param string $userId - user id - * @param string $fileId - file id - * @param bool $createIfNotExist - create folder if not exist - * - * @return array - */ - private static function getView($userId, $fileId, $createIfNotExist = false) { - $view = new View("/" . $userId); - - $path = self::$appName; - if (!self::checkFolderExist($view, $path, $createIfNotExist)) { - return [null, null]; - } - - if ($fileId === null) { - return [$view, $path]; - } - - $path = $path . "/" . $fileId; - if (!self::checkFolderExist($view, $path, $createIfNotExist)) { - return [null, null]; - } - - return [$view, $path]; - } - - /** - * Get changes from stored to history object - * - * @param string $ownerId - file owner id - * @param string $fileId - file id - * @param string $versionId - file version - * @param string $prevVersion - previous version for check - * - * @return array - */ - public static function getHistoryData($ownerId, $fileId, $versionId, $prevVersion) { - $logger = \OC::$server->getLogger(); - - if ($ownerId === null || $fileId === null) { - return null; - } - - list($view, $path) = self::getView($ownerId, $fileId); - if ($view === null) { - return null; - } - - $historyPath = $path . "/" . $versionId . self::$historyExt; - if (!$view->file_exists($historyPath)) { - return null; - } - - $historyDataString = $view->file_get_contents($historyPath); - - try { - $historyData = json_decode($historyDataString, true); - - if ($historyData["prev"] !== $prevVersion) { - $logger->debug("getHistoryData: previous $prevVersion != " . $historyData["prev"], ["app" => self::$appName]); - - $view->unlink($historyPath); - $logger->debug("getHistoryData: delete $historyPath", ["app" => self::$appName]); - - $changesPath = $path . "/" . $versionId . self::$changesExt; - if ($view->file_exists($changesPath)) { - $view->unlink($changesPath); - $logger->debug("getHistoryData: delete $changesPath", ["app" => self::$appName]); - } - return null; - } - - return $historyData; - } catch (\Exception $e) { - $logger->logException($e, ["message" => "getHistoryData: $fileId $versionId", "app" => self::$appName]); - return null; - } - } - - /** - * Check if changes is stored - * - * @param string $ownerId - file owner id - * @param string $fileId - file id - * @param string $versionId - file version - * - * @return bool - */ - public static function hasChanges($ownerId, $fileId, $versionId) { - if ($ownerId === null || $fileId === null) { - return false; - } - - list($view, $path) = self::getView($ownerId, $fileId); - if ($view === null) { - return false; - } - - $changesPath = $path . "/" . $versionId . self::$changesExt; - return $view->file_exists($changesPath); - } - - /** - * Get changes file - * - * @param string $ownerId - file owner id - * @param string $fileId - file id - * @param string $versionId - file version - * - * @return File - */ - public static function getChangesFile($ownerId, $fileId, $versionId) { - if ($ownerId === null || $fileId === null) { - return null; - } - - list($view, $path) = self::getView($ownerId, $fileId); - if ($view === null) { - return null; - } - - $changesPath = $path . "/" . $versionId . self::$changesExt; - if (!$view->file_exists($changesPath)) { - return null; - } - - $changesInfo = $view->getFileInfo($changesPath); - $changes = new File($view->getRoot(), $view, $changesPath, $changesInfo); - - \OC::$server->getLogger()->debug("getChangesFile: $fileId for $ownerId get changes $changesPath", ["app" => self::$appName]); - - return $changes; - } - - /** - * Save history to storage - * - * @param FileInfo $fileInfo - file info - * @param array $history - file history - * @param string $changesurl - file changes - * @param string $prevVersion - previous version for check - */ - public static function saveHistory($fileInfo, $history, $changes, $prevVersion) { - $logger = \OC::$server->getLogger(); - - if ($fileInfo === null) { - return; - } - - $owner = $fileInfo->getOwner(); - if ($owner === null) { - return; - } - - if (empty($history) || empty($changes)) { - return; - } - - if ($fileInfo->getStorage()->instanceOfStorage(SharingExternalStorage::class)) { - return; - } - - $ownerId = $owner->getUID(); - $fileId = $fileInfo->getId(); - $versionId = $fileInfo->getMtime(); - - list($view, $path) = self::getView($ownerId, $fileId, true); - - try { - $changesPath = $path . "/" . $versionId . self::$changesExt; - $view->touch($changesPath); - $view->file_put_contents($changesPath, $changes); - - $history["prev"] = $prevVersion; - $historyPath = $path . "/" . $versionId . self::$historyExt; - $view->touch($historyPath); - $view->file_put_contents($historyPath, json_encode($history)); - - $logger->debug("saveHistory: $fileId for $ownerId stored changes $changesPath history $historyPath", ["app" => self::$appName]); - } catch (\Exception $e) { - $logger->logException($e, ["message" => "saveHistory: save $fileId history error", "app" => self::$appName]); - } - } - - /** - * Delete all versions of file - * - * @param string $ownerId - file owner id - * @param string $fileId - file id - */ - public static function deleteAllVersions($ownerId, $fileId = null) { - $logger = \OC::$server->getLogger(); - - $logger->debug("deleteAllVersions $ownerId $fileId", ["app" => self::$appName]); - - if ($ownerId === null) { - return; - } - - list($view, $path) = self::getView($ownerId, $fileId); - if ($view === null) { - return; - } - - $view->unlink($path); - } - - /** - * Delete changes and history - * - * @param string $ownerId - file owner id - * @param string $fileId - file id - * @param string $versionId - file version - */ - public static function deleteVersion($ownerId, $fileId, $versionId) { - $logger = \OC::$server->getLogger(); - - $logger->debug("deleteVersion $fileId ($versionId)", ["app" => self::$appName]); - - if ($ownerId === null) { - return; - } - if ($fileId === null || empty($versionId)) { - return; - } - - list($view, $path) = self::getView($ownerId, $fileId); - if ($view === null) { - return null; - } - - $historyPath = $path . "/" . $versionId . self::$historyExt; - if ($view->file_exists($historyPath)) { - $view->unlink($historyPath); - $logger->debug("deleteVersion $historyPath", ["app" => self::$appName]); - } - - $changesPath = $path . "/" . $versionId . self::$changesExt; - if ($view->file_exists($changesPath)) { - $view->unlink($changesPath); - $logger->debug("deleteVersion $changesPath", ["app" => self::$appName]); - } - } - - /** - * Clear all version history - */ - public static function clearHistory() { - $logger = \OC::$server->getLogger(); - - $userDatabase = new Database(); - $userIds = $userDatabase->getUsers(); - - $view = new View("/"); - - foreach ($userIds as $userId) { - $path = $userId . "/" . self::$appName; - - if ($view->file_exists($path)) { - $view->unlink($path); - } - } - - $logger->debug("clear all history", ["app" => self::$appName]); - } - - /** - * Save file author - * - * @param FileInfo $fileInfo - file info - * @param IUser $author - version author - */ - public static function saveAuthor($fileInfo, $author) { - $logger = \OC::$server->getLogger(); - - if ($fileInfo === null || $author === null) { - return; - } - - $owner = $fileInfo->getOwner(); - if ($owner === null) { - return; - } - - if ($fileInfo->getStorage()->instanceOfStorage(SharingExternalStorage::class)) { - return; - } - - $ownerId = $owner->getUID(); - $fileId = $fileInfo->getId(); - $versionId = $fileInfo->getMtime(); - - list($view, $path) = self::getView($ownerId, $fileId, true); - - try { - $authorPath = $path . "/" . $versionId . self::$authorExt; - $view->touch($authorPath); - - $authorData = [ - "id" => $author->getUID(), - "name" => $author->getDisplayName() - ]; - $view->file_put_contents($authorPath, json_encode($authorData)); - - $logger->debug("saveAuthor: $fileId for $ownerId stored author $authorPath", ["app" => self::$appName]); - } catch (\Exception $e) { - $logger->logException($e, ["message" => "saveAuthor: save $fileId author error", "app" => self::$appName]); - } - } - - /** - * Get version author id and name - * - * @param string $ownerId - file owner id - * @param string $fileId - file id - * @param string $versionId - file version - * - * @return array - */ - public static function getAuthor($ownerId, $fileId, $versionId) { - if ($ownerId === null || $fileId === null) { - return null; - } - - list($view, $path) = self::getView($ownerId, $fileId); - if ($view === null) { - return null; - } - - $authorPath = $path . "/" . $versionId . self::$authorExt; - if (!$view->file_exists($authorPath)) { - return null; - } - - $authorDataString = $view->file_get_contents($authorPath); - $author = json_decode($authorDataString, true); - - \OC::$server->getLogger()->debug("getAuthor: $fileId v.$versionId for $ownerId get author $authorPath", ["app" => self::$appName]); - - return $author; - } - - /** - * Delete version author info - * - * @param string $ownerId - file owner id - * @param string $fileId - file id - * @param string $versionId - file version - */ - public static function deleteAuthor($ownerId, $fileId, $versionId) { - $logger = \OC::$server->getLogger(); - - $logger->debug("deleteAuthor $fileId ($versionId)", ["app" => self::$appName]); - - if ($ownerId === null) { - return; - } - if ($fileId === null || empty($versionId)) { - return; - } - - list($view, $path) = self::getView($ownerId, $fileId); - if ($view === null) { - return null; - } - - $authorPath = $path . "/" . $versionId . self::$authorExt; - if ($view->file_exists($authorPath)) { - $view->unlink($authorPath); - $logger->debug("deleteAuthor $authorPath", ["app" => self::$appName]); - } - } + /** + * Application name + * + * @var string + */ + private static $appName = "onlyoffice"; + + /** + * Changes file extension + * + * @var string + */ + private static $changesExt = ".zip"; + + /** + * History file extension + * + * @var string + */ + private static $historyExt = ".json"; + + /** + * File name contain author + * + * @var string + */ + private static $authorExt = "_author.json"; + + /** + * Split file path and version id + * + * @param string $pathVersion - version path + * + * @return array + */ + public static function splitPathVersion($pathVersion) { + $pos = strrpos($pathVersion, ".v"); + if ($pos === false) { + return false; + } + $filePath = substr($pathVersion, 0, $pos); + $versionId = substr($pathVersion, 2 + $pos - \strlen($pathVersion)); + return [$filePath, $versionId]; + } + + /** + * Check if folder is not exist + * + * @param View $view - view + * @param string $path - folder path + * @param bool $createIfNotExist - create folder if not exist + * + * @return bool + */ + private static function checkFolderExist($view, $path, $createIfNotExist = false) { + if ($view->is_dir($path)) { + return true; + } + if (!$createIfNotExist) { + return false; + } + $view->mkdir($path); + return true; + } + + /** + * Get view and path for changes + * + * @param string $userId - user id + * @param string $fileId - file id + * @param bool $createIfNotExist - create folder if not exist + * + * @return array + */ + private static function getView($userId, $fileId, $createIfNotExist = false) { + $view = new View("/" . $userId); + + $path = self::$appName; + if (!self::checkFolderExist($view, $path, $createIfNotExist)) { + return [null, null]; + } + + if ($fileId === null) { + return [$view, $path]; + } + + $path = $path . "/" . $fileId; + if (!self::checkFolderExist($view, $path, $createIfNotExist)) { + return [null, null]; + } + + return [$view, $path]; + } + + /** + * Get changes from stored to history object + * + * @param string $ownerId - file owner id + * @param string $fileId - file id + * @param string $versionId - file version + * @param string $prevVersion - previous version for check + * + * @return array + */ + public static function getHistoryData($ownerId, $fileId, $versionId, $prevVersion) { + $logger = \OC::$server->getLogger(); + + if ($ownerId === null || $fileId === null) { + return null; + } + + list($view, $path) = self::getView($ownerId, $fileId); + if ($view === null) { + return null; + } + + $historyPath = $path . "/" . $versionId . self::$historyExt; + if (!$view->file_exists($historyPath)) { + return null; + } + + $historyDataString = $view->file_get_contents($historyPath); + + try { + $historyData = json_decode($historyDataString, true); + + if ($historyData["prev"] !== $prevVersion) { + $logger->debug("getHistoryData: previous $prevVersion != " . $historyData["prev"], ["app" => self::$appName]); + + $view->unlink($historyPath); + $logger->debug("getHistoryData: delete $historyPath", ["app" => self::$appName]); + + $changesPath = $path . "/" . $versionId . self::$changesExt; + if ($view->file_exists($changesPath)) { + $view->unlink($changesPath); + $logger->debug("getHistoryData: delete $changesPath", ["app" => self::$appName]); + } + return null; + } + + return $historyData; + } catch (\Exception $e) { + $logger->logException($e, ["message" => "getHistoryData: $fileId $versionId", "app" => self::$appName]); + return null; + } + } + + /** + * Check if changes is stored + * + * @param string $ownerId - file owner id + * @param string $fileId - file id + * @param string $versionId - file version + * + * @return bool + */ + public static function hasChanges($ownerId, $fileId, $versionId) { + if ($ownerId === null || $fileId === null) { + return false; + } + + list($view, $path) = self::getView($ownerId, $fileId); + if ($view === null) { + return false; + } + + $changesPath = $path . "/" . $versionId . self::$changesExt; + return $view->file_exists($changesPath); + } + + /** + * Get changes file + * + * @param string $ownerId - file owner id + * @param string $fileId - file id + * @param string $versionId - file version + * + * @return File + */ + public static function getChangesFile($ownerId, $fileId, $versionId) { + if ($ownerId === null || $fileId === null) { + return null; + } + + list($view, $path) = self::getView($ownerId, $fileId); + if ($view === null) { + return null; + } + + $changesPath = $path . "/" . $versionId . self::$changesExt; + if (!$view->file_exists($changesPath)) { + return null; + } + + $changesInfo = $view->getFileInfo($changesPath); + $changes = new File($view->getRoot(), $view, $changesPath, $changesInfo); + + \OC::$server->getLogger()->debug("getChangesFile: $fileId for $ownerId get changes $changesPath", ["app" => self::$appName]); + + return $changes; + } + + /** + * Save history to storage + * + * @param FileInfo $fileInfo - file info + * @param array $history - file history + * @param string $changesurl - file changes + * @param string $prevVersion - previous version for check + */ + public static function saveHistory($fileInfo, $history, $changes, $prevVersion) { + $logger = \OC::$server->getLogger(); + + if ($fileInfo === null) { + return; + } + + $owner = $fileInfo->getOwner(); + if ($owner === null) { + return; + } + + if (empty($history) || empty($changes)) { + return; + } + + if ($fileInfo->getStorage()->instanceOfStorage(SharingExternalStorage::class)) { + return; + } + + $ownerId = $owner->getUID(); + $fileId = $fileInfo->getId(); + $versionId = $fileInfo->getMtime(); + + list($view, $path) = self::getView($ownerId, $fileId, true); + + try { + $changesPath = $path . "/" . $versionId . self::$changesExt; + $view->touch($changesPath); + $view->file_put_contents($changesPath, $changes); + + $history["prev"] = $prevVersion; + $historyPath = $path . "/" . $versionId . self::$historyExt; + $view->touch($historyPath); + $view->file_put_contents($historyPath, json_encode($history)); + + $logger->debug("saveHistory: $fileId for $ownerId stored changes $changesPath history $historyPath", ["app" => self::$appName]); + } catch (\Exception $e) { + $logger->logException($e, ["message" => "saveHistory: save $fileId history error", "app" => self::$appName]); + } + } + + /** + * Delete all versions of file + * + * @param string $ownerId - file owner id + * @param string $fileId - file id + */ + public static function deleteAllVersions($ownerId, $fileId = null) { + $logger = \OC::$server->getLogger(); + + $logger->debug("deleteAllVersions $ownerId $fileId", ["app" => self::$appName]); + + if ($ownerId === null) { + return; + } + + list($view, $path) = self::getView($ownerId, $fileId); + if ($view === null) { + return; + } + + $view->unlink($path); + } + + /** + * Delete changes and history + * + * @param string $ownerId - file owner id + * @param string $fileId - file id + * @param string $versionId - file version + */ + public static function deleteVersion($ownerId, $fileId, $versionId) { + $logger = \OC::$server->getLogger(); + + $logger->debug("deleteVersion $fileId ($versionId)", ["app" => self::$appName]); + + if ($ownerId === null) { + return; + } + if ($fileId === null || empty($versionId)) { + return; + } + + list($view, $path) = self::getView($ownerId, $fileId); + if ($view === null) { + return null; + } + + $historyPath = $path . "/" . $versionId . self::$historyExt; + if ($view->file_exists($historyPath)) { + $view->unlink($historyPath); + $logger->debug("deleteVersion $historyPath", ["app" => self::$appName]); + } + + $changesPath = $path . "/" . $versionId . self::$changesExt; + if ($view->file_exists($changesPath)) { + $view->unlink($changesPath); + $logger->debug("deleteVersion $changesPath", ["app" => self::$appName]); + } + } + + /** + * Clear all version history + */ + public static function clearHistory() { + $logger = \OC::$server->getLogger(); + + $userDatabase = new Database(); + $userIds = $userDatabase->getUsers(); + + $view = new View("/"); + + foreach ($userIds as $userId) { + $path = $userId . "/" . self::$appName; + + if ($view->file_exists($path)) { + $view->unlink($path); + } + } + + $logger->debug("clear all history", ["app" => self::$appName]); + } + + /** + * Save file author + * + * @param FileInfo $fileInfo - file info + * @param IUser $author - version author + */ + public static function saveAuthor($fileInfo, $author) { + $logger = \OC::$server->getLogger(); + + if ($fileInfo === null || $author === null) { + return; + } + + $owner = $fileInfo->getOwner(); + if ($owner === null) { + return; + } + + if ($fileInfo->getStorage()->instanceOfStorage(SharingExternalStorage::class)) { + return; + } + + $ownerId = $owner->getUID(); + $fileId = $fileInfo->getId(); + $versionId = $fileInfo->getMtime(); + + list($view, $path) = self::getView($ownerId, $fileId, true); + + try { + $authorPath = $path . "/" . $versionId . self::$authorExt; + $view->touch($authorPath); + + $authorData = [ + "id" => $author->getUID(), + "name" => $author->getDisplayName() + ]; + $view->file_put_contents($authorPath, json_encode($authorData)); + + $logger->debug("saveAuthor: $fileId for $ownerId stored author $authorPath", ["app" => self::$appName]); + } catch (\Exception $e) { + $logger->logException($e, ["message" => "saveAuthor: save $fileId author error", "app" => self::$appName]); + } + } + + /** + * Get version author id and name + * + * @param string $ownerId - file owner id + * @param string $fileId - file id + * @param string $versionId - file version + * + * @return array + */ + public static function getAuthor($ownerId, $fileId, $versionId) { + if ($ownerId === null || $fileId === null) { + return null; + } + + list($view, $path) = self::getView($ownerId, $fileId); + if ($view === null) { + return null; + } + + $authorPath = $path . "/" . $versionId . self::$authorExt; + if (!$view->file_exists($authorPath)) { + return null; + } + + $authorDataString = $view->file_get_contents($authorPath); + $author = json_decode($authorDataString, true); + + \OC::$server->getLogger()->debug("getAuthor: $fileId v.$versionId for $ownerId get author $authorPath", ["app" => self::$appName]); + + return $author; + } + + /** + * Delete version author info + * + * @param string $ownerId - file owner id + * @param string $fileId - file id + * @param string $versionId - file version + */ + public static function deleteAuthor($ownerId, $fileId, $versionId) { + $logger = \OC::$server->getLogger(); + + $logger->debug("deleteAuthor $fileId ($versionId)", ["app" => self::$appName]); + + if ($ownerId === null) { + return; + } + if ($fileId === null || empty($versionId)) { + return; + } + + list($view, $path) = self::getView($ownerId, $fileId); + if ($view === null) { + return null; + } + + $authorPath = $path . "/" . $versionId . self::$authorExt; + if ($view->file_exists($authorPath)) { + $view->unlink($authorPath); + $logger->debug("deleteAuthor $authorPath", ["app" => self::$appName]); + } + } } diff --git a/lib/hookhandler.php b/lib/hookhandler.php index fe74c171..5d7973ca 100644 --- a/lib/hookhandler.php +++ b/lib/hookhandler.php @@ -31,20 +31,20 @@ * @package OCA\Onlyoffice */ class HookHandler { - public static function PublicPage() { - $appName = "onlyoffice"; + public static function PublicPage() { + $appName = "onlyoffice"; - $appConfig = new AppConfig($appName); + $appConfig = new AppConfig($appName); - if (!empty($appConfig->GetDocumentServerUrl()) && $appConfig->SettingsAreSuccessful()) { - Util::addScript("onlyoffice", "main"); - Util::addScript("onlyoffice", "share"); + if (!empty($appConfig->GetDocumentServerUrl()) && $appConfig->SettingsAreSuccessful()) { + Util::addScript("onlyoffice", "main"); + Util::addScript("onlyoffice", "share"); - if ($appConfig->GetSameTab()) { - Util::addScript("onlyoffice", "listener"); - } + if ($appConfig->GetSameTab()) { + Util::addScript("onlyoffice", "listener"); + } - Util::addStyle("onlyoffice", "main"); - } - } + Util::addStyle("onlyoffice", "main"); + } + } } diff --git a/lib/hooks.php b/lib/hooks.php index 87632d2f..2b464f00 100644 --- a/lib/hooks.php +++ b/lib/hooks.php @@ -32,154 +32,154 @@ * @package OCA\Onlyoffice */ class Hooks { - /** - * Application name - * - * @var string - */ - private static $appName = "onlyoffice"; - - public static function connectHooks() { - // Listen user deletion - Util::connectHook("OC_User", "pre_deleteUser", Hooks::class, "userDelete"); - - // Listen file change - Util::connectHook("OC_Filesystem", "write", Hooks::class, "fileUpdate"); - - // Listen file deletion - Util::connectHook("OC_Filesystem", "delete", Hooks::class, "fileDelete"); - - // Listen file version deletion - Util::connectHook("\OCP\Versions", "preDelete", Hooks::class, "fileVersionDelete"); - - // Listen file version restore - Util::connectHook("\OCP\Versions", "rollback", Hooks::class, "fileVersionRestore"); - } - - /** - * Erase user file versions - * - * @param array $params - hook params - */ - public static function userDelete($params) { - $userId = $params["uid"]; - - FileVersions::deleteAllVersions($userId); - } - - /** - * Listen of file change - * - * @param array $params - hook params - */ - public static function fileUpdate($params) { - $filePath = $params[Filesystem::signal_param_path]; - if (empty($filePath)) { - return; - } - - $fileInfo = Filesystem::getFileInfo($filePath); - if ($fileInfo === false) { - return; - } - - $fileId = $fileInfo->getId(); - - KeyManager::delete($fileId); - - \OC::$server->getLogger()->debug("Hook fileUpdate " . json_encode($params), ["app" => self::$appName]); - } - - /** - * Erase versions of deleted file - * - * @param array $params - hook params - */ - public static function fileDelete($params) { - $filePath = $params[Filesystem::signal_param_path]; - if (empty($filePath)) { - return; - } - - try { - $ownerId = Filesystem::getOwner($filePath); - - $fileInfo = Filesystem::getFileInfo($filePath); - if ($fileInfo === false) { - return; - } - - $fileId = $fileInfo->getId(); - - KeyManager::delete($fileId, true); - - FileVersions::deleteAllVersions($ownerId, $fileId); - } catch (\Exception $e) { - \OC::$server->getLogger()->logException($e, ["message" => "Hook: fileDelete " . json_encode($params), "app" => self::$appName]); - } - } - - /** - * Erase versions of deleted version of file - * - * @param array $params - hook param - */ - public static function fileVersionDelete($params) { - $pathVersion = $params["path"]; - if (empty($pathVersion)) { - return; - } - - try { - list($filePath, $versionId) = FileVersions::splitPathVersion($pathVersion); - if (empty($filePath)) { - return; - } - - $ownerId = Filesystem::getOwner($filePath); - - $fileInfo = Filesystem::getFileInfo($filePath); - if ($fileInfo === false) { - return; - } - - $fileId = $fileInfo->getId(); - - FileVersions::deleteVersion($ownerId, $fileId, $versionId); - FileVersions::deleteAuthor($ownerId, $fileId, $versionId); - } catch (\Exception $e) { - \OC::$server->getLogger()->logException($e, ["message" => "Hook: fileVersionDelete " . json_encode($params), "app" => self::$appName]); - } - } - - /** - * Erase versions of restored version of file - * - * @param array $params - hook param - */ - public static function fileVersionRestore($params) { - $filePath = $params["path"]; - if (empty($filePath)) { - return; - } - - $versionId = $params["revision"]; - - try { - $ownerId = Filesystem::getOwner($filePath); - - $fileInfo = Filesystem::getFileInfo($filePath); - if ($fileInfo === false) { - return; - } - - $fileId = $fileInfo->getId(); - - KeyManager::delete($fileId); - - FileVersions::deleteVersion($ownerId, $fileId, $versionId); - } catch (\Exception $e) { - \OC::$server->getLogger()->logException($e, ["message" => "Hook: fileVersionRestore " . json_encode($params), "app" => self::$appName]); - } - } + /** + * Application name + * + * @var string + */ + private static $appName = "onlyoffice"; + + public static function connectHooks() { + // Listen user deletion + Util::connectHook("OC_User", "pre_deleteUser", Hooks::class, "userDelete"); + + // Listen file change + Util::connectHook("OC_Filesystem", "write", Hooks::class, "fileUpdate"); + + // Listen file deletion + Util::connectHook("OC_Filesystem", "delete", Hooks::class, "fileDelete"); + + // Listen file version deletion + Util::connectHook("\OCP\Versions", "preDelete", Hooks::class, "fileVersionDelete"); + + // Listen file version restore + Util::connectHook("\OCP\Versions", "rollback", Hooks::class, "fileVersionRestore"); + } + + /** + * Erase user file versions + * + * @param array $params - hook params + */ + public static function userDelete($params) { + $userId = $params["uid"]; + + FileVersions::deleteAllVersions($userId); + } + + /** + * Listen of file change + * + * @param array $params - hook params + */ + public static function fileUpdate($params) { + $filePath = $params[Filesystem::signal_param_path]; + if (empty($filePath)) { + return; + } + + $fileInfo = Filesystem::getFileInfo($filePath); + if ($fileInfo === false) { + return; + } + + $fileId = $fileInfo->getId(); + + KeyManager::delete($fileId); + + \OC::$server->getLogger()->debug("Hook fileUpdate " . json_encode($params), ["app" => self::$appName]); + } + + /** + * Erase versions of deleted file + * + * @param array $params - hook params + */ + public static function fileDelete($params) { + $filePath = $params[Filesystem::signal_param_path]; + if (empty($filePath)) { + return; + } + + try { + $ownerId = Filesystem::getOwner($filePath); + + $fileInfo = Filesystem::getFileInfo($filePath); + if ($fileInfo === false) { + return; + } + + $fileId = $fileInfo->getId(); + + KeyManager::delete($fileId, true); + + FileVersions::deleteAllVersions($ownerId, $fileId); + } catch (\Exception $e) { + \OC::$server->getLogger()->logException($e, ["message" => "Hook: fileDelete " . json_encode($params), "app" => self::$appName]); + } + } + + /** + * Erase versions of deleted version of file + * + * @param array $params - hook param + */ + public static function fileVersionDelete($params) { + $pathVersion = $params["path"]; + if (empty($pathVersion)) { + return; + } + + try { + list($filePath, $versionId) = FileVersions::splitPathVersion($pathVersion); + if (empty($filePath)) { + return; + } + + $ownerId = Filesystem::getOwner($filePath); + + $fileInfo = Filesystem::getFileInfo($filePath); + if ($fileInfo === false) { + return; + } + + $fileId = $fileInfo->getId(); + + FileVersions::deleteVersion($ownerId, $fileId, $versionId); + FileVersions::deleteAuthor($ownerId, $fileId, $versionId); + } catch (\Exception $e) { + \OC::$server->getLogger()->logException($e, ["message" => "Hook: fileVersionDelete " . json_encode($params), "app" => self::$appName]); + } + } + + /** + * Erase versions of restored version of file + * + * @param array $params - hook param + */ + public static function fileVersionRestore($params) { + $filePath = $params["path"]; + if (empty($filePath)) { + return; + } + + $versionId = $params["revision"]; + + try { + $ownerId = Filesystem::getOwner($filePath); + + $fileInfo = Filesystem::getFileInfo($filePath); + if ($fileInfo === false) { + return; + } + + $fileId = $fileInfo->getId(); + + KeyManager::delete($fileId); + + FileVersions::deleteVersion($ownerId, $fileId, $versionId); + } catch (\Exception $e) { + \OC::$server->getLogger()->logException($e, ["message" => "Hook: fileVersionRestore " . json_encode($params), "app" => self::$appName]); + } + } } diff --git a/lib/keymanager.php b/lib/keymanager.php index 1ab475c9..4cf4a0fa 100644 --- a/lib/keymanager.php +++ b/lib/keymanager.php @@ -25,125 +25,125 @@ * @package OCA\Onlyoffice */ class KeyManager { - /** - * Table name - */ - private const TableName_Key = "onlyoffice_filekey"; + /** + * Table name + */ + private const TableName_Key = "onlyoffice_filekey"; - /** - * Get document identifier - * - * @param integer $fileId - file identifier - * - * @return string - */ - public static function get($fileId) { - $connection = \OC::$server->getDatabaseConnection(); - $select = $connection->prepare(" + /** + * Get document identifier + * + * @param integer $fileId - file identifier + * + * @return string + */ + public static function get($fileId) { + $connection = \OC::$server->getDatabaseConnection(); + $select = $connection->prepare(" SELECT `key` FROM `*PREFIX*" . self::TableName_Key . "` WHERE `file_id` = ? "); - $result = $select->execute([$fileId]); + $result = $select->execute([$fileId]); - $keys = $result ? $select->fetch() : []; - $key = \is_array($keys) && isset($keys["key"]) ? $keys["key"] : ""; + $keys = $result ? $select->fetch() : []; + $key = \is_array($keys) && isset($keys["key"]) ? $keys["key"] : ""; - return $key; - } + return $key; + } - /** - * Store document identifier - * - * @param integer $fileId - file identifier - * @param integer $key - file key - * - * @return bool - */ - public static function set($fileId, $key) { - $connection = \OC::$server->getDatabaseConnection(); - $insert = $connection->prepare(" + /** + * Store document identifier + * + * @param integer $fileId - file identifier + * @param integer $key - file key + * + * @return bool + */ + public static function set($fileId, $key) { + $connection = \OC::$server->getDatabaseConnection(); + $insert = $connection->prepare(" INSERT INTO `*PREFIX*" . self::TableName_Key . "` (`file_id`, `key`) VALUES (?, ?) "); - return (bool)$insert->execute([$fileId, $key]); - } + return (bool)$insert->execute([$fileId, $key]); + } - /** - * Delete document identifier - * - * @param integer $fileId - file identifier - * @param bool $unlock - delete even with lock label - * - * @return bool - */ - public static function delete($fileId, $unlock = false) { - $connection = \OC::$server->getDatabaseConnection(); - $delete = $connection->prepare( - " + /** + * Delete document identifier + * + * @param integer $fileId - file identifier + * @param bool $unlock - delete even with lock label + * + * @return bool + */ + public static function delete($fileId, $unlock = false) { + $connection = \OC::$server->getDatabaseConnection(); + $delete = $connection->prepare( + " DELETE FROM `*PREFIX*" . self::TableName_Key . "` WHERE `file_id` = ? " . ($unlock === false ? "AND `lock` != 1" : "") - ); - return (bool)$delete->execute([$fileId]); - } + ); + return (bool)$delete->execute([$fileId]); + } - /** - * Change lock status - * - * @param integer $fileId - file identifier - * @param bool $lock - status - * - * @return bool - */ - public static function lock($fileId, $lock = true) { - $connection = \OC::$server->getDatabaseConnection(); - $update = $connection->prepare(" + /** + * Change lock status + * + * @param integer $fileId - file identifier + * @param bool $lock - status + * + * @return bool + */ + public static function lock($fileId, $lock = true) { + $connection = \OC::$server->getDatabaseConnection(); + $update = $connection->prepare(" UPDATE `*PREFIX*" . self::TableName_Key . "` SET `lock` = ? WHERE `file_id` = ? "); - return (bool)$update->execute([$lock === true ? 1 : 0, $fileId]); - } + return (bool)$update->execute([$lock === true ? 1 : 0, $fileId]); + } - /** - * Change forcesave status - * - * @param integer $fileId - file identifier - * @param bool $fs - status - * - * @return bool - */ - public static function setForcesave($fileId, $fs = true) { - $connection = \OC::$server->getDatabaseConnection(); - $update = $connection->prepare(" + /** + * Change forcesave status + * + * @param integer $fileId - file identifier + * @param bool $fs - status + * + * @return bool + */ + public static function setForcesave($fileId, $fs = true) { + $connection = \OC::$server->getDatabaseConnection(); + $update = $connection->prepare(" UPDATE `*PREFIX*" . self::TableName_Key . "` SET `fs` = ? WHERE `file_id` = ? "); - return (bool)$update->execute([$fs === true ? 1 : 0, $fileId]); - } + return (bool)$update->execute([$fs === true ? 1 : 0, $fileId]); + } - /** - * Get forcesave status - * - * @param integer $fileId - file identifier - * - * @return bool - */ - public static function wasForcesave($fileId) { - $connection = \OC::$server->getDatabaseConnection(); - $select = $connection->prepare(" + /** + * Get forcesave status + * + * @param integer $fileId - file identifier + * + * @return bool + */ + public static function wasForcesave($fileId) { + $connection = \OC::$server->getDatabaseConnection(); + $select = $connection->prepare(" SELECT `fs` FROM `*PREFIX*" . self::TableName_Key . "` WHERE `file_id` = ? "); - $result = $select->execute([$fileId]); + $result = $select->execute([$fileId]); - $rows = $result ? $select->fetch() : []; - $fs = \is_array($rows) && isset($rows["fs"]) ? $rows["fs"] : ""; + $rows = $result ? $select->fetch() : []; + $fs = \is_array($rows) && isset($rows["fs"]) ? $rows["fs"] : ""; - return $fs === "1"; - } + return $fs === "1"; + } } diff --git a/lib/notifier.php b/lib/notifier.php index 689a5b8d..ecdf1bbd 100644 --- a/lib/notifier.php +++ b/lib/notifier.php @@ -27,110 +27,110 @@ use OCP\Notification\INotifier; class Notifier implements INotifier { - /** - * Application name - * - * @var string - */ - private $appName; - - /** - * IFactory - * - * @var IFactory - */ - private $l10nFactory; - - /** - * Url generator service - * - * @var IURLGenerator - */ - private $urlGenerator; - - /** - * Logger - * - * @var ILogger - */ - private $logger; - - /** - * User manager - * - * @var IUserManager - */ - private $userManager; - - /** - * @param string $AppName - application name - * @param IFactory $l10NFactory - l10n - * @param IURLGenerator $urlGenerator - url generator service - * @param ILogger $logger - logger - * @param IUserManager $userManager - user manager - */ - public function __construct( - string $appName, - IFactory $l10nFactory, - IURLGenerator $urlGenerator, - ILogger $logger, - IUserManager $userManager - ) { - $this->appName = $appName; - $this->l10nFactory = $l10nFactory; - $this->urlGenerator = $urlGenerator; - $this->logger = $logger; - $this->userManager = $userManager; - } - - /** - * @param INotification $notification - notification object - * @param string $languageCode - the code of the language that should be used to prepare the notification - * - * @return INotification - */ - public function prepare($notification, $languageCode) { - if ($notification->getApp() !== $this->appName) { - throw new \InvalidArgumentException("Notification not from " . $this->appName); - } - - $parameters = $notification->getSubjectParameters(); - $trans = $this->l10nFactory->get($this->appName, $languageCode); - - switch ($notification->getObjectType()) { - case "editorsCheck": - $message = $trans->t("Please check the settings to resolve the problem."); - $appSettingsLink = $this->urlGenerator->getAbsoluteURL("/settings/admin?sectionid=additional"); - $notification->setLink($appSettingsLink); - $notification->setParsedSubject($notification->getObjectId()) - ->setIcon($this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath($this->appName, 'app-dark.svg'))); - $notification->setParsedMessage($message); - break; - case "mention": - $notifierId = $parameters["notifierId"]; - $fileId = $parameters["fileId"]; - $fileName = $parameters["fileName"]; - $anchor = $parameters["anchor"]; - - $this->logger->info("Notify prepare: from $notifierId about $fileId ", ["app" => $this->appName]); - - $notifier = $this->userManager->get($notifierId); - $notifierName = $notifier->getDisplayName(); - $trans = $this->l10nFactory->get($this->appName, $languageCode); - - $notification->setIcon($this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath($this->appName, "app-dark.svg"))); - $notification->setParsedSubject($trans->t("%1\$s mentioned in the %2\$s: \"%3\$s\".", [$notifierName, $fileName, $notification->getObjectId()])); - - $editorLink = $this->urlGenerator->linkToRouteAbsolute($this->appName . ".editor.index", [ - "fileId" => $fileId, - "anchor" => $anchor - ]); - - $notification->setLink($editorLink); - break; - default: - $this->logger->info("Unsupported notification object: ".$notification->getObjectType(), ["app" => $this->appName]); - } - return $notification; - } + /** + * Application name + * + * @var string + */ + private $appName; + + /** + * IFactory + * + * @var IFactory + */ + private $l10nFactory; + + /** + * Url generator service + * + * @var IURLGenerator + */ + private $urlGenerator; + + /** + * Logger + * + * @var ILogger + */ + private $logger; + + /** + * User manager + * + * @var IUserManager + */ + private $userManager; + + /** + * @param string $AppName - application name + * @param IFactory $l10NFactory - l10n + * @param IURLGenerator $urlGenerator - url generator service + * @param ILogger $logger - logger + * @param IUserManager $userManager - user manager + */ + public function __construct( + string $appName, + IFactory $l10nFactory, + IURLGenerator $urlGenerator, + ILogger $logger, + IUserManager $userManager + ) { + $this->appName = $appName; + $this->l10nFactory = $l10nFactory; + $this->urlGenerator = $urlGenerator; + $this->logger = $logger; + $this->userManager = $userManager; + } + + /** + * @param INotification $notification - notification object + * @param string $languageCode - the code of the language that should be used to prepare the notification + * + * @return INotification + */ + public function prepare($notification, $languageCode) { + if ($notification->getApp() !== $this->appName) { + throw new \InvalidArgumentException("Notification not from " . $this->appName); + } + + $parameters = $notification->getSubjectParameters(); + $trans = $this->l10nFactory->get($this->appName, $languageCode); + + switch ($notification->getObjectType()) { + case "editorsCheck": + $message = $trans->t("Please check the settings to resolve the problem."); + $appSettingsLink = $this->urlGenerator->getAbsoluteURL("/settings/admin?sectionid=additional"); + $notification->setLink($appSettingsLink); + $notification->setParsedSubject($notification->getObjectId()) + ->setIcon($this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath($this->appName, 'app-dark.svg'))); + $notification->setParsedMessage($message); + break; + case "mention": + $notifierId = $parameters["notifierId"]; + $fileId = $parameters["fileId"]; + $fileName = $parameters["fileName"]; + $anchor = $parameters["anchor"]; + + $this->logger->info("Notify prepare: from $notifierId about $fileId ", ["app" => $this->appName]); + + $notifier = $this->userManager->get($notifierId); + $notifierName = $notifier->getDisplayName(); + $trans = $this->l10nFactory->get($this->appName, $languageCode); + + $notification->setIcon($this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath($this->appName, "app-dark.svg"))); + $notification->setParsedSubject($trans->t("%1\$s mentioned in the %2\$s: \"%3\$s\".", [$notifierName, $fileName, $notification->getObjectId()])); + + $editorLink = $this->urlGenerator->linkToRouteAbsolute($this->appName . ".editor.index", [ + "fileId" => $fileId, + "anchor" => $anchor + ]); + + $notification->setLink($editorLink); + break; + default: + $this->logger->info("Unsupported notification object: ".$notification->getObjectType(), ["app" => $this->appName]); + } + return $notification; + } } diff --git a/lib/preview.php b/lib/preview.php index 86e7444f..585a61b6 100644 --- a/lib/preview.php +++ b/lib/preview.php @@ -45,349 +45,349 @@ * @package OCA\Onlyoffice */ class Preview implements IProvider2 { - /** - * Application name - * - * @var string - */ - private $appName; - - /** - * Root folder - * - * @var IRootFolder - */ - private $root; - - /** - * User manager - * - * @var IUserManager - */ - private $userManager; - - /** - * Logger - * - * @var ILogger - */ - private $logger; - - /** - * l10n service - * - * @var IL10N - */ - private $trans; - - /** - * Application configuration - * - * @var AppConfig - */ - private $config; - - /** - * Url generator service - * - * @var IURLGenerator - */ - private $urlGenerator; - - /** - * Hash generator - * - * @var Crypt - */ - private $crypt; - - /** - * File version manager - * - * @var VersionManager - */ - private $versionManager; - - /** - * File utility - * - * @var FileUtility - */ - private $fileUtility; - - /** - * Capabilities mimetype - * - * @var Array - */ - public static $capabilities = [ - "text/csv", - "application/msword", - "application/vnd.ms-word.document.macroEnabled.12", - "application/vnd.openxmlformats-officedocument.wordprocessingml.document", - "application/vnd.openxmlformats-officedocument.wordprocessingml.document.docxf", - "application/vnd.openxmlformats-officedocument.wordprocessingml.document.oform", - "application/vnd.openxmlformats-officedocument.wordprocessingml.template", - "application/epub+zip", - "text/html", - "application/vnd.oasis.opendocument.presentation", - "application/vnd.oasis.opendocument.spreadsheet", - "application/vnd.oasis.opendocument.text", - "application/vnd.oasis.opendocument.presentation-template", - "application/vnd.oasis.opendocument.spreadsheet-template", - "application/vnd.oasis.opendocument.text-template", - "application/pdf", - "application/vnd.ms-powerpoint.template.macroEnabled.12", - "application/vnd.openxmlformats-officedocument.presentationml.template", - "application/vnd.ms-powerpoint.slideshow.macroEnabled.12", - "application/vnd.openxmlformats-officedocument.presentationml.slideshow", - "application/vnd.ms-powerpoint", - "application/vnd.ms-powerpoint.presentation.macroEnabled.12", - "application/vnd.openxmlformats-officedocument.presentationml.presentation", - "text/rtf", - "text/plain", - "application/vnd.ms-excel", - "application/vnd.ms-excel.sheet.macroEnabled.12", - "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", - "application/vnd.ms-excel.template.macroEnabled.12", - "application/vnd.openxmlformats-officedocument.spreadsheetml.template" - ]; - - /** - * Converted thumbnail format - */ - private const thumbExtension = "jpeg"; - - /** - * @param string $appName - application name - * @param IRootFolder $root - root folder - * @param ILogger $logger - logger - * @param IL10N $trans - l10n service - * @param AppConfig $config - application configuration - * @param IURLGenerator $urlGenerator - url generator service - * @param Crypt $crypt - hash generator - * @param IManager $shareManager - share manager - * @param ISession $session - session - * @param IUserManager $userManager - user manager - */ - public function __construct( - string $appName, - IRootFolder $root, - ILogger $logger, - IL10N $trans, - AppConfig $config, - IURLGenerator $urlGenerator, - Crypt $crypt, - IManager $shareManager, - ISession $session, - IUserManager $userManager - ) { - $this->appName = $appName; - $this->root = $root; - $this->logger = $logger; - $this->trans = $trans; - $this->config = $config; - $this->urlGenerator = $urlGenerator; - $this->crypt = $crypt; - $this->userManager = $userManager; - - $this->versionManager = new VersionManager($appName, $root); - - $this->fileUtility = new FileUtility($appName, $trans, $logger, $config, $shareManager, $session); - } - - /** - * Return mime type - */ - public static function getMimeTypeRegex() { - $mimeTypeRegex = ""; - foreach (self::$capabilities as $format) { - if (!empty($mimeTypeRegex)) { - $mimeTypeRegex = $mimeTypeRegex . "|"; - } - $mimeTypeRegex = $mimeTypeRegex . str_replace("/", "\/", $format); - } - $mimeTypeRegex = "/" . $mimeTypeRegex . "/"; - - return $mimeTypeRegex; - } - - /** - * Return mime type - */ - public function getMimeType() { - $m = self::getMimeTypeRegex(); - return $m; - } - - /** - * The method checks if the file can be converted - * - * @param FileInfo $fileInfo - File - * - * @return bool - */ - public function isAvailable(FileInfo $fileInfo) { - if ($this->config->GetPreview() !== true) { - return false; - } - if (!$fileInfo - || $fileInfo->getSize() === 0 - || $fileInfo->getSize() > $this->config->GetLimitThumbSize()) { - return false; - } - if (!\in_array($fileInfo->getMimetype(), self::$capabilities, true)) { - return false; - } - return true; - } - - /** - * The method is generated thumbnail for file and returned image object - * - * @param File $file - file - * @param int $maxX - The maximum X size of the thumbnail - * @param int $maxY - The maximum Y size of the thumbnail - * @param bool $scalingup - Disable/Enable upscaling of previews - * - * @return Image|bool false if no preview was generated - */ - public function getThumbnail($file, $maxX, $maxY, $scalingup) { - if (empty($file)) { - $this->logger->error("getThumbnail is impossible. File is null", ["app" => $this->appName]); - return false; - } - - $this->logger->debug("getThumbnail " . $file->getPath() . " $maxX $maxY", ["app" => $this->appName]); - - list($fileUrl, $extension, $key) = $this->getFileParam($file); - if ($fileUrl === null || $extension === null || $key === null) { - return false; - } - - $imageUrl = null; - $documentService = new DocumentService($this->trans, $this->config); - try { - $imageUrl = $documentService->GetConvertedUri($fileUrl, $extension, self::thumbExtension, $key); - } catch (\Exception $e) { - $this->logger->logException($e, ["message" => "GetConvertedUri: from $extension to " . self::thumbExtension, "app" => $this->appName]); - return false; - } - - try { - $thumbnail = $documentService->Request($imageUrl); - } catch (\Exception $e) { - $this->logger->logException($e, ["message" => "Failed to download thumbnail", "app" => $this->appName]); - return false; - } - - $image = new Image(); - $image->loadFromData($thumbnail); - - if ($image->valid()) { - $image->scaleDownToFit($maxX, $maxY); - return $image; - } - - return false; - } - - /** - * Generate secure link to download document - * - * @param File $file - file - * @param IUser $user - user with access - * @param int $version - file version - * - * @return string - */ - private function getUrl($file, $user = null, $version = 0) { - $data = [ - "action" => "download", - "fileId" => $file->getId() - ]; - - $userId = null; - if (!empty($user)) { - $userId = $user->getUID(); - $data["userId"] = $userId; - } - if ($version > 0) { - $data["version"] = $version; - } - - $hashUrl = $this->crypt->GetHash($data); - - $fileUrl = $this->urlGenerator->linkToRouteAbsolute($this->appName . ".callback.download", ["doc" => $hashUrl]); - - if (!$this->config->UseDemo() && !empty($this->config->GetStorageUrl())) { - $fileUrl = str_replace($this->urlGenerator->getAbsoluteURL("/"), $this->config->GetStorageUrl(), $fileUrl); - } - - return $fileUrl; - } - - /** - * Generate array with file parameters - * - * @param File $file - file - * - * @return array - */ - private function getFileParam($file) { - if ($file->getSize() === 0) { - return [null, null, null]; - } - - $key = null; - $versionNum = 0; - if ($file instanceof MetaFileVersionNode) { - if ($this->versionManager->available !== true) { - return [null, null, null]; - } - - $fileVersion = $file->getName(); - $sourceFileId = $file->getId(); - - $storage = $file->getStorage(); - $path = $file->getContentDispositionFileName(); - - $ownerId = $storage->getOwner($path); - $owner = $this->userManager->get($ownerId); - if ($owner === null) { - return [null, null, null]; - } - - $files = $this->root->getUserFolder($ownerId)->getById($sourceFileId); - if (empty($files)) { - return [null, null, null]; - } - $file = $files[0]; - - $versions = array_reverse($this->versionManager->getVersionsForFile($owner, $file->getFileInfo())); - - foreach ($versions as $version) { - $versionNum = $versionNum + 1; - - $versionId = $version->getRevisionId(); - if (strcmp($versionId, $fileVersion) === 0) { - $key = $this->fileUtility->getVersionKey($version); - $key = DocumentService::GenerateRevisionId($key); - - break; - } - } - } else { - $owner = $file->getOwner(); - - $key = $this->fileUtility->getKey($file); - $key = DocumentService::GenerateRevisionId($key); - } - - $fileUrl = $this->getUrl($file, $owner, $versionNum); - - $fileExtension = strtolower(pathinfo($file->getName(), PATHINFO_EXTENSION)); - - return [$fileUrl, $fileExtension, $key]; - } + /** + * Application name + * + * @var string + */ + private $appName; + + /** + * Root folder + * + * @var IRootFolder + */ + private $root; + + /** + * User manager + * + * @var IUserManager + */ + private $userManager; + + /** + * Logger + * + * @var ILogger + */ + private $logger; + + /** + * l10n service + * + * @var IL10N + */ + private $trans; + + /** + * Application configuration + * + * @var AppConfig + */ + private $config; + + /** + * Url generator service + * + * @var IURLGenerator + */ + private $urlGenerator; + + /** + * Hash generator + * + * @var Crypt + */ + private $crypt; + + /** + * File version manager + * + * @var VersionManager + */ + private $versionManager; + + /** + * File utility + * + * @var FileUtility + */ + private $fileUtility; + + /** + * Capabilities mimetype + * + * @var Array + */ + public static $capabilities = [ + "text/csv", + "application/msword", + "application/vnd.ms-word.document.macroEnabled.12", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document.docxf", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document.oform", + "application/vnd.openxmlformats-officedocument.wordprocessingml.template", + "application/epub+zip", + "text/html", + "application/vnd.oasis.opendocument.presentation", + "application/vnd.oasis.opendocument.spreadsheet", + "application/vnd.oasis.opendocument.text", + "application/vnd.oasis.opendocument.presentation-template", + "application/vnd.oasis.opendocument.spreadsheet-template", + "application/vnd.oasis.opendocument.text-template", + "application/pdf", + "application/vnd.ms-powerpoint.template.macroEnabled.12", + "application/vnd.openxmlformats-officedocument.presentationml.template", + "application/vnd.ms-powerpoint.slideshow.macroEnabled.12", + "application/vnd.openxmlformats-officedocument.presentationml.slideshow", + "application/vnd.ms-powerpoint", + "application/vnd.ms-powerpoint.presentation.macroEnabled.12", + "application/vnd.openxmlformats-officedocument.presentationml.presentation", + "text/rtf", + "text/plain", + "application/vnd.ms-excel", + "application/vnd.ms-excel.sheet.macroEnabled.12", + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + "application/vnd.ms-excel.template.macroEnabled.12", + "application/vnd.openxmlformats-officedocument.spreadsheetml.template" + ]; + + /** + * Converted thumbnail format + */ + private const thumbExtension = "jpeg"; + + /** + * @param string $appName - application name + * @param IRootFolder $root - root folder + * @param ILogger $logger - logger + * @param IL10N $trans - l10n service + * @param AppConfig $config - application configuration + * @param IURLGenerator $urlGenerator - url generator service + * @param Crypt $crypt - hash generator + * @param IManager $shareManager - share manager + * @param ISession $session - session + * @param IUserManager $userManager - user manager + */ + public function __construct( + string $appName, + IRootFolder $root, + ILogger $logger, + IL10N $trans, + AppConfig $config, + IURLGenerator $urlGenerator, + Crypt $crypt, + IManager $shareManager, + ISession $session, + IUserManager $userManager + ) { + $this->appName = $appName; + $this->root = $root; + $this->logger = $logger; + $this->trans = $trans; + $this->config = $config; + $this->urlGenerator = $urlGenerator; + $this->crypt = $crypt; + $this->userManager = $userManager; + + $this->versionManager = new VersionManager($appName, $root); + + $this->fileUtility = new FileUtility($appName, $trans, $logger, $config, $shareManager, $session); + } + + /** + * Return mime type + */ + public static function getMimeTypeRegex() { + $mimeTypeRegex = ""; + foreach (self::$capabilities as $format) { + if (!empty($mimeTypeRegex)) { + $mimeTypeRegex = $mimeTypeRegex . "|"; + } + $mimeTypeRegex = $mimeTypeRegex . str_replace("/", "\/", $format); + } + $mimeTypeRegex = "/" . $mimeTypeRegex . "/"; + + return $mimeTypeRegex; + } + + /** + * Return mime type + */ + public function getMimeType() { + $m = self::getMimeTypeRegex(); + return $m; + } + + /** + * The method checks if the file can be converted + * + * @param FileInfo $fileInfo - File + * + * @return bool + */ + public function isAvailable(FileInfo $fileInfo) { + if ($this->config->GetPreview() !== true) { + return false; + } + if (!$fileInfo + || $fileInfo->getSize() === 0 + || $fileInfo->getSize() > $this->config->GetLimitThumbSize()) { + return false; + } + if (!\in_array($fileInfo->getMimetype(), self::$capabilities, true)) { + return false; + } + return true; + } + + /** + * The method is generated thumbnail for file and returned image object + * + * @param File $file - file + * @param int $maxX - The maximum X size of the thumbnail + * @param int $maxY - The maximum Y size of the thumbnail + * @param bool $scalingup - Disable/Enable upscaling of previews + * + * @return Image|bool false if no preview was generated + */ + public function getThumbnail($file, $maxX, $maxY, $scalingup) { + if (empty($file)) { + $this->logger->error("getThumbnail is impossible. File is null", ["app" => $this->appName]); + return false; + } + + $this->logger->debug("getThumbnail " . $file->getPath() . " $maxX $maxY", ["app" => $this->appName]); + + list($fileUrl, $extension, $key) = $this->getFileParam($file); + if ($fileUrl === null || $extension === null || $key === null) { + return false; + } + + $imageUrl = null; + $documentService = new DocumentService($this->trans, $this->config); + try { + $imageUrl = $documentService->GetConvertedUri($fileUrl, $extension, self::thumbExtension, $key); + } catch (\Exception $e) { + $this->logger->logException($e, ["message" => "GetConvertedUri: from $extension to " . self::thumbExtension, "app" => $this->appName]); + return false; + } + + try { + $thumbnail = $documentService->Request($imageUrl); + } catch (\Exception $e) { + $this->logger->logException($e, ["message" => "Failed to download thumbnail", "app" => $this->appName]); + return false; + } + + $image = new Image(); + $image->loadFromData($thumbnail); + + if ($image->valid()) { + $image->scaleDownToFit($maxX, $maxY); + return $image; + } + + return false; + } + + /** + * Generate secure link to download document + * + * @param File $file - file + * @param IUser $user - user with access + * @param int $version - file version + * + * @return string + */ + private function getUrl($file, $user = null, $version = 0) { + $data = [ + "action" => "download", + "fileId" => $file->getId() + ]; + + $userId = null; + if (!empty($user)) { + $userId = $user->getUID(); + $data["userId"] = $userId; + } + if ($version > 0) { + $data["version"] = $version; + } + + $hashUrl = $this->crypt->GetHash($data); + + $fileUrl = $this->urlGenerator->linkToRouteAbsolute($this->appName . ".callback.download", ["doc" => $hashUrl]); + + if (!$this->config->UseDemo() && !empty($this->config->GetStorageUrl())) { + $fileUrl = str_replace($this->urlGenerator->getAbsoluteURL("/"), $this->config->GetStorageUrl(), $fileUrl); + } + + return $fileUrl; + } + + /** + * Generate array with file parameters + * + * @param File $file - file + * + * @return array + */ + private function getFileParam($file) { + if ($file->getSize() === 0) { + return [null, null, null]; + } + + $key = null; + $versionNum = 0; + if ($file instanceof MetaFileVersionNode) { + if ($this->versionManager->available !== true) { + return [null, null, null]; + } + + $fileVersion = $file->getName(); + $sourceFileId = $file->getId(); + + $storage = $file->getStorage(); + $path = $file->getContentDispositionFileName(); + + $ownerId = $storage->getOwner($path); + $owner = $this->userManager->get($ownerId); + if ($owner === null) { + return [null, null, null]; + } + + $files = $this->root->getUserFolder($ownerId)->getById($sourceFileId); + if (empty($files)) { + return [null, null, null]; + } + $file = $files[0]; + + $versions = array_reverse($this->versionManager->getVersionsForFile($owner, $file->getFileInfo())); + + foreach ($versions as $version) { + $versionNum = $versionNum + 1; + + $versionId = $version->getRevisionId(); + if (strcmp($versionId, $fileVersion) === 0) { + $key = $this->fileUtility->getVersionKey($version); + $key = DocumentService::GenerateRevisionId($key); + + break; + } + } + } else { + $owner = $file->getOwner(); + + $key = $this->fileUtility->getKey($file); + $key = DocumentService::GenerateRevisionId($key); + } + + $fileUrl = $this->getUrl($file, $owner, $versionNum); + + $fileExtension = strtolower(pathinfo($file->getName(), PATHINFO_EXTENSION)); + + return [$fileUrl, $fileExtension, $key]; + } } diff --git a/lib/remoteinstance.php b/lib/remoteinstance.php index 0d5c00db..8952667c 100644 --- a/lib/remoteinstance.php +++ b/lib/remoteinstance.php @@ -29,254 +29,254 @@ * @package OCA\Onlyoffice */ class RemoteInstance { - /** - * App name - */ - private const App_Name = "onlyoffice"; - - /** - * Table name - */ - private const TableName_Key = "onlyoffice_instance"; - - /** - * Time to live of remote instance (12 hours) - */ - private static $ttl = 60 * 60 * 12; - - /** - * Health remote list - */ - private static $healthRemote = []; - - /** - * Get remote instance - * - * @param string $remote - remote instance - * - * @return array - */ - private static function get($remote) { - $connection = \OC::$server->getDatabaseConnection(); - $select = $connection->prepare(" + /** + * App name + */ + private const App_Name = "onlyoffice"; + + /** + * Table name + */ + private const TableName_Key = "onlyoffice_instance"; + + /** + * Time to live of remote instance (12 hours) + */ + private static $ttl = 60 * 60 * 12; + + /** + * Health remote list + */ + private static $healthRemote = []; + + /** + * Get remote instance + * + * @param string $remote - remote instance + * + * @return array + */ + private static function get($remote) { + $connection = \OC::$server->getDatabaseConnection(); + $select = $connection->prepare(" SELECT remote, expire, status FROM `*PREFIX*" . self::TableName_Key . "` WHERE `remote` = ? "); - $result = $select->execute([$remote]); - - $dbremote = $result ? $select->fetch() : []; - - return $dbremote; - } - - /** - * Store remote instance - * - * @param string $remote - remote instance - * @param bool $status - remote status - * - * @return bool - */ - private static function set($remote, $status) { - $connection = \OC::$server->getDatabaseConnection(); - $insert = $connection->prepare(" + $result = $select->execute([$remote]); + + $dbremote = $result ? $select->fetch() : []; + + return $dbremote; + } + + /** + * Store remote instance + * + * @param string $remote - remote instance + * @param bool $status - remote status + * + * @return bool + */ + private static function set($remote, $status) { + $connection = \OC::$server->getDatabaseConnection(); + $insert = $connection->prepare(" INSERT INTO `*PREFIX*" . self::TableName_Key . "` (`remote`, `status`, `expire`) VALUES (?, ?, ?) "); - return (bool)$insert->execute([$remote, $status === true ? 1 : 0, time()]); - } - - /** - * Update remote instance - * - * @param string $remote - remote instance - * @param bool $status - remote status - * - * @return bool - */ - private static function update($remote, $status) { - $connection = \OC::$server->getDatabaseConnection(); - $update = $connection->prepare(" + return (bool)$insert->execute([$remote, $status === true ? 1 : 0, time()]); + } + + /** + * Update remote instance + * + * @param string $remote - remote instance + * @param bool $status - remote status + * + * @return bool + */ + private static function update($remote, $status) { + $connection = \OC::$server->getDatabaseConnection(); + $update = $connection->prepare(" UPDATE `*PREFIX*" . self::TableName_Key . "` SET status = ?, expire = ? WHERE remote = ? "); - return (bool)$update->execute([$status === true ? 1 : 0, time(), $remote]); - } - - /** - * Health check remote instance - * - * @param string $remote - remote instance - * - * @return bool - */ - public static function healthCheck($remote) { - $logger = \OC::$server->getLogger(); - $remote = rtrim($remote, "/") . "/"; - - if (\in_array($remote, self::$healthRemote)) { - $logger->debug("Remote instance " . $remote . " from local cache status " . $dbremote["status"], ["app" => self::App_Name]); - return true; - } - - $dbremote = self::get($remote); - if (!empty($dbremote) && $dbremote["expire"] + self::$ttl > time()) { - $logger->debug("Remote instance " . $remote . " from database status " . $dbremote["status"], ["app" => self::App_Name]); - self::$healthRemote[$remote] = $dbremote["status"]; - return self::$healthRemote[$remote]; - } - - $httpClientService = \OC::$server->getHTTPClientService(); - $client = $httpClientService->newClient(); - - $status = false; - try { - $response = $client->get($remote . "ocs/v2.php/apps/" . self::App_Name . "/api/v1/healthcheck?format=json"); - $body = json_decode($response->getBody(), true); - - $data = $body["ocs"]["data"]; - if (isset($data["alive"])) { - $status = $data["alive"] === true; - } - } catch (\Exception $e) { - $logger->logException($e, ["message" => "Failed to request federated health check for" . $remote, "app" => self::App_Name]); - } - - if (empty($dbremote)) { - self::set($remote, $status); - } else { - self::update($remote, $status); - } - - $logger->debug("Remote instance " . $remote . " was stored to database status " . $dbremote["status"], ["app" => self::App_Name]); - - self::$healthRemote[$remote] = $status; - - return self::$healthRemote[$remote]; - } - - /** - * Generate unique document identifier in federated share - * - * @param File $file - file - * - * @return string - */ - public function getRemoteKey($file) { - $logger = \OC::$server->getLogger(); - - $remote = $file->getStorage()->getRemote(); - $shareToken = $file->getStorage()->getToken(); - $internalPath = $file->getInternalPath(); - - $httpClientService = \OC::$server->getHTTPClientService(); - $client = $httpClientService->newClient(); - - try { - $response = $client->post($remote . "/ocs/v2.php/apps/" . self::App_Name . "/api/v1/key?format=json", [ - "timeout" => 5, - "json" => [ - "shareToken" => $shareToken, - "path" => $internalPath - ] - ]); - - $body = \json_decode($response->getBody(), true); - - $data = $body["ocs"]["data"]; - if (!empty($data["error"])) { - $logger->error("Error federated key " . $data["error"], ["app" => self::App_Name]); - return null; - } - - $key = $data["key"]; - $logger->debug("Federated key: $key", ["app" => self::App_Name]); - - return $key; - } catch (\Exception $e) { - $logger->logException($e, ["message" => "Failed to request federated key " . $file->getId(), "app" => self::App_Name]); - - if ($e->getResponse()->getStatusCode() === 404) { - self::update($remote, false); - $logger->debug("Changed status for remote instance $remote to false", ["app" => self::App_Name]); - } - - return null; - } - } - - /** - * Change lock status in the federated share - * - * @param File $file - file - * @param bool $lock - status - * @param bool $fs - status - * - * @return bool - */ - public static function lockRemoteKey($file, $lock, $fs) { - $logger = \OC::$server->getLogger(); - $action = $lock ? "lock" : "unlock"; - - $remote = $file->getStorage()->getRemote(); - $shareToken = $file->getStorage()->getToken(); - $internalPath = $file->getInternalPath(); - - $httpClientService = \OC::$server->getHTTPClientService(); - $client = $httpClientService->newClient(); - $data = [ - "timeout" => 5, - "json" => [ - "shareToken" => $shareToken, - "path" => $internalPath, - "lock" => $lock - ] - ]; - if (!empty($fs)) { - $data["json"]["fs"] = $fs; - } - - try { - $response = $client->post($remote . "/ocs/v2.php/apps/" . self::App_Name . "/api/v1/keylock?format=json", $data); - $body = \json_decode($response->getBody(), true); - - $data = $body["ocs"]["data"]; - - if (empty($data)) { - $logger->debug("Federated request" . $action . "for " . $file->getFileInfo()->getId() . " is successful", ["app" => self::App_Name]); - return true; - } - - if (!empty($data["error"])) { - $logger->error("Error" . $action . "federated key for " . $file->getFileInfo()->getId() . ": " . $data["error"], ["app" => self::App_Name]); - return false; - } - } catch(\Exception $e) { - $logger->logException($e, ["message" => "Failed to request federated " . $action . " for " . $file->getFileInfo()->getId(), "app" => self::App_Name]); - return false; - } - } - - /** - * Check of federated capable - * - * @param File $file - file - * - * @return bool - */ - public static function isRemoteFile($file) { - $storage = $file->getStorage(); - - $alive = false; - $isFederated = $storage->instanceOfStorage(SharingExternalStorage::class); - if (!$isFederated) { - return false; - } - - $alive = RemoteInstance::healthCheck($storage->getRemote()); - return $alive; - } + return (bool)$update->execute([$status === true ? 1 : 0, time(), $remote]); + } + + /** + * Health check remote instance + * + * @param string $remote - remote instance + * + * @return bool + */ + public static function healthCheck($remote) { + $logger = \OC::$server->getLogger(); + $remote = rtrim($remote, "/") . "/"; + + if (\in_array($remote, self::$healthRemote)) { + $logger->debug("Remote instance " . $remote . " from local cache status " . $dbremote["status"], ["app" => self::App_Name]); + return true; + } + + $dbremote = self::get($remote); + if (!empty($dbremote) && $dbremote["expire"] + self::$ttl > time()) { + $logger->debug("Remote instance " . $remote . " from database status " . $dbremote["status"], ["app" => self::App_Name]); + self::$healthRemote[$remote] = $dbremote["status"]; + return self::$healthRemote[$remote]; + } + + $httpClientService = \OC::$server->getHTTPClientService(); + $client = $httpClientService->newClient(); + + $status = false; + try { + $response = $client->get($remote . "ocs/v2.php/apps/" . self::App_Name . "/api/v1/healthcheck?format=json"); + $body = json_decode($response->getBody(), true); + + $data = $body["ocs"]["data"]; + if (isset($data["alive"])) { + $status = $data["alive"] === true; + } + } catch (\Exception $e) { + $logger->logException($e, ["message" => "Failed to request federated health check for" . $remote, "app" => self::App_Name]); + } + + if (empty($dbremote)) { + self::set($remote, $status); + } else { + self::update($remote, $status); + } + + $logger->debug("Remote instance " . $remote . " was stored to database status " . $dbremote["status"], ["app" => self::App_Name]); + + self::$healthRemote[$remote] = $status; + + return self::$healthRemote[$remote]; + } + + /** + * Generate unique document identifier in federated share + * + * @param File $file - file + * + * @return string + */ + public function getRemoteKey($file) { + $logger = \OC::$server->getLogger(); + + $remote = $file->getStorage()->getRemote(); + $shareToken = $file->getStorage()->getToken(); + $internalPath = $file->getInternalPath(); + + $httpClientService = \OC::$server->getHTTPClientService(); + $client = $httpClientService->newClient(); + + try { + $response = $client->post($remote . "/ocs/v2.php/apps/" . self::App_Name . "/api/v1/key?format=json", [ + "timeout" => 5, + "json" => [ + "shareToken" => $shareToken, + "path" => $internalPath + ] + ]); + + $body = \json_decode($response->getBody(), true); + + $data = $body["ocs"]["data"]; + if (!empty($data["error"])) { + $logger->error("Error federated key " . $data["error"], ["app" => self::App_Name]); + return null; + } + + $key = $data["key"]; + $logger->debug("Federated key: $key", ["app" => self::App_Name]); + + return $key; + } catch (\Exception $e) { + $logger->logException($e, ["message" => "Failed to request federated key " . $file->getId(), "app" => self::App_Name]); + + if ($e->getResponse()->getStatusCode() === 404) { + self::update($remote, false); + $logger->debug("Changed status for remote instance $remote to false", ["app" => self::App_Name]); + } + + return null; + } + } + + /** + * Change lock status in the federated share + * + * @param File $file - file + * @param bool $lock - status + * @param bool $fs - status + * + * @return bool + */ + public static function lockRemoteKey($file, $lock, $fs) { + $logger = \OC::$server->getLogger(); + $action = $lock ? "lock" : "unlock"; + + $remote = $file->getStorage()->getRemote(); + $shareToken = $file->getStorage()->getToken(); + $internalPath = $file->getInternalPath(); + + $httpClientService = \OC::$server->getHTTPClientService(); + $client = $httpClientService->newClient(); + $data = [ + "timeout" => 5, + "json" => [ + "shareToken" => $shareToken, + "path" => $internalPath, + "lock" => $lock + ] + ]; + if (!empty($fs)) { + $data["json"]["fs"] = $fs; + } + + try { + $response = $client->post($remote . "/ocs/v2.php/apps/" . self::App_Name . "/api/v1/keylock?format=json", $data); + $body = \json_decode($response->getBody(), true); + + $data = $body["ocs"]["data"]; + + if (empty($data)) { + $logger->debug("Federated request" . $action . "for " . $file->getFileInfo()->getId() . " is successful", ["app" => self::App_Name]); + return true; + } + + if (!empty($data["error"])) { + $logger->error("Error" . $action . "federated key for " . $file->getFileInfo()->getId() . ": " . $data["error"], ["app" => self::App_Name]); + return false; + } + } catch(\Exception $e) { + $logger->logException($e, ["message" => "Failed to request federated " . $action . " for " . $file->getFileInfo()->getId(), "app" => self::App_Name]); + return false; + } + } + + /** + * Check of federated capable + * + * @param File $file - file + * + * @return bool + */ + public static function isRemoteFile($file) { + $storage = $file->getStorage(); + + $alive = false; + $isFederated = $storage->instanceOfStorage(SharingExternalStorage::class); + if (!$isFederated) { + return false; + } + + $alive = RemoteInstance::healthCheck($storage->getRemote()); + return $alive; + } } diff --git a/lib/templatemanager.php b/lib/templatemanager.php index c90a9e4f..16e35515 100644 --- a/lib/templatemanager.php +++ b/lib/templatemanager.php @@ -28,190 +28,190 @@ * @package OCA\Onlyoffice */ class TemplateManager { - /** - * Application name - * - * @var string - */ - private static $appName = "onlyoffice"; - - /** - * Template folder name - * - * @var string - */ - private static $templateFolderName = "template"; - - /** - * Get global template directory - * - * @return Folder - */ - public static function GetGlobalTemplateDir() { - $dirPath = self::$appName . "/" . self::$templateFolderName; - - $rootFolder = \OC::$server->getRootFolder(); - $templateDir = null; - try { - $templateDir = $rootFolder->get($dirPath); - } catch (NotFoundException $e) { - $templateDir = $rootFolder->newFolder($dirPath); - } - - return $templateDir; - } - - /** - * Get global templates - * - * @param string $mimetype - mimetype of the template - * - * @return array - */ - public static function GetGlobalTemplates($mimetype = null) { - $templateDir = self::GetGlobalTemplateDir(); - - $templatesList = $templateDir->getDirectoryListing(); - if (!empty($mimetype) - && \is_array($templatesList) && \count($templatesList) > 0) { - $templatesList = $templateDir->searchByMime($mimetype); - } - - return $templatesList; - } - - /** - * Get template file - * - * @param string $templateId - identifier file template - * - * @return File - */ - public static function GetTemplate($templateId) { - $logger = \OC::$server->getLogger(); - - $templateDir = self::GetGlobalTemplateDir(); - try { - $templates = $templateDir->getById($templateId); - } catch(\Exception $e) { - $logger->logException($e, ["message" => "GetTemplate: $templateId", "app" => self::$appName]); - return null; - } - - if (empty($templates)) { - $logger->info("Template not found: $templateId", ["app" => self::$appName]); - return null; - } - - return $templates[0]; - } - - /** - * Get type template from mimetype - * - * @param string $mime - mimetype - * - * @return string - */ - public static function GetTypeTemplate($mime) { - switch($mime) { - case "application/vnd.openxmlformats-officedocument.wordprocessingml.document": - return "document"; - case "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": - return "spreadsheet"; - case "application/vnd.openxmlformats-officedocument.presentationml.presentation": - return "presentation"; - } - - return ""; - } - - /** - * Check template type - * - * @param string $name - template name - * - * @return bool - */ - public static function IsTemplateType($name) { - $ext = strtolower(pathinfo($name, PATHINFO_EXTENSION)); - switch($ext) { - case "docx": - case "xlsx": - case "pptx": - return true; - } - - return false; - } - - /** - * Get empty template content - * - * @param string $fileName - target file name - * - * @return string - */ - public static function GetEmptyTemplate($fileName) { - $ext = strtolower("." . pathinfo($fileName, PATHINFO_EXTENSION)); - $lang = \OC::$server->getL10NFactory("")->get("")->getLanguageCode(); - - $templatePath = self::GetEmptyTemplatePath($lang, $ext); - - $template = file_get_contents($templatePath); - return $template; - } - - /** - * Get template path - * - * @param string $lang - language - * @param string $ext - file extension - * - * @return string - */ - public static function GetEmptyTemplatePath($lang, $ext) { - if (!\array_key_exists($lang, self::$localPath)) { - $lang = "en"; - } - - return \dirname(__DIR__) . DIRECTORY_SEPARATOR . "assets" . DIRECTORY_SEPARATOR . self::$localPath[$lang] . DIRECTORY_SEPARATOR . "new" . $ext; - } - - /** - * Mapping local path to templates - * - * @var Array - */ - private static $localPath = [ - "az" => "az-Latn-AZ", - "bg_BG" => "bg-BG", - "cs" => "cs-CZ", - "de" => "de-DE", - "de_DE" => "de-DE", - "el" => "el-GR", - "en" => "en-US", - "en_GB" => "en-GB", - "es" => "es-ES", - "eu" => "eu-ES", - "fr" => "fr-FR", - "gl" => "gl-ES", - "it" => "it-IT", - "ja" => "ja-JP", - "ko" => "ko-KR", - "lv" => "lv-LV", - "nl" => "nl-NL", - "pl" => "pl-PL", - "pt_BR" => "pt-BR", - "pt_PT" => "pt-PT", - "ru" => "ru-RU", - "si_LK" => "si-LK", - "sk_SK" => "sk-SK", - "sv" => "sv-SE", - "tr" => "tr-TR", - "uk" => "uk-UA", - "vi" => "vi-VN", - "zh_CN" => "zh-CN", - "zh_TW" => "zh-TW" - ]; + /** + * Application name + * + * @var string + */ + private static $appName = "onlyoffice"; + + /** + * Template folder name + * + * @var string + */ + private static $templateFolderName = "template"; + + /** + * Get global template directory + * + * @return Folder + */ + public static function GetGlobalTemplateDir() { + $dirPath = self::$appName . "/" . self::$templateFolderName; + + $rootFolder = \OC::$server->getRootFolder(); + $templateDir = null; + try { + $templateDir = $rootFolder->get($dirPath); + } catch (NotFoundException $e) { + $templateDir = $rootFolder->newFolder($dirPath); + } + + return $templateDir; + } + + /** + * Get global templates + * + * @param string $mimetype - mimetype of the template + * + * @return array + */ + public static function GetGlobalTemplates($mimetype = null) { + $templateDir = self::GetGlobalTemplateDir(); + + $templatesList = $templateDir->getDirectoryListing(); + if (!empty($mimetype) + && \is_array($templatesList) && \count($templatesList) > 0) { + $templatesList = $templateDir->searchByMime($mimetype); + } + + return $templatesList; + } + + /** + * Get template file + * + * @param string $templateId - identifier file template + * + * @return File + */ + public static function GetTemplate($templateId) { + $logger = \OC::$server->getLogger(); + + $templateDir = self::GetGlobalTemplateDir(); + try { + $templates = $templateDir->getById($templateId); + } catch(\Exception $e) { + $logger->logException($e, ["message" => "GetTemplate: $templateId", "app" => self::$appName]); + return null; + } + + if (empty($templates)) { + $logger->info("Template not found: $templateId", ["app" => self::$appName]); + return null; + } + + return $templates[0]; + } + + /** + * Get type template from mimetype + * + * @param string $mime - mimetype + * + * @return string + */ + public static function GetTypeTemplate($mime) { + switch($mime) { + case "application/vnd.openxmlformats-officedocument.wordprocessingml.document": + return "document"; + case "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": + return "spreadsheet"; + case "application/vnd.openxmlformats-officedocument.presentationml.presentation": + return "presentation"; + } + + return ""; + } + + /** + * Check template type + * + * @param string $name - template name + * + * @return bool + */ + public static function IsTemplateType($name) { + $ext = strtolower(pathinfo($name, PATHINFO_EXTENSION)); + switch($ext) { + case "docx": + case "xlsx": + case "pptx": + return true; + } + + return false; + } + + /** + * Get empty template content + * + * @param string $fileName - target file name + * + * @return string + */ + public static function GetEmptyTemplate($fileName) { + $ext = strtolower("." . pathinfo($fileName, PATHINFO_EXTENSION)); + $lang = \OC::$server->getL10NFactory("")->get("")->getLanguageCode(); + + $templatePath = self::GetEmptyTemplatePath($lang, $ext); + + $template = file_get_contents($templatePath); + return $template; + } + + /** + * Get template path + * + * @param string $lang - language + * @param string $ext - file extension + * + * @return string + */ + public static function GetEmptyTemplatePath($lang, $ext) { + if (!\array_key_exists($lang, self::$localPath)) { + $lang = "en"; + } + + return \dirname(__DIR__) . DIRECTORY_SEPARATOR . "assets" . DIRECTORY_SEPARATOR . self::$localPath[$lang] . DIRECTORY_SEPARATOR . "new" . $ext; + } + + /** + * Mapping local path to templates + * + * @var Array + */ + private static $localPath = [ + "az" => "az-Latn-AZ", + "bg_BG" => "bg-BG", + "cs" => "cs-CZ", + "de" => "de-DE", + "de_DE" => "de-DE", + "el" => "el-GR", + "en" => "en-US", + "en_GB" => "en-GB", + "es" => "es-ES", + "eu" => "eu-ES", + "fr" => "fr-FR", + "gl" => "gl-ES", + "it" => "it-IT", + "ja" => "ja-JP", + "ko" => "ko-KR", + "lv" => "lv-LV", + "nl" => "nl-NL", + "pl" => "pl-PL", + "pt_BR" => "pt-BR", + "pt_PT" => "pt-PT", + "ru" => "ru-RU", + "si_LK" => "si-LK", + "sk_SK" => "sk-SK", + "sv" => "sv-SE", + "tr" => "tr-TR", + "uk" => "uk-UA", + "vi" => "vi-VN", + "zh_CN" => "zh-CN", + "zh_TW" => "zh-TW" + ]; } diff --git a/lib/version.php b/lib/version.php index c5a6f981..c89b894f 100644 --- a/lib/version.php +++ b/lib/version.php @@ -27,84 +27,84 @@ * @package OCA\Onlyoffice */ class Version { - /** - * Time of creation - * - * @var int - * */ - private $timestamp; + /** + * Time of creation + * + * @var int + * */ + private $timestamp; - /** - * Version file - * - * @var int|string - * */ - private $revisionId; + /** + * Version file + * + * @var int|string + * */ + private $revisionId; - /** - * File path - * - * @var string - * */ - private $path; + /** + * File path + * + * @var string + * */ + private $path; - /** - * Source file properties - * - * @var FileInfo - * */ - private $sourceFileInfo; + /** + * Source file properties + * + * @var FileInfo + * */ + private $sourceFileInfo; - /** - * @param int $timestamp - file time stamp - * @param int $revisionId - revision id - * @param FileInfo $sourceFileInfo - source file info - */ - public function __construct( - int $timestamp, - int $revisionId, - string $path, - FileInfo $sourceFileInfo - ) { - $this->timestamp = $timestamp; - $this->revisionId = $revisionId; - $this->path = $path; - $this->sourceFileInfo = $sourceFileInfo; - } + /** + * @param int $timestamp - file time stamp + * @param int $revisionId - revision id + * @param FileInfo $sourceFileInfo - source file info + */ + public function __construct( + int $timestamp, + int $revisionId, + string $path, + FileInfo $sourceFileInfo + ) { + $this->timestamp = $timestamp; + $this->revisionId = $revisionId; + $this->path = $path; + $this->sourceFileInfo = $sourceFileInfo; + } - /** - * Get source file - * - * @return FileInfo - */ - public function getSourceFile() { - return $this->sourceFileInfo; - } + /** + * Get source file + * + * @return FileInfo + */ + public function getSourceFile() { + return $this->sourceFileInfo; + } - /** - * Get version file - * - * @return int|string - */ - public function getRevisionId() { - return $this->revisionId; - } + /** + * Get version file + * + * @return int|string + */ + public function getRevisionId() { + return $this->revisionId; + } - /** - * Get timestamp file - * - * @return int - */ - public function getTimestamp() { - return $this->timestamp; - } + /** + * Get timestamp file + * + * @return int + */ + public function getTimestamp() { + return $this->timestamp; + } - /** - * Get file path - * - * @return string - */ - public function getPath() { - return $this->path; - } + /** + * Get file path + * + * @return string + */ + public function getPath() { + return $this->path; + } } diff --git a/lib/versionmanager.php b/lib/versionmanager.php index 6598afe4..f71a9230 100644 --- a/lib/versionmanager.php +++ b/lib/versionmanager.php @@ -36,155 +36,155 @@ * @package OCA\Onlyoffice */ class VersionManager { - /** - * Application name - * - * @var string - */ - private $appName; - - /** - * Root folder - * - * @var IRootFolder - */ - private $rootFolder; - - /** - * File versions storage - * - * @var Storage - */ - private $storage; - - /** - * Version manager is available - * - * @var bool - */ - public $available; - - /** - * @param string $AppName - application name - * @param IRootFolder $rootFolder - root folder - */ - public function __construct(string $AppName, IRootFolder $rootFolder) { - $this->appName = $AppName; - $this->rootFolder = $rootFolder; - - if (\OC::$server->getAppManager()->isInstalled("files_versions")) { - try { - $this->storage = \OC::$server->query(Storage::class); - $this->available = true; - } catch (QueryException $e) { - \OC::$server->getLogger()->logException($e, ["message" => "VersionManager init error", "app" => $this->appName]); - } - } - } - - /** - * Get version folder - * - * @param IUser $user - file owner - * - * @return Folder - */ - private function getVersionFolder($user) { - $userRoot = $this->rootFolder->getUserFolder($user->getUID())->getParent(); - try { - $folder = $userRoot->get("files_versions"); - return $folder; - } catch (NotFoundException $e) { - \OC::$server->getLogger()->logException($e, ["message" => "VersionManager: not found user version folder " . $user->getUID(), "app" => $this->appName]); - return null; - } - } - - /** - * Get file version - * - * @param IUser $user - file owner - * @param FileInfo $sourceFile - file - * @param integer $version - file version - * - * @return File - */ - public function getVersionFile($user, $sourceFile, $version) { - $userFolder = $this->rootFolder->getUserFolder($user->getUID()); - $versionsFolder = $this->getVersionFolder($user); - - $file = $versionsFolder->get($userFolder->getRelativePath($sourceFile->getPath()) . ".v" . $version); - return $file; - } - - /** - * Get versions for file - * - * @param IUser $user - file owner - * @param FileInfo $file - file - * - * @return array - */ - public function getVersionsForFile($user, $file) { - $versions = []; - - $fileId = $file->getId(); - - try { - $userFolder = $this->rootFolder->getUserFolder($user->getUID()); - $nodes = $userFolder->getById($fileId); - $sourceFile = $nodes[0]; - } catch (\Exception $e) { - \OC::$server->getLogger()->logException($e, ["message" => "VersionManager: $fileId", "app" => $this->appName]); - return $versions; - } - - $owner = $sourceFile->getOwner(); - if ($owner === null) { - return $versions; - } - - $ownerId = $owner->getUID(); - $userFolder = $this->rootFolder->getUserFolder($ownerId); - $sourceFilePath = $userFolder->getRelativePath($sourceFile->getPath()); - $propsVersions = $this->storage->getVersions($ownerId, $sourceFilePath); - - foreach ($propsVersions as $propVersion) { - $version = new Version( - $propVersion["timestamp"], - $propVersion["version"], - $propVersion["path"], - $file - ); - - array_push($versions, $version); - } - - return $versions; - } - - /** - * Restore version - * - * @param Version $version - version for restore - * - */ - public function rollback($version) { - $sourceFile = $version->getSourceFile(); - - $ownerId = null; - $owner = $sourceFile->getOwner(); - if (!empty($owner)) { - $ownerId = $owner->getUID(); - } - - $path = $version->getPath(); - $revision = $version->getTimestamp(); - - $versionFile = $this->getVersionFile($owner, $sourceFile, $revision); - $versionFileInfo = $versionFile->getFileInfo(); - $versionPath = $versionFileInfo->getInternalPath(); - - $this->storage->restoreVersion($ownerId, $path, $versionPath, $revision); - } + /** + * Application name + * + * @var string + */ + private $appName; + + /** + * Root folder + * + * @var IRootFolder + */ + private $rootFolder; + + /** + * File versions storage + * + * @var Storage + */ + private $storage; + + /** + * Version manager is available + * + * @var bool + */ + public $available; + + /** + * @param string $AppName - application name + * @param IRootFolder $rootFolder - root folder + */ + public function __construct(string $AppName, IRootFolder $rootFolder) { + $this->appName = $AppName; + $this->rootFolder = $rootFolder; + + if (\OC::$server->getAppManager()->isInstalled("files_versions")) { + try { + $this->storage = \OC::$server->query(Storage::class); + $this->available = true; + } catch (QueryException $e) { + \OC::$server->getLogger()->logException($e, ["message" => "VersionManager init error", "app" => $this->appName]); + } + } + } + + /** + * Get version folder + * + * @param IUser $user - file owner + * + * @return Folder + */ + private function getVersionFolder($user) { + $userRoot = $this->rootFolder->getUserFolder($user->getUID())->getParent(); + try { + $folder = $userRoot->get("files_versions"); + return $folder; + } catch (NotFoundException $e) { + \OC::$server->getLogger()->logException($e, ["message" => "VersionManager: not found user version folder " . $user->getUID(), "app" => $this->appName]); + return null; + } + } + + /** + * Get file version + * + * @param IUser $user - file owner + * @param FileInfo $sourceFile - file + * @param integer $version - file version + * + * @return File + */ + public function getVersionFile($user, $sourceFile, $version) { + $userFolder = $this->rootFolder->getUserFolder($user->getUID()); + $versionsFolder = $this->getVersionFolder($user); + + $file = $versionsFolder->get($userFolder->getRelativePath($sourceFile->getPath()) . ".v" . $version); + return $file; + } + + /** + * Get versions for file + * + * @param IUser $user - file owner + * @param FileInfo $file - file + * + * @return array + */ + public function getVersionsForFile($user, $file) { + $versions = []; + + $fileId = $file->getId(); + + try { + $userFolder = $this->rootFolder->getUserFolder($user->getUID()); + $nodes = $userFolder->getById($fileId); + $sourceFile = $nodes[0]; + } catch (\Exception $e) { + \OC::$server->getLogger()->logException($e, ["message" => "VersionManager: $fileId", "app" => $this->appName]); + return $versions; + } + + $owner = $sourceFile->getOwner(); + if ($owner === null) { + return $versions; + } + + $ownerId = $owner->getUID(); + $userFolder = $this->rootFolder->getUserFolder($ownerId); + $sourceFilePath = $userFolder->getRelativePath($sourceFile->getPath()); + $propsVersions = $this->storage->getVersions($ownerId, $sourceFilePath); + + foreach ($propsVersions as $propVersion) { + $version = new Version( + $propVersion["timestamp"], + $propVersion["version"], + $propVersion["path"], + $file + ); + + array_push($versions, $version); + } + + return $versions; + } + + /** + * Restore version + * + * @param Version $version - version for restore + * + */ + public function rollback($version) { + $sourceFile = $version->getSourceFile(); + + $ownerId = null; + $owner = $sourceFile->getOwner(); + if (!empty($owner)) { + $ownerId = $owner->getUID(); + } + + $path = $version->getPath(); + $revision = $version->getTimestamp(); + + $versionFile = $this->getVersionFile($owner, $sourceFile, $revision); + $versionFileInfo = $versionFile->getFileInfo(); + $versionPath = $versionFileInfo->getInternalPath(); + + $this->storage->restoreVersion($ownerId, $path, $versionPath, $revision); + } } From 4697df55224b692079d5cf7734b88a8e8ce0c000 Mon Sep 17 00:00:00 2001 From: rivexe Date: Tue, 19 Dec 2023 10:37:55 +0300 Subject: [PATCH 028/114] header comment add author --- appinfo/app.php | 3 ++- appinfo/application.php | 3 ++- appinfo/routes.php | 3 ++- controller/callbackcontroller.php | 3 ++- controller/editorapicontroller.php | 3 ++- controller/editorcontroller.php | 3 ++- controller/federationcontroller.php | 3 ++- controller/joblistcontroller.php | 3 ++- controller/settingsapicontroller.php | 3 ++- controller/settingscontroller.php | 3 ++- controller/templatecontroller.php | 3 ++- controller/webassetcontroller.php | 3 ++- lib/adminsettings.php | 3 ++- lib/appconfig.php | 3 ++- lib/command/documentserver.php | 3 ++- lib/cron/editorscheck.php | 3 ++- lib/crypt.php | 3 ++- lib/documentservice.php | 3 ++- lib/fileutility.php | 3 ++- lib/fileversions.php | 3 ++- lib/hookhandler.php | 3 ++- lib/hooks.php | 3 ++- lib/keymanager.php | 3 ++- lib/notifier.php | 3 ++- lib/preview.php | 3 ++- lib/remoteinstance.php | 3 ++- lib/templatemanager.php | 3 ++- lib/version.php | 3 ++- lib/versionmanager.php | 3 ++- templates/editor.php | 3 ++- templates/settings.php | 3 ++- 31 files changed, 62 insertions(+), 31 deletions(-) diff --git a/appinfo/app.php b/appinfo/app.php index bb6cf568..3dd0b91e 100644 --- a/appinfo/app.php +++ b/appinfo/app.php @@ -1,6 +1,7 @@ + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/appinfo/application.php b/appinfo/application.php index 1d21f078..be7a1939 100644 --- a/appinfo/application.php +++ b/appinfo/application.php @@ -1,6 +1,7 @@ + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/appinfo/routes.php b/appinfo/routes.php index 82e0270a..47f186ec 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -1,6 +1,7 @@ + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/controller/callbackcontroller.php b/controller/callbackcontroller.php index f9e1509e..ec0baccc 100644 --- a/controller/callbackcontroller.php +++ b/controller/callbackcontroller.php @@ -1,6 +1,7 @@ + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/controller/editorapicontroller.php b/controller/editorapicontroller.php index bd212e99..ce54d21e 100644 --- a/controller/editorapicontroller.php +++ b/controller/editorapicontroller.php @@ -1,6 +1,7 @@ + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/controller/editorcontroller.php b/controller/editorcontroller.php index 20cfcac4..9c5d22f4 100644 --- a/controller/editorcontroller.php +++ b/controller/editorcontroller.php @@ -1,6 +1,7 @@ + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/controller/federationcontroller.php b/controller/federationcontroller.php index 5070fd5c..b229d68b 100644 --- a/controller/federationcontroller.php +++ b/controller/federationcontroller.php @@ -1,6 +1,7 @@ + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/controller/joblistcontroller.php b/controller/joblistcontroller.php index 562eecdf..95fb7d1c 100644 --- a/controller/joblistcontroller.php +++ b/controller/joblistcontroller.php @@ -1,6 +1,7 @@ + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/controller/settingsapicontroller.php b/controller/settingsapicontroller.php index 45369859..54f24ee9 100644 --- a/controller/settingsapicontroller.php +++ b/controller/settingsapicontroller.php @@ -1,6 +1,7 @@ + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/controller/settingscontroller.php b/controller/settingscontroller.php index 870b8675..55faa4a4 100644 --- a/controller/settingscontroller.php +++ b/controller/settingscontroller.php @@ -1,6 +1,7 @@ + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/controller/templatecontroller.php b/controller/templatecontroller.php index 4dfc1317..0e7b7a71 100644 --- a/controller/templatecontroller.php +++ b/controller/templatecontroller.php @@ -1,6 +1,7 @@ + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/controller/webassetcontroller.php b/controller/webassetcontroller.php index c904fbb2..011f9f66 100644 --- a/controller/webassetcontroller.php +++ b/controller/webassetcontroller.php @@ -1,6 +1,7 @@ + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/lib/adminsettings.php b/lib/adminsettings.php index 14171bc4..65ae0cd1 100644 --- a/lib/adminsettings.php +++ b/lib/adminsettings.php @@ -1,6 +1,7 @@ + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/lib/appconfig.php b/lib/appconfig.php index 8dac94f2..8d8f0398 100644 --- a/lib/appconfig.php +++ b/lib/appconfig.php @@ -1,6 +1,7 @@ + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/lib/command/documentserver.php b/lib/command/documentserver.php index adda3514..324a5be0 100644 --- a/lib/command/documentserver.php +++ b/lib/command/documentserver.php @@ -1,6 +1,7 @@ + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/lib/cron/editorscheck.php b/lib/cron/editorscheck.php index e9aa5054..bd6376fc 100644 --- a/lib/cron/editorscheck.php +++ b/lib/cron/editorscheck.php @@ -1,6 +1,7 @@ + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/lib/crypt.php b/lib/crypt.php index 692064c5..38cccf38 100644 --- a/lib/crypt.php +++ b/lib/crypt.php @@ -1,6 +1,7 @@ + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/lib/documentservice.php b/lib/documentservice.php index 88e59f8c..0ecadbb2 100644 --- a/lib/documentservice.php +++ b/lib/documentservice.php @@ -1,6 +1,7 @@ + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/lib/fileutility.php b/lib/fileutility.php index d413484a..f5064fb6 100644 --- a/lib/fileutility.php +++ b/lib/fileutility.php @@ -1,6 +1,7 @@ + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/lib/fileversions.php b/lib/fileversions.php index 957271c1..80284415 100644 --- a/lib/fileversions.php +++ b/lib/fileversions.php @@ -1,6 +1,7 @@ + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/lib/hookhandler.php b/lib/hookhandler.php index 5d7973ca..a2c6baee 100644 --- a/lib/hookhandler.php +++ b/lib/hookhandler.php @@ -1,6 +1,7 @@ + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/lib/hooks.php b/lib/hooks.php index 2b464f00..40a1787e 100644 --- a/lib/hooks.php +++ b/lib/hooks.php @@ -1,6 +1,7 @@ + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/lib/keymanager.php b/lib/keymanager.php index 4cf4a0fa..62e5f8c7 100644 --- a/lib/keymanager.php +++ b/lib/keymanager.php @@ -1,6 +1,7 @@ + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/lib/notifier.php b/lib/notifier.php index ecdf1bbd..38320083 100644 --- a/lib/notifier.php +++ b/lib/notifier.php @@ -1,6 +1,7 @@ + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/lib/preview.php b/lib/preview.php index 585a61b6..591ce116 100644 --- a/lib/preview.php +++ b/lib/preview.php @@ -1,6 +1,7 @@ + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/lib/remoteinstance.php b/lib/remoteinstance.php index 8952667c..a957ed74 100644 --- a/lib/remoteinstance.php +++ b/lib/remoteinstance.php @@ -1,6 +1,7 @@ + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/lib/templatemanager.php b/lib/templatemanager.php index 16e35515..c27f33d0 100644 --- a/lib/templatemanager.php +++ b/lib/templatemanager.php @@ -1,6 +1,7 @@ + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/lib/version.php b/lib/version.php index c89b894f..d3010497 100644 --- a/lib/version.php +++ b/lib/version.php @@ -1,6 +1,7 @@ + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/lib/versionmanager.php b/lib/versionmanager.php index f71a9230..65b21315 100644 --- a/lib/versionmanager.php +++ b/lib/versionmanager.php @@ -1,6 +1,7 @@ + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/templates/editor.php b/templates/editor.php index 4f9e8ddc..e43d298b 100644 --- a/templates/editor.php +++ b/templates/editor.php @@ -1,6 +1,7 @@ + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/templates/settings.php b/templates/settings.php index 83a17f5d..b1027d82 100644 --- a/templates/settings.php +++ b/templates/settings.php @@ -1,6 +1,7 @@ + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); From dd957511fa78acc95c8169a38358c78418c1a03a Mon Sep 17 00:00:00 2001 From: rivexe Date: Tue, 19 Dec 2023 15:38:07 +0300 Subject: [PATCH 029/114] tab indent for templates --- templates/editor.php | 25 +- templates/settings.php | 623 ++++++++++++++++++++--------------------- 2 files changed, 319 insertions(+), 329 deletions(-) diff --git a/templates/editor.php b/templates/editor.php index e43d298b..78b0015e 100644 --- a/templates/editor.php +++ b/templates/editor.php @@ -24,19 +24,18 @@ ?>
+
" + data-path="" + data-sharetoken="" + data-version="" + data-template="" + data-anchor="" + data-inframe="">
-
" - data-path="" - data-sharetoken="" - data-version="" - data-template="" - data-anchor="" - data-inframe="">
- - - - + + +
diff --git a/templates/settings.php b/templates/settings.php index b1027d82..5556c893 100644 --- a/templates/settings.php +++ b/templates/settings.php @@ -24,321 +24,312 @@ script("onlyoffice", "template"); ?>
-

- ONLYOFFICE - "> -

- -

t("Server settings")) ?>

- - -

- t("Encryption App is enabled, the application cannot work. You can continue working with the application if you enable master key.")) ?> - -

- - -
-

t("ONLYOFFICE Docs Location specifies the address of the server with the document services installed. Please change the '' for the server address in the below line.")) ?>

- -

t("ONLYOFFICE Docs address")) ?>

-

" placeholder="https:///" type="text">

- -

- checked="checked" /> - -

- -

t("Secret key (leave blank to disable)")) ?>

-

- " placeholder="secret" type="password" /> - - -

- -

- - t("Advanced server settings")) ?> - - -

-
-

t("Authorization header (leave blank to use default header)")) ?>

-

" placeholder="Authorization" type="text">

- -

t("ONLYOFFICE Docs address for internal requests from the server")) ?>

-

" placeholder="https:///" type="text">

- -

t("Server address for internal requests from ONLYOFFICE Docs")) ?>

-

" placeholder="" type="text">

-
-
-
- -
- - -
- checked="checked" - disabled="disabled" /> - - -
- - t("This is a public test server, please do not use it for private sensitive data. The server will be available during a 30-day period.")) ?> - - t("The 30-day test period is over, you can no longer connect to demo ONLYOFFICE Docs server.")) ?> - -
- -
-
-
- -
-
-
-
-

t("ONLYOFFICE Docs Cloud")) ?>

-

t("Easily launch the editors in the cloud without downloading and installation")) ?>

-
- -
-
- -
- -
onlyoffice-hide"> -
-

t("Common settings")) ?>

- -

- 0) { ?>checked="checked" /> - -
- " - style="display: block; margin-top: 6px; width: 265px;" /> -

- -

- checked="checked" /> - -

- -

- checked="checked" /> - -

- -

- checked="checked" /> - - -

- -

t("The default application for opening the format")) ?>

-
- $setting) { ?> - -
- checked="checked" /> - -
- - -
- -

- t("Open the file for editing (due to format restrictions, the data might be lost when saving to the formats from the list below)")) ?> - "> -

-
- $setting) { ?> - -
- checked="checked" /> - -
- - -
-
- -

- t("Editor customization settings")) ?> - "> -

- -

- checked="checked" - disabled="disabled"/> - - -
- t("This feature is unavailable due to encryption settings.")) ?> - -

- -

- t("The customization section allows personalizing the editor interface")) ?> -

- -

- checked="checked" /> - -

- -

- checked="checked" /> - -

- -

- checked="checked" /> - -

- -

- checked="checked" /> - -

- -

- checked="checked" /> - -

- -

- t("Review mode for viewing")) ?> -

-
-
- checked="checked" /> - -
-
- checked="checked" /> - -
-
- checked="checked" /> - -
-
- -

- t("Default editor theme")) ?> -

-
-
- checked="checked" /> - -
-
- checked="checked" /> - -
-
- checked="checked" /> - -
-
- -
-

- -

- t("Common templates")) ?> - - -

-
    - -
  • class="onlyoffice-template-item" > - .svg" /> -

    - - -
  • - -
-
- -

t("Security")) ?>

- -

- checked="checked" /> - -

- -

- checked="checked" /> - -

- -

- t("Enable document protection for")) ?> -

-
-
- checked="checked" /> - -
-
- checked="checked" /> - -
-
+

+ ONLYOFFICE + "> +

+ +

t("Server settings")) ?>

+ + +

+ t("Encryption App is enabled, the application cannot work. You can continue working with the application if you enable master key.")) ?> + +

+ +
+

t("ONLYOFFICE Docs Location specifies the address of the server with the document services installed. Please change the '' for the server address in the below line.")) ?>

+

t("ONLYOFFICE Docs address")) ?>

+

" placeholder="https:///" type="text">

+ +

+ checked="checked" /> + +

+ +

t("Secret key (leave blank to disable)")) ?>

+

+ " placeholder="secret" type="password" /> + + +

+ +

+ + t("Advanced server settings")) ?> + + +

+
+

t("Authorization header (leave blank to use default header)")) ?>

+

" placeholder="Authorization" type="text">

+

t("ONLYOFFICE Docs address for internal requests from the server")) ?>

+

" placeholder="https:///" type="text">

+

t("Server address for internal requests from ONLYOFFICE Docs")) ?>

+

" placeholder="" type="text">

+
+
+
+ +
+ +
+ checked="checked" + disabled="disabled" /> + +
+ + t("This is a public test server, please do not use it for private sensitive data. The server will be available during a 30-day period.")) ?> + + t("The 30-day test period is over, you can no longer connect to demo ONLYOFFICE Docs server.")) ?> + +
+ +
+
+
+
+
+
+
+

t("ONLYOFFICE Docs Cloud")) ?>

+

t("Easily launch the editors in the cloud without downloading and installation")) ?>

+
+ +
+
+
-
-

-
+
onlyoffice-hide"> +
+

t("Common settings")) ?>

+

+ 0) { ?>checked="checked" /> + +
+ " + style="display: block; margin-top: 6px; width: 265px;" /> +

+ +

+ checked="checked" /> + +

+ +

+ checked="checked" /> + +

+ +

+ checked="checked" /> + + +

+ +

t("The default application for opening the format")) ?>

+
+ $setting) { ?> + +
+ checked="checked" /> + +
+ + +
+ +

+ t("Open the file for editing (due to format restrictions, the data might be lost when saving to the formats from the list below)")) ?> + "> +

+
+ $setting) { ?> + +
+ checked="checked" /> + +
+ + +
+
+ +

+ t("Editor customization settings")) ?> + "> +

+ +

+ checked="checked" + disabled="disabled"/> + + +
+ t("This feature is unavailable due to encryption settings.")) ?> + +

+ +

+ t("The customization section allows personalizing the editor interface")) ?> +

+ +

+ checked="checked" /> + +

+ +

+ checked="checked" /> + +

+ +

+ checked="checked" /> + +

+ +

+ checked="checked" /> + +

+ +

+ checked="checked" /> + +

+ +

+ t("Review mode for viewing")) ?> +

+
+
+ checked="checked" /> + +
+
+ checked="checked" /> + +
+
+ checked="checked" /> + +
+
+ +

+ t("Default editor theme")) ?> +

+
+
+ checked="checked" /> + +
+
+ checked="checked" /> + +
+
+ checked="checked" /> + +
+
+ +
+

+ +

+ t("Common templates")) ?> + + +

+
    + +
  • class="onlyoffice-template-item" > + .svg" /> +

    + + +
  • + +
+
+ +

t("Security")) ?>

+ +

+ checked="checked" /> + +

+ +

+ checked="checked" /> + +

+ +

+ t("Enable document protection for")) ?> +

+
+
+ checked="checked" /> + +
+
+ checked="checked" /> + +
+
+ +
+

+
From e40c61fb428042990b5665dde39d152a0aad7c0e Mon Sep 17 00:00:00 2001 From: rivexe Date: Tue, 19 Dec 2023 16:42:35 +0300 Subject: [PATCH 030/114] use include_once, correct parenthesis and comment spaces --- appinfo/application.php | 277 ++++++++++++++++------------- controller/callbackcontroller.php | 23 ++- controller/editorapicontroller.php | 25 +-- controller/editorcontroller.php | 47 +++-- controller/joblistcontroller.php | 4 +- controller/webassetcontroller.php | 6 +- lib/adminsettings.php | 2 +- lib/appconfig.php | 11 +- lib/command/documentserver.php | 2 +- lib/cron/editorscheck.php | 3 +- lib/crypt.php | 2 +- lib/documentservice.php | 5 +- lib/fileutility.php | 8 +- lib/fileversions.php | 6 +- lib/hookhandler.php | 2 +- lib/hooks.php | 2 +- lib/keymanager.php | 32 ++-- lib/notifier.php | 11 +- lib/preview.php | 7 +- lib/remoteinstance.php | 27 ++- lib/templatemanager.php | 5 +- lib/version.php | 2 +- lib/versionmanager.php | 2 +- templates/editor.php | 2 +- 24 files changed, 300 insertions(+), 213 deletions(-) diff --git a/appinfo/application.php b/appinfo/application.php index be7a1939..67a091ec 100644 --- a/appinfo/application.php +++ b/appinfo/application.php @@ -72,7 +72,8 @@ public function __construct(array $urlParams = []) { function () { if (!empty($this->appConfig->GetDocumentServerUrl()) && $this->appConfig->SettingsAreSuccessful() - && $this->appConfig->isUserAllowedToUse()) { + && $this->appConfig->isUserAllowedToUse() + ) { Util::addScript("onlyoffice", "desktop"); Util::addScript("onlyoffice", "main"); Util::addScript("onlyoffice", "share"); @@ -90,13 +91,13 @@ function () { Util::connectHook("OCP\Share", "share_link_access", Hookhandler::class, "PublicPage"); - require_once __DIR__ . "/../3rdparty/jwt/BeforeValidException.php"; - require_once __DIR__ . "/../3rdparty/jwt/ExpiredException.php"; - require_once __DIR__ . "/../3rdparty/jwt/SignatureInvalidException.php"; - require_once __DIR__ . "/../3rdparty/jwt/CachedKeySet.php"; - require_once __DIR__ . "/../3rdparty/jwt/JWT.php"; - require_once __DIR__ . "/../3rdparty/jwt/JWK.php"; - require_once __DIR__ . "/../3rdparty/jwt/Key.php"; + include_once __DIR__ . "/../3rdparty/jwt/BeforeValidException.php"; + include_once __DIR__ . "/../3rdparty/jwt/ExpiredException.php"; + include_once __DIR__ . "/../3rdparty/jwt/SignatureInvalidException.php"; + include_once __DIR__ . "/../3rdparty/jwt/CachedKeySet.php"; + include_once __DIR__ . "/../3rdparty/jwt/JWT.php"; + include_once __DIR__ . "/../3rdparty/jwt/JWK.php"; + include_once __DIR__ . "/../3rdparty/jwt/Key.php"; // Set the leeway for the JWT library in case the system clock is a second off \Firebase\JWT\JWT::$leeway = $this->appConfig->GetJwtLeeway(); @@ -113,135 +114,163 @@ function () { $previewManager = $container->query(IPreview::class); if ($this->appConfig->GetPreview()) { - $previewManager->registerProvider(Preview::getMimeTypeRegex(), function () use ($container) { - return $container->query(Preview::class); - }); + $previewManager->registerProvider( + Preview::getMimeTypeRegex(), function () use ($container) { + return $container->query(Preview::class); + } + ); } $notificationManager = \OC::$server->getNotificationManager(); - $notificationManager->registerNotifier(function () use ($appName) { - return new Notifier( - $appName, - \OC::$server->getL10NFactory(), - \OC::$server->getURLGenerator(), - \OC::$server->getLogger(), - \OC::$server->getUserManager() - ); - }, function () use ($appName) { - return [ + $notificationManager->registerNotifier( + function () use ($appName) { + return new Notifier( + $appName, + \OC::$server->getL10NFactory(), + \OC::$server->getURLGenerator(), + \OC::$server->getLogger(), + \OC::$server->getUserManager() + ); + }, function () use ($appName) { + return [ "id" => $appName, "name" => $appName, - ]; - }); + ]; + } + ); - $container->registerService("L10N", function ($c) { - return $c->query("ServerContainer")->getL10N($c->query("AppName")); - }); + $container->registerService( + "L10N", function ($c) { + return $c->query("ServerContainer")->getL10N($c->query("AppName")); + } + ); - $container->registerService("RootStorage", function ($c) { - return $c->query("ServerContainer")->getRootFolder(); - }); + $container->registerService( + "RootStorage", function ($c) { + return $c->query("ServerContainer")->getRootFolder(); + } + ); - $container->registerService("UserSession", function ($c) { - return $c->query("ServerContainer")->getUserSession(); - }); + $container->registerService( + "UserSession", function ($c) { + return $c->query("ServerContainer")->getUserSession(); + } + ); - $container->registerService("Logger", function ($c) { - return $c->query("ServerContainer")->getLogger(); - }); + $container->registerService( + "Logger", function ($c) { + return $c->query("ServerContainer")->getLogger(); + } + ); - $container->registerService("URLGenerator", function ($c) { - return $c->query("ServerContainer")->getURLGenerator(); - }); + $container->registerService( + "URLGenerator", function ($c) { + return $c->query("ServerContainer")->getURLGenerator(); + } + ); // Controllers - $container->registerService("SettingsController", function ($c) { - return new SettingsController( - $c->query("AppName"), - $c->query("Request"), - $c->query("URLGenerator"), - $c->query("L10N"), - $c->query("Logger"), - $this->appConfig, - $this->crypt - ); - }); - - $container->registerService("SettingsApiController", function ($c) { - return new SettingsApiController( - $c->query("AppName"), - $c->query("Request"), - $c->query("URLGenerator"), - $this->appConfig - ); - }); - - $container->registerService("EditorController", function ($c) { - return new EditorController( - $c->query("AppName"), - $c->query("Request"), - $c->query("RootStorage"), - $c->query("UserSession"), - $c->query("ServerContainer")->getUserManager(), - $c->query("URLGenerator"), - $c->query("L10N"), - $c->query("Logger"), - $this->appConfig, - $this->crypt, - $c->query("IManager"), - $c->query("Session"), - $c->query("ServerContainer")->getGroupManager() - ); - }); - - $container->registerService("EditorApiController", function ($c) { - return new EditorApiController( - $c->query("AppName"), - $c->query("Request"), - $c->query("RootStorage"), - $c->query("UserSession"), - $c->query("URLGenerator"), - $c->query("L10N"), - $c->query("Logger"), - $this->appConfig, - $this->crypt, - $c->query("IManager"), - $c->query("Session"), - $c->get(ITagManager::class) - ); - }); - - $container->registerService("CallbackController", function ($c) { - return new CallbackController( - $c->query("AppName"), - $c->query("Request"), - $c->query("RootStorage"), - $c->query("UserSession"), - $c->query("ServerContainer")->getUserManager(), - $c->query("L10N"), - $c->query("Logger"), - $this->appConfig, - $this->crypt, - $c->query("IManager") - ); - }); - - $container->registerService("TemplateController", function ($c) { - return new TemplateController( - $c->query("AppName"), - $c->query("Request"), - $c->query("L10N"), - $c->query("Logger") - ); - }); + $container->registerService( + "SettingsController", function ($c) { + return new SettingsController( + $c->query("AppName"), + $c->query("Request"), + $c->query("URLGenerator"), + $c->query("L10N"), + $c->query("Logger"), + $this->appConfig, + $this->crypt + ); + } + ); - $container->registerService("WebAssetController", function ($c) { - return new WebAssetController( - $c->query("AppName"), - $c->query("Request"), - $c->query("Logger") - ); - }); + $container->registerService( + "SettingsApiController", function ($c) { + return new SettingsApiController( + $c->query("AppName"), + $c->query("Request"), + $c->query("URLGenerator"), + $this->appConfig + ); + } + ); + + $container->registerService( + "EditorController", function ($c) { + return new EditorController( + $c->query("AppName"), + $c->query("Request"), + $c->query("RootStorage"), + $c->query("UserSession"), + $c->query("ServerContainer")->getUserManager(), + $c->query("URLGenerator"), + $c->query("L10N"), + $c->query("Logger"), + $this->appConfig, + $this->crypt, + $c->query("IManager"), + $c->query("Session"), + $c->query("ServerContainer")->getGroupManager() + ); + } + ); + + $container->registerService( + "EditorApiController", function ($c) { + return new EditorApiController( + $c->query("AppName"), + $c->query("Request"), + $c->query("RootStorage"), + $c->query("UserSession"), + $c->query("URLGenerator"), + $c->query("L10N"), + $c->query("Logger"), + $this->appConfig, + $this->crypt, + $c->query("IManager"), + $c->query("Session"), + $c->get(ITagManager::class) + ); + } + ); + + $container->registerService( + "CallbackController", function ($c) { + return new CallbackController( + $c->query("AppName"), + $c->query("Request"), + $c->query("RootStorage"), + $c->query("UserSession"), + $c->query("ServerContainer")->getUserManager(), + $c->query("L10N"), + $c->query("Logger"), + $this->appConfig, + $this->crypt, + $c->query("IManager") + ); + } + ); + + $container->registerService( + "TemplateController", function ($c) { + return new TemplateController( + $c->query("AppName"), + $c->query("Request"), + $c->query("L10N"), + $c->query("Logger") + ); + } + ); + + $container->registerService( + "WebAssetController", function ($c) { + return new WebAssetController( + $c->query("AppName"), + $c->query("Request"), + $c->query("Logger") + ); + } + ); $checkBackgroundJobs = new JobListController( $container->query("AppName"), diff --git a/controller/callbackcontroller.php b/controller/callbackcontroller.php index ec0baccc..bc7f03b5 100644 --- a/controller/callbackcontroller.php +++ b/controller/callbackcontroller.php @@ -194,7 +194,8 @@ public function download($doc) { $this->logger->debug("Download: $fileId ($version)" . ($changes ? " changes" : ""), ["app" => $this->appName]); if (!$this->userSession->isLoggedIn() - && !$changes) { + && !$changes + ) { if (!empty($this->config->GetDocumentServerSecret())) { $header = \OC::$server->getRequest()->getHeader($this->config->JwtHeader()); if (empty($header)) { @@ -253,7 +254,8 @@ public function download($doc) { } if (empty($user) - && $this->config->checkEncryptionModule() !== "master") { + && $this->config->checkEncryptionModule() !== "master" + ) { $owner = $file->getFileInfo()->getOwner(); if ($owner !== null) { \OC_Util::setupFS($owner->getUID()); @@ -459,7 +461,8 @@ public function track($doc, $users, $key, $status, $url, $token, $history, $chan if ($isForcesave && $forcesavetype === 1 - && !empty($actions)) { + && !empty($actions) + ) { // the user who clicked Save $userId = $this->parseUserId($actions[0]["userid"]); } @@ -542,9 +545,11 @@ public function track($doc, $users, $key, $status, $url, $token, $history, $chan } $this->logger->debug("Track put content " . $file->getPath(), ["app" => $this->appName]); - $this->retryOperation(function () use ($file, $newData) { - return $file->putContent($newData); - }); + $this->retryOperation( + function () use ($file, $newData) { + return $file->putContent($newData); + } + ); if (RemoteInstance::isRemoteFile($file)) { if ($isForcesave) { @@ -558,7 +563,8 @@ public function track($doc, $users, $key, $status, $url, $token, $history, $chan if (!$isForcesave && !$prevIsForcesave && $this->versionManager->available - && $this->config->GetVersionHistory()) { + && $this->config->GetVersionHistory() + ) { $changes = null; if (!empty($changesurl)) { $changesurl = $this->config->ReplaceDocumentServerUrlToInternal($changesurl); @@ -572,7 +578,8 @@ public function track($doc, $users, $key, $status, $url, $token, $history, $chan } if ($this->config->checkEncryptionModule() === "master" - && !$isForcesave) { + && !$isForcesave + ) { KeyManager::delete($fileId); } diff --git a/controller/editorapicontroller.php b/controller/editorapicontroller.php index ce54d21e..86d8ce6c 100644 --- a/controller/editorapicontroller.php +++ b/controller/editorapicontroller.php @@ -110,14 +110,14 @@ class EditorApiController extends OCSController { * File version manager * * @var VersionManager - */ + */ private $versionManager; /** * Tag manager * * @var ITagManager - */ + */ private $tagManager; /** @@ -220,8 +220,7 @@ public function fillempty($fileId) { return new JSONResponse(["error" => $this->trans->t("Can't create file")]); } - return new JSONResponse([ - ]); + return new JSONResponse([]); } /** @@ -277,7 +276,8 @@ public function config($fileId, $filePath = null, $shareToken = null, $version = $key = null; if ($version > 0 - && $this->versionManager->available) { + && $this->versionManager->available + ) { $owner = $file->getFileInfo()->getOwner(); if ($owner !== null) { $versions = array_reverse($this->versionManager->getVersionsForFile($owner, $file->getFileInfo())); @@ -360,7 +360,8 @@ public function config($fileId, $filePath = null, $shareToken = null, $version = $isPersistentLock = false; if ($version < 1 && (\OC::$server->getConfig()->getAppValue("files", "enable_lock_file_action", "no") === "yes") - && $fileStorage->instanceOfStorage(IPersistentLockingStorage::class)) { + && $fileStorage->instanceOfStorage(IPersistentLockingStorage::class) + ) { $locks = $fileStorage->getLocks($file->getFileInfo()->getInternalPath(), false); if (\count($locks) > 0) { $activeLock = $locks[0]; @@ -418,7 +419,8 @@ public function config($fileId, $filePath = null, $shareToken = null, $version = if (!$template && $file->isUpdateable() && !$isPersistentLock - && (empty($shareToken) || ($share->getPermissions() & Constants::PERMISSION_UPDATE) === Constants::PERMISSION_UPDATE)) { + && (empty($shareToken) || ($share->getPermissions() & Constants::PERMISSION_UPDATE) === Constants::PERMISSION_UPDATE) + ) { $params["document"]["permissions"]["changeHistory"] = true; } @@ -491,11 +493,13 @@ public function config($fileId, $filePath = null, $shareToken = null, $version = $createParam["templateId"] = $templateItem->getId(); $createParam["name"] = $templateItem->getName(); - array_push($templates, [ + array_push( + $templates, [ "image" => "", "title" => $templateItem->getName(), "url" => urldecode($this->urlGenerator->linkToRouteAbsolute($this->appName . ".editor.create_new", $createParam)) - ]); + ] + ); } $params["editorConfig"]["templates"] = $templates; @@ -508,7 +512,8 @@ public function config($fileId, $filePath = null, $shareToken = null, $version = } if ($folderLink !== null - && $this->config->GetSystemValue($this->config->_customization_goback) !== false) { + && $this->config->GetSystemValue($this->config->_customization_goback) !== false + ) { $params["editorConfig"]["customization"]["goback"] = [ "url" => $folderLink ]; diff --git a/controller/editorcontroller.php b/controller/editorcontroller.php index 9c5d22f4..061afece 100644 --- a/controller/editorcontroller.php +++ b/controller/editorcontroller.php @@ -123,7 +123,7 @@ class EditorController extends Controller { * File version manager * * @var VersionManager - */ + */ private $versionManager; /** @@ -401,10 +401,12 @@ public function users($fileId) { foreach ($users as $user) { $email = $user->getEMailAddress(); if ($user->getUID() != $currentUserId && !empty($email)) { - array_push($result, [ + array_push( + $result, [ "email" => $email, "name" => $user->getDisplayName() - ]); + ] + ); } } @@ -476,12 +478,14 @@ public function mention($fileId, $anchor, $comment, $emails) { $notification->setApp($this->appName) ->setDateTime(new \DateTime()) ->setObject("mention", $comment) - ->setSubject("mention_info", [ + ->setSubject( + "mention_info", [ "notifierId" => $userId, "fileId" => $file->getId(), "fileName" => $file->getName(), "anchor" => $anchor - ]); + ] + ); $shareMemberGroups = $this->shareManager->shareWithGroupMembersOnly(); $canShare = ($file->getPermissions() & Constants::PERMISSION_SHARE) === Constants::PERMISSION_SHARE; @@ -498,7 +502,8 @@ public function mention($fileId, $anchor, $comment, $emails) { $isAvailable = \in_array($recipient, $accessList); if (!$isAvailable - && $file->getFileInfo()->getMountPoint() instanceof \OCA\Files_External\Config\ExternalMountPoint) { + && $file->getFileInfo()->getMountPoint() instanceof \OCA\Files_External\Config\ExternalMountPoint + ) { $recipientFolder = $this->root->getUserFolder($recipientId); $recipientFile = $recipientFolder->getById($file->getId()); @@ -565,17 +570,20 @@ public function reference($referenceData, $path = null) { $file = null; $fileId = (integer)($referenceData["fileKey"] ?? 0); if (!empty($fileId) - && $referenceData["instanceId"] === $this->config->GetSystemValue("instanceid", true)) { + && $referenceData["instanceId"] === $this->config->GetSystemValue("instanceid", true) + ) { list($file, $error, $share) = $this->getFile($userId, $fileId); } $userFolder = $this->root->getUserFolder($userId); if ($file === null && $path !== null - && $userFolder->nodeExists($path)) { + && $userFolder->nodeExists($path) + ) { $node = $userFolder->get($path); if ($node instanceof File - && $node->isReadable()) { + && $node->isReadable() + ) { $file = $node; } } @@ -820,7 +828,8 @@ public function history($fileId) { $versions = []; if ($this->versionManager->available - && $owner !== null) { + && $owner !== null + ) { $versions = array_reverse($this->versionManager->getVersionsForFile($owner, $file->getFileInfo())); } @@ -971,7 +980,8 @@ public function version($fileId, $version) { if ($version > 1 && \count($versions) >= $version - 1 - && FileVersions::hasChanges($ownerId, $fileId, $versionId)) { + && FileVersions::hasChanges($ownerId, $fileId, $versionId) + ) { $changesUrl = $this->getUrl($file, $user, null, $version, true); $result["changesUrl"] = $changesUrl; @@ -1152,7 +1162,8 @@ public function download($fileId, $toExtension = null, $template = false) { if ($toExtension === null || $ext === $toExtension - || $template) { + || $template + ) { return new DataDownloadResponse($file->getContent(), $fileName, $file->getMimeType()); } @@ -1202,9 +1213,11 @@ public function index($fileId, $filePath = null, $shareToken = null, $version = $this->logger->debug("Open: $fileId ($version) $filePath", ["app" => $this->appName]); if (empty($shareToken) && !$this->userSession->isLoggedIn()) { - $redirectUrl = $this->urlGenerator->linkToRoute("core.login.showLoginForm", [ + $redirectUrl = $this->urlGenerator->linkToRoute( + "core.login.showLoginForm", [ "redirect_url" => $this->request->getRequestUri() - ]); + ] + ); return new RedirectResponse($redirectUrl); } @@ -1449,13 +1462,15 @@ private function limitEnumerationToGroups() { * @return TemplateResponse */ private function renderError($error, $hint = "") { - return new TemplateResponse("", "error", [ + return new TemplateResponse( + "", "error", [ "errors" => [ [ "error" => $error, "hint" => $hint ] ] - ], "error"); + ], "error" + ); } } diff --git a/controller/joblistcontroller.php b/controller/joblistcontroller.php index 95fb7d1c..1670638a 100644 --- a/controller/joblistcontroller.php +++ b/controller/joblistcontroller.php @@ -85,7 +85,7 @@ public function __construct($AppName, IRequest $request, ILogger $logger, AppCon private function addJob($job) { if (!$this->jobList->has($job, null)) { $this->jobList->add($job); - $this->logger->debug("Job '".$job."' added to JobList.", ["app" => $this->appName]); + $this->logger->debug("Job '" . $job . "' added to JobList.", ["app" => $this->appName]); } } @@ -97,7 +97,7 @@ private function addJob($job) { private function removeJob($job) { if ($this->jobList->has($job, null)) { $this->jobList->remove($job); - $this->logger->debug("Job '".$job."' removed from JobList.", ["app" => $this->appName]); + $this->logger->debug("Job '" . $job . "' removed from JobList.", ["app" => $this->appName]); } } diff --git a/controller/webassetcontroller.php b/controller/webassetcontroller.php index 011f9f66..8a8c44fb 100644 --- a/controller/webassetcontroller.php +++ b/controller/webassetcontroller.php @@ -63,14 +63,16 @@ public function get(): Response { $basePath = \dirname(__DIR__, 1); $filePath = \realpath($basePath . '/js/web/onlyoffice.js'); try { - return new DataDisplayResponse(\file_get_contents($filePath), Http::STATUS_OK, [ + return new DataDisplayResponse( + \file_get_contents($filePath), Http::STATUS_OK, [ 'Content-Type' => "text/javascript", 'Content-Length' => \filesize($filePath), 'Cache-Control' => 'max-age=0, no-cache, no-store, must-revalidate', 'Pragma' => 'no-cache', 'Expires' => 'Tue, 24 Sep 1985 22:15:00 GMT', 'X-Frame-Options' => 'DENY' - ]); + ] + ); } catch(\Exception $e) { $this->logger->logException($e, ['app' => $this->appName]); return new DataResponse(["message" => $e->getMessage()], Http::STATUS_NOT_FOUND); diff --git a/lib/adminsettings.php b/lib/adminsettings.php index 65ae0cd1..48aa6a57 100644 --- a/lib/adminsettings.php +++ b/lib/adminsettings.php @@ -1,7 +1,7 @@ - * + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/lib/appconfig.php b/lib/appconfig.php index 8d8f0398..028dd1f6 100644 --- a/lib/appconfig.php +++ b/lib/appconfig.php @@ -1,7 +1,7 @@ - * + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -328,7 +328,8 @@ public function GetSystemValue($key, $system = false) { return $this->config->getSystemValue($key); } if (!empty($this->config->getSystemValue($this->appName)) - && \array_key_exists($key, $this->config->getSystemValue($this->appName))) { + && \array_key_exists($key, $this->config->getSystemValue($this->appName)) + ) { return $this->config->getSystemValue($this->appName)[$key]; } return null; @@ -1054,7 +1055,7 @@ public function GetLimitThumbSize() { return $limitSize; } - return 100*1024*1024; + return 100 * 1024 * 1024; } /** @@ -1128,7 +1129,7 @@ public function SettingsAreSuccessful() { * Checking encryption enabled * * @return string|bool - */ + */ public function checkEncryptionModule() { if (!\OC::$server->getAppManager()->isInstalled("encryption")) { return false; @@ -1191,7 +1192,7 @@ public function GetEditorsCheckInterval() { $interval = $this->GetSystemValue($this->_editors_check_interval); if (empty($interval) && $interval !== 0) { - $interval = 60*60*24; + $interval = 60 * 60 * 24; } return (integer)$interval; } diff --git a/lib/command/documentserver.php b/lib/command/documentserver.php index 324a5be0..2e984624 100644 --- a/lib/command/documentserver.php +++ b/lib/command/documentserver.php @@ -1,7 +1,7 @@ - * + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/lib/cron/editorscheck.php b/lib/cron/editorscheck.php index bd6376fc..61ee5e13 100644 --- a/lib/cron/editorscheck.php +++ b/lib/cron/editorscheck.php @@ -1,7 +1,7 @@ - * + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -176,6 +176,7 @@ private function getUsersToNotify() { /** * Send notification to admins + * * @return void */ private function notifyAdmins() { diff --git a/lib/crypt.php b/lib/crypt.php index 38cccf38..1d4e3634 100644 --- a/lib/crypt.php +++ b/lib/crypt.php @@ -1,7 +1,7 @@ - * + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/lib/documentservice.php b/lib/documentservice.php index 0ecadbb2..608ba2e3 100644 --- a/lib/documentservice.php +++ b/lib/documentservice.php @@ -1,7 +1,7 @@ - * + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -380,7 +380,8 @@ public function checkDocServiceUrl($urlGenerator, $crypt) { try { if (preg_match("/^https:\/\//i", $urlGenerator->getAbsoluteURL("/")) - && preg_match("/^http:\/\//i", $this->config->GetDocumentServerUrl())) { + && preg_match("/^http:\/\//i", $this->config->GetDocumentServerUrl()) + ) { throw new \Exception($this->trans->t("Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required.")); } } catch (\Exception $e) { diff --git a/lib/fileutility.php b/lib/fileutility.php index f5064fb6..c74644e9 100644 --- a/lib/fileutility.php +++ b/lib/fileutility.php @@ -1,7 +1,7 @@ - * + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -204,7 +204,8 @@ public function getShare($shareToken) { if ($share->getPassword() && (!$this->session->exists("public_link_authenticated") - || $this->session->get("public_link_authenticated") !== (string) $share->getId())) { + || $this->session->get("public_link_authenticated") !== (string) $share->getId()) + ) { return [null, $this->trans->t("You do not have enough permissions to view the file")]; } @@ -223,7 +224,8 @@ public function getKey($file, $origin = false) { $fileId = $file->getId(); if ($origin - && RemoteInstance::isRemoteFile($file)) { + && RemoteInstance::isRemoteFile($file) + ) { $key = RemoteInstance::getRemoteKey($file); if (!empty($key)) { return $key; diff --git a/lib/fileversions.php b/lib/fileversions.php index 80284415..ad43d634 100644 --- a/lib/fileversions.php +++ b/lib/fileversions.php @@ -1,7 +1,7 @@ - * + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -316,7 +316,7 @@ public static function deleteAllVersions($ownerId, $fileId = null) { * @param string $ownerId - file owner id * @param string $fileId - file id * @param string $versionId - file version - */ + */ public static function deleteVersion($ownerId, $fileId, $versionId) { $logger = \OC::$server->getLogger(); @@ -451,7 +451,7 @@ public static function getAuthor($ownerId, $fileId, $versionId) { * @param string $ownerId - file owner id * @param string $fileId - file id * @param string $versionId - file version - */ + */ public static function deleteAuthor($ownerId, $fileId, $versionId) { $logger = \OC::$server->getLogger(); diff --git a/lib/hookhandler.php b/lib/hookhandler.php index a2c6baee..116bb29d 100644 --- a/lib/hookhandler.php +++ b/lib/hookhandler.php @@ -1,7 +1,7 @@ - * + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/lib/hooks.php b/lib/hooks.php index 40a1787e..7f6e7782 100644 --- a/lib/hooks.php +++ b/lib/hooks.php @@ -1,7 +1,7 @@ - * + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/lib/keymanager.php b/lib/keymanager.php index 62e5f8c7..9343a86f 100644 --- a/lib/keymanager.php +++ b/lib/keymanager.php @@ -1,7 +1,7 @@ - * + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -40,11 +40,13 @@ class KeyManager { */ public static function get($fileId) { $connection = \OC::$server->getDatabaseConnection(); - $select = $connection->prepare(" + $select = $connection->prepare( + " SELECT `key` FROM `*PREFIX*" . self::TableName_Key . "` WHERE `file_id` = ? - "); + " + ); $result = $select->execute([$fileId]); $keys = $result ? $select->fetch() : []; @@ -63,11 +65,13 @@ public static function get($fileId) { */ public static function set($fileId, $key) { $connection = \OC::$server->getDatabaseConnection(); - $insert = $connection->prepare(" + $insert = $connection->prepare( + " INSERT INTO `*PREFIX*" . self::TableName_Key . "` (`file_id`, `key`) VALUES (?, ?) - "); + " + ); return (bool)$insert->execute([$fileId, $key]); } @@ -100,11 +104,13 @@ public static function delete($fileId, $unlock = false) { */ public static function lock($fileId, $lock = true) { $connection = \OC::$server->getDatabaseConnection(); - $update = $connection->prepare(" + $update = $connection->prepare( + " UPDATE `*PREFIX*" . self::TableName_Key . "` SET `lock` = ? WHERE `file_id` = ? - "); + " + ); return (bool)$update->execute([$lock === true ? 1 : 0, $fileId]); } @@ -118,11 +124,13 @@ public static function lock($fileId, $lock = true) { */ public static function setForcesave($fileId, $fs = true) { $connection = \OC::$server->getDatabaseConnection(); - $update = $connection->prepare(" + $update = $connection->prepare( + " UPDATE `*PREFIX*" . self::TableName_Key . "` SET `fs` = ? WHERE `file_id` = ? - "); + " + ); return (bool)$update->execute([$fs === true ? 1 : 0, $fileId]); } @@ -135,11 +143,13 @@ public static function setForcesave($fileId, $fs = true) { */ public static function wasForcesave($fileId) { $connection = \OC::$server->getDatabaseConnection(); - $select = $connection->prepare(" + $select = $connection->prepare( + " SELECT `fs` FROM `*PREFIX*" . self::TableName_Key . "` WHERE `file_id` = ? - "); + " + ); $result = $select->execute([$fileId]); $rows = $result ? $select->fetch() : []; diff --git a/lib/notifier.php b/lib/notifier.php index 38320083..8f40c08b 100644 --- a/lib/notifier.php +++ b/lib/notifier.php @@ -1,7 +1,7 @@ - * + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -122,15 +122,18 @@ public function prepare($notification, $languageCode) { $notification->setIcon($this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath($this->appName, "app-dark.svg"))); $notification->setParsedSubject($trans->t("%1\$s mentioned in the %2\$s: \"%3\$s\".", [$notifierName, $fileName, $notification->getObjectId()])); - $editorLink = $this->urlGenerator->linkToRouteAbsolute($this->appName . ".editor.index", [ + $editorLink = $this->urlGenerator->linkToRouteAbsolute( + $this->appName . ".editor.index", + [ "fileId" => $fileId, "anchor" => $anchor - ]); + ] + ); $notification->setLink($editorLink); break; default: - $this->logger->info("Unsupported notification object: ".$notification->getObjectType(), ["app" => $this->appName]); + $this->logger->info("Unsupported notification object: " . $notification->getObjectType(), ["app" => $this->appName]); } return $notification; } diff --git a/lib/preview.php b/lib/preview.php index 591ce116..9bfce058 100644 --- a/lib/preview.php +++ b/lib/preview.php @@ -1,7 +1,7 @@ - * + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -106,7 +106,7 @@ class Preview implements IProvider2 { * File version manager * * @var VersionManager - */ + */ private $versionManager; /** @@ -234,7 +234,8 @@ public function isAvailable(FileInfo $fileInfo) { } if (!$fileInfo || $fileInfo->getSize() === 0 - || $fileInfo->getSize() > $this->config->GetLimitThumbSize()) { + || $fileInfo->getSize() > $this->config->GetLimitThumbSize() + ) { return false; } if (!\in_array($fileInfo->getMimetype(), self::$capabilities, true)) { diff --git a/lib/remoteinstance.php b/lib/remoteinstance.php index a957ed74..eaabdbde 100644 --- a/lib/remoteinstance.php +++ b/lib/remoteinstance.php @@ -1,7 +1,7 @@ - * + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -59,11 +59,13 @@ class RemoteInstance { */ private static function get($remote) { $connection = \OC::$server->getDatabaseConnection(); - $select = $connection->prepare(" + $select = $connection->prepare( + " SELECT remote, expire, status FROM `*PREFIX*" . self::TableName_Key . "` WHERE `remote` = ? - "); + " + ); $result = $select->execute([$remote]); $dbremote = $result ? $select->fetch() : []; @@ -81,11 +83,13 @@ private static function get($remote) { */ private static function set($remote, $status) { $connection = \OC::$server->getDatabaseConnection(); - $insert = $connection->prepare(" + $insert = $connection->prepare( + " INSERT INTO `*PREFIX*" . self::TableName_Key . "` (`remote`, `status`, `expire`) VALUES (?, ?, ?) - "); + " + ); return (bool)$insert->execute([$remote, $status === true ? 1 : 0, time()]); } @@ -99,11 +103,13 @@ private static function set($remote, $status) { */ private static function update($remote, $status) { $connection = \OC::$server->getDatabaseConnection(); - $update = $connection->prepare(" + $update = $connection->prepare( + " UPDATE `*PREFIX*" . self::TableName_Key . "` SET status = ?, expire = ? WHERE remote = ? - "); + " + ); return (bool)$update->execute([$status === true ? 1 : 0, time(), $remote]); } @@ -177,13 +183,16 @@ public function getRemoteKey($file) { $client = $httpClientService->newClient(); try { - $response = $client->post($remote . "/ocs/v2.php/apps/" . self::App_Name . "/api/v1/key?format=json", [ + $response = $client->post( + $remote . "/ocs/v2.php/apps/" . self::App_Name . "/api/v1/key?format=json", + [ "timeout" => 5, "json" => [ "shareToken" => $shareToken, "path" => $internalPath ] - ]); + ] + ); $body = \json_decode($response->getBody(), true); diff --git a/lib/templatemanager.php b/lib/templatemanager.php index c27f33d0..2c748378 100644 --- a/lib/templatemanager.php +++ b/lib/templatemanager.php @@ -1,7 +1,7 @@ - * + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -74,7 +74,8 @@ public static function GetGlobalTemplates($mimetype = null) { $templatesList = $templateDir->getDirectoryListing(); if (!empty($mimetype) - && \is_array($templatesList) && \count($templatesList) > 0) { + && \is_array($templatesList) && \count($templatesList) > 0 + ) { $templatesList = $templateDir->searchByMime($mimetype); } diff --git a/lib/version.php b/lib/version.php index d3010497..e7f0273b 100644 --- a/lib/version.php +++ b/lib/version.php @@ -1,7 +1,7 @@ - * + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/lib/versionmanager.php b/lib/versionmanager.php index 65b21315..f0cb56b1 100644 --- a/lib/versionmanager.php +++ b/lib/versionmanager.php @@ -1,7 +1,7 @@ - * + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/templates/editor.php b/templates/editor.php index 78b0015e..86581940 100644 --- a/templates/editor.php +++ b/templates/editor.php @@ -36,6 +36,6 @@ - +
From 21eec22abdad049abfc7e918c67b95b84b3c8dff Mon Sep 17 00:00:00 2001 From: rivexe Date: Tue, 19 Dec 2023 16:46:35 +0300 Subject: [PATCH 031/114] templates excluded from ruleset.xml --- ruleset.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ruleset.xml b/ruleset.xml index b3a2c934..d9d7eecc 100644 --- a/ruleset.xml +++ b/ruleset.xml @@ -4,6 +4,8 @@ + */templates/* + From a9f473eb17a5fd70f67ac4a8a66c91afe8b0594a Mon Sep 17 00:00:00 2001 From: rivexe Date: Wed, 20 Dec 2023 10:41:58 +0300 Subject: [PATCH 032/114] class constants to UPPERCASE --- controller/callbackcontroller.php | 26 ++++++++++----------- lib/keymanager.php | 14 ++++++------ lib/preview.php | 6 ++--- lib/remoteinstance.php | 38 +++++++++++++++---------------- 4 files changed, 42 insertions(+), 42 deletions(-) diff --git a/controller/callbackcontroller.php b/controller/callbackcontroller.php index bc7f03b5..904b286a 100644 --- a/controller/callbackcontroller.php +++ b/controller/callbackcontroller.php @@ -119,12 +119,12 @@ class CallbackController extends Controller { /** * Status of the document */ - private const TrackerStatus_Editing = 1; - private const TrackerStatus_MustSave = 2; - private const TrackerStatus_Corrupted = 3; - private const TrackerStatus_Closed = 4; - private const TrackerStatus_ForceSave = 6; - private const TrackerStatus_CorruptedForceSave = 7; + private const TRACKERSTATUS_EDITING = 1; + private const TRACKERSTATUS_MUSTSAVE = 2; + private const TRACKERSTATUS_CORRUPTED = 3; + private const TRACKERSTATUS_CLOSED = 4; + private const TRACKERSTATUS_FORCESAVE = 6; + private const TRACKERSTATUS_CORRUPTEDFORCESAVE = 7; /** * @param string $AppName - application name @@ -439,10 +439,10 @@ public function track($doc, $users, $key, $status, $url, $token, $history, $chan $result = 1; switch ($status) { - case self::TrackerStatus_MustSave: - case self::TrackerStatus_Corrupted: - case self::TrackerStatus_ForceSave: - case self::TrackerStatus_CorruptedForceSave: + case self::TRACKERSTATUS_MUSTSAVE: + case self::TRACKERSTATUS_CORRUPTED: + case self::TRACKERSTATUS_FORCESAVE: + case self::TRACKERSTATUS_CORRUPTEDFORCESAVE: if (empty($url)) { $this->logger->error("Track without url: $fileId status $status", ["app" => $this->appName]); return new JSONResponse(["message" => "Url not found"], Http::STATUS_BAD_REQUEST); @@ -454,7 +454,7 @@ public function track($doc, $users, $key, $status, $url, $token, $history, $chan \OC_Util::tearDownFS(); - $isForcesave = $status === self::TrackerStatus_ForceSave || $status === self::TrackerStatus_CorruptedForceSave; + $isForcesave = $status === self::TRACKERSTATUS_FORCESAVE || $status === self::TRACKERSTATUS_CORRUPTEDFORCESAVE; // author of the latest changes $userId = $this->parseUserId($users[0]); @@ -589,8 +589,8 @@ function () use ($file, $newData) { } break; - case self::TrackerStatus_Editing: - case self::TrackerStatus_Closed: + case self::TRACKERSTATUS_EDITING: + case self::TRACKERSTATUS_CLOSED: $result = 0; break; } diff --git a/lib/keymanager.php b/lib/keymanager.php index 9343a86f..95d3ffe4 100644 --- a/lib/keymanager.php +++ b/lib/keymanager.php @@ -29,7 +29,7 @@ class KeyManager { /** * Table name */ - private const TableName_Key = "onlyoffice_filekey"; + private const TABLENAME_KEY = "onlyoffice_filekey"; /** * Get document identifier @@ -43,7 +43,7 @@ public static function get($fileId) { $select = $connection->prepare( " SELECT `key` - FROM `*PREFIX*" . self::TableName_Key . "` + FROM `*PREFIX*" . self::TABLENAME_KEY . "` WHERE `file_id` = ? " ); @@ -67,7 +67,7 @@ public static function set($fileId, $key) { $connection = \OC::$server->getDatabaseConnection(); $insert = $connection->prepare( " - INSERT INTO `*PREFIX*" . self::TableName_Key . "` + INSERT INTO `*PREFIX*" . self::TABLENAME_KEY . "` (`file_id`, `key`) VALUES (?, ?) " @@ -87,7 +87,7 @@ public static function delete($fileId, $unlock = false) { $connection = \OC::$server->getDatabaseConnection(); $delete = $connection->prepare( " - DELETE FROM `*PREFIX*" . self::TableName_Key . "` + DELETE FROM `*PREFIX*" . self::TABLENAME_KEY . "` WHERE `file_id` = ? " . ($unlock === false ? "AND `lock` != 1" : "") ); @@ -106,7 +106,7 @@ public static function lock($fileId, $lock = true) { $connection = \OC::$server->getDatabaseConnection(); $update = $connection->prepare( " - UPDATE `*PREFIX*" . self::TableName_Key . "` + UPDATE `*PREFIX*" . self::TABLENAME_KEY . "` SET `lock` = ? WHERE `file_id` = ? " @@ -126,7 +126,7 @@ public static function setForcesave($fileId, $fs = true) { $connection = \OC::$server->getDatabaseConnection(); $update = $connection->prepare( " - UPDATE `*PREFIX*" . self::TableName_Key . "` + UPDATE `*PREFIX*" . self::TABLENAME_KEY . "` SET `fs` = ? WHERE `file_id` = ? " @@ -146,7 +146,7 @@ public static function wasForcesave($fileId) { $select = $connection->prepare( " SELECT `fs` - FROM `*PREFIX*" . self::TableName_Key . "` + FROM `*PREFIX*" . self::TABLENAME_KEY . "` WHERE `file_id` = ? " ); diff --git a/lib/preview.php b/lib/preview.php index 9bfce058..88362a27 100644 --- a/lib/preview.php +++ b/lib/preview.php @@ -157,7 +157,7 @@ class Preview implements IProvider2 { /** * Converted thumbnail format */ - private const thumbExtension = "jpeg"; + private const THUMBEXTENSION = "jpeg"; /** * @param string $appName - application name @@ -270,9 +270,9 @@ public function getThumbnail($file, $maxX, $maxY, $scalingup) { $imageUrl = null; $documentService = new DocumentService($this->trans, $this->config); try { - $imageUrl = $documentService->GetConvertedUri($fileUrl, $extension, self::thumbExtension, $key); + $imageUrl = $documentService->GetConvertedUri($fileUrl, $extension, self::THUMBEXTENSION, $key); } catch (\Exception $e) { - $this->logger->logException($e, ["message" => "GetConvertedUri: from $extension to " . self::thumbExtension, "app" => $this->appName]); + $this->logger->logException($e, ["message" => "GetConvertedUri: from $extension to " . self::THUMBEXTENSION, "app" => $this->appName]); return false; } diff --git a/lib/remoteinstance.php b/lib/remoteinstance.php index eaabdbde..971e56f3 100644 --- a/lib/remoteinstance.php +++ b/lib/remoteinstance.php @@ -33,12 +33,12 @@ class RemoteInstance { /** * App name */ - private const App_Name = "onlyoffice"; + private const APP_NAME = "onlyoffice"; /** * Table name */ - private const TableName_Key = "onlyoffice_instance"; + private const TABLENAME_KEY = "onlyoffice_instance"; /** * Time to live of remote instance (12 hours) @@ -62,7 +62,7 @@ private static function get($remote) { $select = $connection->prepare( " SELECT remote, expire, status - FROM `*PREFIX*" . self::TableName_Key . "` + FROM `*PREFIX*" . self::TABLENAME_KEY . "` WHERE `remote` = ? " ); @@ -85,7 +85,7 @@ private static function set($remote, $status) { $connection = \OC::$server->getDatabaseConnection(); $insert = $connection->prepare( " - INSERT INTO `*PREFIX*" . self::TableName_Key . "` + INSERT INTO `*PREFIX*" . self::TABLENAME_KEY . "` (`remote`, `status`, `expire`) VALUES (?, ?, ?) " @@ -105,7 +105,7 @@ private static function update($remote, $status) { $connection = \OC::$server->getDatabaseConnection(); $update = $connection->prepare( " - UPDATE `*PREFIX*" . self::TableName_Key . "` + UPDATE `*PREFIX*" . self::TABLENAME_KEY . "` SET status = ?, expire = ? WHERE remote = ? " @@ -125,13 +125,13 @@ public static function healthCheck($remote) { $remote = rtrim($remote, "/") . "/"; if (\in_array($remote, self::$healthRemote)) { - $logger->debug("Remote instance " . $remote . " from local cache status " . $dbremote["status"], ["app" => self::App_Name]); + $logger->debug("Remote instance " . $remote . " from local cache status " . $dbremote["status"], ["app" => self::APP_NAME]); return true; } $dbremote = self::get($remote); if (!empty($dbremote) && $dbremote["expire"] + self::$ttl > time()) { - $logger->debug("Remote instance " . $remote . " from database status " . $dbremote["status"], ["app" => self::App_Name]); + $logger->debug("Remote instance " . $remote . " from database status " . $dbremote["status"], ["app" => self::APP_NAME]); self::$healthRemote[$remote] = $dbremote["status"]; return self::$healthRemote[$remote]; } @@ -141,7 +141,7 @@ public static function healthCheck($remote) { $status = false; try { - $response = $client->get($remote . "ocs/v2.php/apps/" . self::App_Name . "/api/v1/healthcheck?format=json"); + $response = $client->get($remote . "ocs/v2.php/apps/" . self::APP_NAME . "/api/v1/healthcheck?format=json"); $body = json_decode($response->getBody(), true); $data = $body["ocs"]["data"]; @@ -149,7 +149,7 @@ public static function healthCheck($remote) { $status = $data["alive"] === true; } } catch (\Exception $e) { - $logger->logException($e, ["message" => "Failed to request federated health check for" . $remote, "app" => self::App_Name]); + $logger->logException($e, ["message" => "Failed to request federated health check for" . $remote, "app" => self::APP_NAME]); } if (empty($dbremote)) { @@ -158,7 +158,7 @@ public static function healthCheck($remote) { self::update($remote, $status); } - $logger->debug("Remote instance " . $remote . " was stored to database status " . $dbremote["status"], ["app" => self::App_Name]); + $logger->debug("Remote instance " . $remote . " was stored to database status " . $dbremote["status"], ["app" => self::APP_NAME]); self::$healthRemote[$remote] = $status; @@ -184,7 +184,7 @@ public function getRemoteKey($file) { try { $response = $client->post( - $remote . "/ocs/v2.php/apps/" . self::App_Name . "/api/v1/key?format=json", + $remote . "/ocs/v2.php/apps/" . self::APP_NAME . "/api/v1/key?format=json", [ "timeout" => 5, "json" => [ @@ -198,20 +198,20 @@ public function getRemoteKey($file) { $data = $body["ocs"]["data"]; if (!empty($data["error"])) { - $logger->error("Error federated key " . $data["error"], ["app" => self::App_Name]); + $logger->error("Error federated key " . $data["error"], ["app" => self::APP_NAME]); return null; } $key = $data["key"]; - $logger->debug("Federated key: $key", ["app" => self::App_Name]); + $logger->debug("Federated key: $key", ["app" => self::APP_NAME]); return $key; } catch (\Exception $e) { - $logger->logException($e, ["message" => "Failed to request federated key " . $file->getId(), "app" => self::App_Name]); + $logger->logException($e, ["message" => "Failed to request federated key " . $file->getId(), "app" => self::APP_NAME]); if ($e->getResponse()->getStatusCode() === 404) { self::update($remote, false); - $logger->debug("Changed status for remote instance $remote to false", ["app" => self::App_Name]); + $logger->debug("Changed status for remote instance $remote to false", ["app" => self::APP_NAME]); } return null; @@ -250,22 +250,22 @@ public static function lockRemoteKey($file, $lock, $fs) { } try { - $response = $client->post($remote . "/ocs/v2.php/apps/" . self::App_Name . "/api/v1/keylock?format=json", $data); + $response = $client->post($remote . "/ocs/v2.php/apps/" . self::APP_NAME . "/api/v1/keylock?format=json", $data); $body = \json_decode($response->getBody(), true); $data = $body["ocs"]["data"]; if (empty($data)) { - $logger->debug("Federated request" . $action . "for " . $file->getFileInfo()->getId() . " is successful", ["app" => self::App_Name]); + $logger->debug("Federated request" . $action . "for " . $file->getFileInfo()->getId() . " is successful", ["app" => self::APP_NAME]); return true; } if (!empty($data["error"])) { - $logger->error("Error" . $action . "federated key for " . $file->getFileInfo()->getId() . ": " . $data["error"], ["app" => self::App_Name]); + $logger->error("Error" . $action . "federated key for " . $file->getFileInfo()->getId() . ": " . $data["error"], ["app" => self::APP_NAME]); return false; } } catch(\Exception $e) { - $logger->logException($e, ["message" => "Failed to request federated " . $action . " for " . $file->getFileInfo()->getId(), "app" => self::App_Name]); + $logger->logException($e, ["message" => "Failed to request federated " . $action . " for " . $file->getFileInfo()->getId(), "app" => self::APP_NAME]); return false; } } From c568f47c16e3827b0455cc500b8542fc528c4f59 Mon Sep 17 00:00:00 2001 From: rivexe Date: Wed, 20 Dec 2023 11:43:09 +0300 Subject: [PATCH 033/114] fix doc comments --- appinfo/application.php | 10 ++++++ controller/callbackcontroller.php | 2 ++ controller/editorapicontroller.php | 5 +-- controller/federationcontroller.php | 2 +- controller/joblistcontroller.php | 6 ++++ controller/settingscontroller.php | 2 +- controller/templatecontroller.php | 3 ++ lib/adminsettings.php | 4 +++ lib/appconfig.php | 55 ++++++++++++++++++++++++++++- lib/command/documentserver.php | 7 ++++ lib/cron/editorscheck.php | 3 ++ lib/crypt.php | 2 +- lib/documentservice.php | 2 +- lib/fileutility.php | 2 +- lib/fileversions.php | 14 +++++++- lib/hookhandler.php | 8 +++-- lib/hooks.php | 15 ++++++++ lib/notifier.php | 9 +++-- lib/preview.php | 4 +++ lib/version.php | 1 + lib/versionmanager.php | 1 + settings.php | 3 +- 22 files changed, 146 insertions(+), 14 deletions(-) diff --git a/appinfo/application.php b/appinfo/application.php index 67a091ec..eff730f6 100644 --- a/appinfo/application.php +++ b/appinfo/application.php @@ -42,6 +42,11 @@ use OCA\Onlyoffice\Notifier; use OCA\Onlyoffice\Preview; +/** + * Class Application + * + * @package OCA\Onlyoffice\AppInfo + */ class Application extends App { /** * Application configuration @@ -57,6 +62,11 @@ class Application extends App { */ public $crypt; + /** + * Application constructor. + * + * @param array $urlParams + */ public function __construct(array $urlParams = []) { $appName = "onlyoffice"; diff --git a/controller/callbackcontroller.php b/controller/callbackcontroller.php index 904b286a..b01f7adb 100644 --- a/controller/callbackcontroller.php +++ b/controller/callbackcontroller.php @@ -777,6 +777,8 @@ private function parseUserId($userId) { * @param callable $operation * * @throws LockedException + * + * @return void */ private function retryOperation(callable $operation) { $i = 0; diff --git a/controller/editorapicontroller.php b/controller/editorapicontroller.php index 86d8ce6c..ade9e77c 100644 --- a/controller/editorapicontroller.php +++ b/controller/editorapicontroller.php @@ -136,7 +136,7 @@ class EditorApiController extends OCSController { * @param AppConfig $config - application configuration * @param Crypt $crypt - hash generator * @param IManager $shareManager - Share manager - * @param ISession $ISession - Session + * @param ISession $session - Session * @param ITagManager $tagManager - Tag manager */ public function __construct( @@ -233,6 +233,7 @@ public function fillempty($fileId) { * @param bool $inframe - open in frame * @param bool $desktop - desktop label * @param bool $template - file is template + * @param string $anchor - anchor link * * @return JSONResponse * @@ -668,7 +669,7 @@ private function buildUserId($userId) { /** * Set customization parameters * - * @param array params - file parameters + * @param array $params - file parameters * * @return array */ diff --git a/controller/federationcontroller.php b/controller/federationcontroller.php index b229d68b..a84b777b 100644 --- a/controller/federationcontroller.php +++ b/controller/federationcontroller.php @@ -66,7 +66,7 @@ class FederationController extends OCSController { * @param IL10N $trans - l10n service * @param ILogger $logger - logger * @param IManager $shareManager - Share manager - * @param IManager $ISession - Session + * @param IManager $session - Session */ public function __construct( $AppName, diff --git a/controller/joblistcontroller.php b/controller/joblistcontroller.php index 1670638a..76b80928 100644 --- a/controller/joblistcontroller.php +++ b/controller/joblistcontroller.php @@ -81,6 +81,8 @@ public function __construct($AppName, IRequest $request, ILogger $logger, AppCon * Add a job to list * * @param IJob|string $job + * + * @return void */ private function addJob($job) { if (!$this->jobList->has($job, null)) { @@ -93,6 +95,8 @@ private function addJob($job) { * Remove a job from list * * @param IJob|string $job + * + * @return void */ private function removeJob($job) { if ($this->jobList->has($job, null)) { @@ -104,6 +108,7 @@ private function removeJob($job) { /** * Add or remove EditorsCheck job depending on the value of _editors_check_interval * + * @return void */ private function checkEditorsCheckJob() { if ($this->config->GetEditorsCheckInterval() > 0) { @@ -116,6 +121,7 @@ private function checkEditorsCheckJob() { /** * Method for sequentially calling checks of all jobs * + * @return void */ public function checkAllJobs() { $this->checkEditorsCheckJob(); diff --git a/controller/settingscontroller.php b/controller/settingscontroller.php index 55faa4a4..20bd62e3 100644 --- a/controller/settingscontroller.php +++ b/controller/settingscontroller.php @@ -141,12 +141,12 @@ public function index() { /** * Save address settings * - * @param string $jwtHeader - jwt header * @param string $documentserver - document service address * @param string $documentserverInternal - document service address available from ownCloud * @param string $storageUrl - ownCloud address available from document server * @param bool $verifyPeerOff - parameter verification setting * @param string $secret - secret key for signature + * @param string $jwtHeader - jwt header * @param bool $demo - use demo server * * @return array diff --git a/controller/templatecontroller.php b/controller/templatecontroller.php index 0e7b7a71..301b671d 100644 --- a/controller/templatecontroller.php +++ b/controller/templatecontroller.php @@ -49,6 +49,7 @@ class TemplateController extends Controller { * @param string $AppName - application name * @param IRequest $request - request object * @param IL10N $trans - l10n service + * @param ILogger $logger - logger */ public function __construct( $AppName, @@ -134,6 +135,8 @@ public function AddTemplate() { * Delete template * * @param string $templateId - file identifier + * + * @return array */ public function DeleteTemplate($templateId) { $templateDir = TemplateManager::GetGlobalTemplateDir(); diff --git a/lib/adminsettings.php b/lib/adminsettings.php index 48aa6a57..bcf15d28 100644 --- a/lib/adminsettings.php +++ b/lib/adminsettings.php @@ -26,6 +26,10 @@ * Settings controller for the administration page */ class AdminSettings implements ISettings { + + /** + * Constructor + */ public function __construct() { } diff --git a/lib/appconfig.php b/lib/appconfig.php index 028dd1f6..b6523723 100644 --- a/lib/appconfig.php +++ b/lib/appconfig.php @@ -403,6 +403,8 @@ public function UseDemo() { * Save the document service address to the application configuration * * @param string $documentServer - document service address + * + * @return void */ public function SetDocumentServerUrl($documentServer) { $documentServer = trim($documentServer); @@ -447,6 +449,8 @@ public function GetDocumentServerUrl($origin = false) { * Save the document service address available from ownCloud to the application configuration * * @param string $documentServerInternal - document service address + * + * @return void */ public function SetDocumentServerInternalUrl($documentServerInternal) { $documentServerInternal = rtrim(trim($documentServerInternal), "/"); @@ -514,6 +518,8 @@ public function ReplaceDocumentServerUrlToInternal($url) { * Save the ownCloud address available from document server to the application configuration * * @param string $documentServer - document service address + * + * @return void */ public function SetStorageUrl($storageUrl) { $storageUrl = rtrim(trim($storageUrl), "/"); @@ -546,6 +552,8 @@ public function GetStorageUrl() { * Save the document service secret key to the application configuration * * @param string $secret - secret key + * + * @return void */ public function SetDocumentServerSecret($secret) { $secret = trim($secret); @@ -594,6 +602,8 @@ public function GetSKey() { * Save an array of formats with default action * * @param array $formats - formats with status + * + * @return void */ public function SetDefaultFormats($formats) { $value = json_encode($formats); @@ -619,6 +629,8 @@ private function GetDefaultFormats() { * Save an array of formats that is opened for editing * * @param array $formats - formats with status + * + * @return void */ public function SetEditableFormats($formats) { $value = json_encode($formats); @@ -644,6 +656,8 @@ private function GetEditableFormats() { * Save the opening setting in a same tab * * @param bool $value - same tab + * + * @return void */ public function SetSameTab($value) { $this->logger->info("Set opening in a same tab: " . json_encode($value), ["app" => $this->appName]); @@ -664,6 +678,8 @@ public function GetSameTab() { * Save generate preview setting * * @param bool $value - preview + * + * @return bool */ public function SetPreview($value) { $this->logger->info("Set generate preview: " . json_encode($value), ["app" => $this->appName]); @@ -684,6 +700,8 @@ public function GetPreview() { * Save keep versions history * * @param bool $value - version history + * + * @return void */ public function SetVersionHistory($value) { $this->logger->info("Set keep versions history: " . json_encode($value), ["app" => $this->appName]); @@ -704,6 +722,8 @@ public function GetVersionHistory() { * Save protection * * @param bool $value - version history + * + * @return void */ public function SetProtection($value) { $this->logger->info("Set protection: " . $value, ["app" => $this->appName]); @@ -714,7 +734,7 @@ public function SetProtection($value) { /** * Get protection * - * @return bool + * @return string */ public function GetProtection() { $value = $this->config->getAppValue($this->appName, $this->_protection, "owner"); @@ -728,6 +748,8 @@ public function GetProtection() { * Save chat display setting * * @param bool $value - display chat + * + * @return void */ public function SetCustomizationChat($value) { $this->logger->info("Set chat display: " . json_encode($value), ["app" => $this->appName]); @@ -748,6 +770,8 @@ public function GetCustomizationChat() { * Save compact header setting * * @param bool $value - display compact header + * + * @return void */ public function SetCustomizationCompactHeader($value) { $this->logger->info("Set compact header display: " . json_encode($value), ["app" => $this->appName]); @@ -768,6 +792,8 @@ public function GetCustomizationCompactHeader() { * Save feedback display setting * * @param bool $value - display feedback + * + * @return void */ public function SetCustomizationFeedback($value) { $this->logger->info("Set feedback display: " . json_encode($value), ["app" => $this->appName]); @@ -788,6 +814,8 @@ public function GetCustomizationFeedback() { * Save forcesave setting * * @param bool $value - forcesave + * + * @return void */ public function SetCustomizationForcesave($value) { $this->logger->info("Set forcesave: " . json_encode($value), ["app" => $this->appName]); @@ -810,6 +838,8 @@ public function GetCustomizationForcesave() { * Save help display setting * * @param bool $value - display help + * + * @return void */ public function SetCustomizationHelp($value) { $this->logger->info("Set help display: " . json_encode($value), ["app" => $this->appName]); @@ -830,6 +860,8 @@ public function GetCustomizationHelp() { * Save without tabs setting * * @param bool $value - without tabs + * + * @return void */ public function SetCustomizationToolbarNoTabs($value) { $this->logger->info("Set without tabs: " . json_encode($value), ["app" => $this->appName]); @@ -850,6 +882,8 @@ public function GetCustomizationToolbarNoTabs() { * Save review viewing mode setting * * @param string $value - review mode + * + * @return void */ public function SetCustomizationReviewDisplay($value) { $this->logger->info("Set review mode: " . $value, ["app" => $this->appName]); @@ -877,6 +911,8 @@ public function GetCustomizationReviewDisplay() { * Save theme setting * * @param string $value - theme + * + * @return void */ public function SetCustomizationTheme($value) { $this->logger->info("Set theme: " . $value, ["app" => $this->appName]); @@ -904,6 +940,8 @@ public function GetCustomizationTheme() { * Save macros setting * * @param bool $value - enable macros + * + * @return void */ public function SetCustomizationMacros($value) { $this->logger->info("Set macros enabled: " . json_encode($value), ["app" => $this->appName]); @@ -924,6 +962,8 @@ public function GetCustomizationMacros() { * Save plugins setting * * @param bool $value - enable macros + * + * @return void */ public function SetCustomizationPlugins($value) { $this->logger->info("Set plugins enabled: " . json_encode($value), ["app" => $this->appName]); @@ -944,6 +984,8 @@ public function GetCustomizationPlugins() { * Save the list of groups * * @param array $groups - the list of groups + * + * @return void */ public function SetLimitGroups($groups) { if (!\is_array($groups)) { @@ -1021,6 +1063,8 @@ public function isUserAllowedToUse($userId = null) { * Save the document service verification setting to the application configuration * * @param bool $verifyPeerOff - parameter verification setting + * + * @return void */ public function SetVerifyPeerOff($verifyPeerOff) { $this->logger->info("SetVerifyPeerOff " . json_encode($verifyPeerOff), ["app" => $this->appName]); @@ -1084,6 +1128,8 @@ public function JwtHeader($origin = false) { * Save the jwtHeader setting * * @param string $value - jwtHeader + * + * @return void */ public function SetJwtHeader($value) { $value = trim($value); @@ -1111,6 +1157,8 @@ public function GetJwtLeeway() { * Save the status settings * * @param string $value - error + * + * @return void */ public function SetSettingsError($value) { $this->config->setAppValue($this->appName, $this->_settingsError, $value); @@ -1174,6 +1222,11 @@ public function FormatsSetting() { return $result; } + /** + * Get version of share attributes + * + * @return string + */ public function ShareAttributesVersion() { if (\version_compare(\implode(".", \OCP\Util::getVersion()), "10.3.0", ">=")) { return "v2"; diff --git a/lib/command/documentserver.php b/lib/command/documentserver.php index 2e984624..662ebc8c 100644 --- a/lib/command/documentserver.php +++ b/lib/command/documentserver.php @@ -32,6 +32,11 @@ use OCA\Onlyoffice\DocumentService; use OCA\Onlyoffice\Crypt; +/** + * Class Document Server + * + * @package OCA\Onlyoffice\Command + */ class DocumentServer extends Command { /** * Application configuration @@ -82,6 +87,8 @@ public function __construct( /** * Configures the current command. + * + * @return void */ protected function configure() { $this diff --git a/lib/cron/editorscheck.php b/lib/cron/editorscheck.php index 61ee5e13..b5d2dcbf 100644 --- a/lib/cron/editorscheck.php +++ b/lib/cron/editorscheck.php @@ -94,6 +94,7 @@ class EditorsCheck extends TimedJob { * @param AppConfig $config - application configuration * @param IL10N $trans - l10n service * @param Crypt $crypt - crypt service + * @param IGroupManager $groupManager - group manager */ public function __construct( string $AppName, @@ -119,6 +120,8 @@ public function __construct( * Makes the background check * * @param array $argument unused argument + * + * @return void */ protected function run($argument) { if (empty($this->config->GetDocumentServerUrl())) { diff --git a/lib/crypt.php b/lib/crypt.php index 1d4e3634..588b1643 100644 --- a/lib/crypt.php +++ b/lib/crypt.php @@ -36,7 +36,7 @@ class Crypt { private $config; /** - * @param AppConfig $config - application configutarion + * @param AppConfig $appConfig - application configutarion */ public function __construct(AppConfig $appConfig) { $this->config = $appConfig; diff --git a/lib/documentservice.php b/lib/documentservice.php index 608ba2e3..b2b0f3b0 100644 --- a/lib/documentservice.php +++ b/lib/documentservice.php @@ -53,7 +53,7 @@ class DocumentService { /** * @param IL10N $trans - l10n service - * @param AppConfig $config - application configutarion + * @param AppConfig $appConfig - application configutarion */ public function __construct(IL10N $trans, AppConfig $appConfig) { $this->trans = $trans; diff --git a/lib/fileutility.php b/lib/fileutility.php index c74644e9..658ebc41 100644 --- a/lib/fileutility.php +++ b/lib/fileutility.php @@ -87,7 +87,7 @@ class FileUtility { * @param ILogger $logger - logger * @param AppConfig $config - application configuration * @param IManager $shareManager - Share manager - * @param IManager $ISession - Session + * @param ISession $session - Session */ public function __construct( $AppName, diff --git a/lib/fileversions.php b/lib/fileversions.php index ad43d634..f77df852 100644 --- a/lib/fileversions.php +++ b/lib/fileversions.php @@ -242,8 +242,10 @@ public static function getChangesFile($ownerId, $fileId, $versionId) { * * @param FileInfo $fileInfo - file info * @param array $history - file history - * @param string $changesurl - file changes + * @param string $changes - file changes * @param string $prevVersion - previous version for check + * + * @return void */ public static function saveHistory($fileInfo, $history, $changes, $prevVersion) { $logger = \OC::$server->getLogger(); @@ -292,6 +294,8 @@ public static function saveHistory($fileInfo, $history, $changes, $prevVersion) * * @param string $ownerId - file owner id * @param string $fileId - file id + * + * @return void */ public static function deleteAllVersions($ownerId, $fileId = null) { $logger = \OC::$server->getLogger(); @@ -316,6 +320,8 @@ public static function deleteAllVersions($ownerId, $fileId = null) { * @param string $ownerId - file owner id * @param string $fileId - file id * @param string $versionId - file version + * + * @return void|null */ public static function deleteVersion($ownerId, $fileId, $versionId) { $logger = \OC::$server->getLogger(); @@ -349,6 +355,8 @@ public static function deleteVersion($ownerId, $fileId, $versionId) { /** * Clear all version history + * + * @return void */ public static function clearHistory() { $logger = \OC::$server->getLogger(); @@ -374,6 +382,8 @@ public static function clearHistory() { * * @param FileInfo $fileInfo - file info * @param IUser $author - version author + * + * @return void */ public static function saveAuthor($fileInfo, $author) { $logger = \OC::$server->getLogger(); @@ -451,6 +461,8 @@ public static function getAuthor($ownerId, $fileId, $versionId) { * @param string $ownerId - file owner id * @param string $fileId - file id * @param string $versionId - file version + * + * @return void|null */ public static function deleteAuthor($ownerId, $fileId, $versionId) { $logger = \OC::$server->getLogger(); diff --git a/lib/hookhandler.php b/lib/hookhandler.php index 116bb29d..d0684f19 100644 --- a/lib/hookhandler.php +++ b/lib/hookhandler.php @@ -27,11 +27,15 @@ /** * Class HookHandler * - * handles hooks - * * @package OCA\Onlyoffice */ class HookHandler { + + /** + * Adds scripts and styles + * + * @return void + */ public static function PublicPage() { $appName = "onlyoffice"; diff --git a/lib/hooks.php b/lib/hooks.php index 7f6e7782..66a5d002 100644 --- a/lib/hooks.php +++ b/lib/hooks.php @@ -40,6 +40,11 @@ class Hooks { */ private static $appName = "onlyoffice"; + /** + * Connect hooks + * + * @return void + */ public static function connectHooks() { // Listen user deletion Util::connectHook("OC_User", "pre_deleteUser", Hooks::class, "userDelete"); @@ -61,6 +66,8 @@ public static function connectHooks() { * Erase user file versions * * @param array $params - hook params + * + * @return void */ public static function userDelete($params) { $userId = $params["uid"]; @@ -72,6 +79,8 @@ public static function userDelete($params) { * Listen of file change * * @param array $params - hook params + * + * @return void */ public static function fileUpdate($params) { $filePath = $params[Filesystem::signal_param_path]; @@ -95,6 +104,8 @@ public static function fileUpdate($params) { * Erase versions of deleted file * * @param array $params - hook params + * + * @return void */ public static function fileDelete($params) { $filePath = $params[Filesystem::signal_param_path]; @@ -124,6 +135,8 @@ public static function fileDelete($params) { * Erase versions of deleted version of file * * @param array $params - hook param + * + * @return void */ public static function fileVersionDelete($params) { $pathVersion = $params["path"]; @@ -157,6 +170,8 @@ public static function fileVersionDelete($params) { * Erase versions of restored version of file * * @param array $params - hook param + * + * @return void */ public static function fileVersionRestore($params) { $filePath = $params["path"]; diff --git a/lib/notifier.php b/lib/notifier.php index 8f40c08b..b641dfb4 100644 --- a/lib/notifier.php +++ b/lib/notifier.php @@ -27,6 +27,11 @@ use OCP\Notification\INotification; use OCP\Notification\INotifier; +/** + * Class Notifier + * + * @package OCA\Onlyoffice + */ class Notifier implements INotifier { /** * Application name @@ -64,8 +69,8 @@ class Notifier implements INotifier { private $userManager; /** - * @param string $AppName - application name - * @param IFactory $l10NFactory - l10n + * @param string $appName - application name + * @param IFactory $l10nFactory - l10n * @param IURLGenerator $urlGenerator - url generator service * @param ILogger $logger - logger * @param IUserManager $userManager - user manager diff --git a/lib/preview.php b/lib/preview.php index 88362a27..6e7fdc69 100644 --- a/lib/preview.php +++ b/lib/preview.php @@ -199,6 +199,8 @@ public function __construct( /** * Return mime type + * + * @return string */ public static function getMimeTypeRegex() { $mimeTypeRegex = ""; @@ -215,6 +217,8 @@ public static function getMimeTypeRegex() { /** * Return mime type + * + * @return string */ public function getMimeType() { $m = self::getMimeTypeRegex(); diff --git a/lib/version.php b/lib/version.php index e7f0273b..228b8156 100644 --- a/lib/version.php +++ b/lib/version.php @@ -59,6 +59,7 @@ class Version { /** * @param int $timestamp - file time stamp * @param int $revisionId - revision id + * @param string $path - file path * @param FileInfo $sourceFileInfo - source file info */ public function __construct( diff --git a/lib/versionmanager.php b/lib/versionmanager.php index f0cb56b1..782f41da 100644 --- a/lib/versionmanager.php +++ b/lib/versionmanager.php @@ -169,6 +169,7 @@ public function getVersionsForFile($user, $file) { * * @param Version $version - version for restore * + * @return void */ public function rollback($version) { $sourceFile = $version->getSourceFile(); diff --git a/settings.php b/settings.php index 0a613f16..c474cf38 100644 --- a/settings.php +++ b/settings.php @@ -1,6 +1,7 @@ + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); From 198e86aa1e539c4f38fa32a457103e257bf40e8f Mon Sep 17 00:00:00 2001 From: rivexe Date: Wed, 20 Dec 2023 13:14:38 +0300 Subject: [PATCH 034/114] camelCase format for methods names, no prefixes with an underscore for variables --- appinfo/application.php | 10 +- controller/callbackcontroller.php | 48 +++---- controller/editorapicontroller.php | 72 +++++----- controller/editorcontroller.php | 78 +++++----- controller/federationcontroller.php | 2 +- controller/joblistcontroller.php | 2 +- controller/settingsapicontroller.php | 6 +- controller/settingscontroller.php | 138 +++++++++--------- controller/templatecontroller.php | 20 +-- lib/appconfig.php | 208 +++++++++++++-------------- lib/command/documentserver.php | 4 +- lib/cron/editorscheck.php | 12 +- lib/crypt.php | 8 +- lib/documentservice.php | 90 ++++++------ lib/fileutility.php | 4 +- lib/hookhandler.php | 6 +- lib/preview.php | 20 +-- lib/templatemanager.php | 22 +-- 18 files changed, 375 insertions(+), 375 deletions(-) diff --git a/appinfo/application.php b/appinfo/application.php index eff730f6..de5f43f0 100644 --- a/appinfo/application.php +++ b/appinfo/application.php @@ -80,8 +80,8 @@ public function __construct(array $urlParams = []) { $eventDispatcher->addListener( "OCA\Files::loadAdditionalScripts", function () { - if (!empty($this->appConfig->GetDocumentServerUrl()) - && $this->appConfig->SettingsAreSuccessful() + if (!empty($this->appConfig->getDocumentServerUrl()) + && $this->appConfig->settingsAreSuccessful() && $this->appConfig->isUserAllowedToUse() ) { Util::addScript("onlyoffice", "desktop"); @@ -89,7 +89,7 @@ function () { Util::addScript("onlyoffice", "share"); Util::addScript("onlyoffice", "template"); - if ($this->appConfig->GetSameTab()) { + if ($this->appConfig->getSameTab()) { Util::addScript("onlyoffice", "listener"); } @@ -110,7 +110,7 @@ function () { include_once __DIR__ . "/../3rdparty/jwt/Key.php"; // Set the leeway for the JWT library in case the system clock is a second off - \Firebase\JWT\JWT::$leeway = $this->appConfig->GetJwtLeeway(); + \Firebase\JWT\JWT::$leeway = $this->appConfig->getJwtLeeway(); $container = $this->getContainer(); @@ -123,7 +123,7 @@ function () { $detector->registerType("oform", "application/vnd.openxmlformats-officedocument.wordprocessingml.document.oform"); $previewManager = $container->query(IPreview::class); - if ($this->appConfig->GetPreview()) { + if ($this->appConfig->getPreview()) { $previewManager->registerProvider( Preview::getMimeTypeRegex(), function () use ($container) { return $container->query(Preview::class); diff --git a/controller/callbackcontroller.php b/controller/callbackcontroller.php index b01f7adb..c59e7aa1 100644 --- a/controller/callbackcontroller.php +++ b/controller/callbackcontroller.php @@ -177,7 +177,7 @@ public function __construct( * @CORS */ public function download($doc) { - list($hashData, $error) = $this->crypt->ReadHash($doc); + list($hashData, $error) = $this->crypt->readHash($doc); if ($hashData === null) { $this->logger->error("Download with empty or not correct hash: $error", ["app" => $this->appName]); return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN); @@ -196,8 +196,8 @@ public function download($doc) { if (!$this->userSession->isLoggedIn() && !$changes ) { - if (!empty($this->config->GetDocumentServerSecret())) { - $header = \OC::$server->getRequest()->getHeader($this->config->JwtHeader()); + if (!empty($this->config->getDocumentServerSecret())) { + $header = \OC::$server->getRequest()->getHeader($this->config->jwtHeader()); if (empty($header)) { $this->logger->error("Download without jwt", ["app" => $this->appName]); return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN); @@ -206,7 +206,7 @@ public function download($doc) { $header = substr($header, \strlen("Bearer ")); try { - $decodedHeader = \Firebase\JWT\JWT::decode($header, new \Firebase\JWT\Key($this->config->GetDocumentServerSecret(), "HS256")); + $decodedHeader = \Firebase\JWT\JWT::decode($header, new \Firebase\JWT\Key($this->config->getDocumentServerSecret(), "HS256")); } catch (\UnexpectedValueException $e) { $this->logger->logException($e, ["message" => "Download with invalid jwt", "app" => $this->appName]); return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN); @@ -324,7 +324,7 @@ public function download($doc) { public function emptyfile($doc) { $this->logger->debug("Download empty", ["app" => $this->appName]); - list($hashData, $error) = $this->crypt->ReadHash($doc); + list($hashData, $error) = $this->crypt->readHash($doc); if ($hashData === null) { $this->logger->error("Download empty with empty or not correct hash: $error", ["app" => $this->appName]); return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN); @@ -334,8 +334,8 @@ public function emptyfile($doc) { return new JSONResponse(["message" => $this->trans->t("Invalid request")], Http::STATUS_BAD_REQUEST); } - if (!empty($this->config->GetDocumentServerSecret())) { - $header = \OC::$server->getRequest()->getHeader($this->config->JwtHeader()); + if (!empty($this->config->getDocumentServerSecret())) { + $header = \OC::$server->getRequest()->getHeader($this->config->jwtHeader()); if (empty($header)) { $this->logger->error("Download empty without jwt", ["app" => $this->appName]); return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN); @@ -344,14 +344,14 @@ public function emptyfile($doc) { $header = substr($header, \strlen("Bearer ")); try { - $decodedHeader = \Firebase\JWT\JWT::decode($header, new \Firebase\JWT\Key($this->config->GetDocumentServerSecret(), "HS256")); + $decodedHeader = \Firebase\JWT\JWT::decode($header, new \Firebase\JWT\Key($this->config->getDocumentServerSecret(), "HS256")); } catch (\UnexpectedValueException $e) { $this->logger->logException($e, ["message" => "Download empty with invalid jwt", "app" => $this->appName]); return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN); } } - $templatePath = TemplateManager::GetEmptyTemplatePath("en", ".docx"); + $templatePath = TemplateManager::getEmptyTemplatePath("en", ".docx"); $template = file_get_contents($templatePath); if (!$template) { @@ -391,7 +391,7 @@ public function emptyfile($doc) { * @CORS */ public function track($doc, $users, $key, $status, $url, $token, $history, $changesurl, $forcesavetype, $actions, $filetype) { - list($hashData, $error) = $this->crypt->ReadHash($doc); + list($hashData, $error) = $this->crypt->readHash($doc); if ($hashData === null) { $this->logger->error("Track with empty or not correct hash: $error", ["app" => $this->appName]); return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN); @@ -404,16 +404,16 @@ public function track($doc, $users, $key, $status, $url, $token, $history, $chan $fileId = $hashData->fileId; $this->logger->debug("Track: $fileId status $status", ["app" => $this->appName]); - if (!empty($this->config->GetDocumentServerSecret())) { + if (!empty($this->config->getDocumentServerSecret())) { if (!empty($token)) { try { - $payload = \Firebase\JWT\JWT::decode($token, new \Firebase\JWT\Key($this->config->GetDocumentServerSecret(), "HS256")); + $payload = \Firebase\JWT\JWT::decode($token, new \Firebase\JWT\Key($this->config->getDocumentServerSecret(), "HS256")); } catch (\UnexpectedValueException $e) { $this->logger->logException($e, ["message" => "Track with invalid jwt in body", "app" => $this->appName]); return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN); } } else { - $header = \OC::$server->getRequest()->getHeader($this->config->JwtHeader()); + $header = \OC::$server->getRequest()->getHeader($this->config->jwtHeader()); if (empty($header)) { $this->logger->error("Track without jwt", ["app" => $this->appName]); return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN); @@ -422,7 +422,7 @@ public function track($doc, $users, $key, $status, $url, $token, $history, $chan $header = substr($header, \strlen("Bearer ")); try { - $decodedHeader = \Firebase\JWT\JWT::decode($header, new \Firebase\JWT\Key($this->config->GetDocumentServerSecret(), "HS256")); + $decodedHeader = \Firebase\JWT\JWT::decode($header, new \Firebase\JWT\Key($this->config->getDocumentServerSecret(), "HS256")); $payload = $decodedHeader->payload; } catch (\UnexpectedValueException $e) { @@ -511,7 +511,7 @@ public function track($doc, $users, $key, $status, $url, $token, $history, $chan return $error; } - $url = $this->config->ReplaceDocumentServerUrlToInternal($url); + $url = $this->config->replaceDocumentServerUrlToInternal($url); $prevVersion = $file->getFileInfo()->getMtime(); $fileName = $file->getName(); @@ -520,18 +520,18 @@ public function track($doc, $users, $key, $status, $url, $token, $history, $chan $documentService = new DocumentService($this->trans, $this->config); if ($downloadExt !== $curExt) { - $key = DocumentService::GenerateRevisionId($fileId . $url); + $key = DocumentService::generateRevisionId($fileId . $url); try { $this->logger->debug("Converted from $downloadExt to $curExt", ["app" => $this->appName]); - $url = $documentService->GetConvertedUri($url, $downloadExt, $curExt, $key); + $url = $documentService->getConvertedUri($url, $downloadExt, $curExt, $key); } catch (\Exception $e) { $this->logger->logException($e, ["message" => "Converted on save error", "app" => $this->appName]); return new JSONResponse(["message" => $e->getMessage()], Http::STATUS_INTERNAL_SERVER_ERROR); } } - $newData = $documentService->Request($url); + $newData = $documentService->request($url); $prevIsForcesave = KeyManager::wasForcesave($fileId); @@ -563,17 +563,17 @@ function () use ($file, $newData) { if (!$isForcesave && !$prevIsForcesave && $this->versionManager->available - && $this->config->GetVersionHistory() + && $this->config->getVersionHistory() ) { $changes = null; if (!empty($changesurl)) { - $changesurl = $this->config->ReplaceDocumentServerUrlToInternal($changesurl); - $changes = $documentService->Request($changesurl); + $changesurl = $this->config->replaceDocumentServerUrlToInternal($changesurl); + $changes = $documentService->request($changesurl); } FileVersions::saveHistory($file->getFileInfo(), $history, $changes, $prevVersion); } - if (!empty($user) && $this->config->GetVersionHistory()) { + if (!empty($user) && $this->config->getVersionHistory()) { FileVersions::saveAuthor($file->getFileInfo(), $user); } @@ -617,7 +617,7 @@ private function getFile($userId, $fileId, $filePath = null, $version = 0, $temp } try { - $folder = !$template ? $this->root->getUserFolder($userId) : TemplateManager::GetGlobalTemplateDir(); + $folder = !$template ? $this->root->getUserFolder($userId) : TemplateManager::getGlobalTemplateDir(); $files = $folder->getById($fileId); } catch (\Exception $e) { $this->logger->logException($e, ["message" => "getFile: $fileId", "app" => $this->appName]); @@ -760,7 +760,7 @@ private function getShare($shareToken) { * @return string */ private function parseUserId($userId) { - $instanceId = $this->config->GetSystemValue("instanceid", true); + $instanceId = $this->config->getSystemValue("instanceid", true); $instanceId = $instanceId . "_"; if (substr($userId, 0, \strlen($instanceId)) === $instanceId) { diff --git a/controller/editorapicontroller.php b/controller/editorapicontroller.php index ade9e77c..55ec5c5a 100644 --- a/controller/editorapicontroller.php +++ b/controller/editorapicontroller.php @@ -206,7 +206,7 @@ public function fillempty($fileId) { } $name = $file->getName(); - $template = TemplateManager::GetEmptyTemplate($name); + $template = TemplateManager::getEmptyTemplate($name); if (!$template) { $this->logger->error("Template for file filling not found: $name ($fileId)", ["app" => $this->appName]); @@ -267,7 +267,7 @@ public function config($fileId, $filePath = null, $shareToken = null, $version = $fileName = $file->getName(); $ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION)); - $format = !empty($ext) && \array_key_exists($ext, $this->config->FormatsSetting()) ? $this->config->FormatsSetting()[$ext] : null; + $format = !empty($ext) && \array_key_exists($ext, $this->config->formatsSetting()) ? $this->config->formatsSetting()[$ext] : null; if (!isset($format)) { $this->logger->info("Format is not supported for editing: $fileName", ["app" => $this->appName]); return new JSONResponse(["error" => $this->trans->t("Format is not supported")]); @@ -293,7 +293,7 @@ public function config($fileId, $filePath = null, $shareToken = null, $version = if ($key === null) { $key = $this->fileUtility->getKey($file, true); } - $key = DocumentService::GenerateRevisionId($key); + $key = DocumentService::generateRevisionId($key); $params = [ "document" => [ @@ -304,7 +304,7 @@ public function config($fileId, $filePath = null, $shareToken = null, $version = "url" => $fileUrl, "referenceData" => [ "fileKey" => $file->getId(), - "instanceId" => $this->config->GetSystemValue("instanceid", true), + "instanceId" => $this->config->getSystemValue("instanceid", true), ], ], "documentType" => $format["type"], @@ -391,7 +391,7 @@ public function config($fileId, $filePath = null, $shareToken = null, $version = } $canProtect = true; - if ($this->config->GetProtection() === "owner") { + if ($this->config->getProtection() === "owner") { $canProtect = $ownerId === $userId; } $params["document"]["permissions"]["protect"] = $canProtect; @@ -401,11 +401,11 @@ public function config($fileId, $filePath = null, $shareToken = null, $version = $params["document"]["permissions"]["protect"] = false; } - $hashCallback = $this->crypt->GetHash(["userId" => $userId, "ownerId" => $ownerId, "fileId" => $file->getId(), "filePath" => $filePath, "shareToken" => $shareToken, "action" => "track"]); + $hashCallback = $this->crypt->getHash(["userId" => $userId, "ownerId" => $ownerId, "fileId" => $file->getId(), "filePath" => $filePath, "shareToken" => $shareToken, "action" => "track"]); $callback = $this->urlGenerator->linkToRouteAbsolute($this->appName . ".callback.track", ["doc" => $hashCallback]); - if (!$this->config->UseDemo() && !empty($this->config->GetStorageUrl())) { - $callback = str_replace($this->urlGenerator->getAbsoluteURL("/"), $this->config->GetStorageUrl(), $callback); + if (!$this->config->useDemo() && !empty($this->config->getStorageUrl())) { + $callback = str_replace($this->urlGenerator->getAbsoluteURL("/"), $this->config->getStorageUrl(), $callback); } $params["editorConfig"]["callbackUrl"] = $callback; @@ -487,7 +487,7 @@ public function config($fileId, $filePath = null, $shareToken = null, $version = $params["editorConfig"]["createUrl"] = urldecode($createUrl); - $templatesList = TemplateManager::GetGlobalTemplates($file->getMimeType()); + $templatesList = TemplateManager::getGlobalTemplates($file->getMimeType()); if (!empty($templatesList)) { $templates = []; foreach ($templatesList as $templateItem) { @@ -513,14 +513,14 @@ public function config($fileId, $filePath = null, $shareToken = null, $version = } if ($folderLink !== null - && $this->config->GetSystemValue($this->config->_customization_goback) !== false + && $this->config->getSystemValue($this->config->customization_goback) !== false ) { $params["editorConfig"]["customization"]["goback"] = [ "url" => $folderLink ]; if (!$desktop) { - if ($this->config->GetSameTab()) { + if ($this->config->getSameTab()) { $params["editorConfig"]["customization"]["goback"]["blank"] = false; if ($inframe === true) { $params["editorConfig"]["customization"]["goback"]["requestClose"] = true; @@ -535,8 +535,8 @@ public function config($fileId, $filePath = null, $shareToken = null, $version = $params = $this->setCustomization($params); - if ($this->config->UseDemo()) { - $params["editorConfig"]["tenant"] = $this->config->GetSystemValue("instanceid", true); + if ($this->config->useDemo()) { + $params["editorConfig"]["tenant"] = $this->config->getSystemValue("instanceid", true); } if ($anchor !== null) { @@ -549,8 +549,8 @@ public function config($fileId, $filePath = null, $shareToken = null, $version = } } - if (!empty($this->config->GetDocumentServerSecret())) { - $token = \Firebase\JWT\JWT::encode($params, $this->config->GetDocumentServerSecret(), "HS256"); + if (!empty($this->config->getDocumentServerSecret())) { + $token = \Firebase\JWT\JWT::encode($params, $this->config->getDocumentServerSecret(), "HS256"); $params["token"] = $token; } @@ -575,7 +575,7 @@ private function getFile($userId, $fileId, $filePath = null, $template = false) } try { - $folder = !$template ? $this->root->getUserFolder($userId) : TemplateManager::GetGlobalTemplateDir(); + $folder = !$template ? $this->root->getUserFolder($userId) : TemplateManager::getGlobalTemplateDir(); $files = $folder->getById($fileId); } catch (\Exception $e) { $this->logger->logException($e, ["message" => "getFile: $fileId", "app" => $this->appName]); @@ -642,12 +642,12 @@ private function getUrl($file, $user = null, $shareToken = null, $version = 0, $ $data["template"] = true; } - $hashUrl = $this->crypt->GetHash($data); + $hashUrl = $this->crypt->getHash($data); $fileUrl = $this->urlGenerator->linkToRouteAbsolute($this->appName . ".callback.download", ["doc" => $hashUrl]); - if (!$this->config->UseDemo() && !empty($this->config->GetStorageUrl())) { - $fileUrl = str_replace($this->urlGenerator->getAbsoluteURL("/"), $this->config->GetStorageUrl(), $fileUrl); + if (!$this->config->useDemo() && !empty($this->config->getStorageUrl())) { + $fileUrl = str_replace($this->urlGenerator->getAbsoluteURL("/"), $this->config->getStorageUrl(), $fileUrl); } return $fileUrl; @@ -661,7 +661,7 @@ private function getUrl($file, $user = null, $shareToken = null, $version = 0, $ * @return string */ private function buildUserId($userId) { - $instanceId = $this->config->GetSystemValue("instanceid", true); + $instanceId = $this->config->getSystemValue("instanceid", true); $userId = $instanceId . "_" . $userId; return $userId; } @@ -675,84 +675,84 @@ private function buildUserId($userId) { */ private function setCustomization($params) { //default is true - if ($this->config->GetCustomizationChat() === false) { + if ($this->config->getCustomizationChat() === false) { $params["editorConfig"]["customization"]["chat"] = false; } //default is false - if ($this->config->GetCustomizationCompactHeader() === true) { + if ($this->config->getCustomizationCompactHeader() === true) { $params["editorConfig"]["customization"]["compactHeader"] = true; } //default is false - if ($this->config->GetCustomizationFeedback() === true) { + if ($this->config->getCustomizationFeedback() === true) { $params["editorConfig"]["customization"]["feedback"] = true; } //default is false - if ($this->config->GetCustomizationForcesave() === true) { + if ($this->config->getCustomizationForcesave() === true) { $params["editorConfig"]["customization"]["forcesave"] = true; } //default is true - if ($this->config->GetCustomizationHelp() === false) { + if ($this->config->getCustomizationHelp() === false) { $params["editorConfig"]["customization"]["help"] = false; } //default is original - $reviewDisplay = $this->config->GetCustomizationReviewDisplay(); + $reviewDisplay = $this->config->getCustomizationReviewDisplay(); if ($reviewDisplay !== "original") { $params["editorConfig"]["customization"]["reviewDisplay"] = $reviewDisplay; } - $theme = $this->config->GetCustomizationTheme(); + $theme = $this->config->getCustomizationTheme(); if (isset($theme)) { $params["editorConfig"]["customization"]["uiTheme"] = $theme; } //default is false - if ($this->config->GetCustomizationToolbarNoTabs() === true) { + if ($this->config->getCustomizationToolbarNoTabs() === true) { $params["editorConfig"]["customization"]["toolbarNoTabs"] = true; } //default is true - if ($this->config->GetCustomizationMacros() === false) { + if ($this->config->getCustomizationMacros() === false) { $params["editorConfig"]["customization"]["macros"] = false; } //default is true - if ($this->config->GetCustomizationPlugins() === false) { + if ($this->config->getCustomizationPlugins() === false) { $params["editorConfig"]["customization"]["plugins"] = false; } /* from system config */ - $autosave = $this->config->GetSystemValue($this->config->_customization_autosave); + $autosave = $this->config->getSystemValue($this->config->customization_autosave); if (isset($autosave)) { $params["editorConfig"]["customization"]["autosave"] = $autosave; } - $customer = $this->config->GetSystemValue($this->config->_customization_customer); + $customer = $this->config->getSystemValue($this->config->customization_customer); if (isset($customer)) { $params["editorConfig"]["customization"]["customer"] = $customer; } - $loaderLogo = $this->config->GetSystemValue($this->config->_customization_loaderLogo); + $loaderLogo = $this->config->getSystemValue($this->config->customization_loaderLogo); if (isset($loaderLogo)) { $params["editorConfig"]["customization"]["loaderLogo"] = $loaderLogo; } - $loaderName = $this->config->GetSystemValue($this->config->_customization_loaderName); + $loaderName = $this->config->getSystemValue($this->config->customization_loaderName); if (isset($loaderName)) { $params["editorConfig"]["customization"]["loaderName"] = $loaderName; } - $logo = $this->config->GetSystemValue($this->config->_customization_logo); + $logo = $this->config->getSystemValue($this->config->customization_logo); if (isset($logo)) { $params["editorConfig"]["customization"]["logo"] = $logo; } - $zoom = $this->config->GetSystemValue($this->config->_customization_zoom); + $zoom = $this->config->getSystemValue($this->config->customization_zoom); if (isset($zoom)) { $params["editorConfig"]["customization"]["zoom"] = $zoom; } diff --git a/controller/editorcontroller.php b/controller/editorcontroller.php index 061afece..2556b5d6 100644 --- a/controller/editorcontroller.php +++ b/controller/editorcontroller.php @@ -249,7 +249,7 @@ public function create($name, $dir, $templateId = null, $targetPath = null, $sha } if (!empty($templateId)) { - $templateFile = TemplateManager::GetTemplate($templateId); + $templateFile = TemplateManager::getTemplate($templateId); if ($templateFile) { $template = $templateFile->getContent(); } @@ -271,14 +271,14 @@ public function create($name, $dir, $templateId = null, $targetPath = null, $sha $ext = strtolower(pathinfo($name, PATHINFO_EXTENSION)); $documentService = new DocumentService($this->trans, $this->config); try { - $newFileUri = $documentService->GetConvertedUri($fileUrl, $targetExt, $ext, $targetKey); + $newFileUri = $documentService->getConvertedUri($fileUrl, $targetExt, $ext, $targetKey); } catch (\Exception $e) { - $this->logger->logException($e, ["message" => "GetConvertedUri: " . $targetFile->getId(), "app" => $this->appName]); + $this->logger->logException($e, ["message" => "getConvertedUri: " . $targetFile->getId(), "app" => $this->appName]); return ["error" => $e->getMessage()]; } - $template = $documentService->Request($newFileUri); + $template = $documentService->request($newFileUri); } else { - $template = TemplateManager::GetEmptyTemplate($name); + $template = TemplateManager::getEmptyTemplate($name); } if (!$template) { @@ -570,7 +570,7 @@ public function reference($referenceData, $path = null) { $file = null; $fileId = (integer)($referenceData["fileKey"] ?? 0); if (!empty($fileId) - && $referenceData["instanceId"] === $this->config->GetSystemValue("instanceid", true) + && $referenceData["instanceId"] === $this->config->getSystemValue("instanceid", true) ) { list($file, $error, $share) = $this->getFile($userId, $fileId); } @@ -601,13 +601,13 @@ public function reference($referenceData, $path = null) { "path" => $userFolder->getRelativePath($file->getPath()), "referenceData" => [ "fileKey" => $file->getId(), - "instanceId" => $this->config->GetSystemValue("instanceid", true), + "instanceId" => $this->config->getSystemValue("instanceid", true), ], "url" => $this->getUrl($file, $user), ]; - if (!empty($this->config->GetDocumentServerSecret())) { - $token = \Firebase\JWT\JWT::encode($response, $this->config->GetDocumentServerSecret(), "HS256"); + if (!empty($this->config->getDocumentServerSecret())) { + $token = \Firebase\JWT\JWT::encode($response, $this->config->getDocumentServerSecret(), "HS256"); $response["token"] = $token; } @@ -657,7 +657,7 @@ public function convert($fileId, $shareToken = null) { $fileName = $file->getName(); $ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION)); - $format = $this->config->FormatsSetting()[$ext]; + $format = $this->config->formatsSetting()[$ext]; if (!isset($format)) { $this->logger->info("Format for convertion not supported: $fileName", ["app" => $this->appName]); return ["error" => $this->trans->t("Format is not supported")]; @@ -683,9 +683,9 @@ public function convert($fileId, $shareToken = null) { $key = $this->fileUtility->getKey($file); $fileUrl = $this->getUrl($file, $user, $shareToken); try { - $newFileUri = $documentService->GetConvertedUri($fileUrl, $ext, $internalExtension, $key); + $newFileUri = $documentService->getConvertedUri($fileUrl, $ext, $internalExtension, $key); } catch (\Exception $e) { - $this->logger->logException($e, ["message" => "GetConvertedUri: " . $file->getId(), "app" => $this->appName]); + $this->logger->logException($e, ["message" => "getConvertedUri: " . $file->getId(), "app" => $this->appName]); return ["error" => $e->getMessage()]; } @@ -695,7 +695,7 @@ public function convert($fileId, $shareToken = null) { } try { - $newData = $documentService->Request($newFileUri); + $newData = $documentService->request($newFileUri); } catch (\Exception $e) { $this->logger->logException($e, ["message" => "Failed to download converted file", "app" => $this->appName]); return ["error" => $this->trans->t("Failed to download converted file")]; @@ -755,11 +755,11 @@ public function save($name, $dir, $url) { return ["error" => $this->trans->t("You don't have enough permission to create")]; } - $url = $this->config->ReplaceDocumentServerUrlToInternal($url); + $url = $this->config->replaceDocumentServerUrlToInternal($url); try { $documentService = new DocumentService($this->trans, $this->config); - $newData = $documentService->Request($url); + $newData = $documentService->request($url); } catch (\Exception $e) { $this->logger->logException($e, ["message" => "Failed to download file for saving", "app" => $this->appName]); return ["error" => $this->trans->t("Download failed")]; @@ -795,7 +795,7 @@ public function save($name, $dir, $url) { * @NoAdminRequired */ public function history($fileId) { - $this->logger->debug("Request history for: $fileId", ["app" => $this->appName]); + $this->logger->debug("request history for: $fileId", ["app" => $this->appName]); if (!$this->config->isUserAllowedToUse()) { return ["error" => $this->trans->t("Not permitted")]; @@ -839,7 +839,7 @@ public function history($fileId) { $versionNum = $versionNum + 1; $key = $this->fileUtility->getVersionKey($version); - $key = DocumentService::GenerateRevisionId($key); + $key = DocumentService::generateRevisionId($key); $historyItem = [ "created" => $version->getTimestamp(), @@ -870,7 +870,7 @@ public function history($fileId) { } $key = $this->fileUtility->getKey($file, true); - $key = DocumentService::GenerateRevisionId($key); + $key = DocumentService::generateRevisionId($key); $historyItem = [ "created" => $file->getMTime(), @@ -915,7 +915,7 @@ public function history($fileId) { * @NoAdminRequired */ public function version($fileId, $version) { - $this->logger->debug("Request version for: $fileId ($version)", ["app" => $this->appName]); + $this->logger->debug("request version for: $fileId ($version)", ["app" => $this->appName]); if (!$this->config->isUserAllowedToUse()) { return ["error" => $this->trans->t("Not permitted")]; @@ -967,7 +967,7 @@ public function version($fileId, $version) { $fileUrl = $this->getUrl($file, $user, null, $version); } - $key = DocumentService::GenerateRevisionId($key); + $key = DocumentService::generateRevisionId($key); $fileName = $file->getName(); $ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION)); @@ -987,7 +987,7 @@ public function version($fileId, $version) { $prevVersion = array_values($versions)[$version - 2]; $prevVersionKey = $this->fileUtility->getVersionKey($prevVersion); - $prevVersionKey = DocumentService::GenerateRevisionId($prevVersionKey); + $prevVersionKey = DocumentService::generateRevisionId($prevVersionKey); $prevVersionUrl = $this->getUrl($file, $user, null, $version - 1); @@ -998,8 +998,8 @@ public function version($fileId, $version) { ]; } - if (!empty($this->config->GetDocumentServerSecret())) { - $token = \Firebase\JWT\JWT::encode($result, $this->config->GetDocumentServerSecret(), "HS256"); + if (!empty($this->config->getDocumentServerSecret())) { + $token = \Firebase\JWT\JWT::encode($result, $this->config->getDocumentServerSecret(), "HS256"); $result["token"] = $token; } @@ -1018,7 +1018,7 @@ public function version($fileId, $version) { * @PublicPage */ public function restore($fileId, $version) { - $this->logger->debug("Request restore version for: $fileId ($version)", ["app" => $this->appName]); + $this->logger->debug("request restore version for: $fileId ($version)", ["app" => $this->appName]); if (!$this->config->isUserAllowedToUse()) { return ["error" => $this->trans->t("Not permitted")]; @@ -1070,7 +1070,7 @@ public function restore($fileId, $version) { * @NoAdminRequired */ public function url($filePath) { - $this->logger->debug("Request url for: $filePath", ["app" => $this->appName]); + $this->logger->debug("request url for: $filePath", ["app" => $this->appName]); if (!$this->config->isUserAllowedToUse()) { return ["error" => $this->trans->t("Not permitted")]; @@ -1100,8 +1100,8 @@ public function url($filePath) { "url" => $fileUrl ]; - if (!empty($this->config->GetDocumentServerSecret())) { - $token = \Firebase\JWT\JWT::encode($result, $this->config->GetDocumentServerSecret(), "HS256"); + if (!empty($this->config->getDocumentServerSecret())) { + $token = \Firebase\JWT\JWT::encode($result, $this->config->getDocumentServerSecret(), "HS256"); $result["token"] = $token; } @@ -1128,7 +1128,7 @@ public function download($fileId, $toExtension = null, $template = false) { } if ($template) { - $templateFile = TemplateManager::GetTemplate($fileId); + $templateFile = TemplateManager::getTemplate($fileId); if (empty($templateFile)) { $this->logger->info("Download: template not found: $fileId", ["app" => $this->appName]); @@ -1172,14 +1172,14 @@ public function download($fileId, $toExtension = null, $template = false) { $key = $this->fileUtility->getKey($file); $fileUrl = $this->getUrl($file, $user); try { - $newFileUri = $documentService->GetConvertedUri($fileUrl, $ext, $toExtension, $key); + $newFileUri = $documentService->getConvertedUri($fileUrl, $ext, $toExtension, $key); } catch (\Exception $e) { - $this->logger->logException($e, ["message" => "GetConvertedUri: " . $file->getId(), "app" => $this->appName]); + $this->logger->logException($e, ["message" => "getConvertedUri: " . $file->getId(), "app" => $this->appName]); return $this->renderError($e->getMessage()); } try { - $newData = $documentService->Request($newFileUri); + $newData = $documentService->request($newFileUri); } catch (\Exception $e) { $this->logger->logException($e, ["message" => "Failed to download converted file", "app" => $this->appName]); return $this->renderError($this->trans->t("Failed to download converted file")); @@ -1188,7 +1188,7 @@ public function download($fileId, $toExtension = null, $template = false) { $fileNameWithoutExt = substr($fileName, 0, \strlen($fileName) - \strlen($ext) - 1); $newFileName = $fileNameWithoutExt . "." . $toExtension; - $formats = $this->config->FormatsSetting(); + $formats = $this->config->formatsSetting(); return new DataDownloadResponse($newData, $newFileName, $formats[$toExtension]["mime"]); } @@ -1233,7 +1233,7 @@ public function index($fileId, $filePath = null, $shareToken = null, $version = return $this->renderError($this->trans->t("Not permitted")); } - $documentServerUrl = $this->config->GetDocumentServerUrl(); + $documentServerUrl = $this->config->getDocumentServerUrl(); if (empty($documentServerUrl)) { $this->logger->error("documentServerUrl is empty", ["app" => $this->appName]); @@ -1286,7 +1286,7 @@ public function index($fileId, $filePath = null, $shareToken = null, $version = * @NoCSRFRequired * @PublicPage */ - public function PublicPage($fileId, $shareToken, $version = 0, $inframe = false) { + public function publicPage($fileId, $shareToken, $version = 0, $inframe = false) { return $this->index($fileId, null, $shareToken, $version, $inframe); } @@ -1306,7 +1306,7 @@ private function getFile($userId, $fileId, $filePath = null, $template = false) } try { - $folder = !$template ? $this->root->getUserFolder($userId) : TemplateManager::GetGlobalTemplateDir(); + $folder = !$template ? $this->root->getUserFolder($userId) : TemplateManager::getGlobalTemplateDir(); $files = $folder->getById($fileId); } catch (\Exception $e) { $this->logger->logException($e, ["message" => "getFile: $fileId", "app" => $this->appName]); @@ -1373,12 +1373,12 @@ private function getUrl($file, $user = null, $shareToken = null, $version = 0, $ $data["template"] = true; } - $hashUrl = $this->crypt->GetHash($data); + $hashUrl = $this->crypt->getHash($data); $fileUrl = $this->urlGenerator->linkToRouteAbsolute($this->appName . ".callback.download", ["doc" => $hashUrl]); - if (!$this->config->UseDemo() && !empty($this->config->GetStorageUrl())) { - $fileUrl = str_replace($this->urlGenerator->getAbsoluteURL("/"), $this->config->GetStorageUrl(), $fileUrl); + if (!$this->config->useDemo() && !empty($this->config->getStorageUrl())) { + $fileUrl = str_replace($this->urlGenerator->getAbsoluteURL("/"), $this->config->getStorageUrl(), $fileUrl); } return $fileUrl; @@ -1392,7 +1392,7 @@ private function getUrl($file, $user = null, $shareToken = null, $version = 0, $ * @return string */ private function buildUserId($userId) { - $instanceId = $this->config->GetSystemValue("instanceid", true); + $instanceId = $this->config->getSystemValue("instanceid", true); $userId = $instanceId . "_" . $userId; return $userId; } diff --git a/controller/federationcontroller.php b/controller/federationcontroller.php index a84b777b..b66df40a 100644 --- a/controller/federationcontroller.php +++ b/controller/federationcontroller.php @@ -106,7 +106,7 @@ public function key($shareToken, $path) { $key = $this->fileUtility->getKey($file, true); - $key = DocumentService::GenerateRevisionId($key); + $key = DocumentService::generateRevisionId($key); $this->logger->debug("Federated request get for " . $file->getId() . " key $key", ["app" => $this->appName]); diff --git a/controller/joblistcontroller.php b/controller/joblistcontroller.php index 76b80928..a7b03f93 100644 --- a/controller/joblistcontroller.php +++ b/controller/joblistcontroller.php @@ -111,7 +111,7 @@ private function removeJob($job) { * @return void */ private function checkEditorsCheckJob() { - if ($this->config->GetEditorsCheckInterval() > 0) { + if ($this->config->getEditorsCheckInterval() > 0) { $this->addJob(EditorsCheck::class); } else { $this->removeJob(EditorsCheck::class); diff --git a/controller/settingsapicontroller.php b/controller/settingsapicontroller.php index 54f24ee9..2e8a948f 100644 --- a/controller/settingsapicontroller.php +++ b/controller/settingsapicontroller.php @@ -71,9 +71,9 @@ public function __construct( * @NoAdminRequired * @CORS */ - public function GetDocServerUrl() { - $url = $this->config->GetDocumentServerUrl(); - if (!$this->config->SettingsAreSuccessful()) { + public function getDocServerUrl() { + $url = $this->config->getDocumentServerUrl(); + if (!$this->config->settingsAreSuccessful()) { $url = ""; } elseif (!preg_match("/^https?:\/\//i", $url)) { $url = $this->urlGenerator->getAbsoluteURL($url); diff --git a/controller/settingscontroller.php b/controller/settingscontroller.php index 20bd62e3..bf1dd2cd 100644 --- a/controller/settingscontroller.php +++ b/controller/settingscontroller.php @@ -106,34 +106,34 @@ public function __construct( */ public function index() { $data = [ - "documentserver" => $this->config->GetDocumentServerUrl(true), - "documentserverInternal" => $this->config->GetDocumentServerInternalUrl(true), - "storageUrl" => $this->config->GetStorageUrl(), - "verifyPeerOff" => $this->config->GetVerifyPeerOff(), - "secret" => $this->config->GetDocumentServerSecret(true), - "jwtHeader" => $this->config->JwtHeader(true), - "demo" => $this->config->GetDemoData(), + "documentserver" => $this->config->getDocumentServerUrl(true), + "documentserverInternal" => $this->config->getDocumentServerInternalUrl(true), + "storageUrl" => $this->config->getStorageUrl(), + "verifyPeerOff" => $this->config->getVerifyPeerOff(), + "secret" => $this->config->getDocumentServerSecret(true), + "jwtHeader" => $this->config->jwtHeader(true), + "demo" => $this->config->getDemoData(), "currentServer" => $this->urlGenerator->getAbsoluteURL("/"), - "formats" => $this->config->FormatsSetting(), - "sameTab" => $this->config->GetSameTab(), - "preview" => $this->config->GetPreview(), - "versionHistory" => $this->config->GetVersionHistory(), - "protection" => $this->config->GetProtection(), + "formats" => $this->config->formatsSetting(), + "sameTab" => $this->config->getSameTab(), + "preview" => $this->config->getPreview(), + "versionHistory" => $this->config->getVersionHistory(), + "protection" => $this->config->getProtection(), "encryption" => $this->config->checkEncryptionModule(), - "limitGroups" => $this->config->GetLimitGroups(), - "chat" => $this->config->GetCustomizationChat(), - "compactHeader" => $this->config->GetCustomizationCompactHeader(), - "feedback" => $this->config->GetCustomizationFeedback(), - "forcesave" => $this->config->GetCustomizationForcesave(), - "help" => $this->config->GetCustomizationHelp(), - "toolbarNoTabs" => $this->config->GetCustomizationToolbarNoTabs(), - "successful" => $this->config->SettingsAreSuccessful(), - "plugins" => $this->config->GetCustomizationPlugins(), - "macros" => $this->config->GetCustomizationMacros(), - "reviewDisplay" => $this->config->GetCustomizationReviewDisplay(), - "theme" => $this->config->GetCustomizationTheme(), - "templates" => $this->GetGlobalTemplates(), - "linkToDocs" => $this->config->GetLinkToDocs() + "limitGroups" => $this->config->getLimitGroups(), + "chat" => $this->config->getCustomizationChat(), + "compactHeader" => $this->config->getCustomizationCompactHeader(), + "feedback" => $this->config->getCustomizationFeedback(), + "forcesave" => $this->config->getCustomizationForcesave(), + "help" => $this->config->getCustomizationHelp(), + "toolbarNoTabs" => $this->config->getCustomizationToolbarNoTabs(), + "successful" => $this->config->settingsAreSuccessful(), + "plugins" => $this->config->getCustomizationPlugins(), + "macros" => $this->config->getCustomizationMacros(), + "reviewDisplay" => $this->config->getCustomizationReviewDisplay(), + "theme" => $this->config->getCustomizationTheme(), + "templates" => $this->getGlobalTemplates(), + "linkToDocs" => $this->config->getLinkToDocs() ]; return new TemplateResponse($this->appName, "settings", $data, "blank"); } @@ -151,7 +151,7 @@ public function index() { * * @return array */ - public function SaveAddress( + public function saveAddress( $documentserver, $documentserverInternal, $storageUrl, @@ -161,25 +161,25 @@ public function SaveAddress( $demo ) { $error = null; - if (!$this->config->SelectDemo($demo === true)) { + if (!$this->config->selectDemo($demo === true)) { $error = $this->trans->t("The 30-day test period is over, you can no longer connect to demo ONLYOFFICE Docs server."); } if ($demo !== true) { - $this->config->SetDocumentServerUrl($documentserver); - $this->config->SetVerifyPeerOff($verifyPeerOff); - $this->config->SetDocumentServerInternalUrl($documentserverInternal); - $this->config->SetDocumentServerSecret($secret); - $this->config->SetJwtHeader($jwtHeader); + $this->config->setDocumentServerUrl($documentserver); + $this->config->setVerifyPeerOff($verifyPeerOff); + $this->config->setDocumentServerInternalUrl($documentserverInternal); + $this->config->setDocumentServerSecret($secret); + $this->config->setJwtHeader($jwtHeader); } - $this->config->SetStorageUrl($storageUrl); + $this->config->setStorageUrl($storageUrl); $version = null; if (empty($error)) { - $documentserver = $this->config->GetDocumentServerUrl(); + $documentserver = $this->config->getDocumentServerUrl(); if (!empty($documentserver)) { $documentService = new DocumentService($this->trans, $this->config); list($error, $version) = $documentService->checkDocServiceUrl($this->urlGenerator, $this->crypt); - $this->config->SetSettingsError($error); + $this->config->setSettingsError($error); } if ($this->config->checkEncryptionModule() === true) { @@ -188,12 +188,12 @@ public function SaveAddress( } return [ - "documentserver" => $this->config->GetDocumentServerUrl(true), - "verifyPeerOff" => $this->config->GetVerifyPeerOff(), - "documentserverInternal" => $this->config->GetDocumentServerInternalUrl(true), - "storageUrl" => $this->config->GetStorageUrl(), - "secret" => $this->config->GetDocumentServerSecret(true), - "jwtHeader" => $this->config->JwtHeader(true), + "documentserver" => $this->config->getDocumentServerUrl(true), + "verifyPeerOff" => $this->config->getVerifyPeerOff(), + "documentserverInternal" => $this->config->getDocumentServerInternalUrl(true), + "storageUrl" => $this->config->getStorageUrl(), + "secret" => $this->config->getDocumentServerSecret(true), + "jwtHeader" => $this->config->jwtHeader(true), "error" => $error, "version" => $version, ]; @@ -219,7 +219,7 @@ public function SaveAddress( * * @return array */ - public function SaveCommon( + public function saveCommon( $defFormats, $editFormats, $sameTab, @@ -235,20 +235,20 @@ public function SaveCommon( $reviewDisplay, $theme ) { - $this->config->SetDefaultFormats($defFormats); - $this->config->SetEditableFormats($editFormats); - $this->config->SetSameTab($sameTab); - $this->config->SetPreview($preview); - $this->config->SetVersionHistory($versionHistory); - $this->config->SetLimitGroups($limitGroups); - $this->config->SetCustomizationChat($chat); - $this->config->SetCustomizationCompactHeader($compactHeader); - $this->config->SetCustomizationFeedback($feedback); - $this->config->SetCustomizationForcesave($forcesave); - $this->config->SetCustomizationHelp($help); - $this->config->SetCustomizationToolbarNoTabs($toolbarNoTabs); - $this->config->SetCustomizationReviewDisplay($reviewDisplay); - $this->config->SetCustomizationTheme($theme); + $this->config->setDefaultFormats($defFormats); + $this->config->setEditableFormats($editFormats); + $this->config->setSameTab($sameTab); + $this->config->setPreview($preview); + $this->config->setVersionHistory($versionHistory); + $this->config->setLimitGroups($limitGroups); + $this->config->setCustomizationChat($chat); + $this->config->setCustomizationCompactHeader($compactHeader); + $this->config->setCustomizationFeedback($feedback); + $this->config->setCustomizationForcesave($forcesave); + $this->config->setCustomizationHelp($help); + $this->config->setCustomizationToolbarNoTabs($toolbarNoTabs); + $this->config->setCustomizationReviewDisplay($reviewDisplay); + $this->config->setCustomizationTheme($theme); return [ ]; @@ -263,14 +263,14 @@ public function SaveCommon( * * @return array */ - public function SaveSecurity( + public function saveSecurity( $plugins, $macros, $protection ) { - $this->config->SetCustomizationPlugins($plugins); - $this->config->SetCustomizationMacros($macros); - $this->config->SetProtection($protection); + $this->config->setCustomizationPlugins($plugins); + $this->config->setCustomizationMacros($macros); + $this->config->setProtection($protection); return [ ]; @@ -281,7 +281,7 @@ public function SaveSecurity( * * @return array */ - public function ClearHistory() { + public function clearHistory() { FileVersions::clearHistory(); return [ @@ -296,11 +296,11 @@ public function ClearHistory() { * @NoAdminRequired * @PublicPage */ - public function GetSettings() { + public function getSettings() { $result = [ - "formats" => $this->config->FormatsSetting(), - "sameTab" => $this->config->GetSameTab(), - "shareAttributesVersion" => $this->config->ShareAttributesVersion() + "formats" => $this->config->formatsSetting(), + "sameTab" => $this->config->getSameTab(), + "shareAttributesVersion" => $this->config->shareAttributesVersion() ]; return $result; } @@ -310,15 +310,15 @@ public function GetSettings() { * * @return array */ - private function GetGlobalTemplates() { + private function getGlobalTemplates() { $templates = []; - $templatesList = TemplateManager::GetGlobalTemplates(); + $templatesList = TemplateManager::getGlobalTemplates(); foreach ($templatesList as $templateItem) { $template = [ "id" => $templateItem->getId(), "name" => $templateItem->getName(), - "type" => TemplateManager::GetTypeTemplate($templateItem->getMimeType()) + "type" => TemplateManager::getTypeTemplate($templateItem->getMimeType()) ]; array_push($templates, $template); } diff --git a/controller/templatecontroller.php b/controller/templatecontroller.php index 301b671d..d833b625 100644 --- a/controller/templatecontroller.php +++ b/controller/templatecontroller.php @@ -70,15 +70,15 @@ public function __construct( * * @NoAdminRequired */ - public function GetTemplates() { - $templatesList = TemplateManager::GetGlobalTemplates(); + public function getTemplates() { + $templatesList = TemplateManager::getGlobalTemplates(); $templates = []; foreach ($templatesList as $templatesItem) { $template = [ "id" => $templatesItem->getId(), "name" => $templatesItem->getName(), - "type" => TemplateManager::GetTypeTemplate($templatesItem->getMimeType()) + "type" => TemplateManager::getTypeTemplate($templatesItem->getMimeType()) ]; array_push($templates, $template); } @@ -91,18 +91,18 @@ public function GetTemplates() { * * @return array */ - public function AddTemplate() { + public function addTemplate() { $file = $this->request->getUploadedFile("file"); if ($file !== null) { if (is_uploaded_file($file["tmp_name"]) && $file["error"] === 0) { - if (!TemplateManager::IsTemplateType($file["name"])) { + if (!TemplateManager::isTemplateType($file["name"])) { return [ "error" => $this->trans->t("Template must be in OOXML format") ]; } - $templateDir = TemplateManager::GetGlobalTemplateDir(); + $templateDir = TemplateManager::getGlobalTemplateDir(); if ($templateDir->nodeExists($file["name"])) { return [ "error" => $this->trans->t("Template already exists") @@ -117,7 +117,7 @@ public function AddTemplate() { $result = [ "id" => $fileInfo->getId(), "name" => $fileInfo->getName(), - "type" => TemplateManager::GetTypeTemplate($fileInfo->getMimeType()) + "type" => TemplateManager::getTypeTemplate($fileInfo->getMimeType()) ]; $this->logger->debug("Template: added " . $fileInfo->getName(), ["app" => $this->appName]); @@ -138,13 +138,13 @@ public function AddTemplate() { * * @return array */ - public function DeleteTemplate($templateId) { - $templateDir = TemplateManager::GetGlobalTemplateDir(); + public function deleteTemplate($templateId) { + $templateDir = TemplateManager::getGlobalTemplateDir(); try { $templates = $templateDir->getById($templateId); } catch(\Exception $e) { - $this->logger->logException($e, ["message" => "DeleteTemplate: $templateId", "app" => $this->AppName]); + $this->logger->logException($e, ["message" => "deleteTemplate: $templateId", "app" => $this->AppName]); return [ "error" => $this->trans->t("Failed to delete template") ]; diff --git a/lib/appconfig.php b/lib/appconfig.php index b6523723..b00fd7b0 100644 --- a/lib/appconfig.php +++ b/lib/appconfig.php @@ -233,70 +233,70 @@ class AppConfig { * * @var string */ - public $_limitThumbSize = "limit_thumb_size"; + public $limitThumbSize = "limit_thumb_size"; /** * The config key for the customer * * @var string */ - public $_customization_customer = "customization_customer"; + public $customization_customer = "customization_customer"; /** * The config key for the loaderLogo * * @var string */ - public $_customization_loaderLogo = "customization_loaderLogo"; + public $customization_loaderLogo = "customization_loaderLogo"; /** * The config key for the loaderName * * @var string */ - public $_customization_loaderName = "customization_loaderName"; + public $customization_loaderName = "customization_loaderName"; /** * The config key for the logo * * @var string */ - public $_customization_logo = "customization_logo"; + public $customization_logo = "customization_logo"; /** * The config key for the zoom * * @var string */ - public $_customization_zoom = "customization_zoom"; + public $customization_zoom = "customization_zoom"; /** * The config key for the autosave * * @var string */ - public $_customization_autosave = "customization_autosave"; + public $customization_autosave = "customization_autosave"; /** * The config key for the goback * * @var string */ - public $_customization_goback = "customization_goback"; + public $customization_goback = "customization_goback"; /** * The config key for the macros * * @var string */ - public $_customization_macros = "customization_macros"; + public $customization_macros = "customization_macros"; /** * The config key for the plugins * * @var string */ - public $_customizationPlugins = "customization_plugins"; + public $customizationPlugins = "customization_plugins"; /** * The config key for the interval of editors availability check by cron @@ -323,7 +323,7 @@ public function __construct($AppName) { * * @return string */ - public function GetSystemValue($key, $system = false) { + public function getSystemValue($key, $system = false) { if ($system) { return $this->config->getSystemValue($key); } @@ -342,10 +342,10 @@ public function GetSystemValue($key, $system = false) { * * @return bool */ - public function SelectDemo($value) { + public function selectDemo($value) { $this->logger->info("Select demo: " . json_encode($value), ["app" => $this->appName]); - $data = $this->GetDemoData(); + $data = $this->getDemoData(); if ($value === true && !$data["available"]) { $this->logger->info("Trial demo is overdue: " . json_encode($data), ["app" => $this->appName]); @@ -366,7 +366,7 @@ public function SelectDemo($value) { * * @return array */ - public function GetDemoData() { + public function getDemoData() { $data = $this->config->getAppValue($this->appName, $this->_demo, ""); if (empty($data)) { @@ -395,8 +395,8 @@ public function GetDemoData() { * * @return bool */ - public function UseDemo() { - return $this->GetDemoData()["enabled"] === true; + public function useDemo() { + return $this->getDemoData()["enabled"] === true; } /** @@ -406,7 +406,7 @@ public function UseDemo() { * * @return void */ - public function SetDocumentServerUrl($documentServer) { + public function setDocumentServerUrl($documentServer) { $documentServer = trim($documentServer); if (\strlen($documentServer) > 0) { $documentServer = rtrim($documentServer, "/") . "/"; @@ -415,7 +415,7 @@ public function SetDocumentServerUrl($documentServer) { } } - $this->logger->info("SetDocumentServerUrl: $documentServer", ["app" => $this->appName]); + $this->logger->info("setDocumentServerUrl: $documentServer", ["app" => $this->appName]); $this->config->setAppValue($this->appName, $this->_documentserver, $documentServer); } @@ -427,14 +427,14 @@ public function SetDocumentServerUrl($documentServer) { * * @return string */ - public function GetDocumentServerUrl($origin = false) { - if (!$origin && $this->UseDemo()) { + public function getDocumentServerUrl($origin = false) { + if (!$origin && $this->useDemo()) { return $this->DEMO_PARAM["ADDR"]; } $url = $this->config->getAppValue($this->appName, $this->_documentserver, ""); if (empty($url)) { - $url = $this->GetSystemValue($this->_documentserver); + $url = $this->getSystemValue($this->_documentserver); } if ($url !== "/") { $url = rtrim($url, "/"); @@ -452,7 +452,7 @@ public function GetDocumentServerUrl($origin = false) { * * @return void */ - public function SetDocumentServerInternalUrl($documentServerInternal) { + public function setDocumentServerInternalUrl($documentServerInternal) { $documentServerInternal = rtrim(trim($documentServerInternal), "/"); if (\strlen($documentServerInternal) > 0) { $documentServerInternal = $documentServerInternal . "/"; @@ -461,7 +461,7 @@ public function SetDocumentServerInternalUrl($documentServerInternal) { } } - $this->logger->info("SetDocumentServerInternalUrl: $documentServerInternal", ["app" => $this->appName]); + $this->logger->info("setDocumentServerInternalUrl: $documentServerInternal", ["app" => $this->appName]); $this->config->setAppValue($this->appName, $this->_documentserverInternal, $documentServerInternal); } @@ -473,17 +473,17 @@ public function SetDocumentServerInternalUrl($documentServerInternal) { * * @return string */ - public function GetDocumentServerInternalUrl($origin = false) { - if (!$origin && $this->UseDemo()) { - return $this->GetDocumentServerUrl(); + public function getDocumentServerInternalUrl($origin = false) { + if (!$origin && $this->useDemo()) { + return $this->getDocumentServerUrl(); } $url = $this->config->getAppValue($this->appName, $this->_documentserverInternal, ""); if (empty($url)) { - $url = $this->GetSystemValue($this->_documentserverInternal); + $url = $this->getSystemValue($this->_documentserverInternal); } if (!$origin && empty($url)) { - $url = $this->GetDocumentServerUrl(); + $url = $this->getDocumentServerUrl(); } return $url; } @@ -495,10 +495,10 @@ public function GetDocumentServerInternalUrl($origin = false) { * * @return string */ - public function ReplaceDocumentServerUrlToInternal($url) { - $documentServerUrl = $this->GetDocumentServerInternalUrl(); + public function replaceDocumentServerUrlToInternal($url) { + $documentServerUrl = $this->getDocumentServerInternalUrl(); if (!empty($documentServerUrl)) { - $from = $this->GetDocumentServerUrl(); + $from = $this->getDocumentServerUrl(); if (!preg_match("/^https?:\/\//i", $from)) { $parsedUrl = parse_url($url); @@ -517,11 +517,11 @@ public function ReplaceDocumentServerUrlToInternal($url) { /** * Save the ownCloud address available from document server to the application configuration * - * @param string $documentServer - document service address + * @param string $storageUrl - storage url * * @return void */ - public function SetStorageUrl($storageUrl) { + public function setStorageUrl($storageUrl) { $storageUrl = rtrim(trim($storageUrl), "/"); if (\strlen($storageUrl) > 0) { $storageUrl = $storageUrl . "/"; @@ -530,7 +530,7 @@ public function SetStorageUrl($storageUrl) { } } - $this->logger->info("SetStorageUrl: $storageUrl", ["app" => $this->appName]); + $this->logger->info("setStorageUrl: $storageUrl", ["app" => $this->appName]); $this->config->setAppValue($this->appName, $this->_storageUrl, $storageUrl); } @@ -540,10 +540,10 @@ public function SetStorageUrl($storageUrl) { * * @return string */ - public function GetStorageUrl() { + public function getStorageUrl() { $url = $this->config->getAppValue($this->appName, $this->_storageUrl, ""); if (empty($url)) { - $url = $this->GetSystemValue($this->_storageUrl); + $url = $this->getSystemValue($this->_storageUrl); } return $url; } @@ -555,7 +555,7 @@ public function GetStorageUrl() { * * @return void */ - public function SetDocumentServerSecret($secret) { + public function setDocumentServerSecret($secret) { $secret = trim($secret); if (empty($secret)) { $this->logger->info("Clear secret key", ["app" => $this->appName]); @@ -573,14 +573,14 @@ public function SetDocumentServerSecret($secret) { * * @return string */ - public function GetDocumentServerSecret($origin = false) { - if (!$origin && $this->UseDemo()) { + public function getDocumentServerSecret($origin = false) { + if (!$origin && $this->useDemo()) { return $this->DEMO_PARAM["SECRET"]; } $secret = $this->config->getAppValue($this->appName, $this->_jwtSecret, ""); if (empty($secret)) { - $secret = $this->GetSystemValue($this->_jwtSecret); + $secret = $this->getSystemValue($this->_jwtSecret); } return $secret; } @@ -590,10 +590,10 @@ public function GetDocumentServerSecret($origin = false) { * * @return string */ - public function GetSKey() { - $secret = $this->GetDocumentServerSecret(); + public function getSKey() { + $secret = $this->getDocumentServerSecret(); if (empty($secret)) { - $secret = $this->GetSystemValue($this->_cryptSecret, true); + $secret = $this->getSystemValue($this->_cryptSecret, true); } return $secret; } @@ -605,7 +605,7 @@ public function GetSKey() { * * @return void */ - public function SetDefaultFormats($formats) { + public function setDefaultFormats($formats) { $value = json_encode($formats); $this->logger->info("Set default formats: $value", ["app" => $this->appName]); @@ -617,7 +617,7 @@ public function SetDefaultFormats($formats) { * * @return array */ - private function GetDefaultFormats() { + private function getDefaultFormats() { $value = $this->config->getAppValue($this->appName, $this->_defFormats, ""); if (empty($value)) { return []; @@ -632,7 +632,7 @@ private function GetDefaultFormats() { * * @return void */ - public function SetEditableFormats($formats) { + public function setEditableFormats($formats) { $value = json_encode($formats); $this->logger->info("Set editing formats: $value", ["app" => $this->appName]); @@ -644,7 +644,7 @@ public function SetEditableFormats($formats) { * * @return array */ - private function GetEditableFormats() { + private function getEditableFormats() { $value = $this->config->getAppValue($this->appName, $this->_editFormats, ""); if (empty($value)) { return []; @@ -659,7 +659,7 @@ private function GetEditableFormats() { * * @return void */ - public function SetSameTab($value) { + public function setSameTab($value) { $this->logger->info("Set opening in a same tab: " . json_encode($value), ["app" => $this->appName]); $this->config->setAppValue($this->appName, $this->_sameTab, json_encode($value)); @@ -670,7 +670,7 @@ public function SetSameTab($value) { * * @return bool */ - public function GetSameTab() { + public function getSameTab() { return $this->config->getAppValue($this->appName, $this->_sameTab, "false") === "true"; } @@ -681,7 +681,7 @@ public function GetSameTab() { * * @return bool */ - public function SetPreview($value) { + public function setPreview($value) { $this->logger->info("Set generate preview: " . json_encode($value), ["app" => $this->appName]); $this->config->setAppValue($this->appName, $this->_preview, json_encode($value)); @@ -692,7 +692,7 @@ public function SetPreview($value) { * * @return bool */ - public function GetPreview() { + public function getPreview() { return $this->config->getAppValue($this->appName, $this->_preview, "true") === "true"; } @@ -703,7 +703,7 @@ public function GetPreview() { * * @return void */ - public function SetVersionHistory($value) { + public function setVersionHistory($value) { $this->logger->info("Set keep versions history: " . json_encode($value), ["app" => $this->appName]); $this->config->setAppValue($this->appName, $this->_versionHistory, json_encode($value)); @@ -714,7 +714,7 @@ public function SetVersionHistory($value) { * * @return bool */ - public function GetVersionHistory() { + public function getVersionHistory() { return $this->config->getAppValue($this->appName, $this->_versionHistory, "true") === "true"; } @@ -725,7 +725,7 @@ public function GetVersionHistory() { * * @return void */ - public function SetProtection($value) { + public function setProtection($value) { $this->logger->info("Set protection: " . $value, ["app" => $this->appName]); $this->config->setAppValue($this->appName, $this->_protection, $value); @@ -736,7 +736,7 @@ public function SetProtection($value) { * * @return string */ - public function GetProtection() { + public function getProtection() { $value = $this->config->getAppValue($this->appName, $this->_protection, "owner"); if ($value === "all") { return "all"; @@ -751,7 +751,7 @@ public function GetProtection() { * * @return void */ - public function SetCustomizationChat($value) { + public function setCustomizationChat($value) { $this->logger->info("Set chat display: " . json_encode($value), ["app" => $this->appName]); $this->config->setAppValue($this->appName, $this->_customizationChat, json_encode($value)); @@ -762,7 +762,7 @@ public function SetCustomizationChat($value) { * * @return bool */ - public function GetCustomizationChat() { + public function getCustomizationChat() { return $this->config->getAppValue($this->appName, $this->_customizationChat, "true") === "true"; } @@ -773,7 +773,7 @@ public function GetCustomizationChat() { * * @return void */ - public function SetCustomizationCompactHeader($value) { + public function setCustomizationCompactHeader($value) { $this->logger->info("Set compact header display: " . json_encode($value), ["app" => $this->appName]); $this->config->setAppValue($this->appName, $this->_customizationCompactHeader, json_encode($value)); @@ -784,7 +784,7 @@ public function SetCustomizationCompactHeader($value) { * * @return bool */ - public function GetCustomizationCompactHeader() { + public function getCustomizationCompactHeader() { return $this->config->getAppValue($this->appName, $this->_customizationCompactHeader, "true") === "true"; } @@ -795,7 +795,7 @@ public function GetCustomizationCompactHeader() { * * @return void */ - public function SetCustomizationFeedback($value) { + public function setCustomizationFeedback($value) { $this->logger->info("Set feedback display: " . json_encode($value), ["app" => $this->appName]); $this->config->setAppValue($this->appName, $this->_customizationFeedback, json_encode($value)); @@ -806,7 +806,7 @@ public function SetCustomizationFeedback($value) { * * @return bool */ - public function GetCustomizationFeedback() { + public function getCustomizationFeedback() { return $this->config->getAppValue($this->appName, $this->_customizationFeedback, "true") === "true"; } @@ -817,7 +817,7 @@ public function GetCustomizationFeedback() { * * @return void */ - public function SetCustomizationForcesave($value) { + public function setCustomizationForcesave($value) { $this->logger->info("Set forcesave: " . json_encode($value), ["app" => $this->appName]); $this->config->setAppValue($this->appName, $this->_customizationForcesave, json_encode($value)); @@ -828,7 +828,7 @@ public function SetCustomizationForcesave($value) { * * @return bool */ - public function GetCustomizationForcesave() { + public function getCustomizationForcesave() { $value = $this->config->getAppValue($this->appName, $this->_customizationForcesave, "false") === "true"; return $value && ($this->checkEncryptionModule() === false); @@ -841,7 +841,7 @@ public function GetCustomizationForcesave() { * * @return void */ - public function SetCustomizationHelp($value) { + public function setCustomizationHelp($value) { $this->logger->info("Set help display: " . json_encode($value), ["app" => $this->appName]); $this->config->setAppValue($this->appName, $this->_customizationHelp, json_encode($value)); @@ -852,7 +852,7 @@ public function SetCustomizationHelp($value) { * * @return bool */ - public function GetCustomizationHelp() { + public function getCustomizationHelp() { return $this->config->getAppValue($this->appName, $this->_customizationHelp, "true") === "true"; } @@ -863,7 +863,7 @@ public function GetCustomizationHelp() { * * @return void */ - public function SetCustomizationToolbarNoTabs($value) { + public function setCustomizationToolbarNoTabs($value) { $this->logger->info("Set without tabs: " . json_encode($value), ["app" => $this->appName]); $this->config->setAppValue($this->appName, $this->_customizationToolbarNoTabs, json_encode($value)); @@ -874,7 +874,7 @@ public function SetCustomizationToolbarNoTabs($value) { * * @return bool */ - public function GetCustomizationToolbarNoTabs() { + public function getCustomizationToolbarNoTabs() { return $this->config->getAppValue($this->appName, $this->_customizationToolbarNoTabs, "true") === "true"; } @@ -885,7 +885,7 @@ public function GetCustomizationToolbarNoTabs() { * * @return void */ - public function SetCustomizationReviewDisplay($value) { + public function setCustomizationReviewDisplay($value) { $this->logger->info("Set review mode: " . $value, ["app" => $this->appName]); $this->config->setAppValue($this->appName, $this->_customizationReviewDisplay, $value); @@ -896,7 +896,7 @@ public function SetCustomizationReviewDisplay($value) { * * @return string */ - public function GetCustomizationReviewDisplay() { + public function getCustomizationReviewDisplay() { $value = $this->config->getAppValue($this->appName, $this->_customizationReviewDisplay, "original"); if ($value === "markup") { return "markup"; @@ -914,7 +914,7 @@ public function GetCustomizationReviewDisplay() { * * @return void */ - public function SetCustomizationTheme($value) { + public function setCustomizationTheme($value) { $this->logger->info("Set theme: " . $value, ["app" => $this->appName]); $this->config->setAppValue($this->appName, $this->_customizationTheme, $value); @@ -925,7 +925,7 @@ public function SetCustomizationTheme($value) { * * @return string */ - public function GetCustomizationTheme() { + public function getCustomizationTheme() { $value = $this->config->getAppValue($this->appName, $this->_customizationTheme, "theme-classic-light"); if ($value === "theme-light") { return "theme-light"; @@ -943,10 +943,10 @@ public function GetCustomizationTheme() { * * @return void */ - public function SetCustomizationMacros($value) { + public function setCustomizationMacros($value) { $this->logger->info("Set macros enabled: " . json_encode($value), ["app" => $this->appName]); - $this->config->setAppValue($this->appName, $this->_customization_macros, json_encode($value)); + $this->config->setAppValue($this->appName, $this->customization_macros, json_encode($value)); } /** @@ -954,8 +954,8 @@ public function SetCustomizationMacros($value) { * * @return bool */ - public function GetCustomizationMacros() { - return $this->config->getAppValue($this->appName, $this->_customization_macros, "true") === "true"; + public function getCustomizationMacros() { + return $this->config->getAppValue($this->appName, $this->customization_macros, "true") === "true"; } /** @@ -965,10 +965,10 @@ public function GetCustomizationMacros() { * * @return void */ - public function SetCustomizationPlugins($value) { + public function setCustomizationPlugins($value) { $this->logger->info("Set plugins enabled: " . json_encode($value), ["app" => $this->appName]); - $this->config->setAppValue($this->appName, $this->_customizationPlugins, json_encode($value)); + $this->config->setAppValue($this->appName, $this->customizationPlugins, json_encode($value)); } /** @@ -976,8 +976,8 @@ public function SetCustomizationPlugins($value) { * * @return bool */ - public function GetCustomizationPlugins() { - return $this->config->getAppValue($this->appName, $this->_customizationPlugins, "true") === "true"; + public function getCustomizationPlugins() { + return $this->config->getAppValue($this->appName, $this->customizationPlugins, "true") === "true"; } /** @@ -987,7 +987,7 @@ public function GetCustomizationPlugins() { * * @return void */ - public function SetLimitGroups($groups) { + public function setLimitGroups($groups) { if (!\is_array($groups)) { $groups = []; } @@ -1002,7 +1002,7 @@ public function SetLimitGroups($groups) { * * @return array */ - public function GetLimitGroups() { + public function getLimitGroups() { $value = $this->config->getAppValue($this->appName, $this->_groups, ""); if (empty($value)) { return []; @@ -1028,7 +1028,7 @@ public function isUserAllowedToUse($userId = null) { return false; } - $groups = $this->GetLimitGroups(); + $groups = $this->getLimitGroups(); // no group set -> all users are allowed if (\count($groups) === 0) { return true; @@ -1048,7 +1048,7 @@ public function isUserAllowedToUse($userId = null) { $group = \OC::$server->getGroupManager()->get($groupName); if ($group === null) { \OC::$server->getLogger()->error("Group is unknown $groupName", ["app" => $this->appName]); - $this->SetLimitGroups(array_diff($groups, [$groupName])); + $this->setLimitGroups(array_diff($groups, [$groupName])); } else { if ($group->inGroup($user)) { return true; @@ -1066,8 +1066,8 @@ public function isUserAllowedToUse($userId = null) { * * @return void */ - public function SetVerifyPeerOff($verifyPeerOff) { - $this->logger->info("SetVerifyPeerOff " . json_encode($verifyPeerOff), ["app" => $this->appName]); + public function setVerifyPeerOff($verifyPeerOff) { + $this->logger->info("setVerifyPeerOff " . json_encode($verifyPeerOff), ["app" => $this->appName]); $this->config->setAppValue($this->appName, $this->_verification, json_encode($verifyPeerOff)); } @@ -1077,14 +1077,14 @@ public function SetVerifyPeerOff($verifyPeerOff) { * * @return bool */ - public function GetVerifyPeerOff() { + public function getVerifyPeerOff() { $turnOff = $this->config->getAppValue($this->appName, $this->_verification, ""); if (!empty($turnOff)) { return $turnOff === "true"; } - return $this->GetSystemValue($this->_verification); + return $this->getSystemValue($this->_verification); } /** @@ -1092,8 +1092,8 @@ public function GetVerifyPeerOff() { * * @return int */ - public function GetLimitThumbSize() { - $limitSize = (integer)$this->GetSystemValue($this->_limitThumbSize); + public function getLimitThumbSize() { + $limitSize = (integer)$this->getSystemValue($this->limitThumbSize); if (!empty($limitSize)) { return $limitSize; @@ -1109,14 +1109,14 @@ public function GetLimitThumbSize() { * * @return string */ - public function JwtHeader($origin = false) { - if (!$origin && $this->UseDemo()) { + public function jwtHeader($origin = false) { + if (!$origin && $this->useDemo()) { return $this->DEMO_PARAM["HEADER"]; } $header = $this->config->getAppValue($this->appName, $this->_jwtHeader, ""); if (empty($header)) { - $header = $this->GetSystemValue($this->_jwtHeader); + $header = $this->getSystemValue($this->_jwtHeader); } if (!$origin && empty($header)) { $header = "Authorization"; @@ -1131,7 +1131,7 @@ public function JwtHeader($origin = false) { * * @return void */ - public function SetJwtHeader($value) { + public function setJwtHeader($value) { $value = trim($value); if (empty($value)) { $this->logger->info("Clear header key", ["app" => $this->appName]); @@ -1147,8 +1147,8 @@ public function SetJwtHeader($value) { * * @return int */ - public function GetJwtLeeway() { - $jwtLeeway = (integer)$this->GetSystemValue($this->_jwtLeeway); + public function getJwtLeeway() { + $jwtLeeway = (integer)$this->getSystemValue($this->_jwtLeeway); return $jwtLeeway; } @@ -1160,7 +1160,7 @@ public function GetJwtLeeway() { * * @return void */ - public function SetSettingsError($value) { + public function setSettingsError($value) { $this->config->setAppValue($this->appName, $this->_settingsError, $value); } @@ -1169,7 +1169,7 @@ public function SetSettingsError($value) { * * @return bool */ - public function SettingsAreSuccessful() { + public function settingsAreSuccessful() { return empty($this->config->getAppValue($this->appName, $this->_settingsError, "")); } @@ -1202,17 +1202,17 @@ public function checkEncryptionModule() { * * @NoAdminRequired */ - public function FormatsSetting() { + public function formatsSetting() { $result = $this->formats; - $defFormats = $this->GetDefaultFormats(); + $defFormats = $this->getDefaultFormats(); foreach ($defFormats as $format => $setting) { if (\array_key_exists($format, $result)) { $result[$format]["def"] = ($setting === true || $setting === "true"); } } - $editFormats = $this->GetEditableFormats(); + $editFormats = $this->getEditableFormats(); foreach ($editFormats as $format => $setting) { if (\array_key_exists($format, $result)) { $result[$format]["edit"] = ($setting === true || $setting === "true"); @@ -1227,7 +1227,7 @@ public function FormatsSetting() { * * @return string */ - public function ShareAttributesVersion() { + public function shareAttributesVersion() { if (\version_compare(\implode(".", \OCP\Util::getVersion()), "10.3.0", ">=")) { return "v2"; } elseif (\version_compare(\implode(".", \OCP\Util::getVersion()), "10.2.0", ">=")) { @@ -1241,8 +1241,8 @@ public function ShareAttributesVersion() { * * @return int */ - public function GetEditorsCheckInterval() { - $interval = $this->GetSystemValue($this->_editors_check_interval); + public function getEditorsCheckInterval() { + $interval = $this->getSystemValue($this->_editors_check_interval); if (empty($interval) && $interval !== 0) { $interval = 60 * 60 * 24; @@ -1310,7 +1310,7 @@ public function GetEditorsCheckInterval() { * * @return string */ - public function GetLinkToDocs() { + public function getLinkToDocs() { return $this->linkToDocs; } } diff --git a/lib/command/documentserver.php b/lib/command/documentserver.php index 662ebc8c..811f4ceb 100644 --- a/lib/command/documentserver.php +++ b/lib/command/documentserver.php @@ -113,7 +113,7 @@ protected function configure() { protected function execute(InputInterface $input, OutputInterface $output) { $check = $input->getOption("check"); - $documentserver = $this->config->GetDocumentServerUrl(true); + $documentserver = $this->config->getDocumentServerUrl(true); if (empty($documentserver)) { $output->writeln("Document server is not configured"); return 1; @@ -123,7 +123,7 @@ protected function execute(InputInterface $input, OutputInterface $output) { $documentService = new DocumentService($this->trans, $this->config); list($error, $version) = $documentService->checkDocServiceUrl($this->urlGenerator, $this->crypt); - $this->config->SetSettingsError($error); + $this->config->setSettingsError($error); if (!empty($error)) { $output->writeln("Error connection: $error"); diff --git a/lib/cron/editorscheck.php b/lib/cron/editorscheck.php index b5d2dcbf..7a734745 100644 --- a/lib/cron/editorscheck.php +++ b/lib/cron/editorscheck.php @@ -113,7 +113,7 @@ public function __construct( $this->trans = $trans; $this->crypt = $crypt; $this->groupManager = $groupManager; - $this->setInterval($this->config->GetEditorsCheckInterval()); + $this->setInterval($this->config->getEditorsCheckInterval()); } /** @@ -124,17 +124,17 @@ public function __construct( * @return void */ protected function run($argument) { - if (empty($this->config->GetDocumentServerUrl())) { + if (empty($this->config->getDocumentServerUrl())) { $this->logger->debug("Settings are empty", ["app" => $this->appName]); return; } - if (!$this->config->SettingsAreSuccessful()) { + if (!$this->config->settingsAreSuccessful()) { $this->logger->debug("Settings are not correct", ["app" => $this->appName]); return; } $fileUrl = $this->urlGenerator->linkToRouteAbsolute($this->appName . ".callback.emptyfile"); - if (!$this->config->UseDemo() && !empty($this->config->GetStorageUrl())) { - $fileUrl = str_replace($this->urlGenerator->getAbsoluteURL("/"), $this->config->GetStorageUrl(), $fileUrl); + if (!$this->config->useDemo() && !empty($this->config->getStorageUrl())) { + $fileUrl = str_replace($this->urlGenerator->getAbsoluteURL("/"), $this->config->getStorageUrl(), $fileUrl); } $host = parse_url($fileUrl)["host"]; if ($host === "localhost" || $host === "127.0.0.1") { @@ -148,7 +148,7 @@ protected function run($argument) { list($error, $version) = $documentService->checkDocServiceUrl($this->urlGenerator, $this->crypt); if (!empty($error)) { $this->logger->info("ONLYOFFICE server is not available", ["app" => $this->appName]); - $this->config->SetSettingsError($error); + $this->config->setSettingsError($error); $this->notifyAdmins(); } else { $this->logger->debug("ONLYOFFICE server availability check is finished successfully", ["app" => $this->appName]); diff --git a/lib/crypt.php b/lib/crypt.php index 588b1643..377b98e1 100644 --- a/lib/crypt.php +++ b/lib/crypt.php @@ -49,8 +49,8 @@ public function __construct(AppConfig $appConfig) { * * @return string */ - public function GetHash($object) { - return \Firebase\JWT\JWT::encode($object, $this->config->GetSKey(), "HS256"); + public function getHash($object) { + return \Firebase\JWT\JWT::encode($object, $this->config->getSKey(), "HS256"); } /** @@ -60,14 +60,14 @@ public function GetHash($object) { * * @return array */ - public function ReadHash($token) { + public function readHash($token) { $result = null; $error = null; if ($token === null) { return [$result, "token is empty"]; } try { - $result = \Firebase\JWT\JWT::decode($token, new \Firebase\JWT\Key($this->config->GetSKey(), "HS256")); + $result = \Firebase\JWT\JWT::decode($token, new \Firebase\JWT\Key($this->config->getSKey(), "HS256")); } catch (\UnexpectedValueException $e) { $error = $e->getMessage(); } diff --git a/lib/documentservice.php b/lib/documentservice.php index b2b0f3b0..2d47c46d 100644 --- a/lib/documentservice.php +++ b/lib/documentservice.php @@ -67,7 +67,7 @@ public function __construct(IL10N $trans, AppConfig $appConfig) { * * @return string */ - public static function GenerateRevisionId($expected_key) { + public static function generateRevisionId($expected_key) { if (\strlen($expected_key) > 20) { $expected_key = crc32($expected_key); } @@ -86,12 +86,12 @@ public static function GenerateRevisionId($expected_key) { * * @return string */ - public function GetConvertedUri($document_uri, $from_extension, $to_extension, $document_revision_id) { - $responceFromConvertService = $this->SendRequestToConvertService($document_uri, $from_extension, $to_extension, $document_revision_id, false); + public function getConvertedUri($document_uri, $from_extension, $to_extension, $document_revision_id) { + $responceFromConvertService = $this->sendRequestToConvertService($document_uri, $from_extension, $to_extension, $document_revision_id, false); $errorElement = $responceFromConvertService->Error; if ($errorElement->count() > 0) { - $this->ProcessConvServResponceError($errorElement . ""); + $this->processConvServResponceError($errorElement . ""); } $isEndConvert = $responceFromConvertService->EndConvert; @@ -104,7 +104,7 @@ public function GetConvertedUri($document_uri, $from_extension, $to_extension, $ } /** - * Request for conversion to a service + * request for conversion to a service * * @param string $document_uri - Uri for the document to convert * @param string $from_extension - Document extension @@ -114,8 +114,8 @@ public function GetConvertedUri($document_uri, $from_extension, $to_extension, $ * * @return array */ - public function SendRequestToConvertService($document_uri, $from_extension, $to_extension, $document_revision_id, $is_async) { - $documentServerUrl = $this->config->GetDocumentServerInternalUrl(); + public function sendRequestToConvertService($document_uri, $from_extension, $to_extension, $document_revision_id, $is_async) { + $documentServerUrl = $this->config->getDocumentServerInternalUrl(); if (empty($documentServerUrl)) { throw new \Exception($this->trans->t("ONLYOFFICE app is not configured. Please contact admin")); @@ -127,7 +127,7 @@ public function SendRequestToConvertService($document_uri, $from_extension, $to_ $document_revision_id = $document_uri; } - $document_revision_id = self::GenerateRevisionId($document_revision_id); + $document_revision_id = self::generateRevisionId($document_revision_id); if (empty($from_extension)) { $from_extension = pathinfo($document_uri)["extension"]; @@ -145,8 +145,8 @@ public function SendRequestToConvertService($document_uri, $from_extension, $to_ "region" => str_replace("_", "-", \OC::$server->getL10NFactory("")->get("")->getLanguageCode()) ]; - if ($this->config->UseDemo()) { - $data["tenant"] = $this->config->GetSystemValue("instanceid", true); + if ($this->config->useDemo()) { + $data["tenant"] = $this->config->getSystemValue("instanceid", true); } $opts = [ @@ -157,19 +157,19 @@ public function SendRequestToConvertService($document_uri, $from_extension, $to_ "body" => json_encode($data) ]; - if (!empty($this->config->GetDocumentServerSecret())) { + if (!empty($this->config->getDocumentServerSecret())) { $params = [ "payload" => $data ]; - $token = \Firebase\JWT\JWT::encode($params, $this->config->GetDocumentServerSecret(), "HS256"); - $opts["headers"][$this->config->JwtHeader()] = "Bearer " . $token; + $token = \Firebase\JWT\JWT::encode($params, $this->config->getDocumentServerSecret(), "HS256"); + $opts["headers"][$this->config->jwtHeader()] = "Bearer " . $token; - $token = \Firebase\JWT\JWT::encode($data, $this->config->GetDocumentServerSecret(), "HS256"); + $token = \Firebase\JWT\JWT::encode($data, $this->config->getDocumentServerSecret(), "HS256"); $data["token"] = $token; $opts["body"] = json_encode($data); } - $response_xml_data = $this->Request($urlToConverter, "post", $opts); + $response_xml_data = $this->request($urlToConverter, "post", $opts); libxml_use_internal_errors(true); if (!\function_exists("simplexml_load_file")) { @@ -194,7 +194,7 @@ public function SendRequestToConvertService($document_uri, $from_extension, $to_ * * @return null */ - public function ProcessConvServResponceError($errorCode) { + public function processConvServResponceError($errorCode) { $errorMessageTemplate = $this->trans->t("Error occurred in the document service"); $errorMessage = ""; @@ -237,12 +237,12 @@ public function ProcessConvServResponceError($errorCode) { } /** - * Request health status + * request health status * * @return bool */ - public function HealthcheckRequest() { - $documentServerUrl = $this->config->GetDocumentServerInternalUrl(); + public function healthcheckRequest() { + $documentServerUrl = $this->config->getDocumentServerInternalUrl(); if (empty($documentServerUrl)) { throw new \Exception($this->trans->t("ONLYOFFICE app is not configured. Please contact admin")); @@ -250,7 +250,7 @@ public function HealthcheckRequest() { $urlHealthcheck = $documentServerUrl . "healthcheck"; - $response = $this->Request($urlHealthcheck); + $response = $this->request($urlHealthcheck); return $response === "true"; } @@ -262,8 +262,8 @@ public function HealthcheckRequest() { * * @return array */ - public function CommandRequest($method) { - $documentServerUrl = $this->config->GetDocumentServerInternalUrl(); + public function commandRequest($method) { + $documentServerUrl = $this->config->getDocumentServerInternalUrl(); if (empty($documentServerUrl)) { throw new \Exception($this->trans->t("ONLYOFFICE app is not configured. Please contact admin")); @@ -282,23 +282,23 @@ public function CommandRequest($method) { "body" => json_encode($data) ]; - if (!empty($this->config->GetDocumentServerSecret())) { + if (!empty($this->config->getDocumentServerSecret())) { $params = [ "payload" => $data ]; - $token = \Firebase\JWT\JWT::encode($params, $this->config->GetDocumentServerSecret(), "HS256"); - $opts["headers"][$this->config->JwtHeader()] = "Bearer " . $token; + $token = \Firebase\JWT\JWT::encode($params, $this->config->getDocumentServerSecret(), "HS256"); + $opts["headers"][$this->config->jwtHeader()] = "Bearer " . $token; - $token = \Firebase\JWT\JWT::encode($data, $this->config->GetDocumentServerSecret(), "HS256"); + $token = \Firebase\JWT\JWT::encode($data, $this->config->getDocumentServerSecret(), "HS256"); $data["token"] = $token; $opts["body"] = json_encode($data); } - $response = $this->Request($urlCommand, "post", $opts); + $response = $this->request($urlCommand, "post", $opts); $data = json_decode($response); - $this->ProcessCommandServResponceError($data->error); + $this->processCommandServResponceError($data->error); return $data; } @@ -310,7 +310,7 @@ public function CommandRequest($method) { * * @return null */ - public function ProcessCommandServResponceError($errorCode) { + public function processCommandServResponceError($errorCode) { $errorMessageTemplate = $this->trans->t("Error occurred in the document service"); $errorMessage = ""; @@ -335,7 +335,7 @@ public function ProcessCommandServResponceError($errorCode) { } /** - * Request to Document Server with turn off verification + * request to Document Server with turn off verification * * @param string $url - request address * @param array $method - request method @@ -343,14 +343,14 @@ public function ProcessCommandServResponceError($errorCode) { * * @return string */ - public function Request($url, $method = "get", $opts = null) { + public function request($url, $method = "get", $opts = null) { $httpClientService = \OC::$server->getHTTPClientService(); $client = $httpClientService->newClient(); if ($opts === null) { $opts = []; } - if (substr($url, 0, \strlen("https")) === "https" && $this->config->GetVerifyPeerOff()) { + if (substr($url, 0, \strlen("https")) === "https" && $this->config->getVerifyPeerOff()) { $opts["verify"] = false; } if (!\array_key_exists("timeout", $opts)) { @@ -380,7 +380,7 @@ public function checkDocServiceUrl($urlGenerator, $crypt) { try { if (preg_match("/^https:\/\//i", $urlGenerator->getAbsoluteURL("/")) - && preg_match("/^http:\/\//i", $this->config->GetDocumentServerUrl()) + && preg_match("/^http:\/\//i", $this->config->getDocumentServerUrl()) ) { throw new \Exception($this->trans->t("Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required.")); } @@ -390,19 +390,19 @@ public function checkDocServiceUrl($urlGenerator, $crypt) { } try { - $healthcheckResponse = $this->HealthcheckRequest(); + $healthcheckResponse = $this->healthcheckRequest(); if (!$healthcheckResponse) { throw new \Exception($this->trans->t("Bad healthcheck status")); } } catch (\Exception $e) { - $logger->logException($e, ["message" => "HealthcheckRequest on check error", "app" => self::$appName]); + $logger->logException($e, ["message" => "healthcheckRequest on check error", "app" => self::$appName]); return [$e->getMessage(), $version]; } try { - $commandResponse = $this->CommandRequest("version"); + $commandResponse = $this->commandRequest("version"); - $logger->debug("CommandRequest on check: " . json_encode($commandResponse), ["app" => self::$appName]); + $logger->debug("commandRequest on check: " . json_encode($commandResponse), ["app" => self::$appName]); if (empty($commandResponse)) { throw new \Exception($this->trans->t("Error occurred in the document service")); @@ -414,28 +414,28 @@ public function checkDocServiceUrl($urlGenerator, $crypt) { throw new \Exception($this->trans->t("Not supported version")); } } catch (\Exception $e) { - $logger->logException($e, ["message" => "CommandRequest on check error", "app" => self::$appName]); + $logger->logException($e, ["message" => "commandRequest on check error", "app" => self::$appName]); return [$e->getMessage(), $version]; } $convertedFileUri = null; try { - $hashUrl = $crypt->GetHash(["action" => "empty"]); + $hashUrl = $crypt->getHash(["action" => "empty"]); $fileUrl = $urlGenerator->linkToRouteAbsolute(self::$appName . ".callback.emptyfile", ["doc" => $hashUrl]); - if (!$this->config->UseDemo() && !empty($this->config->GetStorageUrl())) { - $fileUrl = str_replace($urlGenerator->getAbsoluteURL("/"), $this->config->GetStorageUrl(), $fileUrl); + if (!$this->config->useDemo() && !empty($this->config->getStorageUrl())) { + $fileUrl = str_replace($urlGenerator->getAbsoluteURL("/"), $this->config->getStorageUrl(), $fileUrl); } - $convertedFileUri = $this->GetConvertedUri($fileUrl, "docx", "docx", "check_" . rand()); + $convertedFileUri = $this->getConvertedUri($fileUrl, "docx", "docx", "check_" . rand()); } catch (\Exception $e) { - $logger->logException($e, ["message" => "GetConvertedUri on check error", "app" => self::$appName]); + $logger->logException($e, ["message" => "getConvertedUri on check error", "app" => self::$appName]); return [$e->getMessage(), $version]; } try { - $this->Request($convertedFileUri); + $this->request($convertedFileUri); } catch (\Exception $e) { - $logger->logException($e, ["message" => "Request converted file on check error", "app" => self::$appName]); + $logger->logException($e, ["message" => "request converted file on check error", "app" => self::$appName]); return [$e->getMessage(), $version]; } diff --git a/lib/fileutility.php b/lib/fileutility.php index 658ebc41..cb754411 100644 --- a/lib/fileutility.php +++ b/lib/fileutility.php @@ -235,7 +235,7 @@ public function getKey($file, $origin = false) { $key = KeyManager::get($fileId); if (empty($key)) { - $instanceId = $this->config->GetSystemValue("instanceid", true); + $instanceId = $this->config->getSystemValue("instanceid", true); $key = $instanceId . "_" . $this->GUID(); @@ -291,7 +291,7 @@ private function GUID() { * @return string */ public function getVersionKey($version) { - $instanceId = $this->config->GetSystemValue("instanceid", true); + $instanceId = $this->config->getSystemValue("instanceid", true); $key = $instanceId . "_" . $version->getSourceFile()->getEtag() . "_" . $version->getRevisionId(); diff --git a/lib/hookhandler.php b/lib/hookhandler.php index d0684f19..5effbf19 100644 --- a/lib/hookhandler.php +++ b/lib/hookhandler.php @@ -36,16 +36,16 @@ class HookHandler { * * @return void */ - public static function PublicPage() { + public static function publicPage() { $appName = "onlyoffice"; $appConfig = new AppConfig($appName); - if (!empty($appConfig->GetDocumentServerUrl()) && $appConfig->SettingsAreSuccessful()) { + if (!empty($appConfig->getDocumentServerUrl()) && $appConfig->settingsAreSuccessful()) { Util::addScript("onlyoffice", "main"); Util::addScript("onlyoffice", "share"); - if ($appConfig->GetSameTab()) { + if ($appConfig->getSameTab()) { Util::addScript("onlyoffice", "listener"); } diff --git a/lib/preview.php b/lib/preview.php index 6e7fdc69..c24274e6 100644 --- a/lib/preview.php +++ b/lib/preview.php @@ -233,12 +233,12 @@ public function getMimeType() { * @return bool */ public function isAvailable(FileInfo $fileInfo) { - if ($this->config->GetPreview() !== true) { + if ($this->config->getPreview() !== true) { return false; } if (!$fileInfo || $fileInfo->getSize() === 0 - || $fileInfo->getSize() > $this->config->GetLimitThumbSize() + || $fileInfo->getSize() > $this->config->getLimitThumbSize() ) { return false; } @@ -274,14 +274,14 @@ public function getThumbnail($file, $maxX, $maxY, $scalingup) { $imageUrl = null; $documentService = new DocumentService($this->trans, $this->config); try { - $imageUrl = $documentService->GetConvertedUri($fileUrl, $extension, self::THUMBEXTENSION, $key); + $imageUrl = $documentService->getConvertedUri($fileUrl, $extension, self::THUMBEXTENSION, $key); } catch (\Exception $e) { - $this->logger->logException($e, ["message" => "GetConvertedUri: from $extension to " . self::THUMBEXTENSION, "app" => $this->appName]); + $this->logger->logException($e, ["message" => "getConvertedUri: from $extension to " . self::THUMBEXTENSION, "app" => $this->appName]); return false; } try { - $thumbnail = $documentService->Request($imageUrl); + $thumbnail = $documentService->request($imageUrl); } catch (\Exception $e) { $this->logger->logException($e, ["message" => "Failed to download thumbnail", "app" => $this->appName]); return false; @@ -322,12 +322,12 @@ private function getUrl($file, $user = null, $version = 0) { $data["version"] = $version; } - $hashUrl = $this->crypt->GetHash($data); + $hashUrl = $this->crypt->getHash($data); $fileUrl = $this->urlGenerator->linkToRouteAbsolute($this->appName . ".callback.download", ["doc" => $hashUrl]); - if (!$this->config->UseDemo() && !empty($this->config->GetStorageUrl())) { - $fileUrl = str_replace($this->urlGenerator->getAbsoluteURL("/"), $this->config->GetStorageUrl(), $fileUrl); + if (!$this->config->useDemo() && !empty($this->config->getStorageUrl())) { + $fileUrl = str_replace($this->urlGenerator->getAbsoluteURL("/"), $this->config->getStorageUrl(), $fileUrl); } return $fileUrl; @@ -378,7 +378,7 @@ private function getFileParam($file) { $versionId = $version->getRevisionId(); if (strcmp($versionId, $fileVersion) === 0) { $key = $this->fileUtility->getVersionKey($version); - $key = DocumentService::GenerateRevisionId($key); + $key = DocumentService::generateRevisionId($key); break; } @@ -387,7 +387,7 @@ private function getFileParam($file) { $owner = $file->getOwner(); $key = $this->fileUtility->getKey($file); - $key = DocumentService::GenerateRevisionId($key); + $key = DocumentService::generateRevisionId($key); } $fileUrl = $this->getUrl($file, $owner, $versionNum); diff --git a/lib/templatemanager.php b/lib/templatemanager.php index 2c748378..02d81be1 100644 --- a/lib/templatemanager.php +++ b/lib/templatemanager.php @@ -48,7 +48,7 @@ class TemplateManager { * * @return Folder */ - public static function GetGlobalTemplateDir() { + public static function getGlobalTemplateDir() { $dirPath = self::$appName . "/" . self::$templateFolderName; $rootFolder = \OC::$server->getRootFolder(); @@ -69,8 +69,8 @@ public static function GetGlobalTemplateDir() { * * @return array */ - public static function GetGlobalTemplates($mimetype = null) { - $templateDir = self::GetGlobalTemplateDir(); + public static function getGlobalTemplates($mimetype = null) { + $templateDir = self::getGlobalTemplateDir(); $templatesList = $templateDir->getDirectoryListing(); if (!empty($mimetype) @@ -89,14 +89,14 @@ public static function GetGlobalTemplates($mimetype = null) { * * @return File */ - public static function GetTemplate($templateId) { + public static function getTemplate($templateId) { $logger = \OC::$server->getLogger(); - $templateDir = self::GetGlobalTemplateDir(); + $templateDir = self::getGlobalTemplateDir(); try { $templates = $templateDir->getById($templateId); } catch(\Exception $e) { - $logger->logException($e, ["message" => "GetTemplate: $templateId", "app" => self::$appName]); + $logger->logException($e, ["message" => "getTemplate: $templateId", "app" => self::$appName]); return null; } @@ -115,7 +115,7 @@ public static function GetTemplate($templateId) { * * @return string */ - public static function GetTypeTemplate($mime) { + public static function getTypeTemplate($mime) { switch($mime) { case "application/vnd.openxmlformats-officedocument.wordprocessingml.document": return "document"; @@ -135,7 +135,7 @@ public static function GetTypeTemplate($mime) { * * @return bool */ - public static function IsTemplateType($name) { + public static function isTemplateType($name) { $ext = strtolower(pathinfo($name, PATHINFO_EXTENSION)); switch($ext) { case "docx": @@ -154,11 +154,11 @@ public static function IsTemplateType($name) { * * @return string */ - public static function GetEmptyTemplate($fileName) { + public static function getEmptyTemplate($fileName) { $ext = strtolower("." . pathinfo($fileName, PATHINFO_EXTENSION)); $lang = \OC::$server->getL10NFactory("")->get("")->getLanguageCode(); - $templatePath = self::GetEmptyTemplatePath($lang, $ext); + $templatePath = self::getEmptyTemplatePath($lang, $ext); $template = file_get_contents($templatePath); return $template; @@ -172,7 +172,7 @@ public static function GetEmptyTemplate($fileName) { * * @return string */ - public static function GetEmptyTemplatePath($lang, $ext) { + public static function getEmptyTemplatePath($lang, $ext) { if (!\array_key_exists($lang, self::$localPath)) { $lang = "en"; } From bc0ae8de19548520576f03bac3521223c7bd30d3 Mon Sep 17 00:00:00 2001 From: Stepan Mayorov Date: Wed, 20 Dec 2023 13:15:57 +0300 Subject: [PATCH 035/114] Update lint-phpcs.yml --- .github/workflows/lint-phpcs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint-phpcs.yml b/.github/workflows/lint-phpcs.yml index be5bea29..25cf3ca3 100644 --- a/.github/workflows/lint-phpcs.yml +++ b/.github/workflows/lint-phpcs.yml @@ -5,7 +5,7 @@ on: push: branches: [master] pull_request: - branches: [master, develop, linter-formatting] + branches: [master, develop] permissions: contents: read From e2cd53a902224971302bf4e41924d119711380f5 Mon Sep 17 00:00:00 2001 From: rivexe Date: Mon, 25 Dec 2023 13:44:01 +0300 Subject: [PATCH 036/114] empty spaces in comments fix, multiline parenthesis fix --- appinfo/app.php | 2 +- appinfo/application.php | 44 ++++++++++++++++--------- appinfo/routes.php | 2 +- controller/callbackcontroller.php | 4 +-- controller/editorapicontroller.php | 5 +-- controller/editorcontroller.php | 18 +++++++---- controller/federationcontroller.php | 2 +- controller/joblistcontroller.php | 6 ++-- controller/settingsapicontroller.php | 2 +- controller/settingscontroller.php | 2 +- controller/templatecontroller.php | 4 +-- controller/webassetcontroller.php | 6 ++-- lib/adminsettings.php | 1 - lib/appconfig.php | 48 ++++++++++++++-------------- lib/command/documentserver.php | 2 +- lib/cron/editorscheck.php | 2 +- lib/fileversions.php | 12 +++---- lib/hookhandler.php | 3 +- lib/hooks.php | 10 +++--- lib/preview.php | 4 +-- 20 files changed, 100 insertions(+), 79 deletions(-) diff --git a/appinfo/app.php b/appinfo/app.php index 3dd0b91e..db16f003 100644 --- a/appinfo/app.php +++ b/appinfo/app.php @@ -1,7 +1,7 @@ - * + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/appinfo/application.php b/appinfo/application.php index de5f43f0..45904f9c 100644 --- a/appinfo/application.php +++ b/appinfo/application.php @@ -1,7 +1,7 @@ - * + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -125,7 +125,8 @@ function () { $previewManager = $container->query(IPreview::class); if ($this->appConfig->getPreview()) { $previewManager->registerProvider( - Preview::getMimeTypeRegex(), function () use ($container) { + Preview::getMimeTypeRegex(), + function () use ($container) { return $container->query(Preview::class); } ); @@ -141,7 +142,8 @@ function () use ($appName) { \OC::$server->getLogger(), \OC::$server->getUserManager() ); - }, function () use ($appName) { + }, + function () use ($appName) { return [ "id" => $appName, "name" => $appName, @@ -150,38 +152,44 @@ function () use ($appName) { ); $container->registerService( - "L10N", function ($c) { + "L10N", + function ($c) { return $c->query("ServerContainer")->getL10N($c->query("AppName")); } ); $container->registerService( - "RootStorage", function ($c) { + "RootStorage", + function ($c) { return $c->query("ServerContainer")->getRootFolder(); } ); $container->registerService( - "UserSession", function ($c) { + "UserSession", + function ($c) { return $c->query("ServerContainer")->getUserSession(); } ); $container->registerService( - "Logger", function ($c) { + "Logger", + function ($c) { return $c->query("ServerContainer")->getLogger(); } ); $container->registerService( - "URLGenerator", function ($c) { + "URLGenerator", + function ($c) { return $c->query("ServerContainer")->getURLGenerator(); } ); // Controllers $container->registerService( - "SettingsController", function ($c) { + "SettingsController", + function ($c) { return new SettingsController( $c->query("AppName"), $c->query("Request"), @@ -195,7 +203,8 @@ function () use ($appName) { ); $container->registerService( - "SettingsApiController", function ($c) { + "SettingsApiController", + function ($c) { return new SettingsApiController( $c->query("AppName"), $c->query("Request"), @@ -206,7 +215,8 @@ function () use ($appName) { ); $container->registerService( - "EditorController", function ($c) { + "EditorController", + function ($c) { return new EditorController( $c->query("AppName"), $c->query("Request"), @@ -226,7 +236,8 @@ function () use ($appName) { ); $container->registerService( - "EditorApiController", function ($c) { + "EditorApiController", + function ($c) { return new EditorApiController( $c->query("AppName"), $c->query("Request"), @@ -245,7 +256,8 @@ function () use ($appName) { ); $container->registerService( - "CallbackController", function ($c) { + "CallbackController", + function ($c) { return new CallbackController( $c->query("AppName"), $c->query("Request"), @@ -262,7 +274,8 @@ function () use ($appName) { ); $container->registerService( - "TemplateController", function ($c) { + "TemplateController", + function ($c) { return new TemplateController( $c->query("AppName"), $c->query("Request"), @@ -273,7 +286,8 @@ function () use ($appName) { ); $container->registerService( - "WebAssetController", function ($c) { + "WebAssetController", + function ($c) { return new WebAssetController( $c->query("AppName"), $c->query("Request"), diff --git a/appinfo/routes.php b/appinfo/routes.php index 47f186ec..016a4e3d 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -1,7 +1,7 @@ - * + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/controller/callbackcontroller.php b/controller/callbackcontroller.php index c59e7aa1..04fc0b61 100644 --- a/controller/callbackcontroller.php +++ b/controller/callbackcontroller.php @@ -1,7 +1,7 @@ - * + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -777,7 +777,7 @@ private function parseUserId($userId) { * @param callable $operation * * @throws LockedException - * + * * @return void */ private function retryOperation(callable $operation) { diff --git a/controller/editorapicontroller.php b/controller/editorapicontroller.php index 55ec5c5a..28fff137 100644 --- a/controller/editorapicontroller.php +++ b/controller/editorapicontroller.php @@ -1,7 +1,7 @@ - * + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -495,7 +495,8 @@ public function config($fileId, $filePath = null, $shareToken = null, $version = $createParam["name"] = $templateItem->getName(); array_push( - $templates, [ + $templates, + [ "image" => "", "title" => $templateItem->getName(), "url" => urldecode($this->urlGenerator->linkToRouteAbsolute($this->appName . ".editor.create_new", $createParam)) diff --git a/controller/editorcontroller.php b/controller/editorcontroller.php index 2556b5d6..a78f4fa7 100644 --- a/controller/editorcontroller.php +++ b/controller/editorcontroller.php @@ -1,7 +1,7 @@ - * + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -402,7 +402,8 @@ public function users($fileId) { $email = $user->getEMailAddress(); if ($user->getUID() != $currentUserId && !empty($email)) { array_push( - $result, [ + $result, + [ "email" => $email, "name" => $user->getDisplayName() ] @@ -479,7 +480,8 @@ public function mention($fileId, $anchor, $comment, $emails) { ->setDateTime(new \DateTime()) ->setObject("mention", $comment) ->setSubject( - "mention_info", [ + "mention_info", + [ "notifierId" => $userId, "fileId" => $file->getId(), "fileName" => $file->getName(), @@ -1214,7 +1216,8 @@ public function index($fileId, $filePath = null, $shareToken = null, $version = if (empty($shareToken) && !$this->userSession->isLoggedIn()) { $redirectUrl = $this->urlGenerator->linkToRoute( - "core.login.showLoginForm", [ + "core.login.showLoginForm", + [ "redirect_url" => $this->request->getRequestUri() ] ); @@ -1463,14 +1466,17 @@ private function limitEnumerationToGroups() { */ private function renderError($error, $hint = "") { return new TemplateResponse( - "", "error", [ + "", + "error", + [ "errors" => [ [ "error" => $error, "hint" => $hint ] ] - ], "error" + ], + "error" ); } } diff --git a/controller/federationcontroller.php b/controller/federationcontroller.php index b66df40a..d3e5684b 100644 --- a/controller/federationcontroller.php +++ b/controller/federationcontroller.php @@ -1,7 +1,7 @@ - * + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/controller/joblistcontroller.php b/controller/joblistcontroller.php index a7b03f93..a85b14ef 100644 --- a/controller/joblistcontroller.php +++ b/controller/joblistcontroller.php @@ -1,7 +1,7 @@ - * + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -81,7 +81,7 @@ public function __construct($AppName, IRequest $request, ILogger $logger, AppCon * Add a job to list * * @param IJob|string $job - * + * * @return void */ private function addJob($job) { @@ -95,7 +95,7 @@ private function addJob($job) { * Remove a job from list * * @param IJob|string $job - * + * * @return void */ private function removeJob($job) { diff --git a/controller/settingsapicontroller.php b/controller/settingsapicontroller.php index 2e8a948f..7d6636e9 100644 --- a/controller/settingsapicontroller.php +++ b/controller/settingsapicontroller.php @@ -1,7 +1,7 @@ - * + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/controller/settingscontroller.php b/controller/settingscontroller.php index bf1dd2cd..b41caee5 100644 --- a/controller/settingscontroller.php +++ b/controller/settingscontroller.php @@ -1,7 +1,7 @@ - * + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/controller/templatecontroller.php b/controller/templatecontroller.php index d833b625..06cd9922 100644 --- a/controller/templatecontroller.php +++ b/controller/templatecontroller.php @@ -1,7 +1,7 @@ - * + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -135,7 +135,7 @@ public function addTemplate() { * Delete template * * @param string $templateId - file identifier - * + * * @return array */ public function deleteTemplate($templateId) { diff --git a/controller/webassetcontroller.php b/controller/webassetcontroller.php index 8a8c44fb..baaa4a6d 100644 --- a/controller/webassetcontroller.php +++ b/controller/webassetcontroller.php @@ -1,7 +1,7 @@ - * + * * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -64,7 +64,9 @@ public function get(): Response { $filePath = \realpath($basePath . '/js/web/onlyoffice.js'); try { return new DataDisplayResponse( - \file_get_contents($filePath), Http::STATUS_OK, [ + \file_get_contents($filePath), + Http::STATUS_OK, + [ 'Content-Type' => "text/javascript", 'Content-Length' => \filesize($filePath), 'Cache-Control' => 'max-age=0, no-cache, no-store, must-revalidate', diff --git a/lib/adminsettings.php b/lib/adminsettings.php index bcf15d28..7374b546 100644 --- a/lib/adminsettings.php +++ b/lib/adminsettings.php @@ -26,7 +26,6 @@ * Settings controller for the administration page */ class AdminSettings implements ISettings { - /** * Constructor */ diff --git a/lib/appconfig.php b/lib/appconfig.php index b00fd7b0..fc03881b 100644 --- a/lib/appconfig.php +++ b/lib/appconfig.php @@ -403,7 +403,7 @@ public function useDemo() { * Save the document service address to the application configuration * * @param string $documentServer - document service address - * + * * @return void */ public function setDocumentServerUrl($documentServer) { @@ -449,7 +449,7 @@ public function getDocumentServerUrl($origin = false) { * Save the document service address available from ownCloud to the application configuration * * @param string $documentServerInternal - document service address - * + * * @return void */ public function setDocumentServerInternalUrl($documentServerInternal) { @@ -518,7 +518,7 @@ public function replaceDocumentServerUrlToInternal($url) { * Save the ownCloud address available from document server to the application configuration * * @param string $storageUrl - storage url - * + * * @return void */ public function setStorageUrl($storageUrl) { @@ -552,7 +552,7 @@ public function getStorageUrl() { * Save the document service secret key to the application configuration * * @param string $secret - secret key - * + * * @return void */ public function setDocumentServerSecret($secret) { @@ -602,7 +602,7 @@ public function getSKey() { * Save an array of formats with default action * * @param array $formats - formats with status - * + * * @return void */ public function setDefaultFormats($formats) { @@ -629,7 +629,7 @@ private function getDefaultFormats() { * Save an array of formats that is opened for editing * * @param array $formats - formats with status - * + * * @return void */ public function setEditableFormats($formats) { @@ -656,7 +656,7 @@ private function getEditableFormats() { * Save the opening setting in a same tab * * @param bool $value - same tab - * + * * @return void */ public function setSameTab($value) { @@ -678,7 +678,7 @@ public function getSameTab() { * Save generate preview setting * * @param bool $value - preview - * + * * @return bool */ public function setPreview($value) { @@ -700,7 +700,7 @@ public function getPreview() { * Save keep versions history * * @param bool $value - version history - * + * * @return void */ public function setVersionHistory($value) { @@ -722,7 +722,7 @@ public function getVersionHistory() { * Save protection * * @param bool $value - version history - * + * * @return void */ public function setProtection($value) { @@ -748,7 +748,7 @@ public function getProtection() { * Save chat display setting * * @param bool $value - display chat - * + * * @return void */ public function setCustomizationChat($value) { @@ -770,7 +770,7 @@ public function getCustomizationChat() { * Save compact header setting * * @param bool $value - display compact header - * + * * @return void */ public function setCustomizationCompactHeader($value) { @@ -792,7 +792,7 @@ public function getCustomizationCompactHeader() { * Save feedback display setting * * @param bool $value - display feedback - * + * * @return void */ public function setCustomizationFeedback($value) { @@ -814,7 +814,7 @@ public function getCustomizationFeedback() { * Save forcesave setting * * @param bool $value - forcesave - * + * * @return void */ public function setCustomizationForcesave($value) { @@ -838,7 +838,7 @@ public function getCustomizationForcesave() { * Save help display setting * * @param bool $value - display help - * + * * @return void */ public function setCustomizationHelp($value) { @@ -860,7 +860,7 @@ public function getCustomizationHelp() { * Save without tabs setting * * @param bool $value - without tabs - * + * * @return void */ public function setCustomizationToolbarNoTabs($value) { @@ -882,7 +882,7 @@ public function getCustomizationToolbarNoTabs() { * Save review viewing mode setting * * @param string $value - review mode - * + * * @return void */ public function setCustomizationReviewDisplay($value) { @@ -911,7 +911,7 @@ public function getCustomizationReviewDisplay() { * Save theme setting * * @param string $value - theme - * + * * @return void */ public function setCustomizationTheme($value) { @@ -940,7 +940,7 @@ public function getCustomizationTheme() { * Save macros setting * * @param bool $value - enable macros - * + * * @return void */ public function setCustomizationMacros($value) { @@ -962,7 +962,7 @@ public function getCustomizationMacros() { * Save plugins setting * * @param bool $value - enable macros - * + * * @return void */ public function setCustomizationPlugins($value) { @@ -984,7 +984,7 @@ public function getCustomizationPlugins() { * Save the list of groups * * @param array $groups - the list of groups - * + * * @return void */ public function setLimitGroups($groups) { @@ -1063,7 +1063,7 @@ public function isUserAllowedToUse($userId = null) { * Save the document service verification setting to the application configuration * * @param bool $verifyPeerOff - parameter verification setting - * + * * @return void */ public function setVerifyPeerOff($verifyPeerOff) { @@ -1128,7 +1128,7 @@ public function jwtHeader($origin = false) { * Save the jwtHeader setting * * @param string $value - jwtHeader - * + * * @return void */ public function setJwtHeader($value) { @@ -1157,7 +1157,7 @@ public function getJwtLeeway() { * Save the status settings * * @param string $value - error - * + * * @return void */ public function setSettingsError($value) { diff --git a/lib/command/documentserver.php b/lib/command/documentserver.php index 811f4ceb..39ecc667 100644 --- a/lib/command/documentserver.php +++ b/lib/command/documentserver.php @@ -87,7 +87,7 @@ public function __construct( /** * Configures the current command. - * + * * @return void */ protected function configure() { diff --git a/lib/cron/editorscheck.php b/lib/cron/editorscheck.php index 7a734745..07582248 100644 --- a/lib/cron/editorscheck.php +++ b/lib/cron/editorscheck.php @@ -120,7 +120,7 @@ public function __construct( * Makes the background check * * @param array $argument unused argument - * + * * @return void */ protected function run($argument) { diff --git a/lib/fileversions.php b/lib/fileversions.php index f77df852..aa5a364a 100644 --- a/lib/fileversions.php +++ b/lib/fileversions.php @@ -244,7 +244,7 @@ public static function getChangesFile($ownerId, $fileId, $versionId) { * @param array $history - file history * @param string $changes - file changes * @param string $prevVersion - previous version for check - * + * * @return void */ public static function saveHistory($fileInfo, $history, $changes, $prevVersion) { @@ -294,7 +294,7 @@ public static function saveHistory($fileInfo, $history, $changes, $prevVersion) * * @param string $ownerId - file owner id * @param string $fileId - file id - * + * * @return void */ public static function deleteAllVersions($ownerId, $fileId = null) { @@ -320,7 +320,7 @@ public static function deleteAllVersions($ownerId, $fileId = null) { * @param string $ownerId - file owner id * @param string $fileId - file id * @param string $versionId - file version - * + * * @return void|null */ public static function deleteVersion($ownerId, $fileId, $versionId) { @@ -355,7 +355,7 @@ public static function deleteVersion($ownerId, $fileId, $versionId) { /** * Clear all version history - * + * * @return void */ public static function clearHistory() { @@ -382,7 +382,7 @@ public static function clearHistory() { * * @param FileInfo $fileInfo - file info * @param IUser $author - version author - * + * * @return void */ public static function saveAuthor($fileInfo, $author) { @@ -461,7 +461,7 @@ public static function getAuthor($ownerId, $fileId, $versionId) { * @param string $ownerId - file owner id * @param string $fileId - file id * @param string $versionId - file version - * + * * @return void|null */ public static function deleteAuthor($ownerId, $fileId, $versionId) { diff --git a/lib/hookhandler.php b/lib/hookhandler.php index 5effbf19..7536e0c4 100644 --- a/lib/hookhandler.php +++ b/lib/hookhandler.php @@ -30,10 +30,9 @@ * @package OCA\Onlyoffice */ class HookHandler { - /** * Adds scripts and styles - * + * * @return void */ public static function publicPage() { diff --git a/lib/hooks.php b/lib/hooks.php index 66a5d002..3868b9f6 100644 --- a/lib/hooks.php +++ b/lib/hooks.php @@ -66,7 +66,7 @@ public static function connectHooks() { * Erase user file versions * * @param array $params - hook params - * + * * @return void */ public static function userDelete($params) { @@ -79,7 +79,7 @@ public static function userDelete($params) { * Listen of file change * * @param array $params - hook params - * + * * @return void */ public static function fileUpdate($params) { @@ -104,7 +104,7 @@ public static function fileUpdate($params) { * Erase versions of deleted file * * @param array $params - hook params - * + * * @return void */ public static function fileDelete($params) { @@ -135,7 +135,7 @@ public static function fileDelete($params) { * Erase versions of deleted version of file * * @param array $params - hook param - * + * * @return void */ public static function fileVersionDelete($params) { @@ -170,7 +170,7 @@ public static function fileVersionDelete($params) { * Erase versions of restored version of file * * @param array $params - hook param - * + * * @return void */ public static function fileVersionRestore($params) { diff --git a/lib/preview.php b/lib/preview.php index c24274e6..18aa2f20 100644 --- a/lib/preview.php +++ b/lib/preview.php @@ -199,7 +199,7 @@ public function __construct( /** * Return mime type - * + * * @return string */ public static function getMimeTypeRegex() { @@ -217,7 +217,7 @@ public static function getMimeTypeRegex() { /** * Return mime type - * + * * @return string */ public function getMimeType() { From 689bc39dc30ee0fcbf89987dde3d4034da43b3c5 Mon Sep 17 00:00:00 2001 From: rivexe Date: Mon, 25 Dec 2023 17:47:29 +0300 Subject: [PATCH 037/114] default frame height if editors opened in same tab --- js/editor.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/js/editor.js b/js/editor.js index a925aafb..829d5c98 100644 --- a/js/editor.js +++ b/js/editor.js @@ -182,7 +182,8 @@ OCA.Onlyoffice.docEditor = new DocsAPI.DocEditor("iframeEditor", config); - if (config.type === "mobile" && $("#app > iframe").css("position") === "fixed") { + if (config.type === "mobile" && $("#app > iframe").css("position") === "fixed" + && !OCA.Onlyoffice.inframe) { $("#app > iframe").css("height", "calc(100% - 45px)"); } From f352dbd03ea06a245df93e324223b7be734c42e4 Mon Sep 17 00:00:00 2001 From: rivexe Date: Tue, 26 Dec 2023 13:38:30 +0300 Subject: [PATCH 038/114] key added to referenceData --- controller/editorcontroller.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/controller/editorcontroller.php b/controller/editorcontroller.php index a78f4fa7..5fb12953 100644 --- a/controller/editorcontroller.php +++ b/controller/editorcontroller.php @@ -597,10 +597,12 @@ public function reference($referenceData, $path = null) { $fileName = $file->getName(); $ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION)); + $key = $this->fileUtility->getKey($file); $response = [ "fileType" => $ext, "path" => $userFolder->getRelativePath($file->getPath()), + "key" => $key, "referenceData" => [ "fileKey" => $file->getId(), "instanceId" => $this->config->getSystemValue("instanceid", true), From f5c71bb465d28274a774bbfcc18838ce0debdb79 Mon Sep 17 00:00:00 2001 From: rivexe Date: Tue, 26 Dec 2023 13:38:47 +0300 Subject: [PATCH 039/114] key into referenceData to CHANGELOG --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 98da63be..3d9f7604 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,9 @@ ### Changed - compatible with ownCloud Web 7.0 +## Added +- reference data from coediting + ## 8.2.3 ## Added - Ukrainian translation From acd92ccd437defb91008b836236be5ff0283c562 Mon Sep 17 00:00:00 2001 From: rivexe Date: Thu, 11 Jan 2024 11:42:29 +0300 Subject: [PATCH 040/114] events.onRequestSelectDocument used instead of events.onRequestCompareFile --- js/editor.js | 23 ++++++++++++++++------- js/listener.js | 18 +++++++++++++----- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/js/editor.js b/js/editor.js index 829d5c98..56ec60dd 100644 --- a/js/editor.js +++ b/js/editor.js @@ -146,7 +146,7 @@ config.events.onRequestSaveAs = OCA.Onlyoffice.onRequestSaveAs; config.events.onRequestInsertImage = OCA.Onlyoffice.onRequestInsertImage; config.events.onRequestMailMergeRecipients = OCA.Onlyoffice.onRequestMailMergeRecipients; - config.events.onRequestCompareFile = OCA.Onlyoffice.onRequestCompareFile; + config.events.onRequestSelectDocument = OCA.Onlyoffice.onRequestSelectDocument; config.events.onRequestSendNotify = OCA.Onlyoffice.onRequestSendNotify; config.events.onRequestReferenceData = OCA.Onlyoffice.onRequestReferenceData; config.events.onMetaChange = OCA.Onlyoffice.onMetaChange; @@ -417,27 +417,36 @@ "*"); }; - OCA.Onlyoffice.onRequestCompareFile = function () { + OCA.Onlyoffice.onRequestSelectDocument = function (event) { var revisedMimes = [ "application/vnd.openxmlformats-officedocument.wordprocessingml.document" ]; if (OCA.Onlyoffice.inframe) { window.parent.postMessage({ - method: "editorRequestCompareFile", - param: revisedMimes + method: "editorRequestSelectDocument", + param: revisedMimes, + documentSelectionType: event.data.c }, "*"); } else { - OC.dialogs.filepicker(t(OCA.Onlyoffice.AppName, "Select file to compare"), - OCA.Onlyoffice.editorSetRevised, + let title; + switch (event.data.c) { + case "combine": + title = t(OCA.Onlyoffice.AppName, "Select file to combine"); + break; + default: + title = t(OCA.Onlyoffice.AppName, "Select file to compare"); + } + OC.dialogs.filepicker(title, + OCA.Onlyoffice.editorSetRequested.bind({documentSelectionType: event.data.c}), false, revisedMimes, true); } }; - OCA.Onlyoffice.editorSetRevised = function (filePath) { + OCA.Onlyoffice.editorSetRequested = function (filePath) { $.get(OC.generateUrl("apps/" + OCA.Onlyoffice.AppName + "/ajax/url?filePath={filePath}", { filePath: filePath diff --git a/js/listener.js b/js/listener.js index 03069aa7..75cb1987 100644 --- a/js/listener.js +++ b/js/listener.js @@ -56,9 +56,17 @@ true); }; - OCA.Onlyoffice.onRequestCompareFile = function (revisedMimes) { - OC.dialogs.filepicker(t(OCA.Onlyoffice.AppName, "Select file to compare"), - $("#onlyofficeFrame")[0].contentWindow.OCA.Onlyoffice.editorSetRevised, + OCA.Onlyoffice.onRequestSelectDocument = function (revisedMimes, documentSelectionType) { + let title; + switch (documentSelectionType) { + case "combine": + title = t(OCA.Onlyoffice.AppName, "Select file to combine"); + break; + default: + title = t(OCA.Onlyoffice.AppName, "Select file to compare"); + } + OC.dialogs.filepicker(title, + $("#onlyofficeFrame")[0].contentWindow.OCA.Onlyoffice.editorSetRequested.bind({documentSelectionType: documentSelectionType}), false, revisedMimes, true); @@ -110,8 +118,8 @@ case "editorRequestMailMergeRecipients": OCA.Onlyoffice.onRequestMailMergeRecipients(event.data.param); break; - case "editorRequestCompareFile": - OCA.Onlyoffice.onRequestCompareFile(event.data.param); + case "editorRequestSelectDocument": + OCA.Onlyoffice.onRequestSelectDocument(event.data.param, event.data.documentSelectionType); break; case "onDocumentReady": OCA.Onlyoffice.onDocumentReady(event.data.param); From 9e3d7d33dd13b13b7a1349bff8cb5ef676626ce6 Mon Sep 17 00:00:00 2001 From: rivexe Date: Thu, 11 Jan 2024 11:42:50 +0300 Subject: [PATCH 041/114] translation added --- l10n/ru.js | 3 ++- l10n/ru.json | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/l10n/ru.js b/l10n/ru.js index 0ccf5a92..237c0c6e 100644 --- a/l10n/ru.js +++ b/l10n/ru.js @@ -123,6 +123,7 @@ OC.L10N.register( "View settings": "Посмотреть настройки", "ONLYOFFICE Docs Cloud": "ONLYOFFICE Docs Cloud", "Easily launch the editors in the cloud without downloading and installation": "Легко запускайте редакторы в облаке без скачивания и установки", - "Get Now": "Получить сейчас" + "Get Now": "Получить сейчас", + "Select file to combine" : "Выбрать файл для объединения" }, "nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);"); diff --git a/l10n/ru.json b/l10n/ru.json index 026884ea..01029522 100644 --- a/l10n/ru.json +++ b/l10n/ru.json @@ -121,6 +121,7 @@ "View settings": "Посмотреть настройки", "ONLYOFFICE Docs Cloud": "ONLYOFFICE Docs Cloud", "Easily launch the editors in the cloud without downloading and installation": "Легко запускайте редакторы в облаке без скачивания и установки", - "Get Now": "Получить сейчас" + "Get Now": "Получить сейчас", + "Select file to combine" : "Выбрать файл для объединения" },"pluralForm" :"nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);" } \ No newline at end of file From 0b1c360ed030118ac1f42ae09d797bfdd5678a13 Mon Sep 17 00:00:00 2001 From: rivexe Date: Thu, 11 Jan 2024 11:43:22 +0300 Subject: [PATCH 042/114] selecting a document to combine from the storage to CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d9f7604..8aba412c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ## Added - reference data from coediting +- selecting a document to combine from the storage ## 8.2.3 ## Added From 4cea073f319f65fb4a3521dc73cee927d4fedb6f Mon Sep 17 00:00:00 2001 From: Sergey Linnik Date: Mon, 22 Jan 2024 13:40:27 +0300 Subject: [PATCH 043/114] ar-SA and sr-Latn-RS empty file templates --- CHANGELOG.md | 1 + assets | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d9f7604..a06534df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ## Added - reference data from coediting +- Arabic and Serbian empty file templates ## 8.2.3 ## Added diff --git a/assets b/assets index f00ab3a3..e0771eb5 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit f00ab3a3efe6e2f8542ba026d1fc1d72df7dfd5f +Subproject commit e0771eb517facd02b2c9f2f4ee10b278da694d5d From 9a5d94ff9ee049c1617c4aad2e71c5ebbe14f1ec Mon Sep 17 00:00:00 2001 From: rivexe Date: Fri, 26 Jan 2024 13:46:36 +0300 Subject: [PATCH 044/114] feat: ar-SA and sr-Latn-RS to mapping --- lib/templatemanager.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/templatemanager.php b/lib/templatemanager.php index 02d81be1..1cfb8b4a 100644 --- a/lib/templatemanager.php +++ b/lib/templatemanager.php @@ -186,6 +186,7 @@ public static function getEmptyTemplatePath($lang, $ext) { * @var Array */ private static $localPath = [ + "ar" => "ar-SA", "az" => "az-Latn-AZ", "bg_BG" => "bg-BG", "cs" => "cs-CZ", @@ -209,6 +210,7 @@ public static function getEmptyTemplatePath($lang, $ext) { "ru" => "ru-RU", "si_LK" => "si-LK", "sk_SK" => "sk-SK", + "sr" => "sr-Latn-RS", "sv" => "sv-SE", "tr" => "tr-TR", "uk" => "uk-UA", From 94a2c8b98f6526f4dca8d0760461f0701acffa5a Mon Sep 17 00:00:00 2001 From: Sergey Linnik Date: Fri, 26 Jan 2024 17:27:47 +0300 Subject: [PATCH 045/114] setRequestedDocument instead setRevisedFile --- js/editor.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/js/editor.js b/js/editor.js index 56ec60dd..57bcbd2c 100644 --- a/js/editor.js +++ b/js/editor.js @@ -459,8 +459,9 @@ }); return; } + response.c = documentSelectionType; - OCA.Onlyoffice.docEditor.setRevisedFile(response); + OCA.Onlyoffice.docEditor.setRequestedDocument(response); }); }; From 9162a1a570e7dd639168d8a95396349e2f2b18ad Mon Sep 17 00:00:00 2001 From: rivexe Date: Mon, 29 Jan 2024 13:06:18 +0300 Subject: [PATCH 046/114] feat: added method for open referenceData source document --- js/editor.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/js/editor.js b/js/editor.js index 57bcbd2c..43efdcd4 100644 --- a/js/editor.js +++ b/js/editor.js @@ -149,6 +149,7 @@ config.events.onRequestSelectDocument = OCA.Onlyoffice.onRequestSelectDocument; config.events.onRequestSendNotify = OCA.Onlyoffice.onRequestSendNotify; config.events.onRequestReferenceData = OCA.Onlyoffice.onRequestReferenceData; + config.events.onRequestOpen = OCA.Onlyoffice.onRequestOpen; config.events.onMetaChange = OCA.Onlyoffice.onMetaChange; if (OC.currentUser) { @@ -553,6 +554,14 @@ }); }; + OCA.Onlyoffice.onRequestOpen = function (event) { + let filePath = event.data.path; + let fileId = event.data.referenceData.fileKey; + let windowName = event.data.windowName; + let sourceUrl = OC.generateUrl(`apps/${OCA.Onlyoffice.AppName}/${fileId}?filePath=${OC.encodePath(filePath)}`); + window.open(sourceUrl, windowName); + }; + OCA.Onlyoffice.onMetaChange = function (event) { if (event.data.favorite !== undefined) { $.ajax({ From d73a052b7ee7da23f8c276090d0b60acaf97ee9d Mon Sep 17 00:00:00 2001 From: rivexe Date: Mon, 29 Jan 2024 13:06:51 +0300 Subject: [PATCH 047/114] docs: onRequestOpen to CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8aba412c..adf4e632 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ ## Added - reference data from coediting - selecting a document to combine from the storage +- opening a reference data source ## 8.2.3 ## Added From 5f44f424e96dbaba6c48e4422fc90ba3800b3294 Mon Sep 17 00:00:00 2001 From: rivexe Date: Mon, 29 Jan 2024 13:22:56 +0300 Subject: [PATCH 048/114] feat: added method for change referenceData source --- js/editor.js | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/js/editor.js b/js/editor.js index 43efdcd4..5e6da4e0 100644 --- a/js/editor.js +++ b/js/editor.js @@ -150,6 +150,7 @@ config.events.onRequestSendNotify = OCA.Onlyoffice.onRequestSendNotify; config.events.onRequestReferenceData = OCA.Onlyoffice.onRequestReferenceData; config.events.onRequestOpen = OCA.Onlyoffice.onRequestOpen; + config.events.onRequestReferenceSource = OCA.Onlyoffice.onRequestReferenceSource; config.events.onMetaChange = OCA.Onlyoffice.onMetaChange; if (OC.currentUser) { @@ -402,6 +403,25 @@ }); }; + OCA.Onlyoffice.editorReferenceSource = function (filePath) { + if (filePath === OCA.Onlyoffice.filePath) { + OCA.Onlyoffice.showMessage(t(OCA.Onlyoffice.AppName, "The data source must not be the current document"), "error"); + return; + } + + $.post(OC.generateUrl("apps/" + OCA.Onlyoffice.AppName + "/ajax/reference"), + { + path: filePath + }, + function onSuccess(response) { + if (response.error) { + OCA.Onlyoffice.showMessage(response.error, "error"); + return; + } + OCA.Onlyoffice.docEditor.setReferenceSource(response); + }); + } + OCA.Onlyoffice.onRequestClose = function () { OCA.Onlyoffice.docEditor.destroyEditor(); @@ -562,6 +582,25 @@ window.open(sourceUrl, windowName); }; + OCA.Onlyoffice.onRequestReferenceSource = function (event) { + let referenceSourceMimes = [ + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" + ]; + if (OCA.Onlyoffice.inframe) { + window.parent.postMessage({ + method: "editorRequestReferenceSource", + param: referenceSourceMimes + }, + "*"); + } else { + OC.dialogs.filepicker(t(OCA.Onlyoffice.AppName, "Select data source"), + OCA.Onlyoffice.editorReferenceSource, + false, + referenceSourceMimes, + true); + } + }; + OCA.Onlyoffice.onMetaChange = function (event) { if (event.data.favorite !== undefined) { $.ajax({ From 46fca801a29bec786f4c96a5099bc000d8a79621 Mon Sep 17 00:00:00 2001 From: rivexe Date: Mon, 29 Jan 2024 13:25:15 +0300 Subject: [PATCH 049/114] feat: added listener for change referenceData source when editors in frame --- js/listener.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/js/listener.js b/js/listener.js index 75cb1987..53cfc268 100644 --- a/js/listener.js +++ b/js/listener.js @@ -72,6 +72,14 @@ true); }; + OCA.Onlyoffice.onRequestReferenceSource = function (referenceSourceMimes) { + OC.dialogs.filepicker(t(OCA.Onlyoffice.AppName, "Select data source"), + $("#onlyofficeFrame")[0].contentWindow.OCA.Onlyoffice.editorReferenceSource, + false, + referenceSourceMimes, + true); + } + OCA.Onlyoffice.onDocumentReady = function (documentType) { if (documentType === "word") { OCA.Onlyoffice.bindVersionClick(); @@ -121,6 +129,9 @@ case "editorRequestSelectDocument": OCA.Onlyoffice.onRequestSelectDocument(event.data.param, event.data.documentSelectionType); break; + case "editorRequestReferenceSource": + OCA.Onlyoffice.onRequestReferenceSource(event.data.param); + break; case "onDocumentReady": OCA.Onlyoffice.onDocumentReady(event.data.param); break; From e39bb00a7157a6d389b887c36d3c58fcbc4876cc Mon Sep 17 00:00:00 2001 From: rivexe Date: Mon, 29 Jan 2024 13:26:52 +0300 Subject: [PATCH 050/114] feat: translations --- l10n/ru.js | 4 +++- l10n/ru.json | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/l10n/ru.js b/l10n/ru.js index 237c0c6e..de09aebf 100644 --- a/l10n/ru.js +++ b/l10n/ru.js @@ -124,6 +124,8 @@ OC.L10N.register( "ONLYOFFICE Docs Cloud": "ONLYOFFICE Docs Cloud", "Easily launch the editors in the cloud without downloading and installation": "Легко запускайте редакторы в облаке без скачивания и установки", "Get Now": "Получить сейчас", - "Select file to combine" : "Выбрать файл для объединения" + "Select file to combine" : "Выбрать файл для объединения", + "Select data source": "Выбрать источник данных", + "The data source must not be the current document": "Источником данных не должен быть текущий документ" }, "nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);"); diff --git a/l10n/ru.json b/l10n/ru.json index 01029522..be2a216c 100644 --- a/l10n/ru.json +++ b/l10n/ru.json @@ -122,6 +122,8 @@ "ONLYOFFICE Docs Cloud": "ONLYOFFICE Docs Cloud", "Easily launch the editors in the cloud without downloading and installation": "Легко запускайте редакторы в облаке без скачивания и установки", "Get Now": "Получить сейчас", - "Select file to combine" : "Выбрать файл для объединения" + "Select file to combine" : "Выбрать файл для объединения", + "Select data source": "Выбрать источник данных", + "The data source must not be the current document": "Источником данных не должен быть текущий документ" },"pluralForm" :"nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);" } \ No newline at end of file From 82cbeb4284a0f1bcff0a17d2ddce8f14e2184896 Mon Sep 17 00:00:00 2001 From: rivexe Date: Mon, 29 Jan 2024 13:27:33 +0300 Subject: [PATCH 051/114] docs: changing reference data source to CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index adf4e632..3494f863 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - reference data from coediting - selecting a document to combine from the storage - opening a reference data source +- changing a reference data source ## 8.2.3 ## Added From 439775f707374065163ca75f07cb48596c8263cd Mon Sep 17 00:00:00 2001 From: rivexe Date: Wed, 7 Feb 2024 17:31:56 +0300 Subject: [PATCH 052/114] fix: generate revision id for file key in reference() --- controller/editorcontroller.php | 1 + 1 file changed, 1 insertion(+) diff --git a/controller/editorcontroller.php b/controller/editorcontroller.php index 5fb12953..7957572d 100644 --- a/controller/editorcontroller.php +++ b/controller/editorcontroller.php @@ -598,6 +598,7 @@ public function reference($referenceData, $path = null) { $fileName = $file->getName(); $ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION)); $key = $this->fileUtility->getKey($file); + $key = DocumentService::generateRevisionId($key); $response = [ "fileType" => $ext, From 19504ed9e47095600ee2fff0fda8269d18855970 Mon Sep 17 00:00:00 2001 From: Sergey Linnik Date: Thu, 8 Feb 2024 18:10:43 +0300 Subject: [PATCH 053/114] history is available for word, cell and slide type --- js/listener.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/js/listener.js b/js/listener.js index 53cfc268..f4e6e466 100644 --- a/js/listener.js +++ b/js/listener.js @@ -81,7 +81,9 @@ } OCA.Onlyoffice.onDocumentReady = function (documentType) { - if (documentType === "word") { + if (documentType === "word" + || documentType === "cell" + || documentType === "slide") { OCA.Onlyoffice.bindVersionClick(); } else { OCA.Onlyoffice.unbindVersionClick(); From 7747539c5e9a04ed2d6cca573ae6940795c5a844 Mon Sep 17 00:00:00 2001 From: Sergey Linnik Date: Thu, 8 Feb 2024 18:29:58 +0300 Subject: [PATCH 054/114] do not require DS v7.0 (c94cc7211a4f2943a6cc347964df9dd4bca9865a) --- js/editor.js | 6 ------ l10n/bg_BG.js | 1 - l10n/bg_BG.json | 1 - l10n/ca.js | 1 - l10n/ca.json | 1 - l10n/da.js | 1 - l10n/da.json | 1 - l10n/de.js | 1 - l10n/de.json | 1 - l10n/de_DE.js | 1 - l10n/de_DE.json | 1 - l10n/es.js | 1 - l10n/es.json | 1 - l10n/fr.js | 1 - l10n/fr.json | 1 - l10n/it.js | 1 - l10n/it.json | 1 - l10n/ja.js | 1 - l10n/ja.json | 1 - l10n/nl.js | 1 - l10n/nl.json | 1 - l10n/pl.js | 1 - l10n/pl.json | 1 - l10n/pt_BR.js | 1 - l10n/pt_BR.json | 1 - l10n/ru.js | 1 - l10n/ru.json | 1 - l10n/sv.js | 1 - l10n/sv.json | 1 - l10n/uk.js | 1 - l10n/uk.json | 1 - l10n/zh_CN.js | 1 - l10n/zh_CN.json | 1 - 33 files changed, 38 deletions(-) diff --git a/js/editor.js b/js/editor.js index 5e6da4e0..f5e9141d 100644 --- a/js/editor.js +++ b/js/editor.js @@ -100,12 +100,6 @@ return; } - if ((config.document.fileType === "docxf" || config.document.fileType === "oform") - && docsVersion[0] < 7) { - OCA.Onlyoffice.showMessage(t(OCA.Onlyoffice.AppName, "Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online"), {type: "error"}); - return; - } - var docIsChanged = null; var docIsChangedTimeout = null; diff --git a/l10n/bg_BG.js b/l10n/bg_BG.js index 1fc558a9..7c347b84 100644 --- a/l10n/bg_BG.js +++ b/l10n/bg_BG.js @@ -105,7 +105,6 @@ OC.L10N.register( "Create form": "Създайте формуляр", "Fill in form in ONLYOFFICE": "Попълнете формуляр в ONLYOFFICE", "Create new Form template": "Създайте нов шаблон на формуляр", - "Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online": "Молим да актуализирате ONLYOFFICE Docs към версия 7.0, за да работи с онлайн формуляри за попълване", "Security": "Сигурност", "Light": "Светла", "Classic Light": "Класически светла", diff --git a/l10n/bg_BG.json b/l10n/bg_BG.json index b6666515..3a9ca5ea 100644 --- a/l10n/bg_BG.json +++ b/l10n/bg_BG.json @@ -103,7 +103,6 @@ "Create form": "Създайте формуляр", "Fill in form in ONLYOFFICE": "Попълнете формуляр в ONLYOFFICE", "Create new Form template": "Създайте нов шаблон на формуляр", - "Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online": "Молим да актуализирате ONLYOFFICE Docs към версия 7.0, за да работи с онлайн формуляри за попълване", "Security": "Сигурност", "Light": "Светла", "Classic Light": "Класически светла", diff --git a/l10n/ca.js b/l10n/ca.js index c230910f..cc90ed8b 100644 --- a/l10n/ca.js +++ b/l10n/ca.js @@ -105,7 +105,6 @@ OC.L10N.register( "Create form": "Crear formulari", "Fill in form in ONLYOFFICE": "Omplir el formulari en ONLYOFFICE", "Create new Form template": "Crear nova plantilla de formulari", - "Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online": "Si us plau, actualitzi ONLYOFFICE Docs a la versió 7.0 per a poder treballar amb formularis emplenables en línia", "Security": "Seguretat", "Light": "Llum", "Classic Light": "Llum clàssica", diff --git a/l10n/ca.json b/l10n/ca.json index f15dba9e..0c5c2d77 100644 --- a/l10n/ca.json +++ b/l10n/ca.json @@ -103,7 +103,6 @@ "Create form": "Crear formulari", "Fill in form in ONLYOFFICE": "Omplir el formulari en ONLYOFFICE", "Create new Form template": "Crear nova plantilla de formulari", - "Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online": "Si us plau, actualitzi ONLYOFFICE Docs a la versió 7.0 per a poder treballar amb formularis emplenables en línia", "Security": "Seguretat", "Light": "Llum", "Classic Light": "Llum clàssica", diff --git a/l10n/da.js b/l10n/da.js index 586a0082..e33675e0 100644 --- a/l10n/da.js +++ b/l10n/da.js @@ -105,7 +105,6 @@ OC.L10N.register( "Create form": "Opret formular", "Fill in form in ONLYOFFICE": "Udfyld formularen i ONLYOFFICE", "Create new Form template": "Opret ny formularskabelon", - "Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online": "Opdater venligst ONLYOFFICE Docs til version 7.0 for at arbejde på udfyldelige formularer online", "Security": "Sikkerhed", "Run document macros": "Kør dokumentmakroer", "Default editor theme": "Standard editortema", diff --git a/l10n/da.json b/l10n/da.json index 6223424c..ab763d23 100644 --- a/l10n/da.json +++ b/l10n/da.json @@ -103,7 +103,6 @@ "Create form": "Opret formular", "Fill in form in ONLYOFFICE": "Udfyld formularen i ONLYOFFICE", "Create new Form template": "Opret ny formularskabelon", - "Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online": "Opdater venligst ONLYOFFICE Docs til version 7.0 for at arbejde på udfyldelige formularer online", "Security": "Sikkerhed", "Run document macros": "Kør dokumentmakroer", "Default editor theme": "Standard editortema", diff --git a/l10n/de.js b/l10n/de.js index 855ee303..2775dfa2 100644 --- a/l10n/de.js +++ b/l10n/de.js @@ -105,7 +105,6 @@ OC.L10N.register( "Create form": "Formular erstellen", "Fill in form in ONLYOFFICE": "Formular in ONLYOFFICE ausfüllen", "Create new Form template": "Neue Formularvorlage erstellen", - "Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online": "Für Online-Arbeit mit Formularen ist Version 7.0 von ONLYOFFICE Docs erforderlich", "Security": "Sicherheit", "Run document macros": "Makros im Dokument ausführen", "Default editor theme": "Standardmäßiges Thema des Editors", diff --git a/l10n/de.json b/l10n/de.json index eb5b5f90..50341aa4 100644 --- a/l10n/de.json +++ b/l10n/de.json @@ -103,7 +103,6 @@ "Create form": "Formular erstellen", "Fill in form in ONLYOFFICE": "Formular in ONLYOFFICE ausfüllen", "Create new Form template": "Neue Formularvorlage erstellen", - "Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online": "Für Online-Arbeit mit Formularen ist Version 7.0 von ONLYOFFICE Docs erforderlich", "Security": "Sicherheit", "Run document macros": "Makros im Dokument ausführen", "Default editor theme": "Standardmäßiges Thema des Editors", diff --git a/l10n/de_DE.js b/l10n/de_DE.js index fc25407c..5b6ee59d 100644 --- a/l10n/de_DE.js +++ b/l10n/de_DE.js @@ -105,7 +105,6 @@ OC.L10N.register( "Create form": "Formular erstellen", "Fill in form in ONLYOFFICE": "Formular in ONLYOFFICE ausfüllen", "Create new Form template": "Neue Formularvorlage erstellen", - "Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online": "Für Online-Arbeit mit Formularen ist Version 7.0 von ONLYOFFICE Docs erforderlich", "Security": "Sicherheit", "Run document macros": "Makros im Dokument ausführen", "Default editor theme": "Standardmäßiges Thema des Editors", diff --git a/l10n/de_DE.json b/l10n/de_DE.json index 967c3eb8..b8af5d12 100644 --- a/l10n/de_DE.json +++ b/l10n/de_DE.json @@ -103,7 +103,6 @@ "Create form": "Formular erstellen", "Fill in form in ONLYOFFICE": "Formular in ONLYOFFICE ausfüllen", "Create new Form template": "Neue Formularvorlage erstellen", - "Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online": "Für Online-Arbeit mit Formularen ist Version 7.0 von ONLYOFFICE Docs erforderlich", "Security": "Sicherheit", "Run document macros": "Makros im Dokument ausführen", "Default editor theme": "Standardmäßiges Thema des Editors", diff --git a/l10n/es.js b/l10n/es.js index a2cb53eb..d74c17b8 100644 --- a/l10n/es.js +++ b/l10n/es.js @@ -105,7 +105,6 @@ OC.L10N.register( "Create form": "Crear formulario", "Fill in form in ONLYOFFICE": "Rellenar el formulario en ONLYOFFICE", "Create new Form template": "Crear nueva plantilla de formulario", - "Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online": "Por favor, actualice ONLYOFFICE Docs a la versión 7.0 para poder trabajar con formularios rellenables en línea", "Security": "Seguridad", "Run document macros": "Ejecutar macros de documentos", "Default editor theme": "Tema del editor predeterminado", diff --git a/l10n/es.json b/l10n/es.json index 2713e30b..acde70c5 100644 --- a/l10n/es.json +++ b/l10n/es.json @@ -103,7 +103,6 @@ "Create form": "Crear formulario", "Fill in form in ONLYOFFICE": "Rellenar el formulario en ONLYOFFICE", "Create new Form template": "Crear nueva plantilla de formulario", - "Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online": "Por favor, actualice ONLYOFFICE Docs a la versión 7.0 para poder trabajar con formularios rellenables en línea", "Security": "Seguridad", "Run document macros": "Ejecutar macros de documentos", "Default editor theme": "Tema del editor predeterminado", diff --git a/l10n/fr.js b/l10n/fr.js index f1dfcaa9..2d19adc9 100644 --- a/l10n/fr.js +++ b/l10n/fr.js @@ -105,7 +105,6 @@ OC.L10N.register( "Create form": "Créer un formulaire", "Fill in form in ONLYOFFICE": "Remplir le formulaire dans ONLYOFFICE", "Create new Form template": "Créer un nouveau modèle de formulaire", - "Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online": "Veuillez mettre à jour ONLYOFFICE Docs vers la version 7.0 pour travailler sur les formulaires à remplir en ligne", "Security": "Sécurité", "Run document macros": "Exécuter des macros de documents", "Default editor theme": "Thème d'éditeur par défaut", diff --git a/l10n/fr.json b/l10n/fr.json index 959369dd..88530c32 100644 --- a/l10n/fr.json +++ b/l10n/fr.json @@ -103,7 +103,6 @@ "Create form": "Créer un formulaire", "Fill in form in ONLYOFFICE": "Remplir le formulaire dans ONLYOFFICE", "Create new Form template": "Créer un nouveau modèle de formulaire", - "Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online": "Veuillez mettre à jour ONLYOFFICE Docs vers la version 7.0 pour travailler sur les formulaires à remplir en ligne", "Security": "Sécurité", "Run document macros": "Exécuter des macros de documents", "Default editor theme": "Thème d'éditeur par défaut", diff --git a/l10n/it.js b/l10n/it.js index ae29a205..51228800 100644 --- a/l10n/it.js +++ b/l10n/it.js @@ -105,7 +105,6 @@ OC.L10N.register( "Create form": "Creare modulo", "Fill in form in ONLYOFFICE": "Compilare il modulo in ONLYOFFICE", "Create new Form template": "Creare un nuovo modello di modulo", - "Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online": "Si prega di aggiornare ONLYOFFICE Docs alla versione 7.0 per lavorare su moduli compilabili online", "Security": "Sicurezza", "Run document macros": "Esegui le macro del documento", "Default editor theme": "Tema dell'editor predefinito", diff --git a/l10n/it.json b/l10n/it.json index 0a0b4694..e329bdb9 100644 --- a/l10n/it.json +++ b/l10n/it.json @@ -103,7 +103,6 @@ "Create form": "Creare modulo", "Fill in form in ONLYOFFICE": "Compilare il modulo in ONLYOFFICE", "Create new Form template": "Creare un nuovo modello di modulo", - "Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online": "Si prega di aggiornare ONLYOFFICE Docs alla versione 7.0 per lavorare su moduli compilabili online", "Security": "Sicurezza", "Run document macros": "Esegui le macro del documento", "Default editor theme": "Tema dell'editor predefinito", diff --git a/l10n/ja.js b/l10n/ja.js index daa72df4..c3fb00f9 100644 --- a/l10n/ja.js +++ b/l10n/ja.js @@ -105,7 +105,6 @@ OC.L10N.register( "Create form": "フォームの作成", "Fill in form in ONLYOFFICE": "ONLYOFFICEでフォームを記入する", "Create new Form template": "新しいフォームテンプレートの作成", - "Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online": "オンラインで入力可能なフォームを作成するには、ONLYOFFICE Docs 7.0版まで更新してください", "Security": "セキュリティ", "Run document macros": "ドキュメントマクロを実行する", "Default editor theme": "エディターのデフォルトテーマ", diff --git a/l10n/ja.json b/l10n/ja.json index b33590db..429711ae 100644 --- a/l10n/ja.json +++ b/l10n/ja.json @@ -103,7 +103,6 @@ "Create form": "フォームの作成", "Fill in form in ONLYOFFICE": "ONLYOFFICEでフォームを記入する", "Create new Form template": "新しいフォームテンプレートの作成", - "Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online": "オンラインで入力可能なフォームを作成するには、ONLYOFFICE Docs 7.0版まで更新してください", "Security": "セキュリティ", "Run document macros": "ドキュメントマクロを実行する", "Default editor theme": "エディターのデフォルトテーマ", diff --git a/l10n/nl.js b/l10n/nl.js index c0157064..87c460ab 100644 --- a/l10n/nl.js +++ b/l10n/nl.js @@ -105,7 +105,6 @@ OC.L10N.register( "Create form": "Formulier maken", "Fill in form in ONLYOFFICE": "Formulier invullen in ONLYOFFICE", "Create new Form template": "Nieuw Formulier sjabloon maken", - "Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online": "Update ONLYOFFICE Docs naar versie 7.0 om online invulbare formulieren te kunnen gebruiken", "Security": "Beveiliging", "Run document macros": "Document macro's uitvoeren", "Default editor theme": "Standaard editor thema", diff --git a/l10n/nl.json b/l10n/nl.json index 96f55b0f..1b25aff8 100644 --- a/l10n/nl.json +++ b/l10n/nl.json @@ -103,7 +103,6 @@ "Create form": "Formulier maken", "Fill in form in ONLYOFFICE": "Formulier invullen in ONLYOFFICE", "Create new Form template": "Nieuw Formulier sjabloon maken", - "Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online": "Update ONLYOFFICE Docs naar versie 7.0 om online invulbare formulieren te kunnen gebruiken", "Security": "Beveiliging", "Run document macros": "Document macro's uitvoeren", "Default editor theme": "Standaard editor thema", diff --git a/l10n/pl.js b/l10n/pl.js index 15646175..89638335 100644 --- a/l10n/pl.js +++ b/l10n/pl.js @@ -105,7 +105,6 @@ OC.L10N.register( "Create form": "Utwórz formularz", "Fill in form in ONLYOFFICE": "Wypełnić formularz w ONLYOFFICE", "Create new Form template": "Utwórz nowy szablon formularza", - "Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online": "Zaktualizuj ONLYOFFICE Docs do wersji 7.0, aby działały w formularzach do wypełniania online", "Security": "Bezpieczeństwo", "Run document macros": "Uruchom makra dokumentu", "Default editor theme": "Domyślny motyw edytora", diff --git a/l10n/pl.json b/l10n/pl.json index d76aa75f..6cab5c1f 100644 --- a/l10n/pl.json +++ b/l10n/pl.json @@ -103,7 +103,6 @@ "Create form": "Utwórz formularz", "Fill in form in ONLYOFFICE": "Wypełnić formularz w ONLYOFFICE", "Create new Form template": "Utwórz nowy szablon formularza", - "Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online": "Zaktualizuj ONLYOFFICE Docs do wersji 7.0, aby działały w formularzach do wypełniania online", "Security": "Bezpieczeństwo", "Run document macros": "Uruchom makra dokumentu", "Default editor theme": "Domyślny motyw edytora", diff --git a/l10n/pt_BR.js b/l10n/pt_BR.js index 5a8b9747..79d6445b 100644 --- a/l10n/pt_BR.js +++ b/l10n/pt_BR.js @@ -105,7 +105,6 @@ OC.L10N.register( "Create form": "Criar formulário", "Fill in form in ONLYOFFICE": "Preencher formulário no ONLYOFFICE", "Create new Form template": "Criar novo modelo de Formulário", - "Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online": "Atualize o ONLYOFFICE Docs para a versão 7.0 para trabalhar em formulários preenchíveis online", "Security": "Segurança", "Run document macros": "Executar macros de documento", "Default editor theme": "Tema do editor padrão", diff --git a/l10n/pt_BR.json b/l10n/pt_BR.json index 02352a56..e48c95ae 100644 --- a/l10n/pt_BR.json +++ b/l10n/pt_BR.json @@ -103,7 +103,6 @@ "Create form": "Criar formulário", "Fill in form in ONLYOFFICE": "Preencher formulário no ONLYOFFICE", "Create new Form template": "Criar novo modelo de Formulário", - "Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online": "Atualize o ONLYOFFICE Docs para a versão 7.0 para trabalhar em formulários preenchíveis online", "Security": "Segurança", "Run document macros": "Executar macros de documento", "Default editor theme": "Tema do editor padrão", diff --git a/l10n/ru.js b/l10n/ru.js index de09aebf..5459882d 100644 --- a/l10n/ru.js +++ b/l10n/ru.js @@ -105,7 +105,6 @@ OC.L10N.register( "Create form": "Создать форму", "Fill in form in ONLYOFFICE": "Заполнить форму в ONLYOFFICE", "Create new Form template": "Создать новый шаблон формы", - "Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online": "Обновите сервер ONLYOFFICE Docs до версии 7.0 для работы с формами онлайн", "Security": "Безопасность", "Run document macros": "Запускать макросы документа", "Default editor theme": "Тема редактора по умолчанию", diff --git a/l10n/ru.json b/l10n/ru.json index be2a216c..860a051f 100644 --- a/l10n/ru.json +++ b/l10n/ru.json @@ -103,7 +103,6 @@ "Create form": "Создать форму", "Fill in form in ONLYOFFICE": "Заполнить форму в ONLYOFFICE", "Create new Form template": "Создать новый шаблон формы", - "Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online": "Обновите сервер ONLYOFFICE Docs до версии 7.0 для работы с формами онлайн", "Security": "Безопасность", "Run document macros": "Запускать макросы документа", "Default editor theme": "Тема редактора по умолчанию", diff --git a/l10n/sv.js b/l10n/sv.js index 8e405982..07ef1ebf 100644 --- a/l10n/sv.js +++ b/l10n/sv.js @@ -105,7 +105,6 @@ OC.L10N.register( "Create form": "Skapa formulär", "Fill in form in ONLYOFFICE": "Fylla i formulär i ONLYOFFICE", "Create new Form template": "Skapa ny formulärmall", - "Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online": "Uppdatera ONLYOFFICE Docs till version 7.0 för att arbeta med ifyllbart onlineformulär", "Security": "Säkerhet", "Run document macros": "Kör dokumentmakron", "Light": "Ljus", diff --git a/l10n/sv.json b/l10n/sv.json index e1fa4f18..d8fc44bf 100644 --- a/l10n/sv.json +++ b/l10n/sv.json @@ -103,7 +103,6 @@ "Create form": "Skapa formulär", "Fill in form in ONLYOFFICE": "Fylla i formulär i ONLYOFFICE", "Create new Form template": "Skapa ny formulärmall", - "Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online": "Uppdatera ONLYOFFICE Docs till version 7.0 för att arbeta med ifyllbart onlineformulär", "Security": "Säkerhet", "Run document macros": "Kör dokumentmakron", "Light": "Ljus", diff --git a/l10n/uk.js b/l10n/uk.js index bb9b820f..1c00d8ac 100644 --- a/l10n/uk.js +++ b/l10n/uk.js @@ -103,7 +103,6 @@ OC.L10N.register( "Create form": "Створити форму", "Fill in form in ONLYOFFICE": "Заповнити форму у ONLYOFFICE", "Create new Form template": "Створити новий шаблон форми", - "Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online": "Оновіть сервер ONLYOFFICE Docs до версії 7.0 для роботи з формами в онлайні", "Security": "Безпека", "Run document macros": "Виконувати макроси документу", "Default editor theme": "Типова тема редактора", diff --git a/l10n/uk.json b/l10n/uk.json index dde01d0a..044a3aa2 100644 --- a/l10n/uk.json +++ b/l10n/uk.json @@ -102,7 +102,6 @@ "Create form": "Створити форму", "Fill in form in ONLYOFFICE": "Заповнити форму у ONLYOFFICE", "Create new Form template": "Створити новий шаблон форми", - "Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online": "Оновіть сервер ONLYOFFICE Docs до версії 7.0 для роботи з формами в онлайні", "Security": "Безпека", "Run document macros": "Виконувати макроси документу", "Default editor theme": "Типова тема редактора", diff --git a/l10n/zh_CN.js b/l10n/zh_CN.js index 5c454330..c743a56f 100644 --- a/l10n/zh_CN.js +++ b/l10n/zh_CN.js @@ -105,7 +105,6 @@ OC.L10N.register( "Create form": "创建表单", "Fill in form in ONLYOFFICE": "在ONLYOFFICE上填写表单", "Create new Form template": "创建新的表单模板", - "Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online": "请将ONLYOFFICE Docs更新到7.0版本,以便在线编辑可填写的表单", "Security": "安全", "Run document macros": "运行文档宏", "Default editor theme": "编辑器默认的主题", diff --git a/l10n/zh_CN.json b/l10n/zh_CN.json index 100dc87c..4dc8ae70 100644 --- a/l10n/zh_CN.json +++ b/l10n/zh_CN.json @@ -103,7 +103,6 @@ "Create form": "创建表单", "Fill in form in ONLYOFFICE": "在ONLYOFFICE上填写表单", "Create new Form template": "创建新的表单模板", - "Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online": "请将ONLYOFFICE Docs更新到7.0版本,以便在线编辑可填写的表单", "Security": "安全", "Run document macros": "运行文档宏", "Default editor theme": "编辑器默认的主题", From 9ef96036d6dc954ae96e4615b39c9413523af346 Mon Sep 17 00:00:00 2001 From: rivexe Date: Fri, 9 Feb 2024 12:59:40 +0300 Subject: [PATCH 055/114] feat: operation type support --- controller/editorcontroller.php | 20 ++++++++++---------- js/editor.js | 4 +++- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/controller/editorcontroller.php b/controller/editorcontroller.php index 7957572d..db947736 100644 --- a/controller/editorcontroller.php +++ b/controller/editorcontroller.php @@ -340,7 +340,7 @@ public function createNew($name, $dir, $templateId = null) { * @NoAdminRequired * @NoCSRFRequired */ - public function users($fileId) { + public function users($fileId, $operationType = null) { $this->logger->debug("Search users", ["app" => $this->appName]); $result = []; @@ -400,17 +400,17 @@ public function users($fileId) { foreach ($users as $user) { $email = $user->getEMailAddress(); - if ($user->getUID() != $currentUserId && !empty($email)) { - array_push( - $result, - [ - "email" => $email, - "name" => $user->getDisplayName() - ] - ); + if ($user->getUID() != $currentUserId && (!empty($email) || $operationType === "protect")) { + $userElement = [ + "name" => $user->getDisplayName(), + "id" => $user->getUID() + ]; + if (!empty($email)) { + $userElement["email"] = $email; + } + array_push($result, $userElement); } } - return $result; } diff --git a/js/editor.js b/js/editor.js index f5e9141d..99313ed3 100644 --- a/js/editor.js +++ b/js/editor.js @@ -509,12 +509,14 @@ }; OCA.Onlyoffice.onRequestUsers = function (event) { - $.get(OC.generateUrl("apps/" + OCA.Onlyoffice.AppName + "/ajax/users?fileId={fileId}", + let operationType = typeof(event.data.c) !== "undefined" ? event.data.c : null; + $.get(OC.generateUrl("apps/" + OCA.Onlyoffice.AppName + "/ajax/users?fileId={fileId}&operationType=" + operationType, { fileId: OCA.Onlyoffice.fileId || 0 }), function onSuccess(response) { OCA.Onlyoffice.docEditor.setUsers({ + "c": operationType, "users": response }); }); From 69695b66eaa562f17ea41f9d6a5f48d64e3ca0a9 Mon Sep 17 00:00:00 2001 From: rivexe Date: Fri, 9 Feb 2024 12:59:55 +0300 Subject: [PATCH 056/114] docs: userId and operation type control added to CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fca54726..cd4bc491 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ### Changed - compatible with ownCloud Web 7.0 +- list of users to protect ranges of cells ## Added - reference data from coediting From d872a60a716c913b23a3202febc0ba02ab02125a Mon Sep 17 00:00:00 2001 From: rivexe Date: Fri, 9 Feb 2024 13:19:02 +0300 Subject: [PATCH 057/114] fix: lint comment --- controller/editorcontroller.php | 1 + 1 file changed, 1 insertion(+) diff --git a/controller/editorcontroller.php b/controller/editorcontroller.php index db947736..e4692aa5 100644 --- a/controller/editorcontroller.php +++ b/controller/editorcontroller.php @@ -334,6 +334,7 @@ public function createNew($name, $dir, $templateId = null) { * Get users * * @param $fileId - file identifier + * @param $operationType - type of operation * * @return array * From 822d4d80fbf764a2f95b8322412ad53d4bb6064d Mon Sep 17 00:00:00 2001 From: Sergey Linnik Date: Fri, 9 Feb 2024 14:05:04 +0300 Subject: [PATCH 058/114] copyright 2024 --- appinfo/app.php | 2 +- appinfo/application.php | 2 +- appinfo/routes.php | 2 +- controller/callbackcontroller.php | 2 +- controller/editorapicontroller.php | 2 +- controller/editorcontroller.php | 2 +- controller/federationcontroller.php | 2 +- controller/joblistcontroller.php | 2 +- controller/settingsapicontroller.php | 2 +- controller/settingscontroller.php | 2 +- controller/templatecontroller.php | 2 +- controller/webassetcontroller.php | 2 +- css/editor.css | 2 +- css/main.css | 2 +- css/settings.css | 2 +- css/template.css | 2 +- js/desktop.js | 2 +- js/editor.js | 2 +- js/listener.js | 2 +- js/main.js | 2 +- js/settings.js | 2 +- js/share.js | 2 +- js/template.js | 2 +- js/web/onlyoffice.js | 2 +- lib/adminsettings.php | 2 +- lib/appconfig.php | 2 +- lib/command/documentserver.php | 2 +- lib/cron/editorscheck.php | 2 +- lib/crypt.php | 2 +- lib/documentservice.php | 2 +- lib/fileutility.php | 2 +- lib/fileversions.php | 2 +- lib/hookhandler.php | 2 +- lib/hooks.php | 2 +- lib/keymanager.php | 2 +- lib/notifier.php | 2 +- lib/preview.php | 2 +- lib/remoteinstance.php | 2 +- lib/templatemanager.php | 2 +- lib/version.php | 2 +- lib/versionmanager.php | 2 +- settings.php | 2 +- templates/editor.php | 2 +- templates/settings.php | 2 +- 44 files changed, 44 insertions(+), 44 deletions(-) diff --git a/appinfo/app.php b/appinfo/app.php index db16f003..e0209e25 100644 --- a/appinfo/app.php +++ b/appinfo/app.php @@ -2,7 +2,7 @@ /** * @author Ascensio System SIA * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/appinfo/application.php b/appinfo/application.php index 45904f9c..4ed7930d 100644 --- a/appinfo/application.php +++ b/appinfo/application.php @@ -2,7 +2,7 @@ /** * @author Ascensio System SIA * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/appinfo/routes.php b/appinfo/routes.php index 016a4e3d..0edcc195 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -2,7 +2,7 @@ /** * @author Ascensio System SIA * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/controller/callbackcontroller.php b/controller/callbackcontroller.php index 04fc0b61..58992b79 100644 --- a/controller/callbackcontroller.php +++ b/controller/callbackcontroller.php @@ -2,7 +2,7 @@ /** * @author Ascensio System SIA * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/controller/editorapicontroller.php b/controller/editorapicontroller.php index 28fff137..cb9ae897 100644 --- a/controller/editorapicontroller.php +++ b/controller/editorapicontroller.php @@ -2,7 +2,7 @@ /** * @author Ascensio System SIA * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/controller/editorcontroller.php b/controller/editorcontroller.php index 7957572d..de37880b 100644 --- a/controller/editorcontroller.php +++ b/controller/editorcontroller.php @@ -2,7 +2,7 @@ /** * @author Ascensio System SIA * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/controller/federationcontroller.php b/controller/federationcontroller.php index d3e5684b..ff6610cd 100644 --- a/controller/federationcontroller.php +++ b/controller/federationcontroller.php @@ -2,7 +2,7 @@ /** * @author Ascensio System SIA * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/controller/joblistcontroller.php b/controller/joblistcontroller.php index a85b14ef..ccd83ea4 100644 --- a/controller/joblistcontroller.php +++ b/controller/joblistcontroller.php @@ -2,7 +2,7 @@ /** * @author Ascensio System SIA * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/controller/settingsapicontroller.php b/controller/settingsapicontroller.php index 7d6636e9..74483722 100644 --- a/controller/settingsapicontroller.php +++ b/controller/settingsapicontroller.php @@ -2,7 +2,7 @@ /** * @author Ascensio System SIA * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/controller/settingscontroller.php b/controller/settingscontroller.php index b41caee5..08509b33 100644 --- a/controller/settingscontroller.php +++ b/controller/settingscontroller.php @@ -2,7 +2,7 @@ /** * @author Ascensio System SIA * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/controller/templatecontroller.php b/controller/templatecontroller.php index 06cd9922..481769fd 100644 --- a/controller/templatecontroller.php +++ b/controller/templatecontroller.php @@ -2,7 +2,7 @@ /** * @author Ascensio System SIA * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/controller/webassetcontroller.php b/controller/webassetcontroller.php index baaa4a6d..ada20499 100644 --- a/controller/webassetcontroller.php +++ b/controller/webassetcontroller.php @@ -2,7 +2,7 @@ /** * @author Ascensio System SIA * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/css/editor.css b/css/editor.css index 33ff19a1..8ef19922 100644 --- a/css/editor.css +++ b/css/editor.css @@ -1,6 +1,6 @@ /** * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/css/main.css b/css/main.css index 061319e8..f32e89ce 100644 --- a/css/main.css +++ b/css/main.css @@ -1,6 +1,6 @@ /** * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/css/settings.css b/css/settings.css index 0899c3ba..8292bef7 100644 --- a/css/settings.css +++ b/css/settings.css @@ -1,6 +1,6 @@ /** * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/css/template.css b/css/template.css index 617239bd..3e7505d6 100644 --- a/css/template.css +++ b/css/template.css @@ -1,6 +1,6 @@ /** * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/js/desktop.js b/js/desktop.js index cbcc3b42..b7747dcb 100644 --- a/js/desktop.js +++ b/js/desktop.js @@ -1,6 +1,6 @@ /** * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/js/editor.js b/js/editor.js index f5e9141d..6d41a877 100644 --- a/js/editor.js +++ b/js/editor.js @@ -1,6 +1,6 @@ /** * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/js/listener.js b/js/listener.js index f4e6e466..e7d41af5 100644 --- a/js/listener.js +++ b/js/listener.js @@ -1,6 +1,6 @@ /** * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/js/main.js b/js/main.js index d26ae1a2..2e71b6e0 100644 --- a/js/main.js +++ b/js/main.js @@ -1,6 +1,6 @@ /** * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/js/settings.js b/js/settings.js index f60bd02b..ec54bcf9 100644 --- a/js/settings.js +++ b/js/settings.js @@ -1,6 +1,6 @@ /** * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/js/share.js b/js/share.js index 1de32b3a..a1364f54 100644 --- a/js/share.js +++ b/js/share.js @@ -1,6 +1,6 @@ /** * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/js/template.js b/js/template.js index 6a6e2c24..db6a0e3a 100644 --- a/js/template.js +++ b/js/template.js @@ -1,6 +1,6 @@ /** * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/js/web/onlyoffice.js b/js/web/onlyoffice.js index f745fa04..98211ae2 100644 --- a/js/web/onlyoffice.js +++ b/js/web/onlyoffice.js @@ -6762,7 +6762,7 @@ define(['vue'], (function (vue) { 'use strict'; /** * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/lib/adminsettings.php b/lib/adminsettings.php index 7374b546..30acaa54 100644 --- a/lib/adminsettings.php +++ b/lib/adminsettings.php @@ -2,7 +2,7 @@ /** * @author Ascensio System SIA * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/lib/appconfig.php b/lib/appconfig.php index fc03881b..e4afe3bb 100644 --- a/lib/appconfig.php +++ b/lib/appconfig.php @@ -2,7 +2,7 @@ /** * @author Ascensio System SIA * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/lib/command/documentserver.php b/lib/command/documentserver.php index 39ecc667..f757beda 100644 --- a/lib/command/documentserver.php +++ b/lib/command/documentserver.php @@ -2,7 +2,7 @@ /** * @author Ascensio System SIA * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/lib/cron/editorscheck.php b/lib/cron/editorscheck.php index 07582248..15df13d4 100644 --- a/lib/cron/editorscheck.php +++ b/lib/cron/editorscheck.php @@ -2,7 +2,7 @@ /** * @author Ascensio System SIA * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/lib/crypt.php b/lib/crypt.php index 377b98e1..02923f60 100644 --- a/lib/crypt.php +++ b/lib/crypt.php @@ -2,7 +2,7 @@ /** * @author Ascensio System SIA * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/lib/documentservice.php b/lib/documentservice.php index 2d47c46d..8894bc9b 100644 --- a/lib/documentservice.php +++ b/lib/documentservice.php @@ -2,7 +2,7 @@ /** * @author Ascensio System SIA * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/lib/fileutility.php b/lib/fileutility.php index cb754411..8f2b6dab 100644 --- a/lib/fileutility.php +++ b/lib/fileutility.php @@ -2,7 +2,7 @@ /** * @author Ascensio System SIA * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/lib/fileversions.php b/lib/fileversions.php index aa5a364a..9aaea3ca 100644 --- a/lib/fileversions.php +++ b/lib/fileversions.php @@ -2,7 +2,7 @@ /** * @author Ascensio System SIA * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/lib/hookhandler.php b/lib/hookhandler.php index 7536e0c4..b1ca06e5 100644 --- a/lib/hookhandler.php +++ b/lib/hookhandler.php @@ -2,7 +2,7 @@ /** * @author Ascensio System SIA * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/lib/hooks.php b/lib/hooks.php index 3868b9f6..20ba2879 100644 --- a/lib/hooks.php +++ b/lib/hooks.php @@ -2,7 +2,7 @@ /** * @author Ascensio System SIA * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/lib/keymanager.php b/lib/keymanager.php index 95d3ffe4..969ff7a4 100644 --- a/lib/keymanager.php +++ b/lib/keymanager.php @@ -2,7 +2,7 @@ /** * @author Ascensio System SIA * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/lib/notifier.php b/lib/notifier.php index b641dfb4..85a91991 100644 --- a/lib/notifier.php +++ b/lib/notifier.php @@ -2,7 +2,7 @@ /** * @author Ascensio System SIA * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/lib/preview.php b/lib/preview.php index 18aa2f20..98c1afe6 100644 --- a/lib/preview.php +++ b/lib/preview.php @@ -2,7 +2,7 @@ /** * @author Ascensio System SIA * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/lib/remoteinstance.php b/lib/remoteinstance.php index 971e56f3..f11f74b4 100644 --- a/lib/remoteinstance.php +++ b/lib/remoteinstance.php @@ -2,7 +2,7 @@ /** * @author Ascensio System SIA * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/lib/templatemanager.php b/lib/templatemanager.php index 1cfb8b4a..19fc4f86 100644 --- a/lib/templatemanager.php +++ b/lib/templatemanager.php @@ -2,7 +2,7 @@ /** * @author Ascensio System SIA * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/lib/version.php b/lib/version.php index 228b8156..d95ff1c3 100644 --- a/lib/version.php +++ b/lib/version.php @@ -2,7 +2,7 @@ /** * @author Ascensio System SIA * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/lib/versionmanager.php b/lib/versionmanager.php index 782f41da..93e06f08 100644 --- a/lib/versionmanager.php +++ b/lib/versionmanager.php @@ -2,7 +2,7 @@ /** * @author Ascensio System SIA * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/settings.php b/settings.php index c474cf38..e559e518 100644 --- a/settings.php +++ b/settings.php @@ -2,7 +2,7 @@ /** * @author Ascensio System SIA * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/templates/editor.php b/templates/editor.php index 86581940..a6e4a997 100644 --- a/templates/editor.php +++ b/templates/editor.php @@ -2,7 +2,7 @@ /** * @author Ascensio System SIA * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/templates/settings.php b/templates/settings.php index 5556c893..0e251fd7 100644 --- a/templates/settings.php +++ b/templates/settings.php @@ -2,7 +2,7 @@ /** * @author Ascensio System SIA * - * (c) Copyright Ascensio System SIA 2023 + * (c) Copyright Ascensio System SIA 2024 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From ddbe7b46d6b9bd8a787aeebdb47276e542b633c1 Mon Sep 17 00:00:00 2001 From: rivexe Date: Fri, 9 Feb 2024 14:08:19 +0300 Subject: [PATCH 059/114] feat: cron checker setting to user interface --- controller/joblistcontroller.php | 4 ++++ controller/settingscontroller.php | 4 ++++ js/settings.js | 2 ++ l10n/ru.js | 3 ++- l10n/ru.json | 3 ++- lib/appconfig.php | 27 +++++++++++++++++++++++++++ templates/settings.php | 6 ++++++ 7 files changed, 47 insertions(+), 2 deletions(-) diff --git a/controller/joblistcontroller.php b/controller/joblistcontroller.php index a85b14ef..d02fbc9a 100644 --- a/controller/joblistcontroller.php +++ b/controller/joblistcontroller.php @@ -111,6 +111,10 @@ private function removeJob($job) { * @return void */ private function checkEditorsCheckJob() { + if (!$this->config->getCronChecker()) { + $this->removeJob(EditorsCheck::class); + return; + } if ($this->config->getEditorsCheckInterval() > 0) { $this->addJob(EditorsCheck::class); } else { diff --git a/controller/settingscontroller.php b/controller/settingscontroller.php index b41caee5..e3b143a7 100644 --- a/controller/settingscontroller.php +++ b/controller/settingscontroller.php @@ -117,6 +117,7 @@ public function index() { "formats" => $this->config->formatsSetting(), "sameTab" => $this->config->getSameTab(), "preview" => $this->config->getPreview(), + "cronChecker" => $this->config->getCronChecker(), "versionHistory" => $this->config->getVersionHistory(), "protection" => $this->config->getProtection(), "encryption" => $this->config->checkEncryptionModule(), @@ -206,6 +207,7 @@ public function saveAddress( * @param array $editFormats - editable formats array * @param bool $sameTab - open in the same tab * @param bool $preview - generate preview files + * @param bool $cronChecker - disable cron checker * @param bool $versionHistory - keep version history * @param array $limitGroups - list of groups * @param bool $chat - display chat @@ -224,6 +226,7 @@ public function saveCommon( $editFormats, $sameTab, $preview, + $cronChecker, $versionHistory, $limitGroups, $chat, @@ -239,6 +242,7 @@ public function saveCommon( $this->config->setEditableFormats($editFormats); $this->config->setSameTab($sameTab); $this->config->setPreview($preview); + $this->config->setCronChecker($cronChecker); $this->config->setVersionHistory($versionHistory); $this->config->setLimitGroups($limitGroups); $this->config->setCustomizationChat($chat); diff --git a/js/settings.js b/js/settings.js index f60bd02b..ef1e52a9 100644 --- a/js/settings.js +++ b/js/settings.js @@ -130,6 +130,7 @@ var sameTab = $("#onlyofficeSameTab").is(":checked"); var preview = $("#onlyofficePreview").is(":checked"); + var cronChecker = $("#onlyofficeCronChecker").is(":checked"); var versionHistory = $("#onlyofficeVersionHistory").is(":checked"); var limitGroupsString = $("#onlyofficeGroups").prop("checked") ? $("#onlyofficeLimitGroups").val() : ""; @@ -152,6 +153,7 @@ editFormats: editFormats, sameTab: sameTab, preview: preview, + cronChecker: cronChecker, versionHistory: versionHistory, limitGroups: limitGroups, chat: chat, diff --git a/l10n/ru.js b/l10n/ru.js index 5459882d..7af5ebe2 100644 --- a/l10n/ru.js +++ b/l10n/ru.js @@ -125,6 +125,7 @@ OC.L10N.register( "Get Now": "Получить сейчас", "Select file to combine" : "Выбрать файл для объединения", "Select data source": "Выбрать источник данных", - "The data source must not be the current document": "Источником данных не должен быть текущий документ" + "The data source must not be the current document": "Источником данных не должен быть текущий документ", + "Enable background connection check to the editors": "Включить фоновую проверку подключения к редакторам" }, "nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);"); diff --git a/l10n/ru.json b/l10n/ru.json index 860a051f..6a03657d 100644 --- a/l10n/ru.json +++ b/l10n/ru.json @@ -123,6 +123,7 @@ "Get Now": "Получить сейчас", "Select file to combine" : "Выбрать файл для объединения", "Select data source": "Выбрать источник данных", - "The data source must not be the current document": "Источником данных не должен быть текущий документ" + "The data source must not be the current document": "Источником данных не должен быть текущий документ", + "Enable background connection check to the editors": "Включить фоновую проверку подключения к редакторам" },"pluralForm" :"nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);" } \ No newline at end of file diff --git a/lib/appconfig.php b/lib/appconfig.php index fc03881b..4b29802f 100644 --- a/lib/appconfig.php +++ b/lib/appconfig.php @@ -116,6 +116,13 @@ class AppConfig { */ private $_preview = "preview"; + /** + * The config key for the cronChecker + * + * @var string + */ + private $_cronChecker = "cronChecker"; + /** * The config key for the keep versions history * @@ -696,6 +703,26 @@ public function getPreview() { return $this->config->getAppValue($this->appName, $this->_preview, "true") === "true"; } + /** + * Get cron checker setting + * + * @return bool + */ + public function getCronChecker() { + return $this->config->getAppValue($this->appName, $this->_cronChecker, "true") !== "false"; + } + + /** + * Save cron checker setting + * + * @param bool $value - cronChecker + */ + public function setCronChecker($value) { + $this->logger->info("Set cron checker: " . json_encode($value), ["app" => $this->appName]); + + $this->config->setAppValue($this->appName, $this->_cronChecker, json_encode($value)); + } + /** * Save keep versions history * diff --git a/templates/settings.php b/templates/settings.php index 5556c893..3b6a8af7 100644 --- a/templates/settings.php +++ b/templates/settings.php @@ -137,6 +137,12 @@

+

+ checked="checked" /> + +

+

t("The default application for opening the format")) ?>

$setting) { ?> From f33fd6f039d96ee322da2711c35280cdc43ea14d Mon Sep 17 00:00:00 2001 From: rivexe Date: Fri, 9 Feb 2024 14:08:39 +0300 Subject: [PATCH 060/114] docs: cron checker setting to CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fca54726..d00a50c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ - Arabic and Serbian empty file templates - opening a reference data source - changing a reference data source +- setting for disable editors cron check ## 8.2.3 ## Added From f105d15b9b0031dc1cbcd2a240d7a68aacf4065c Mon Sep 17 00:00:00 2001 From: rivexe Date: Fri, 9 Feb 2024 14:13:37 +0300 Subject: [PATCH 061/114] fix: lint comment --- lib/appconfig.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/appconfig.php b/lib/appconfig.php index 4b29802f..6acb966e 100644 --- a/lib/appconfig.php +++ b/lib/appconfig.php @@ -716,6 +716,8 @@ public function getCronChecker() { * Save cron checker setting * * @param bool $value - cronChecker + * + * @return void */ public function setCronChecker($value) { $this->logger->info("Set cron checker: " . json_encode($value), ["app" => $this->appName]); From e1451bc033f94fdea664eae18b2bf9f19f17e721 Mon Sep 17 00:00:00 2001 From: rivexe Date: Fri, 9 Feb 2024 14:19:26 +0300 Subject: [PATCH 062/114] feat: offline viewer in share --- controller/editorapicontroller.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/controller/editorapicontroller.php b/controller/editorapicontroller.php index cb9ae897..e5fe209c 100644 --- a/controller/editorapicontroller.php +++ b/controller/editorapicontroller.php @@ -316,6 +316,11 @@ public function config($fileId, $filePath = null, $shareToken = null, $version = $restrictedEditing = false; $fileStorage = $file->getStorage(); if (empty($shareToken) && $fileStorage->instanceOfStorage("\OCA\Files_Sharing\SharedStorage")) { + + $params["editorConfig"]["coEditing"] = [ + "mode" => "strict", + "change" => false + ]; $storageShare = $fileStorage->getShare(); if (method_exists($storageShare, "getAttributes")) { $attributes = $storageShare->getAttributes(); From 74715fb66169aaf940b7bd4017e89da3bf3f7bed Mon Sep 17 00:00:00 2001 From: rivexe Date: Fri, 9 Feb 2024 14:19:40 +0300 Subject: [PATCH 063/114] docs: offline viewer for share to CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fca54726..8193bd9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ### Changed - compatible with ownCloud Web 7.0 +- offline viewer for share link ## Added - reference data from coediting From 750898d5b998bb16cb20d8dce971e76c31dbb95a Mon Sep 17 00:00:00 2001 From: rivexe Date: Tue, 13 Feb 2024 15:23:15 +0300 Subject: [PATCH 064/114] refactor: delete submodule "assets" --- .gitmodules | 4 ---- assets | 1 - 2 files changed, 5 deletions(-) delete mode 160000 assets diff --git a/.gitmodules b/.gitmodules index f7a93934..e69de29b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +0,0 @@ -[submodule "assets"] - path = assets - url = https://github.com/ONLYOFFICE/document-templates - branch = main/new diff --git a/assets b/assets deleted file mode 160000 index e0771eb5..00000000 --- a/assets +++ /dev/null @@ -1 +0,0 @@ -Subproject commit e0771eb517facd02b2c9f2f4ee10b278da694d5d From e698e8f73e8b80e583df3f5ba00e836422074ccb Mon Sep 17 00:00:00 2001 From: rivexe Date: Tue, 13 Feb 2024 15:32:38 +0300 Subject: [PATCH 065/114] refactor: change path to document-templates submodule --- .gitmodules | 4 ++++ assets/document-templates | 1 + 2 files changed, 5 insertions(+) create mode 160000 assets/document-templates diff --git a/.gitmodules b/.gitmodules index e69de29b..7aeeb33f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "assets/document-templates"] + path = assets/document-templates + url = https://github.com/ONLYOFFICE/document-templates + branch = main/new diff --git a/assets/document-templates b/assets/document-templates new file mode 160000 index 00000000..e0771eb5 --- /dev/null +++ b/assets/document-templates @@ -0,0 +1 @@ +Subproject commit e0771eb517facd02b2c9f2f4ee10b278da694d5d From 4d1f113c3732e8025973ed1b2b6634b4935fbf6e Mon Sep 17 00:00:00 2001 From: rivexe Date: Tue, 13 Feb 2024 15:34:17 +0300 Subject: [PATCH 066/114] refactor: update artifact.yml --- .github/workflows/artifact.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/artifact.yml b/.github/workflows/artifact.yml index 2592ac23..ed1954dc 100644 --- a/.github/workflows/artifact.yml +++ b/.github/workflows/artifact.yml @@ -27,7 +27,7 @@ jobs: rm -rf ./.github/ rm -rf ./.git/ rm ./.gitmodules - rm -rf ./assets/.git + rm -rf ./assets/document-templates/.git cd ./appinfo sed -i 's|apl2|agpl|' info.xml cd $cwd From 1e5c3dda278cd624817f581b726b3ff0b0438088 Mon Sep 17 00:00:00 2001 From: rivexe Date: Tue, 13 Feb 2024 15:36:02 +0300 Subject: [PATCH 067/114] refactor: update getEmptyTemplatePath() method --- lib/templatemanager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/templatemanager.php b/lib/templatemanager.php index 19fc4f86..a2d99dcc 100644 --- a/lib/templatemanager.php +++ b/lib/templatemanager.php @@ -177,7 +177,7 @@ public static function getEmptyTemplatePath($lang, $ext) { $lang = "en"; } - return \dirname(__DIR__) . DIRECTORY_SEPARATOR . "assets" . DIRECTORY_SEPARATOR . self::$localPath[$lang] . DIRECTORY_SEPARATOR . "new" . $ext; + return \dirname(__DIR__) . DIRECTORY_SEPARATOR . "assets" . DIRECTORY_SEPARATOR . "document-templates" . DIRECTORY_SEPARATOR . self::$localPath[$lang] . DIRECTORY_SEPARATOR . "new" . $ext; } /** From 78d3ce5dbcf7b6e6bfa49714df38ecd060feff49 Mon Sep 17 00:00:00 2001 From: rivexe Date: Tue, 13 Feb 2024 19:16:58 +0300 Subject: [PATCH 068/114] feat: document-formats submodule added --- .gitmodules | 3 +++ assets/document-formats | 1 + 2 files changed, 4 insertions(+) create mode 160000 assets/document-formats diff --git a/.gitmodules b/.gitmodules index 7aeeb33f..e7c7242c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,3 +2,6 @@ path = assets/document-templates url = https://github.com/ONLYOFFICE/document-templates branch = main/new +[submodule "assets/document-formats"] + path = assets/document-formats + url = https://github.com/ONLYOFFICE/document-formats diff --git a/assets/document-formats b/assets/document-formats new file mode 160000 index 00000000..730e13c8 --- /dev/null +++ b/assets/document-formats @@ -0,0 +1 @@ +Subproject commit 730e13c89d717c03eabd845a51ad1ddc673b13ac From 57c07b9c2b5dd5fb17503c044f361b495899f141 Mon Sep 17 00:00:00 2001 From: rivexe Date: Tue, 13 Feb 2024 19:35:01 +0300 Subject: [PATCH 069/114] feat: update artifact.yml --- .github/workflows/artifact.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/artifact.yml b/.github/workflows/artifact.yml index ed1954dc..ad9c6a3a 100644 --- a/.github/workflows/artifact.yml +++ b/.github/workflows/artifact.yml @@ -28,6 +28,7 @@ jobs: rm -rf ./.git/ rm ./.gitmodules rm -rf ./assets/document-templates/.git + rm -rf ./assets/document-formats/.git cd ./appinfo sed -i 's|apl2|agpl|' info.xml cd $cwd From 8c9ef2d19ca4a553e6db3507eb0b1af57bf4b086 Mon Sep 17 00:00:00 2001 From: rivexe Date: Tue, 13 Feb 2024 19:37:59 +0300 Subject: [PATCH 070/114] fix: editable formats in settings template --- templates/settings.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/settings.php b/templates/settings.php index a49f1cf7..ebd4c575 100644 --- a/templates/settings.php +++ b/templates/settings.php @@ -164,7 +164,7 @@

$setting) { ?> - +
Date: Tue, 13 Feb 2024 19:51:59 +0300 Subject: [PATCH 071/114] feat: get document formats from file or cache --- lib/appconfig.php | 152 +++++++++++++++++++++++++++++++++------------- 1 file changed, 110 insertions(+), 42 deletions(-) diff --git a/lib/appconfig.php b/lib/appconfig.php index 77c84e2f..46084493 100644 --- a/lib/appconfig.php +++ b/lib/appconfig.php @@ -23,6 +23,8 @@ use \DateInterval; use \DateTime; +use OCP\ICache; +use OCP\ICacheFactory; use OCP\IConfig; use OCP\ILogger; @@ -312,6 +314,13 @@ class AppConfig { */ private $_editors_check_interval = "editors_check_interval"; + /** + * The config key for store cache + * + * @var ICache + */ + private $cache; + /** * @param string $AppName - application name */ @@ -320,6 +329,8 @@ public function __construct($AppName) { $this->config = \OC::$server->getConfig(); $this->logger = \OC::$server->getLogger(); + $cacheFactory = \OC::$server->get(ICacheFactory::class); + $this->cache = $cacheFactory->createLocal($this->appName); } /** @@ -1232,7 +1243,7 @@ public function checkEncryptionModule() { * @NoAdminRequired */ public function formatsSetting() { - $result = $this->formats; + $result = $this->buildOnlyofficeFormats(); $defFormats = $this->getDefaultFormats(); foreach ($defFormats as $format => $setting) { @@ -1280,47 +1291,104 @@ public function getEditorsCheckInterval() { } /** - * Additional data about formats - * - * @var array - */ - private $formats = [ - "csv" => [ "mime" => "text/csv", "type" => "cell", "edit" => true, "editable" => true, "saveas" => ["ods", "pdf", "xlsx"] ], - "doc" => [ "mime" => "application/msword", "type" => "word", "conv" => true, "saveas" => ["docx", "odt", "pdf", "rtf", "txt"] ], - "docm" => [ "mime" => "application/vnd.ms-word.document.macroEnabled.12", "type" => "word", "conv" => true, "saveas" => ["docx", "odt", "pdf", "rtf", "txt"] ], - "docx" => [ "mime" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "type" => "word", "edit" => true, "def" => true, "review" => true, "comment" => true, "saveas" => ["odt", "pdf", "rtf", "txt"] ], - "docxf" => [ "mime" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document.docxf", "type" => "word", "edit" => true, "def" => true, "review" => true, "comment" => true, "saveas" => ["odt", "pdf", "rtf", "txt"], "createForm" => true ], - "oform" => [ "mime" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document.oform", "type" => "word", "fillForms" => true, "def" => true ], - "dot" => [ "type" => "word", "conv" => true, "saveas" => ["docx", "odt", "pdf", "rtf", "txt"] ], - "dotx" => [ "mime" => "application/vnd.openxmlformats-officedocument.wordprocessingml.template", "type" => "word", "conv" => true, "saveas" => ["docx", "odt", "pdf", "rtf", "txt"] ], - "epub" => [ "mime" => "application/epub+zip", "type" => "word", "conv" => true, "saveas" => ["docx", "odt", "pdf", "rtf", "txt"] ], - "htm" => [ "type" => "word", "conv" => true ], - "html" => [ "mime" => "text/html", "type" => "word", "conv" => true, "saveas" => ["docx", "odt", "pdf", "rtf", "txt"] ], - "odp" => [ "mime" => "application/vnd.oasis.opendocument.presentation", "type" => "slide", "conv" => true, "editable" => true, "saveas" => ["pdf", "pptx"] ], - "ods" => [ "mime" => "application/vnd.oasis.opendocument.spreadsheet", "type" => "cell", "conv" => true, "editable" => true, "saveas" => ["csv", "pdf", "xlsx"] ], - "odt" => [ "mime" => "application/vnd.oasis.opendocument.text", "type" => "word", "conv" => true, "editable" => true, "saveas" => ["docx", "pdf", "rtf", "txt"] ], - "otp" => [ "mime" => "application/vnd.oasis.opendocument.presentation-template", "type" => "slide", "conv" => true, "saveas" => ["pdf", "pptx", "odp"] ], - "ots" => [ "mime" => "application/vnd.oasis.opendocument.spreadsheet-template", "type" => "cell", "conv" => true, "saveas" => ["csv", "ods", "pdf", "xlsx"] ], - "ott" => [ "mime" => "application/vnd.oasis.opendocument.text-template", "type" => "word", "conv" => true, "saveas" => ["docx", "odt", "pdf", "rtf", "txt"] ], - "pdf" => [ "mime" => "application/pdf", "type" => "word" ], - "pot" => [ "type" => "slide", "conv" => true, "saveas" => ["pdf", "pptx", "odp"] ], - "potm" => [ "mime" => "application/vnd.ms-powerpoint.template.macroEnabled.12", "type" => "slide", "conv" => true, "saveas" => ["pdf", "pptx", "odp"] ], - "potx" => [ "mime" => "application/vnd.openxmlformats-officedocument.presentationml.template", "type" => "slide", "conv" => true, "saveas" => ["pdf", "pptx", "odp"] ], - "pps" => [ "type" => "slide", "conv" => true, "saveas" => ["pdf", "pptx", "odp"] ], - "ppsm" => [ "mime" => "application/vnd.ms-powerpoint.slideshow.macroEnabled.12", "type" => "slide", "conv" => true, "saveas" => ["pdf", "pptx", "odp"] ], - "ppsx" => [ "mime" => "application/vnd.openxmlformats-officedocument.presentationml.slideshow", "type" => "slide", "conv" => true, "saveas" => ["pdf", "pptx", "odp"] ], - "ppt" => [ "mime" => "application/vnd.ms-powerpoint", "type" => "slide", "conv" => true, "saveas" => ["pdf", "pptx", "odp"] ], - "pptm" => [ "mime" => "application/vnd.ms-powerpoint.presentation.macroEnabled.12", "type" => "slide", "conv" => true, "saveas" => ["pdf", "pptx", "odp"] ], - "pptx" => [ "mime" => "application/vnd.openxmlformats-officedocument.presentationml.presentation", "type" => "slide", "edit" => true, "def" => true, "comment" => true, "saveas" => ["pdf", "odp"] ], - "rtf" => [ "mime" => "text/rtf", "type" => "word", "conv" => true, "editable" => true, "saveas" => ["docx", "odt", "pdf", "txt"] ], - "txt" => [ "mime" => "text/plain", "type" => "word", "edit" => true, "editable" => true, "saveas" => ["docx", "odt", "pdf", "rtf"] ], - "xls" => [ "mime" => "application/vnd.ms-excel", "type" => "cell", "conv" => true, "saveas" => ["csv", "ods", "pdf", "xlsx"] ], - "xlsm" => [ "mime" => "application/vnd.ms-excel.sheet.macroEnabled.12", "type" => "cell", "conv" => true, "saveas" => ["csv", "ods", "pdf", "xlsx"] ], - "xlsx" => [ "mime" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "type" => "cell", "edit" => true, "def" => true, "comment" => true, "modifyFilter" => true, "saveas" => ["csv", "ods", "pdf"] ], - "xlt" => [ "type" => "cell", "conv" => true, "saveas" => ["csv", "ods", "pdf", "xlsx"] ], - "xltm" => [ "mime" => "application/vnd.ms-excel.template.macroEnabled.12", "type" => "cell", "conv" => true, "saveas" => ["csv", "ods", "pdf", "xlsx"] ], - "xltx" => [ "mime" => "application/vnd.openxmlformats-officedocument.spreadsheetml.template", "type" => "cell", "conv" => true, "saveas" => ["csv", "ods", "pdf", "xlsx"] ] - ]; + * Get ONLYOFFICE formats list + * + * @return array + */ + private function buildOnlyofficeFormats() { + try { + $onlyofficeFormats = $this->getFormats(); + $result = []; + $additionalFormats = $this->getAdditionalFormatAttributes(); + + if ($onlyofficeFormats !== false) { + foreach ($onlyofficeFormats as $onlyOfficeFormat) { + if ($onlyOfficeFormat["name"] + && $onlyOfficeFormat["mime"] + && $onlyOfficeFormat["type"] + && $onlyOfficeFormat["actions"] + && $onlyOfficeFormat["convert"]) { + $result[$onlyOfficeFormat["name"]] = [ + "mime" => $onlyOfficeFormat["mime"], + "type" => $onlyOfficeFormat["type"], + "edit" => in_array("edit", $onlyOfficeFormat["actions"]), + "editable" => in_array("lossy-edit", $onlyOfficeFormat["actions"]), + "conv" => in_array("auto-convert", $onlyOfficeFormat["actions"]), + "fillForms" => in_array("fill", $onlyOfficeFormat["actions"]), + "saveas" => $onlyOfficeFormat["convert"], + ]; + if (isset($additionalFormats[$onlyOfficeFormat["name"]])) { + $result[$onlyOfficeFormat["name"]] = array_merge($result[$onlyOfficeFormat["name"]], $additionalFormats[$onlyOfficeFormat["name"]]); + } + } + } + } + return $result; + } catch (\Exception $e) { + $this->logger->logException($e, ["message" => "Format matrix error", "app" => $this->appName]); + return []; + } + } + + /** + * Get the additional format attributes + * + * @return array + */ + private function getAdditionalFormatAttributes() { + $additionalFormatAttributes = [ + "docx" => [ + "def" => true, + "review" => true, + "comment" => true, + ], + "docxf" => [ + "def" => true, + "review" => true, + "comment" => true, + "createForm" => true, + ], + "oform" => [ + "def" => true, + ], + "pdf" => [ + "def" => true, + ], + "pptx" => [ + "def" => true, + "comment" => true, + ], + "xlsx" => [ + "def" => true, + "comment" => true, + "modifyFilter" => true, + ], + "txt" => [ + "edit" => true, + ], + "csv" => [ + "edit" => true, + ], + ]; + return $additionalFormatAttributes; + } + + /** + * Get the formats list from cache or file + * + * @return array + */ + public function getFormats() { + $cachedFormats = $this->cache->get("document_formats"); + if ($cachedFormats !== null) { + return json_decode($cachedFormats, true); + } + + $formats = file_get_contents(dirname(__DIR__) . DIRECTORY_SEPARATOR . "assets" . DIRECTORY_SEPARATOR . "document-formats" . DIRECTORY_SEPARATOR . "onlyoffice-docs-formats.json"); + $this->cache->set("document_formats", $formats, 6 * 3600); + $this->logger->debug("Getting formats from file", ["app" => $this->appName]); + return json_decode($formats, true); + } /** * DEMO DATA From 74a9d328190b10311bd0817b619a22eab82f2f43 Mon Sep 17 00:00:00 2001 From: rivexe Date: Tue, 13 Feb 2024 19:56:49 +0300 Subject: [PATCH 072/114] feat: register actions for all mime types of formats --- js/main.js | 121 +++++++++++++++++++++++++---------------------------- 1 file changed, 56 insertions(+), 65 deletions(-) diff --git a/js/main.js b/js/main.js index 2e71b6e0..d63dcc93 100644 --- a/js/main.js +++ b/js/main.js @@ -329,75 +329,66 @@ if (!config.mime) { return true; } - - OCA.Files.fileActions.registerAction({ - name: "onlyofficeOpen", - displayName: t(OCA.Onlyoffice.AppName, "Open in ONLYOFFICE"), - mime: config.mime, - permissions: OC.PERMISSION_READ, - iconClass: "icon-onlyoffice-open", - actionHandler: OCA.Onlyoffice.FileClick - }); - - if (config.def) { - OCA.Files.fileActions.setDefault(config.mime, "onlyofficeOpen"); - } - - if (config.conv) { + + let mimeTypes = config.mime; + mimeTypes.forEach((mime) => { OCA.Files.fileActions.registerAction({ - name: "onlyofficeConvert", - displayName: t(OCA.Onlyoffice.AppName, "Convert with ONLYOFFICE"), - mime: config.mime, - permissions: ($("#isPublic").val() ? OC.PERMISSION_UPDATE : OC.PERMISSION_READ), - iconClass: "icon-onlyoffice-convert", - actionHandler: OCA.Onlyoffice.FileConvertClick - }); - } - - if (config.fillForms) { - OCA.Files.fileActions.registerAction({ - name: "onlyofficeFill", - displayName: t(OCA.Onlyoffice.AppName, "Fill in form in ONLYOFFICE"), - mime: config.mime, - permissions: OC.PERMISSION_UPDATE, - iconClass: "icon-onlyoffice-fill", + name: "onlyofficeOpen", + displayName: t(OCA.Onlyoffice.AppName, "Open in ONLYOFFICE"), + mime: mime, + permissions: OC.PERMISSION_READ, + iconClass: "icon-onlyoffice-open", actionHandler: OCA.Onlyoffice.FileClick }); - } - - if (config.fillForms) { - OCA.Files.fileActions.setDefault(config.mime, "onlyofficeFill"); - } - - if (config.createForm) { - var permission = OC.PERMISSION_READ; - if ($("#isPublic").val()) { - permission = OC.PERMISSION_UPDATE; - if (parseInt($("#sharePermission").val()) === (OC.PERMISSION_READ | OC.PERMISSION_CREATE)) { - permission = OC.PERMISSION_READ; - } + + if (config.def) { + OCA.Files.fileActions.setDefault(mime, "onlyofficeOpen"); } - - OCA.Files.fileActions.registerAction({ - name: "onlyofficeCreateForm", - displayName: t(OCA.Onlyoffice.AppName, "Create form"), - mime: config.mime, - permissions: permission, - iconClass: "icon-onlyoffice-create", - actionHandler: OCA.Onlyoffice.CreateFormClick - }); - } - - if (config.saveas && !$("#isPublic").val()) { - OCA.Files.fileActions.registerAction({ - name: "onlyofficeDownload", - displayName: t(OCA.Onlyoffice.AppName, "Download as"), - mime: config.mime, - permissions: OC.PERMISSION_READ, - iconClass: "icon-onlyoffice-download", - actionHandler: OCA.Onlyoffice.DownloadClick - }); - } + + if (config.conv) { + OCA.Files.fileActions.registerAction({ + name: "onlyofficeConvert", + displayName: t(OCA.Onlyoffice.AppName, "Convert with ONLYOFFICE"), + mime: mime, + permissions: ($("#isPublic").val() ? OC.PERMISSION_UPDATE : OC.PERMISSION_READ), + iconClass: "icon-onlyoffice-convert", + actionHandler: OCA.Onlyoffice.FileConvertClick + }); + } + + if (config.fillForms) { + OCA.Files.fileActions.registerAction({ + name: "onlyofficeFill", + displayName: t(OCA.Onlyoffice.AppName, "Fill in form in ONLYOFFICE"), + mime: mime, + permissions: OC.PERMISSION_UPDATE, + iconClass: "icon-onlyoffice-fill", + actionHandler: OCA.Onlyoffice.FileClick + }); + } + + if (config.createForm) { + OCA.Files.fileActions.registerAction({ + name: "onlyofficeCreateForm", + displayName: t(OCA.Onlyoffice.AppName, "Create form"), + mime: mime, + permissions: ($("#isPublic").val() ? OC.PERMISSION_UPDATE : OC.PERMISSION_READ), + iconClass: "icon-onlyoffice-create", + actionHandler: OCA.Onlyoffice.CreateFormClick + }); + } + + if (config.saveas && !$("#isPublic").val()) { + OCA.Files.fileActions.registerAction({ + name: "onlyofficeDownload", + displayName: t(OCA.Onlyoffice.AppName, "Download as"), + mime: mime, + permissions: OC.PERMISSION_READ, + iconClass: "icon-onlyoffice-download", + actionHandler: OCA.Onlyoffice.DownloadClick + }); + } + }); }); } From 0d4e6341dc4d1f6ea065f8481f584fae9dc588dd Mon Sep 17 00:00:00 2001 From: rivexe Date: Tue, 13 Feb 2024 19:58:06 +0300 Subject: [PATCH 073/114] docs: document formats to CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d7fe68d7..ac21e52d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - compatible with ownCloud Web 7.0 - list of users to protect ranges of cells - offline viewer for share link +- updatable list of supported formats ## Added - reference data from coediting From dfc666106b2cc4f89d3047b7f6db7aa7a13059fc Mon Sep 17 00:00:00 2001 From: rivexe Date: Tue, 13 Feb 2024 20:02:29 +0300 Subject: [PATCH 074/114] docs: formats list to README --- README.md | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index d2e64e4c..10f8988d 100644 --- a/README.md +++ b/README.md @@ -13,9 +13,8 @@ The app allows to: Supported formats: -* For viewing and editing: DOCX, XLSX, PPTX, CSV, TXT, DOCXF, OFORM. -* For viewing only: PDF. -* For converting to Office Open XML formats: DOC, DOCM, DOT, DOTX, EPUB, HTM, HTML, ODP, ODT, POT, POTM, POTX, PPS, PPSM, PPSX, PPT, PPTM, RTF, XLS, XLSM, XLT, XLTM, XLTX. +* For editing: DOCM, DOCX, DOCXF, DOTM, DOTX, EPUB, FB2, HTML, ODT, OTT, RTF, TXT, CSV, ODS, OTS, XLSM, XLSX, XLTM, XLTX, ODP, OTP, POTM, POTX, PPSM, PPSX, PPTM, PPTX. +* For viewing only: DJVU, DOC, DOT, FODT, HTM, MHT, MHTML, OFORM, PDF, STW, SXW, WPS, WPT, XML, XPS, ET, ETT, FODS, SXC, XLS, XLSB, XLT, DPS, DPT, FODP, POT, PPS, PPT, SXI. ODT, ODS, and ODP is also available for instant conversion. After you enable the corresponding option in the admin settings, ODF-formatted documents are immediately converted in the editor and opened after you click on it. @@ -234,12 +233,12 @@ The table below will help you to make the right choice. | Conversion Service | + | + | | Document Builder Service | + | + | | **Interface** | **Community Edition** | **Enterprise Edition** | -| Tabbed interface | + | + | -| Dark theme | + | + | -| 125%, 150%, 175%, 200% scaling | + | + | -| White Label | - | - | -| Integrated test example (node.js) | + | + | -| Mobile web editors | - | +* | +| Tabbed interface | + | + | +| Dark theme | + | + | +| 125%, 150%, 175%, 200% scaling | + | + | +| White Label | - | - | +| Integrated test example (node.js) | + | + | +| Mobile web editors | - | +* | | **Plugins & Macros** | **Community Edition** | **Enterprise Edition** | | Plugins | + | + | | Macros | + | + | From 49cad428a442ff40c2b0c9ec1824f57f12870c5d Mon Sep 17 00:00:00 2001 From: rivexe Date: Wed, 14 Feb 2024 11:02:29 +0300 Subject: [PATCH 075/114] fix: getting CacheFactory --- lib/appconfig.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/appconfig.php b/lib/appconfig.php index 46084493..3558c4e0 100644 --- a/lib/appconfig.php +++ b/lib/appconfig.php @@ -329,7 +329,7 @@ public function __construct($AppName) { $this->config = \OC::$server->getConfig(); $this->logger = \OC::$server->getLogger(); - $cacheFactory = \OC::$server->get(ICacheFactory::class); + $cacheFactory = \OC::$server->getMemCacheFactory(); $this->cache = $cacheFactory->createLocal($this->appName); } From 2cbf05391b374a68bd0138c9f31d0157a61bf568 Mon Sep 17 00:00:00 2001 From: rivexe Date: Wed, 14 Feb 2024 14:31:46 +0300 Subject: [PATCH 076/114] feat: create pdf from docxf instead of oform --- js/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/main.js b/js/main.js index d63dcc93..c9273d21 100644 --- a/js/main.js +++ b/js/main.js @@ -295,7 +295,7 @@ OCA.Onlyoffice.CreateFormClick = function (fileName, context) { var fileList = context.fileList; - var name = fileName.replace(/\.[^.]+$/, ".oform"); + var name = fileName.replace(/\.[^.]+$/, ".pdf"); var attr = context.fileInfoModel.attributes; var targetPath = attr.path + "/" + attr.name; From c9eb3d33259f8263e6f1caf72e5b79c2a8547b78 Mon Sep 17 00:00:00 2001 From: rivexe Date: Wed, 14 Feb 2024 14:34:35 +0300 Subject: [PATCH 077/114] feat: do not add oform mime --- appinfo/application.php | 1 - 1 file changed, 1 deletion(-) diff --git a/appinfo/application.php b/appinfo/application.php index 4ed7930d..d71e89aa 100644 --- a/appinfo/application.php +++ b/appinfo/application.php @@ -120,7 +120,6 @@ function () { $detector->registerType("ots", "application/vnd.oasis.opendocument.spreadsheet-template"); $detector->registerType("otp", "application/vnd.oasis.opendocument.presentation-template"); $detector->registerType("docxf", "application/vnd.openxmlformats-officedocument.wordprocessingml.document.docxf"); - $detector->registerType("oform", "application/vnd.openxmlformats-officedocument.wordprocessingml.document.oform"); $previewManager = $container->query(IPreview::class); if ($this->appConfig->getPreview()) { From bb5992f685ceab882c02e46ed6f9a4dc2502d886 Mon Sep 17 00:00:00 2001 From: rivexe Date: Wed, 14 Feb 2024 14:34:53 +0300 Subject: [PATCH 078/114] docs: filling pdf to CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac21e52d..d331cb45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - list of users to protect ranges of cells - offline viewer for share link - updatable list of supported formats +- filling pdf instead oform ## Added - reference data from coediting From 66df7f459fc4c70548168360489b7e67e2d05c37 Mon Sep 17 00:00:00 2001 From: Sergey Linnik Date: Wed, 14 Feb 2024 17:36:27 +0300 Subject: [PATCH 079/114] Form template rename as PDF form --- js/main.js | 10 +++++----- l10n/bg_BG.js | 3 --- l10n/bg_BG.json | 3 --- l10n/ca.js | 3 --- l10n/ca.json | 3 --- l10n/da.js | 3 --- l10n/da.json | 3 --- l10n/de.js | 3 --- l10n/de.json | 3 --- l10n/de_DE.js | 3 --- l10n/de_DE.json | 3 --- l10n/es.js | 3 --- l10n/es.json | 3 --- l10n/fr.js | 3 --- l10n/fr.json | 3 --- l10n/it.js | 3 --- l10n/it.json | 3 --- l10n/ja.js | 3 --- l10n/ja.json | 3 --- l10n/nl.js | 3 --- l10n/nl.json | 3 --- l10n/pl.js | 3 --- l10n/pl.json | 3 --- l10n/pt_BR.js | 3 --- l10n/pt_BR.json | 3 --- l10n/ru.js | 6 +++--- l10n/ru.json | 6 +++--- l10n/sv.js | 3 --- l10n/sv.json | 3 --- l10n/uk.js | 2 -- l10n/uk.json | 2 -- l10n/zh_CN.js | 3 --- l10n/zh_CN.json | 3 --- 33 files changed, 11 insertions(+), 99 deletions(-) diff --git a/js/main.js b/js/main.js index 2e71b6e0..809b85dd 100644 --- a/js/main.js +++ b/js/main.js @@ -284,7 +284,7 @@ "application/vnd.openxmlformats-officedocument.wordprocessingml.document" ]; - OC.dialogs.filepicker(t(OCA.Onlyoffice.AppName, "Create new Form template"), + OC.dialogs.filepicker(t(OCA.Onlyoffice.AppName, "Create new PDF form"), function (filePath) { OCA.Onlyoffice.CreateFile(name, fileList, 0, filePath); }, @@ -459,8 +459,8 @@ menu.addMenuEntry({ id: "onlyofficeDocxf", - displayName: t(OCA.Onlyoffice.AppName, "Form template"), - templateName: t(OCA.Onlyoffice.AppName, "Form template"), + displayName: t(OCA.Onlyoffice.AppName, "PDF form"), + templateName: t(OCA.Onlyoffice.AppName, "PDF form"), iconClass: "icon-onlyoffice-new-docxf", fileType: "docxf", actionHandler: function (name) { @@ -471,8 +471,8 @@ if (!$("#isPublic").val()) { menu.addMenuEntry({ id: "onlyofficeDocxfExist", - displayName: t(OCA.Onlyoffice.AppName, "Form template from existing text file"), - templateName: t(OCA.Onlyoffice.AppName, "Form template from existing text file"), + displayName: t(OCA.Onlyoffice.AppName, "PDF form from existing text file"), + templateName: t(OCA.Onlyoffice.AppName, "PDF form from existing text file"), iconClass: "icon-onlyoffice-new-docxf", fileType: "docxf", actionHandler: function (name) { diff --git a/l10n/bg_BG.js b/l10n/bg_BG.js index 7c347b84..240a5b3c 100644 --- a/l10n/bg_BG.js +++ b/l10n/bg_BG.js @@ -100,11 +100,8 @@ OC.L10N.register( "Notification sent successfully": "Успешно изпратено известие", "%1\$s mentioned in the %2\$s: \"%3\$s\".": "%1\$s, Ви спомена във %2\$s: \"%3\$s\".", "Choose a format to convert {fileName}": "Изберете формат за конвертиране {fileName}", - "Form template": "Шаблон на формуляр", - "Form template from existing text file": "Шаблон на формуляр от съществуващ текстов файл", "Create form": "Създайте формуляр", "Fill in form in ONLYOFFICE": "Попълнете формуляр в ONLYOFFICE", - "Create new Form template": "Създайте нов шаблон на формуляр", "Security": "Сигурност", "Light": "Светла", "Classic Light": "Класически светла", diff --git a/l10n/bg_BG.json b/l10n/bg_BG.json index 3a9ca5ea..e169214b 100644 --- a/l10n/bg_BG.json +++ b/l10n/bg_BG.json @@ -98,11 +98,8 @@ "Notification sent successfully": "Успешно изпратено известие", "%1$s mentioned in the %2$s: \"%3$s\".": "%1$s, Ви спомена във %2$s: \"%3$s\".", "Choose a format to convert {fileName}": "Изберете формат за конвертиране {fileName}", - "Form template": "Шаблон на формуляр", - "Form template from existing text file": "Шаблон на формуляр от съществуващ текстов файл", "Create form": "Създайте формуляр", "Fill in form in ONLYOFFICE": "Попълнете формуляр в ONLYOFFICE", - "Create new Form template": "Създайте нов шаблон на формуляр", "Security": "Сигурност", "Light": "Светла", "Classic Light": "Класически светла", diff --git a/l10n/ca.js b/l10n/ca.js index cc90ed8b..d8c2649e 100644 --- a/l10n/ca.js +++ b/l10n/ca.js @@ -100,11 +100,8 @@ OC.L10N.register( "Notification sent successfully": "Notificació enviada correctament", "%1\$s mentioned in the %2\$s: \"%3\$s\".": "%1\$s ha esmentat en %2\$s: \"%3\$s\".", "Choose a format to convert {fileName}": "Triï un format per a convertir {fileName}", - "Form template": "Plantilla de formulari", - "Form template from existing text file": "Plantilla de formulari d'un fitxer de text existent", "Create form": "Crear formulari", "Fill in form in ONLYOFFICE": "Omplir el formulari en ONLYOFFICE", - "Create new Form template": "Crear nova plantilla de formulari", "Security": "Seguretat", "Light": "Llum", "Classic Light": "Llum clàssica", diff --git a/l10n/ca.json b/l10n/ca.json index 0c5c2d77..0d037d65 100644 --- a/l10n/ca.json +++ b/l10n/ca.json @@ -98,11 +98,8 @@ "Notification sent successfully": "Notificació enviada correctament", "%1$s mentioned in the %2$s: \"%3$s\".": "%1$s ha esmentat en %2$s: \"%3$s\".", "Choose a format to convert {fileName}": "Triï un format per a convertir {fileName}", - "Form template": "Plantilla de formulari", - "Form template from existing text file": "Plantilla de formulari d'un fitxer de text existent", "Create form": "Crear formulari", "Fill in form in ONLYOFFICE": "Omplir el formulari en ONLYOFFICE", - "Create new Form template": "Crear nova plantilla de formulari", "Security": "Seguretat", "Light": "Llum", "Classic Light": "Llum clàssica", diff --git a/l10n/da.js b/l10n/da.js index e33675e0..f82aed55 100644 --- a/l10n/da.js +++ b/l10n/da.js @@ -100,11 +100,8 @@ OC.L10N.register( "Notification sent successfully": "Meddelelse sendt", "%1\$s mentioned in the %2\$s: \"%3\$s\".": "%1\$s nævnt i %2\$s: \"%3\$s\".", "Choose a format to convert {fileName}": "Vælg et format til at konvertere {fileName}", - "Form template": "Formularskabelon", - "Form template from existing text file": "Formularskabelon fra eksisterende tekstfil", "Create form": "Opret formular", "Fill in form in ONLYOFFICE": "Udfyld formularen i ONLYOFFICE", - "Create new Form template": "Opret ny formularskabelon", "Security": "Sikkerhed", "Run document macros": "Kør dokumentmakroer", "Default editor theme": "Standard editortema", diff --git a/l10n/da.json b/l10n/da.json index ab763d23..f651f019 100644 --- a/l10n/da.json +++ b/l10n/da.json @@ -98,11 +98,8 @@ "Notification sent successfully": "Meddelelse sendt", "%1$s mentioned in the %2$s: \"%3$s\".": "%1$s nævnt i %2$s: \"%3$s\".", "Choose a format to convert {fileName}": "Vælg et format til at konvertere {fileName}", - "Form template": "Formularskabelon", - "Form template from existing text file": "Formularskabelon fra eksisterende tekstfil", "Create form": "Opret formular", "Fill in form in ONLYOFFICE": "Udfyld formularen i ONLYOFFICE", - "Create new Form template": "Opret ny formularskabelon", "Security": "Sikkerhed", "Run document macros": "Kør dokumentmakroer", "Default editor theme": "Standard editortema", diff --git a/l10n/de.js b/l10n/de.js index 2775dfa2..284937b8 100644 --- a/l10n/de.js +++ b/l10n/de.js @@ -100,11 +100,8 @@ OC.L10N.register( "Notification sent successfully": "Benachrichtigung erfolgreich gesendet", "%1\$s mentioned in the %2\$s: \"%3\$s\".": "%1\$s hat dich in %2\$s erwähnt: \"%3\$s\".", "Choose a format to convert {fileName}": "Wählen Sie das Format für {fileName} aus", - "Form template": "Formularvorlage", - "Form template from existing text file": "Formularvorlage aus Textdatei", "Create form": "Formular erstellen", "Fill in form in ONLYOFFICE": "Formular in ONLYOFFICE ausfüllen", - "Create new Form template": "Neue Formularvorlage erstellen", "Security": "Sicherheit", "Run document macros": "Makros im Dokument ausführen", "Default editor theme": "Standardmäßiges Thema des Editors", diff --git a/l10n/de.json b/l10n/de.json index 50341aa4..17a3e527 100644 --- a/l10n/de.json +++ b/l10n/de.json @@ -98,11 +98,8 @@ "Notification sent successfully": "Benachrichtigung erfolgreich gesendet", "%1$s mentioned in the %2$s: \"%3$s\".": "%1$s hat dich in %2$s erwähnt: \"%3$s\".", "Choose a format to convert {fileName}": "Wählen Sie das Format für {fileName} aus", - "Form template": "Formularvorlage", - "Form template from existing text file": "Formularvorlage aus Textdatei", "Create form": "Formular erstellen", "Fill in form in ONLYOFFICE": "Formular in ONLYOFFICE ausfüllen", - "Create new Form template": "Neue Formularvorlage erstellen", "Security": "Sicherheit", "Run document macros": "Makros im Dokument ausführen", "Default editor theme": "Standardmäßiges Thema des Editors", diff --git a/l10n/de_DE.js b/l10n/de_DE.js index 5b6ee59d..647b3236 100644 --- a/l10n/de_DE.js +++ b/l10n/de_DE.js @@ -100,11 +100,8 @@ OC.L10N.register( "Notification sent successfully": "Benachrichtigung erfolgreich gesendet", "%1\$s mentioned in the %2\$s: \"%3\$s\".": "%1\$s hat dich in %2\$s erwähnt: \"%3\$s\".", "Choose a format to convert {fileName}": "Wählen Sie das Format für {fileName} aus", - "Form template": "Formularvorlage", - "Form template from existing text file": "Formularvorlage aus Textdatei", "Create form": "Formular erstellen", "Fill in form in ONLYOFFICE": "Formular in ONLYOFFICE ausfüllen", - "Create new Form template": "Neue Formularvorlage erstellen", "Security": "Sicherheit", "Run document macros": "Makros im Dokument ausführen", "Default editor theme": "Standardmäßiges Thema des Editors", diff --git a/l10n/de_DE.json b/l10n/de_DE.json index b8af5d12..0d5502c8 100644 --- a/l10n/de_DE.json +++ b/l10n/de_DE.json @@ -98,11 +98,8 @@ "Notification sent successfully": "Benachrichtigung erfolgreich gesendet", "%1$s mentioned in the %2$s: \"%3$s\".": "%1$s hat dich in %2$s erwähnt: \"%3$s\".", "Choose a format to convert {fileName}": "Wählen Sie das Format für {fileName} aus", - "Form template": "Formularvorlage", - "Form template from existing text file": "Formularvorlage aus Textdatei", "Create form": "Formular erstellen", "Fill in form in ONLYOFFICE": "Formular in ONLYOFFICE ausfüllen", - "Create new Form template": "Neue Formularvorlage erstellen", "Security": "Sicherheit", "Run document macros": "Makros im Dokument ausführen", "Default editor theme": "Standardmäßiges Thema des Editors", diff --git a/l10n/es.js b/l10n/es.js index d74c17b8..05e233d6 100644 --- a/l10n/es.js +++ b/l10n/es.js @@ -100,11 +100,8 @@ OC.L10N.register( "Notification sent successfully": "Notificación enviada correctamente", "%1\$s mentioned in the %2\$s: \"%3\$s\".": "%1\$s le ha mencionado en %2\$s: \"%3\$s\".", "Choose a format to convert {fileName}": "Elija un formato para convertir {fileName}", - "Form template": "Plantilla de formulario", - "Form template from existing text file": "Plantilla de formulario desde un archivo de texto existente", "Create form": "Crear formulario", "Fill in form in ONLYOFFICE": "Rellenar el formulario en ONLYOFFICE", - "Create new Form template": "Crear nueva plantilla de formulario", "Security": "Seguridad", "Run document macros": "Ejecutar macros de documentos", "Default editor theme": "Tema del editor predeterminado", diff --git a/l10n/es.json b/l10n/es.json index acde70c5..3508ec87 100644 --- a/l10n/es.json +++ b/l10n/es.json @@ -98,11 +98,8 @@ "Notification sent successfully": "Notificación enviada correctamente", "%1$s mentioned in the %2$s: \"%3$s\".": "%1$s le ha mencionado en %2$s: \"%3$s\".", "Choose a format to convert {fileName}": "Elija un formato para convertir {fileName}", - "Form template": "Plantilla de formulario", - "Form template from existing text file": "Plantilla de formulario desde un archivo de texto existente", "Create form": "Crear formulario", "Fill in form in ONLYOFFICE": "Rellenar el formulario en ONLYOFFICE", - "Create new Form template": "Crear nueva plantilla de formulario", "Security": "Seguridad", "Run document macros": "Ejecutar macros de documentos", "Default editor theme": "Tema del editor predeterminado", diff --git a/l10n/fr.js b/l10n/fr.js index 2d19adc9..fd532962 100644 --- a/l10n/fr.js +++ b/l10n/fr.js @@ -100,11 +100,8 @@ OC.L10N.register( "Notification sent successfully": "Notification a été envoyée avec succès", "%1\$s mentioned in the %2\$s: \"%3\$s\".": "%1\$s vous a mentionné dans %2\$s: \"%3\$s\".", "Choose a format to convert {fileName}": "Choisissez un format à convertir {fileName}", - "Form template": "Modèle de formulaire", - "Form template from existing text file": "Modèle de formulaire à partir d'un fichier texte existant", "Create form": "Créer un formulaire", "Fill in form in ONLYOFFICE": "Remplir le formulaire dans ONLYOFFICE", - "Create new Form template": "Créer un nouveau modèle de formulaire", "Security": "Sécurité", "Run document macros": "Exécuter des macros de documents", "Default editor theme": "Thème d'éditeur par défaut", diff --git a/l10n/fr.json b/l10n/fr.json index 88530c32..637cc6e4 100644 --- a/l10n/fr.json +++ b/l10n/fr.json @@ -98,11 +98,8 @@ "Notification sent successfully": "Notification a été envoyée avec succès", "%1$s mentioned in the %2$s: \"%3$s\".": "%1$s vous a mentionné dans %2$s: \"%3$s\".", "Choose a format to convert {fileName}": "Choisissez un format à convertir {fileName}", - "Form template": "Modèle de formulaire ", - "Form template from existing text file": "Modèle de formulaire à partir d'un fichier texte existant", "Create form": "Créer un formulaire", "Fill in form in ONLYOFFICE": "Remplir le formulaire dans ONLYOFFICE", - "Create new Form template": "Créer un nouveau modèle de formulaire", "Security": "Sécurité", "Run document macros": "Exécuter des macros de documents", "Default editor theme": "Thème d'éditeur par défaut", diff --git a/l10n/it.js b/l10n/it.js index 51228800..0c748d66 100644 --- a/l10n/it.js +++ b/l10n/it.js @@ -100,11 +100,8 @@ OC.L10N.register( "Notification sent successfully": "Notifica è stata inviata con successo", "%1\$s mentioned in the %2\$s: \"%3\$s\".": "%1\$s ti ha menzionato in %2\$s: \"%3\$s\".", "Choose a format to convert {fileName}": "Scegli un formato per convertire {fileName}", - "Form template": "Modello di modulo", - "Form template from existing text file": "Modello di modulo da file di testo esistente", "Create form": "Creare modulo", "Fill in form in ONLYOFFICE": "Compilare il modulo in ONLYOFFICE", - "Create new Form template": "Creare un nuovo modello di modulo", "Security": "Sicurezza", "Run document macros": "Esegui le macro del documento", "Default editor theme": "Tema dell'editor predefinito", diff --git a/l10n/it.json b/l10n/it.json index e329bdb9..7d15e8b7 100644 --- a/l10n/it.json +++ b/l10n/it.json @@ -98,11 +98,8 @@ "Notification sent successfully": "Notifica è stata inviata con successo", "%1$s mentioned in the %2$s: \"%3$s\".": "%1$s ti ha menzionato in %2$s: \"%3$s\".", "Choose a format to convert {fileName}": "Scegli un formato per convertire {fileName}", - "Form template": "Modello di modulo", - "Form template from existing text file": "Modello di modulo da file di testo esistente", "Create form": "Creare modulo", "Fill in form in ONLYOFFICE": "Compilare il modulo in ONLYOFFICE", - "Create new Form template": "Creare un nuovo modello di modulo", "Security": "Sicurezza", "Run document macros": "Esegui le macro del documento", "Default editor theme": "Tema dell'editor predefinito", diff --git a/l10n/ja.js b/l10n/ja.js index c3fb00f9..5cd04bf3 100644 --- a/l10n/ja.js +++ b/l10n/ja.js @@ -100,11 +100,8 @@ OC.L10N.register( "Notification sent successfully": "通知を送信しました", "%1\$s mentioned in the %2\$s: \"%3\$s\".": "%1\$s は あなたを %2\$s: \"%3\$s\"に記載されました。", "Choose a format to convert {fileName}": "{fileName}を変換する形式を選択してください", - "Form template": "フォーム テンプレート", - "Form template from existing text file": "既存のテキストファイルからフォームテンプレートを作成する", "Create form": "フォームの作成", "Fill in form in ONLYOFFICE": "ONLYOFFICEでフォームを記入する", - "Create new Form template": "新しいフォームテンプレートの作成", "Security": "セキュリティ", "Run document macros": "ドキュメントマクロを実行する", "Default editor theme": "エディターのデフォルトテーマ", diff --git a/l10n/ja.json b/l10n/ja.json index 429711ae..cd9ceb55 100644 --- a/l10n/ja.json +++ b/l10n/ja.json @@ -98,11 +98,8 @@ "Notification sent successfully": "通知を送信しました", "%1$s mentioned in the %2$s: \"%3$s\".": "%1$s は あなたを %2$s: \"%3$s\"に記載されました。", "Choose a format to convert {fileName}": "{fileName}を変換する形式を選択してください", - "Form template": "フォーム テンプレート", - "Form template from existing text file": "既存のテキストファイルからフォームテンプレートを作成する", "Create form": "フォームの作成", "Fill in form in ONLYOFFICE": "ONLYOFFICEでフォームを記入する", - "Create new Form template": "新しいフォームテンプレートの作成", "Security": "セキュリティ", "Run document macros": "ドキュメントマクロを実行する", "Default editor theme": "エディターのデフォルトテーマ", diff --git a/l10n/nl.js b/l10n/nl.js index 87c460ab..c77193e9 100644 --- a/l10n/nl.js +++ b/l10n/nl.js @@ -100,11 +100,8 @@ OC.L10N.register( "Notification sent successfully": "Kennisgeving succesvol verzonden", "%1\$s mentioned in the %2\$s: \"%3\$s\".": "%1\$s genoemd in de %2\$s: \"%3\$s\".", "Choose a format to convert {fileName}": "Kies een formaat om {fileName} te converteren", - "Form template": "Formulier sjabloon", - "Form template from existing text file": "Formulier sjabloon uit bestaand tekstbestand", "Create form": "Formulier maken", "Fill in form in ONLYOFFICE": "Formulier invullen in ONLYOFFICE", - "Create new Form template": "Nieuw Formulier sjabloon maken", "Security": "Beveiliging", "Run document macros": "Document macro's uitvoeren", "Default editor theme": "Standaard editor thema", diff --git a/l10n/nl.json b/l10n/nl.json index 1b25aff8..572f5fa7 100644 --- a/l10n/nl.json +++ b/l10n/nl.json @@ -98,11 +98,8 @@ "Notification sent successfully": "Kennisgeving succesvol verzonden", "%1$s mentioned in the %2$s: \"%3$s\".": "%1$s genoemd in de %2$s: \"%3$s\".", "Choose a format to convert {fileName}": "Kies een formaat om {fileName} te converteren", - "Form template": "Formulier sjabloon", - "Form template from existing text file": "Formulier sjabloon uit bestaand tekstbestand", "Create form": "Formulier maken", "Fill in form in ONLYOFFICE": "Formulier invullen in ONLYOFFICE", - "Create new Form template": "Nieuw Formulier sjabloon maken", "Security": "Beveiliging", "Run document macros": "Document macro's uitvoeren", "Default editor theme": "Standaard editor thema", diff --git a/l10n/pl.js b/l10n/pl.js index 89638335..3d97e2f5 100644 --- a/l10n/pl.js +++ b/l10n/pl.js @@ -100,11 +100,8 @@ OC.L10N.register( "Notification sent successfully": "Powiadomienie zostało wysłane", "%1\$s mentioned in the %2\$s: \"%3\$s\".": "%1\$s dodał(a) Cię w %2\$s następujący komentarz: \"%3\$s\".", "Choose a format to convert {fileName}": "Wybierz format, do którego chcesz przekonwertować {fileName}", - "Form template": "Szablon formularza", - "Form template from existing text file": "Szablon formularza z istniejącego pliku tekstowego", "Create form": "Utwórz formularz", "Fill in form in ONLYOFFICE": "Wypełnić formularz w ONLYOFFICE", - "Create new Form template": "Utwórz nowy szablon formularza", "Security": "Bezpieczeństwo", "Run document macros": "Uruchom makra dokumentu", "Default editor theme": "Domyślny motyw edytora", diff --git a/l10n/pl.json b/l10n/pl.json index 6cab5c1f..387688bd 100644 --- a/l10n/pl.json +++ b/l10n/pl.json @@ -98,11 +98,8 @@ "Notification sent successfully": "Powiadomienie zostało wysłane", "%1$s mentioned in the %2$s: \"%3$s\".": "%1$s dodał(a) Cię w %2$s następujący komentarz: \"%3$s\".", "Choose a format to convert {fileName}": "Wybierz format, do którego chcesz przekonwertować {fileName}", - "Form template": "Szablon formularza", - "Form template from existing text file": "Szablon formularza z istniejącego pliku tekstowego", "Create form": "Utwórz formularz", "Fill in form in ONLYOFFICE": "Wypełnić formularz w ONLYOFFICE", - "Create new Form template": "Utwórz nowy szablon formularza", "Security": "Bezpieczeństwo", "Run document macros": "Uruchom makra dokumentu", "Default editor theme": "Domyślny motyw edytora", diff --git a/l10n/pt_BR.js b/l10n/pt_BR.js index 79d6445b..9d041625 100644 --- a/l10n/pt_BR.js +++ b/l10n/pt_BR.js @@ -100,11 +100,8 @@ OC.L10N.register( "Notification sent successfully": "Notificação enviada com sucesso", "%1\$s mentioned in the %2\$s: \"%3\$s\".": "%1\$s mencionado você em %2\$s: \"%3\$s\".", "Choose a format to convert {fileName}": "Escolha um formato para converter {fileName}", - "Form template": "Modelo de formulário", - "Form template from existing text file": "Modelo de formulário a partir de arquivo de texto existente", "Create form": "Criar formulário", "Fill in form in ONLYOFFICE": "Preencher formulário no ONLYOFFICE", - "Create new Form template": "Criar novo modelo de Formulário", "Security": "Segurança", "Run document macros": "Executar macros de documento", "Default editor theme": "Tema do editor padrão", diff --git a/l10n/pt_BR.json b/l10n/pt_BR.json index e48c95ae..5d084772 100644 --- a/l10n/pt_BR.json +++ b/l10n/pt_BR.json @@ -98,11 +98,8 @@ "Notification sent successfully": "Notificação enviada com sucesso", "%1$s mentioned in the %2$s: \"%3$s\".": "%1$s mencionado você em %2$s: \"%3$s\".", "Choose a format to convert {fileName}": "Escolha um formato para converter {fileName}", - "Form template": "Modelo de formulário", - "Form template from existing text file": "Modelo de formulário a partir de arquivo de texto existente", "Create form": "Criar formulário", "Fill in form in ONLYOFFICE": "Preencher formulário no ONLYOFFICE", - "Create new Form template": "Criar novo modelo de Formulário", "Security": "Segurança", "Run document macros": "Executar macros de documento", "Default editor theme": "Tema do editor padrão", diff --git a/l10n/ru.js b/l10n/ru.js index 7af5ebe2..104bf03a 100644 --- a/l10n/ru.js +++ b/l10n/ru.js @@ -100,11 +100,11 @@ OC.L10N.register( "Notification sent successfully": "Оповещение успешно отправлено", "%1\$s mentioned in the %2\$s: \"%3\$s\".": "%1\$s упомянул вас в %2\$s: \"%3\$s\".", "Choose a format to convert {fileName}": "Выберите формат для {fileName}", - "Form template": "Шаблон формы", - "Form template from existing text file": "Шаблон формы из существующего текстового файла", + "PDF form": "PDF форма", + "PDF form from existing text file": "PDF форма из существующего текстового файла", "Create form": "Создать форму", "Fill in form in ONLYOFFICE": "Заполнить форму в ONLYOFFICE", - "Create new Form template": "Создать новый шаблон формы", + "Create new PDF form": "Создать новую PDF форму", "Security": "Безопасность", "Run document macros": "Запускать макросы документа", "Default editor theme": "Тема редактора по умолчанию", diff --git a/l10n/ru.json b/l10n/ru.json index 6a03657d..3dcca661 100644 --- a/l10n/ru.json +++ b/l10n/ru.json @@ -98,11 +98,11 @@ "Notification sent successfully": "Оповещение успешно отправлено", "%1$s mentioned in the %2$s: \"%3$s\".": "%1$s упомянул вас в %2$s: \"%3$s\".", "Choose a format to convert {fileName}": "Выберите формат для {fileName}", - "Form template": "Шаблон формы", - "Form template from existing text file": "Шаблон формы из существующего текстового файла", + "PDF form": "PDF форма", + "PDF form from existing text file": "PDF форма из существующего текстового файла", "Create form": "Создать форму", "Fill in form in ONLYOFFICE": "Заполнить форму в ONLYOFFICE", - "Create new Form template": "Создать новый шаблон формы", + "Create new PDF form": "Создать новую PDF форму", "Security": "Безопасность", "Run document macros": "Запускать макросы документа", "Default editor theme": "Тема редактора по умолчанию", diff --git a/l10n/sv.js b/l10n/sv.js index 07ef1ebf..736e8142 100644 --- a/l10n/sv.js +++ b/l10n/sv.js @@ -100,11 +100,8 @@ OC.L10N.register( "Notification sent successfully": "Aviseringen har skickats", "%1\$s mentioned in the %2\$s: \"%3\$s\".": "%1\$s nämnde dig i %2\$s: \"%3\$s\".", "Choose a format to convert {fileName}": "Välj det filformat som {fileName} ska konverteras till.", - "Form template": "Formulärmall", - "Form template from existing text file": "Formulärmall från befintlig textfil", "Create form": "Skapa formulär", "Fill in form in ONLYOFFICE": "Fylla i formulär i ONLYOFFICE", - "Create new Form template": "Skapa ny formulärmall", "Security": "Säkerhet", "Run document macros": "Kör dokumentmakron", "Light": "Ljus", diff --git a/l10n/sv.json b/l10n/sv.json index d8fc44bf..69956b00 100644 --- a/l10n/sv.json +++ b/l10n/sv.json @@ -98,11 +98,8 @@ "Notification sent successfully": "Aviseringen har skickats", "%1$s mentioned in the %2$s: \"%3$s\".": "%1$s nämnde dig i %2$s: \"%3$s\".", "Choose a format to convert {fileName}": "Välj det filformat som {fileName} ska konverteras till.", - "Form template": "Formulärmall", - "Form template from existing text file": "Formulärmall från befintlig textfil", "Create form": "Skapa formulär", "Fill in form in ONLYOFFICE": "Fylla i formulär i ONLYOFFICE", - "Create new Form template": "Skapa ny formulärmall", "Security": "Säkerhet", "Run document macros": "Kör dokumentmakron", "Light": "Ljus", diff --git a/l10n/uk.js b/l10n/uk.js index 1c00d8ac..e1fdfb0a 100644 --- a/l10n/uk.js +++ b/l10n/uk.js @@ -99,10 +99,8 @@ OC.L10N.register( "Notification sent successfully": "Сповіщення успішно надіслено", "%1\$s mentioned in the %2\$s: \"%3\$s\".": "%1\$s згадав у %2\$s: \"%3\$s\".", "Choose a format to convert {fileName}": "Виберіть формат для {fileName}", - "Form template": "Шаблон форми", "Create form": "Створити форму", "Fill in form in ONLYOFFICE": "Заповнити форму у ONLYOFFICE", - "Create new Form template": "Створити новий шаблон форми", "Security": "Безпека", "Run document macros": "Виконувати макроси документу", "Default editor theme": "Типова тема редактора", diff --git a/l10n/uk.json b/l10n/uk.json index 044a3aa2..de91615b 100644 --- a/l10n/uk.json +++ b/l10n/uk.json @@ -98,10 +98,8 @@ "Notification sent successfully": "Сповіщення успішно надіслено", "%1$s mentioned in the %2$s: \"%3$s\".": "%1$s згадав у %2$s: \"%3$s\".", "Choose a format to convert {fileName}": "Виберіть формат для {fileName}", - "Form template": "Шаблон форми", "Create form": "Створити форму", "Fill in form in ONLYOFFICE": "Заповнити форму у ONLYOFFICE", - "Create new Form template": "Створити новий шаблон форми", "Security": "Безпека", "Run document macros": "Виконувати макроси документу", "Default editor theme": "Типова тема редактора", diff --git a/l10n/zh_CN.js b/l10n/zh_CN.js index c743a56f..b356622a 100644 --- a/l10n/zh_CN.js +++ b/l10n/zh_CN.js @@ -100,11 +100,8 @@ OC.L10N.register( "Notification sent successfully": "通知发送成功", "%1\$s mentioned in the %2\$s: \"%3\$s\".": "%1\$s 在 %2\$s: \"%3\$s\"中提到了您.", "Choose a format to convert {fileName}": "转换 {fileName} 为选中的格式", - "Form template": "表单模板", - "Form template from existing text file": "用现有的文本文件创建模板", "Create form": "创建表单", "Fill in form in ONLYOFFICE": "在ONLYOFFICE上填写表单", - "Create new Form template": "创建新的表单模板", "Security": "安全", "Run document macros": "运行文档宏", "Default editor theme": "编辑器默认的主题", diff --git a/l10n/zh_CN.json b/l10n/zh_CN.json index 4dc8ae70..3981b395 100644 --- a/l10n/zh_CN.json +++ b/l10n/zh_CN.json @@ -98,11 +98,8 @@ "Notification sent successfully": "通知发送成功", "%1$s mentioned in the %2$s: \"%3$s\".": "%1$s 在 %2$s: \"%3$s\"中提到了您.", "Choose a format to convert {fileName}": "转换 {fileName} 为选中的格式", - "Form template": "表单模板", - "Form template from existing text file": "用现有的文本文件创建模板", "Create form": "创建表单", "Fill in form in ONLYOFFICE": "在ONLYOFFICE上填写表单", - "Create new Form template": "创建新的表单模板", "Security": "安全", "Run document macros": "运行文档宏", "Default editor theme": "编辑器默认的主题", From 33f96560cb4a370f23ebabb8bf7b18c9018e11de Mon Sep 17 00:00:00 2001 From: rivexe Date: Mon, 19 Feb 2024 11:20:14 +0300 Subject: [PATCH 080/114] fix: added check for the case when there is no context.$file --- js/main.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/js/main.js b/js/main.js index 809b85dd..fdd7a124 100644 --- a/js/main.js +++ b/js/main.js @@ -173,7 +173,7 @@ OCA.Onlyoffice.FileClick = function (fileName, context) { var fileInfoModel = context.fileInfoModel || context.fileList.getModelForFile(fileName); - var fileId = context.$file[0].dataset.id || fileInfoModel.id; + var fileId = context.$file && context.$file[0].dataset.id || fileInfoModel.id; var winEditor = !fileInfoModel && !OCA.Onlyoffice.setting.sameTab ? document : null; OCA.Onlyoffice.OpenEditor(fileId, context.dir, fileName, 0, winEditor); @@ -185,9 +185,10 @@ OCA.Onlyoffice.FileConvertClick = function (fileName, context) { var fileInfoModel = context.fileInfoModel || context.fileList.getModelForFile(fileName); var fileList = context.fileList; + var fileId = context.$file ? context.$file[0].dataset.id : fileInfoModel.id; var convertData = { - fileId: context.$file[0].dataset.id || fileInfoModel.id + fileId: fileId }; if ($("#isPublic").val()) { From 5f85766097b1ca2b6f3c788a7409b008cdae0870 Mon Sep 17 00:00:00 2001 From: Sergey Linnik Date: Mon, 19 Feb 2024 12:26:32 +0300 Subject: [PATCH 081/114] format --- js/main.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/js/main.js b/js/main.js index d63dcc93..e065fb0a 100644 --- a/js/main.js +++ b/js/main.js @@ -329,7 +329,7 @@ if (!config.mime) { return true; } - + let mimeTypes = config.mime; mimeTypes.forEach((mime) => { OCA.Files.fileActions.registerAction({ @@ -340,11 +340,11 @@ iconClass: "icon-onlyoffice-open", actionHandler: OCA.Onlyoffice.FileClick }); - + if (config.def) { OCA.Files.fileActions.setDefault(mime, "onlyofficeOpen"); } - + if (config.conv) { OCA.Files.fileActions.registerAction({ name: "onlyofficeConvert", @@ -355,7 +355,7 @@ actionHandler: OCA.Onlyoffice.FileConvertClick }); } - + if (config.fillForms) { OCA.Files.fileActions.registerAction({ name: "onlyofficeFill", @@ -366,7 +366,7 @@ actionHandler: OCA.Onlyoffice.FileClick }); } - + if (config.createForm) { OCA.Files.fileActions.registerAction({ name: "onlyofficeCreateForm", @@ -377,7 +377,7 @@ actionHandler: OCA.Onlyoffice.CreateFormClick }); } - + if (config.saveas && !$("#isPublic").val()) { OCA.Files.fileActions.registerAction({ name: "onlyofficeDownload", From 7596c75ff8e77fd8d385e7eaf4ea618a04bc9650 Mon Sep 17 00:00:00 2001 From: rivexe Date: Mon, 19 Feb 2024 14:32:07 +0300 Subject: [PATCH 082/114] fix: lint closing parenthesis --- lib/appconfig.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/appconfig.php b/lib/appconfig.php index 3558c4e0..4928a17f 100644 --- a/lib/appconfig.php +++ b/lib/appconfig.php @@ -1307,7 +1307,8 @@ private function buildOnlyofficeFormats() { && $onlyOfficeFormat["mime"] && $onlyOfficeFormat["type"] && $onlyOfficeFormat["actions"] - && $onlyOfficeFormat["convert"]) { + && $onlyOfficeFormat["convert"] + ) { $result[$onlyOfficeFormat["name"]] = [ "mime" => $onlyOfficeFormat["mime"], "type" => $onlyOfficeFormat["type"], From 38cbf78527a993edc8f4e4f7eaf5ff01f482c093 Mon Sep 17 00:00:00 2001 From: rivexe Date: Mon, 26 Feb 2024 10:20:58 +0300 Subject: [PATCH 083/114] fix: onRequestCompareFile event listener for editors 7.4 --- js/editor.js | 1 + 1 file changed, 1 insertion(+) diff --git a/js/editor.js b/js/editor.js index 1c62b0dd..512df2a0 100644 --- a/js/editor.js +++ b/js/editor.js @@ -141,6 +141,7 @@ config.events.onRequestInsertImage = OCA.Onlyoffice.onRequestInsertImage; config.events.onRequestMailMergeRecipients = OCA.Onlyoffice.onRequestMailMergeRecipients; config.events.onRequestSelectDocument = OCA.Onlyoffice.onRequestSelectDocument; + config.events.onRequestCompareFile = OCA.Onlyoffice.onRequestSelectDocument; //todo: remove (for editors 7.4) config.events.onRequestSendNotify = OCA.Onlyoffice.onRequestSendNotify; config.events.onRequestReferenceData = OCA.Onlyoffice.onRequestReferenceData; config.events.onRequestOpen = OCA.Onlyoffice.onRequestOpen; From b0b87fc177976cad6a0c382f5e566cad52a059f3 Mon Sep 17 00:00:00 2001 From: rivexe Date: Mon, 26 Feb 2024 13:13:59 +0300 Subject: [PATCH 084/114] fix: security vulnerability when file downloading is not permit --- controller/callbackcontroller.php | 40 +++++++++++++++++++----------- controller/editorapicontroller.php | 7 ++---- controller/editorcontroller.php | 19 +++++++++++++- lib/fileutility.php | 38 ++++++++++++++++++++++++++++ 4 files changed, 84 insertions(+), 20 deletions(-) diff --git a/controller/callbackcontroller.php b/controller/callbackcontroller.php index 58992b79..7e9b5f1b 100644 --- a/controller/callbackcontroller.php +++ b/controller/callbackcontroller.php @@ -42,6 +42,7 @@ use OCA\Onlyoffice\Crypt; use OCA\Onlyoffice\DocumentService; use OCA\Onlyoffice\FileVersions; +use OCA\Onlyoffice\FileUtility; use OCA\Onlyoffice\VersionManager; use OCA\Onlyoffice\KeyManager; use OCA\Onlyoffice\RemoteInstance; @@ -242,13 +243,24 @@ public function download($doc) { } $shareToken = isset($hashData->shareToken) ? $hashData->shareToken : null; - list($file, $error) = empty($shareToken) ? $this->getFile($userId, $fileId, null, $changes ? null : $version, $template) : $this->getFileByToken($fileId, $shareToken, $changes ? null : $version); + list($file, $error, $share) = empty($shareToken) ? $this->getFile($userId, $fileId, null, $changes ? null : $version, $template) : $this->getFileByToken($fileId, $shareToken, $changes ? null : $version); if (isset($error)) { return $error; } - if ($this->userSession->isLoggedIn() && !$file->isReadable()) { + $canDownload = true; + + $fileStorage = $file->getStorage(); + if ($fileStorage->instanceOfStorage("\OCA\Files_Sharing\SharedStorage") || !empty($shareToken)) { + $share = empty($share) ? $fileStorage->getShare() : $share; + $canDownload = FileUtility::canShareDownload($share); + if (!$canDownload && !empty($this->config->getDocumentServerSecret())) { + $canDownload = true; + } + } + + if ($this->userSession->isLoggedIn() && !$file->isReadable() || !$canDownload) { $this->logger->error("Download without access right", ["app" => $this->appName]); return new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN); } @@ -504,7 +516,7 @@ public function track($doc, $users, $key, $status, $url, $token, $history, $chan \OC_Util::setupFS($userId); } - list($file, $error) = empty($shareToken) ? $this->getFile($userId, $fileId, $filePath) : $this->getFileByToken($fileId, $shareToken); + list($file, $error, $share) = empty($shareToken) ? $this->getFile($userId, $fileId, $filePath) : $this->getFileByToken($fileId, $shareToken); if (isset($error)) { $this->logger->error("track error: $fileId " . json_encode($error->getData()), ["app" => $this->appName]); @@ -613,7 +625,7 @@ function () use ($file, $newData) { */ private function getFile($userId, $fileId, $filePath = null, $version = 0, $template = false) { if (empty($fileId)) { - return [null, new JSONResponse(["message" => $this->trans->t("FileId is empty")], Http::STATUS_BAD_REQUEST)]; + return [null, new JSONResponse(["message" => $this->trans->t("FileId is empty")], Http::STATUS_BAD_REQUEST), null]; } try { @@ -621,12 +633,12 @@ private function getFile($userId, $fileId, $filePath = null, $version = 0, $temp $files = $folder->getById($fileId); } catch (\Exception $e) { $this->logger->logException($e, ["message" => "getFile: $fileId", "app" => $this->appName]); - return [null, new JSONResponse(["message" => $this->trans->t("Invalid request")], Http::STATUS_BAD_REQUEST)]; + return [null, new JSONResponse(["message" => $this->trans->t("Invalid request")], Http::STATUS_BAD_REQUEST), null]; } if (empty($files)) { $this->logger->error("Files not found: $fileId", ["app" => $this->appName]); - return [null, new JSONResponse(["message" => $this->trans->t("Files not found")], Http::STATUS_NOT_FOUND)]; + return [null, new JSONResponse(["message" => $this->trans->t("Files not found")], Http::STATUS_NOT_FOUND), null]; } $file = $files[0]; @@ -651,10 +663,10 @@ private function getFile($userId, $fileId, $filePath = null, $version = 0, $temp if ($owner !== null) { if ($owner->getUID() !== $userId) { - list($file, $error) = $this->getFile($owner->getUID(), $file->getId()); + list($file, $error, $share) = $this->getFile($owner->getUID(), $file->getId()); if (isset($error)) { - return [null, $error]; + return [null, $error, null]; } } @@ -667,7 +679,7 @@ private function getFile($userId, $fileId, $filePath = null, $version = 0, $temp } } - return [$file, null]; + return [$file, null, null]; } /** @@ -683,14 +695,14 @@ private function getFileByToken($fileId, $shareToken, $version = 0) { list($share, $error) = $this->getShare($shareToken); if (isset($error)) { - return [null, $error]; + return [null, $error, null]; } try { $node = $share->getNode(); } catch (NotFoundException $e) { $this->logger->logException($e, ["message" => "getFileByToken error", "app" => $this->appName]); - return [null, new JSONResponse(["message" => $this->trans->t("File not found")], Http::STATUS_NOT_FOUND)]; + return [null, new JSONResponse(["message" => $this->trans->t("File not found")], Http::STATUS_NOT_FOUND), null]; } if ($node instanceof Folder) { @@ -698,11 +710,11 @@ private function getFileByToken($fileId, $shareToken, $version = 0) { $files = $node->getById($fileId); } catch (\Exception $e) { $this->logger->logException($e, ["message" => "getFileByToken: $fileId", "app" => $this->appName]); - return [null, new JSONResponse(["message" => $this->trans->t("Invalid request")], Http::STATUS_NOT_FOUND)]; + return [null, new JSONResponse(["message" => $this->trans->t("Invalid request")], Http::STATUS_NOT_FOUND), null]; } if (empty($files)) { - return [null, new JSONResponse(["message" => $this->trans->t("File not found")], Http::STATUS_NOT_FOUND)]; + return [null, new JSONResponse(["message" => $this->trans->t("File not found")], Http::STATUS_NOT_FOUND), null]; } $file = $files[0]; } else { @@ -722,7 +734,7 @@ private function getFileByToken($fileId, $shareToken, $version = 0) { } } - return [$file, null]; + return [$file, null, $share]; } /** diff --git a/controller/editorapicontroller.php b/controller/editorapicontroller.php index 91558b84..f0d0d852 100644 --- a/controller/editorapicontroller.php +++ b/controller/editorapicontroller.php @@ -325,11 +325,8 @@ public function config($fileId, $filePath = null, $shareToken = null, $version = $storageShare = $fileStorage->getShare(); if (method_exists($storageShare, "getAttributes")) { $attributes = $storageShare->getAttributes(); - - $permissionsDownload = $attributes->getAttribute("permissions", "download"); - if ($permissionsDownload !== null) { - $params["document"]["permissions"]["download"] = $params["document"]["permissions"]["print"] = $params["document"]["permissions"]["copy"] = $permissionsDownload === true; - } + $canDownload = FileUtility::canShareDownload($storageShare); + $params["document"]["permissions"]["download"] = $params["document"]["permissions"]["print"] = $params["document"]["permissions"]["copy"] = $canDownload === true; if (isset($format["review"]) && $format["review"]) { $permissionsReviewOnly = $attributes->getAttribute($this->appName, "review"); diff --git a/controller/editorcontroller.php b/controller/editorcontroller.php index db269095..ee42e442 100644 --- a/controller/editorcontroller.php +++ b/controller/editorcontroller.php @@ -1092,7 +1092,16 @@ public function url($filePath) { $this->logger->error("File for generate presigned url was not found: $dir", ["app" => $this->appName]); return ["error" => $this->trans->t("File not found")]; } - if (!$file->isReadable()) { + + $canDownload = true; + + $fileStorage = $file->getStorage(); + if ($fileStorage->instanceOfStorage("\OCA\Files_Sharing\SharedStorage")) { + $share = $fileStorage->getShare(); + $canDownload = FileUtility::canShareDownload($share); + } + + if (!$file->isReadable() || !$canDownload) { $this->logger->error("File without permission: $dir", ["app" => $this->appName]); return ["error" => $this->trans->t("You do not have enough permissions to view the file")]; } @@ -1162,6 +1171,14 @@ public function download($fileId, $toExtension = null, $template = false) { return $this->renderError($this->trans->t("Not permitted")); } + $fileStorage = $file->getStorage(); + if ($fileStorage->instanceOfStorage("\OCA\Files_Sharing\SharedStorage")) { + $share = empty($share) ? $fileStorage->getShare() : $share; + if (!FileUtility::canShareDownload($share)) { + return $this->renderError($this->trans->t("Not permitted")); + } + } + $fileName = $file->getName(); $ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION)); $toExtension = strtolower($toExtension); diff --git a/lib/fileutility.php b/lib/fileutility.php index 8f2b6dab..2d0782db 100644 --- a/lib/fileutility.php +++ b/lib/fileutility.php @@ -27,6 +27,7 @@ use OCP\ILogger; use OCP\ISession; use OCP\Share\IManager; +use OCP\Share\IShare; use OCA\Onlyoffice\AppConfig; use OCA\Onlyoffice\Version; @@ -297,4 +298,41 @@ public function getVersionKey($version) { return $key; } + + /** + * The method checks download permission + * + * @param IShare $share - share object + * + * @return bool + */ + public static function canShareDownload($share) { + $can = true; + + $downloadAttribute = self::getShareAttrubute($share, "download"); + if (isset($downloadAttribute)) { + $can = $downloadAttribute; + } + + return $can; + } + + /** + * The method extracts share attribute + * + * @param IShare $share - share object + * @param string $attribute - attribute name + * + * @return bool|null + */ + private static function getShareAttrubute($share, $attribute) { + $attributes = null; + if (method_exists(IShare::class, "getAttributes")) { + $attributes = $share->getAttributes(); + } + + $attribute = isset($attributes) ? $attributes->getAttribute("permissions", $attribute) : null; + + return $attribute; + } } From 464c01ad80790e0e7f474ec4c50f87329857c099 Mon Sep 17 00:00:00 2001 From: rivexe Date: Mon, 26 Feb 2024 14:22:05 +0300 Subject: [PATCH 085/114] feat: if editors are available only for any group, don't add scripts --- lib/hookhandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/hookhandler.php b/lib/hookhandler.php index b1ca06e5..36c6b465 100644 --- a/lib/hookhandler.php +++ b/lib/hookhandler.php @@ -40,7 +40,7 @@ public static function publicPage() { $appConfig = new AppConfig($appName); - if (!empty($appConfig->getDocumentServerUrl()) && $appConfig->settingsAreSuccessful()) { + if (!empty($appConfig->getDocumentServerUrl()) && $appConfig->settingsAreSuccessful() && empty($appConfig->getLimitGroups())) { Util::addScript("onlyoffice", "main"); Util::addScript("onlyoffice", "share"); From 66407cb546c0a9ee081b2ee14623731e0280b62b Mon Sep 17 00:00:00 2001 From: rivexe Date: Mon, 26 Feb 2024 14:22:18 +0300 Subject: [PATCH 086/114] refactor: use empty() instead of count() for check limitGroups --- lib/appconfig.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/appconfig.php b/lib/appconfig.php index 4928a17f..f2cc4691 100644 --- a/lib/appconfig.php +++ b/lib/appconfig.php @@ -1070,7 +1070,7 @@ public function isUserAllowedToUse($userId = null) { $groups = $this->getLimitGroups(); // no group set -> all users are allowed - if (\count($groups) === 0) { + if (empty($groups)) { return true; } From af8cabfb0ddc5759896a50637450f73c2a82d405 Mon Sep 17 00:00:00 2001 From: rivexe Date: Mon, 26 Feb 2024 14:22:45 +0300 Subject: [PATCH 087/114] docs: fix guest redirect to changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d331cb45..67eeae49 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - offline viewer for share link - updatable list of supported formats - filling pdf instead oform +- fixed guest redirect when limiting the app to groups ## Added - reference data from coediting From fd5453eb4434208c2d52b07cdd16778fdc1c986d Mon Sep 17 00:00:00 2001 From: rivexe Date: Tue, 27 Feb 2024 11:01:54 +0300 Subject: [PATCH 088/114] feat: support of user avatar in editors --- appinfo/routes.php | 1 + controller/editorapicontroller.php | 18 +++++++++ controller/editorcontroller.php | 63 ++++++++++++++++++++++++++++++ js/editor.js | 35 ++++++++++++----- 4 files changed, 107 insertions(+), 10 deletions(-) diff --git a/appinfo/routes.php b/appinfo/routes.php index 0edcc195..cac20538 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -27,6 +27,7 @@ ["name" => "editor#download", "url" => "/downloadas", "verb" => "GET"], ["name" => "editor#index", "url" => "/{fileId}", "verb" => "GET"], ["name" => "editor#public_page", "url" => "/s/{shareToken}", "verb" => "GET"], + ["name" => "editor#user_info", "url" => "/ajax/userInfo", "verb" => "GET"], ["name" => "editor#users", "url" => "/ajax/users", "verb" => "GET"], ["name" => "editor#mention", "url" => "/ajax/mention", "verb" => "POST"], ["name" => "editor#reference", "url" => "/ajax/reference", "verb" => "POST"], diff --git a/controller/editorapicontroller.php b/controller/editorapicontroller.php index 91558b84..4e86bd94 100644 --- a/controller/editorapicontroller.php +++ b/controller/editorapicontroller.php @@ -113,6 +113,13 @@ class EditorApiController extends OCSController { */ private $versionManager; + /** + * Avatar manager + * + * @var IAvatarManager + */ + private $avatarManager; + /** * Tag manager * @@ -167,6 +174,7 @@ public function __construct( $this->versionManager = new VersionManager($AppName, $root); $this->fileUtility = new FileUtility($AppName, $trans, $logger, $config, $shareManager, $session); + $this->avatarManager = \OC::$server->getAvatarManager(); } /** @@ -436,6 +444,16 @@ public function config($fileId, $filePath = null, $shareToken = null, $version = "id" => $this->buildUserId($userId), "name" => $user->getDisplayName() ]; + $avatar = $this->avatarManager->getAvatar($userId); + if ($avatar->exists()) { + $userAvatarUrl = $this->urlGenerator->getAbsoluteURL( + $this->urlGenerator->linkToRoute("core.avatar.getAvatar", [ + "userId" => $userId, + "size" => 64, + ]) + ); + $params["editorConfig"]["user"]["image"] = $userAvatarUrl; + } } $folderLink = null; diff --git a/controller/editorcontroller.php b/controller/editorcontroller.php index db269095..324f1878 100644 --- a/controller/editorcontroller.php +++ b/controller/editorcontroller.php @@ -140,6 +140,13 @@ class EditorController extends Controller { */ private $groupManager; + /** + * Avatar manager + * + * @var IAvatarManager + */ + private $avatarManager; + /** * @param string $AppName - application name * @param IRequest $request - request object @@ -186,6 +193,7 @@ public function __construct( $this->versionManager = new VersionManager($AppName, $root); $this->fileUtility = new FileUtility($AppName, $trans, $logger, $config, $shareManager, $session); + $this->avatarManager = \OC::$server->getAvatarManager(); } /** @@ -415,6 +423,46 @@ public function users($fileId, $operationType = null) { return $result; } + /** + * Get user for Info + * + * @param string $userIds - users identifiers + * + * @return array + * + * @NoAdminRequired + * @NoCSRFRequired + */ + public function userInfo($userIds) { + $result = []; + $userIds = json_decode($userIds, true); + + if ($userIds !== null && is_array($userIds)) { + foreach ($userIds as $userId) { + $userData = []; + $user = $this->userManager->get($this->getUserId($userId)); + if (!empty($user)) { + $userData = [ + "name" => $user->getDisplayName(), + "id" => $userId + ]; + $avatar = $this->avatarManager->getAvatar($user->getUID()); + if ($avatar->exists()) { + $userAvatarUrl = $this->urlGenerator->getAbsoluteURL( + $this->urlGenerator->linkToRoute("core.avatar.getAvatar", [ + "userId" => $user->getUID(), + "size" => 64, + ]) + ); + $userData["image"] = $userAvatarUrl; + } + array_push($result, $userData); + } + } + } + return $result; + } + /** * Send notify about mention * @@ -1460,6 +1508,21 @@ private function limitEnumerationToGroups() { return false; } + /** + * Get Nextcloud userId from unique user identifier + * + * @param string $userId - current user identifier + * + * @return string + */ + private function getUserId($userId) { + if (str_contains($userId, "_")) { + $userIdExp = explode("_", $userId); + $userId = end($userIdExp); + } + return $userId; + } + /** * Print error page * diff --git a/js/editor.js b/js/editor.js index 512df2a0..f637724c 100644 --- a/js/editor.js +++ b/js/editor.js @@ -511,16 +511,31 @@ OCA.Onlyoffice.onRequestUsers = function (event) { let operationType = typeof(event.data.c) !== "undefined" ? event.data.c : null; - $.get(OC.generateUrl("apps/" + OCA.Onlyoffice.AppName + "/ajax/users?fileId={fileId}&operationType=" + operationType, - { - fileId: OCA.Onlyoffice.fileId || 0 - }), - function onSuccess(response) { - OCA.Onlyoffice.docEditor.setUsers({ - "c": operationType, - "users": response - }); - }); + switch (operationType) { + case "info": + $.get(OC.generateUrl("apps/" + OCA.Onlyoffice.AppName + "/ajax/userInfo?userIds={userIds}", + { + userIds: JSON.stringify(event.data.id) + }), + function onSuccess(response) { + OCA.Onlyoffice.docEditor.setUsers({ + "c": operationType, + "users": response + }); + }); + break; + default: + $.get(OC.generateUrl("apps/" + OCA.Onlyoffice.AppName + "/ajax/users?fileId={fileId}&operationType=" + operationType, + { + fileId: OCA.Onlyoffice.fileId || 0 + }), + function onSuccess(response) { + OCA.Onlyoffice.docEditor.setUsers({ + "c": operationType, + "users": response + }); + }); + } }; OCA.Onlyoffice.onRequestReferenceData = function (event) { From f6801961c6da729ec91ccb525d3b0fb3974a2a4e Mon Sep 17 00:00:00 2001 From: rivexe Date: Tue, 27 Feb 2024 11:02:12 +0300 Subject: [PATCH 089/114] docs: user avatar to CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d331cb45..3ff449e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ - opening a reference data source - changing a reference data source - setting for disable editors cron check +- support of user avatar in editor ## 8.2.3 ## Added From cf7e5bd125979e4742ddccfce5289efe02fa7a5a Mon Sep 17 00:00:00 2001 From: rivexe Date: Tue, 27 Feb 2024 11:14:10 +0300 Subject: [PATCH 090/114] refactor: format for linter --- controller/editorapicontroller.php | 11 +++++++---- controller/editorcontroller.php | 11 +++++++---- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/controller/editorapicontroller.php b/controller/editorapicontroller.php index 4e86bd94..822b25e7 100644 --- a/controller/editorapicontroller.php +++ b/controller/editorapicontroller.php @@ -447,10 +447,13 @@ public function config($fileId, $filePath = null, $shareToken = null, $version = $avatar = $this->avatarManager->getAvatar($userId); if ($avatar->exists()) { $userAvatarUrl = $this->urlGenerator->getAbsoluteURL( - $this->urlGenerator->linkToRoute("core.avatar.getAvatar", [ - "userId" => $userId, - "size" => 64, - ]) + $this->urlGenerator->linkToRoute( + "core.avatar.getAvatar", + [ + "userId" => $userId, + "size" => 64, + ] + ) ); $params["editorConfig"]["user"]["image"] = $userAvatarUrl; } diff --git a/controller/editorcontroller.php b/controller/editorcontroller.php index 324f1878..4fe95373 100644 --- a/controller/editorcontroller.php +++ b/controller/editorcontroller.php @@ -449,10 +449,13 @@ public function userInfo($userIds) { $avatar = $this->avatarManager->getAvatar($user->getUID()); if ($avatar->exists()) { $userAvatarUrl = $this->urlGenerator->getAbsoluteURL( - $this->urlGenerator->linkToRoute("core.avatar.getAvatar", [ - "userId" => $user->getUID(), - "size" => 64, - ]) + $this->urlGenerator->linkToRoute( + "core.avatar.getAvatar", + [ + "userId" => $userId, + "size" => 64, + ] + ) ); $userData["image"] = $userAvatarUrl; } From f749e9aff53f2a322177d3b806d724c972ef0bd7 Mon Sep 17 00:00:00 2001 From: rivexe Date: Wed, 28 Feb 2024 11:14:44 +0300 Subject: [PATCH 091/114] feat: size window for mobile --- css/editor.css | 3 +++ js/editor.js | 31 +++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/css/editor.css b/css/editor.css index 8ef19922..d2533d7d 100644 --- a/css/editor.css +++ b/css/editor.css @@ -23,6 +23,9 @@ #body-public #content { height: 100%; } +#content-wrapper #content { + height: calc(100dvh - 45px); +} .AscDesktopEditor #header { display: none; diff --git a/js/editor.js b/js/editor.js index 512df2a0..9e2c44bb 100644 --- a/js/editor.js +++ b/js/editor.js @@ -99,6 +99,10 @@ OCA.Onlyoffice.showMessage(config.error, {type: "error"}); return; } + OCA.Onlyoffice.device = config.type; + if (OCA.Onlyoffice.device === "mobile") { + OCA.Onlyoffice.resizeEvents(); + } var docIsChanged = null; var docIsChangedTimeout = null; @@ -267,6 +271,8 @@ if (OCA.Onlyoffice.version > 0) { OCA.Onlyoffice.onRequestHistory(OCA.Onlyoffice.version); } + + OCA.Onlyoffice.resize(); }; OCA.Onlyoffice.onRequestSaveAs = function (event) { @@ -661,6 +667,31 @@ OCA.Onlyoffice.docEditor.refreshHistory(data); } + OCA.Onlyoffice.resize = function () { + if (OCA.Onlyoffice.device !== "mobile") { + return; + } + + var headerHeight = $("#header").length > 0 ? $("#header").height() : 45; + var wrapEl = $("#app>iframe"); + if (wrapEl.length > 0) { + wrapEl[0].style.height = (screen.availHeight - headerHeight) + "px"; + window.scrollTo(0, -1); + wrapEl[0].style.height = (window.innerHeight - headerHeight) + "px"; + } + }; + + OCA.Onlyoffice.resizeEvents = function() { + if (window.addEventListener) { + if (/Android/i.test(navigator.userAgent)) { + window.addEventListener("resize", OCA.Onlyoffice.resize); + } + if (/iPhone|iPad|iPod/i.test(navigator.userAgent)) { + window.addEventListener("orientationchange", OCA.Onlyoffice.resize); + } + } + }; + $(document).ready(OCA.Onlyoffice.InitEditor); })(jQuery, OCA); From dbff74acbf5646cdb79b2c0e09b590fd3ce80d49 Mon Sep 17 00:00:00 2001 From: rivexe Date: Wed, 28 Feb 2024 11:15:00 +0300 Subject: [PATCH 092/114] docs: size window for mobile to CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d331cb45..2b997e8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - offline viewer for share link - updatable list of supported formats - filling pdf instead oform +- fixed mobile editor size ## Added - reference data from coediting From abe2379d9a317b7684a5c5d5884d2af38c590108 Mon Sep 17 00:00:00 2001 From: rivexe Date: Fri, 1 Mar 2024 11:38:18 +0300 Subject: [PATCH 093/114] fix: "restrict" to "allow" access translations --- l10n/bg_BG.js | 2 +- l10n/bg_BG.json | 2 +- l10n/ca.js | 1 - l10n/ca.json | 1 - l10n/da.js | 1 - l10n/da.json | 1 - l10n/de.js | 2 +- l10n/de.json | 2 +- l10n/de_DE.js | 2 +- l10n/de_DE.json | 2 +- l10n/es.js | 1 - l10n/es.json | 1 - l10n/fr.js | 1 - l10n/fr.json | 1 - l10n/it.js | 1 - l10n/it.json | 1 - l10n/ja.js | 1 - l10n/ja.json | 1 - l10n/nl.js | 1 - l10n/nl.json | 1 - l10n/pl.js | 1 - l10n/pl.json | 1 - l10n/pt_BR.js | 2 +- l10n/pt_BR.json | 2 +- l10n/ru.js | 2 +- l10n/ru.json | 2 +- l10n/sv.js | 1 - l10n/sv.json | 1 - l10n/uk.js | 2 +- l10n/uk.json | 2 +- l10n/zh_CN.js | 2 +- l10n/zh_CN.json | 2 +- templates/settings.php | 2 +- 33 files changed, 15 insertions(+), 33 deletions(-) diff --git a/l10n/bg_BG.js b/l10n/bg_BG.js index 240a5b3c..238b57d5 100644 --- a/l10n/bg_BG.js +++ b/l10n/bg_BG.js @@ -45,7 +45,7 @@ OC.L10N.register( "View details" : "Виж детайли", "Save" : "Запази", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "Смесеното активно съдържание е недопустимо. За ONLYOFFICE Docs е необходимо използването на HTTPS-адрес.", - "Restrict access to editors to following groups" : "Разреши достъп до редакторите само за тези групи", + "Allow the following groups to access the editors" : "Разреши достъп до редакторите само за тези групи", "review" : "преглед", "form filling" : "попълване на формуляр", "comment" : "коментар", diff --git a/l10n/bg_BG.json b/l10n/bg_BG.json index e169214b..70141394 100644 --- a/l10n/bg_BG.json +++ b/l10n/bg_BG.json @@ -43,7 +43,7 @@ "View details" : "Виж детайли", "Save" : "Запази", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "Смесеното активно съдържание е недопустимо. За ONLYOFFICE Docs е необходимо използването на HTTPS-адрес.", - "Restrict access to editors to following groups" : "Разреши достъп до редакторите само за тези групи", + "Allow the following groups to access the editors" : "Разреши достъп до редакторите само за тези групи", "review" : "преглед", "form filling" : "попълване на формуляр", "comment" : "коментар", diff --git a/l10n/ca.js b/l10n/ca.js index d8c2649e..5bf486b7 100644 --- a/l10n/ca.js +++ b/l10n/ca.js @@ -45,7 +45,6 @@ OC.L10N.register( "View details" : "Veure detalls", "Save" : "Guardar", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "Contingut Mixt Actiu no està permès. Es requereix la direcció HTTPS per a ONLYOFFICE Docs.", - "Restrict access to editors to following groups" : "Restringir l'accés a editors a següents grups", "review" : "", "form filling" : "", "comment" : "", diff --git a/l10n/ca.json b/l10n/ca.json index 0d037d65..eed5666a 100644 --- a/l10n/ca.json +++ b/l10n/ca.json @@ -43,7 +43,6 @@ "View details" : "Veure detalls", "Save" : "Guardar", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "Contingut Mixt Actiu no està permès. Es requereix la direcció HTTPS per a ONLYOFFICE Docs.", - "Restrict access to editors to following groups" : "Restringir l'accés a editors a següents grups", "review" : "", "form filling" : "", "comment" : "", diff --git a/l10n/da.js b/l10n/da.js index f82aed55..bba50686 100644 --- a/l10n/da.js +++ b/l10n/da.js @@ -45,7 +45,6 @@ OC.L10N.register( "View details": "Se detaljer", "Save": "Gem", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required.": "Blandet aktivt indhold er ikke tilladt. HTTPS-adresse for ONLYOFFICE Docs er påkrævet.", - "Restrict access to editors to following groups": "Begræns adgangen til redaktører til følgende grupper", "review": "Anmeldelse", "form filling": "Formular udfyldning", "comment": "Kommentar", diff --git a/l10n/da.json b/l10n/da.json index f651f019..4a558a42 100644 --- a/l10n/da.json +++ b/l10n/da.json @@ -43,7 +43,6 @@ "View details": "Se detaljer", "Save": "Gem", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required.": "Blandet aktivt indhold er ikke tilladt. HTTPS-adresse for ONLYOFFICE Docs er påkrævet.", - "Restrict access to editors to following groups": "Begræns adgangen til redaktører til følgende grupper", "review": "Anmeldelse", "form filling": "Formular udfyldning", "comment": "Kommentar", diff --git a/l10n/de.js b/l10n/de.js index 284937b8..65cfbc04 100644 --- a/l10n/de.js +++ b/l10n/de.js @@ -45,7 +45,7 @@ OC.L10N.register( "View details" : "Details anzeigen", "Save" : "Speichern", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "Mixed Active Content ist nicht möglich. HTTPS-Adresse für ONLYOFFICE Docs ist erforderlich.", - "Restrict access to editors to following groups" : "Den Zugriff auf Editoren auf folgende Gruppen gewähren", + "Allow the following groups to access the editors" : "Den Zugriff auf Editoren auf folgende Gruppen gewähren", "review" : "review", "form filling" : "ausfüllen von formularen", "comment" : "kommentarе", diff --git a/l10n/de.json b/l10n/de.json index 17a3e527..f33c723d 100644 --- a/l10n/de.json +++ b/l10n/de.json @@ -43,7 +43,7 @@ "View details" : "Details anzeigen", "Save" : "Speichern", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "Mixed Active Content ist nicht möglich. HTTPS-Adresse für ONLYOFFICE Docs ist erforderlich.", - "Restrict access to editors to following groups" : "Den Zugriff auf Editoren auf folgende Gruppen gewähren", + "Allow the following groups to access the editors" : "Den Zugriff auf Editoren auf folgende Gruppen gewähren", "review" : "review", "form filling" : "ausfüllen von formularen", "comment" : "kommentarе", diff --git a/l10n/de_DE.js b/l10n/de_DE.js index 647b3236..4229fe57 100644 --- a/l10n/de_DE.js +++ b/l10n/de_DE.js @@ -45,7 +45,7 @@ OC.L10N.register( "View details" : "Details anzeigen", "Save" : "Speichern", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "Mixed Active Content ist nicht möglich. HTTPS-Adresse für ONLYOFFICE Docs ist erforderlich.", - "Restrict access to editors to following groups" : "Den Zugriff auf Editoren auf folgende Gruppen gewähren", + "Allow the following groups to access the editors" : "Den Zugriff auf Editoren auf folgende Gruppen gewähren", "review" : "review", "form filling" : "ausfüllen von formularen", "comment" : "kommentarе", diff --git a/l10n/de_DE.json b/l10n/de_DE.json index 0d5502c8..05d424c7 100644 --- a/l10n/de_DE.json +++ b/l10n/de_DE.json @@ -43,7 +43,7 @@ "View details" : "Details anzeigen", "Save" : "Speichern", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "Mixed Active Content ist nicht möglich. HTTPS-Adresse für ONLYOFFICE Docs ist erforderlich.", - "Restrict access to editors to following groups" : "Den Zugriff auf Editoren auf folgende Gruppen gewähren", + "Allow the following groups to access the editors" : "Den Zugriff auf Editoren auf folgende Gruppen gewähren", "review" : "review", "form filling" : "ausfüllen von formularen", "comment" : "kommentarе", diff --git a/l10n/es.js b/l10n/es.js index 05e233d6..ada1556f 100644 --- a/l10n/es.js +++ b/l10n/es.js @@ -45,7 +45,6 @@ OC.L10N.register( "View details" : "Ver detalles", "Save" : "Guardar", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "Contenido Mixto Activo no está permitido. Se requiere la dirección HTTPS para ONLYOFFICE Docs.", - "Restrict access to editors to following groups" : "Restringir el acceso a editores a siguientes grupos", "review" : "revista", "form filling" : "relleno de formulario", "comment" : "comentarios", diff --git a/l10n/es.json b/l10n/es.json index 3508ec87..946741c4 100644 --- a/l10n/es.json +++ b/l10n/es.json @@ -43,7 +43,6 @@ "View details" : "Ver detalles", "Save" : "Guardar", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "Contenido Mixto Activo no está permitido. Se requiere la dirección HTTPS para ONLYOFFICE Docs.", - "Restrict access to editors to following groups" : "Restringir el acceso a editores a siguientes grupos", "review" : "revista", "form filling" : "relleno de formulario", "comment" : "comentarios", diff --git a/l10n/fr.js b/l10n/fr.js index fd532962..b0636bac 100644 --- a/l10n/fr.js +++ b/l10n/fr.js @@ -45,7 +45,6 @@ OC.L10N.register( "View details" : "Voir les détails", "Save" : "Enregistrer", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "Le contenu mixte actif n'est pas autorisé. Une adresse HTTPS pour le ONLYOFFICE Docs est requise", - "Restrict access to editors to following groups" : "Restreindre l'accès aux éditeurs pour les groupes suivants", "review" : "révision", "form filling" : "remplissage de formulaire", "comment" : "commentaire", diff --git a/l10n/fr.json b/l10n/fr.json index 637cc6e4..50d01b55 100644 --- a/l10n/fr.json +++ b/l10n/fr.json @@ -43,7 +43,6 @@ "View details" : "Voir les détails", "Save" : "Enregistrer", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "Le contenu mixte actif n'est pas autorisé. Une adresse HTTPS pour le ONLYOFFICE Docs est requise", - "Restrict access to editors to following groups" : "Restreindre l'accès aux éditeurs pour les groupes suivants", "review" : "révision", "form filling" : "remplissage de formulaire", "comment" : "commentaire", diff --git a/l10n/it.js b/l10n/it.js index 0c748d66..bb0c4372 100644 --- a/l10n/it.js +++ b/l10n/it.js @@ -45,7 +45,6 @@ OC.L10N.register( "View details" : "Vedi dettagli", "Save" : "Salva", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "Il contenuto attivo misto non è consentito. È richiesto l'indirizzo HTTPS per ONLYOFFICE Docs.", - "Restrict access to editors to following groups" : "Limita l'accesso degli editor ai seguenti gruppi", "review" : "Revisione", "form filling" : "Compilare un modulo", "comment" : "Commento", diff --git a/l10n/it.json b/l10n/it.json index 7d15e8b7..e94ec4f6 100644 --- a/l10n/it.json +++ b/l10n/it.json @@ -43,7 +43,6 @@ "View details" : "Vedi dettagli", "Save" : "Salva", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "Il contenuto attivo misto non è consentito. È richiesto l'indirizzo HTTPS per ONLYOFFICE Docs.", - "Restrict access to editors to following groups" : "Limita l'accesso degli editor ai seguenti gruppi", "review" : "Revisione", "form filling" : "Compilare un modulo", "comment" : "Commento", diff --git a/l10n/ja.js b/l10n/ja.js index 5cd04bf3..33f7d454 100644 --- a/l10n/ja.js +++ b/l10n/ja.js @@ -45,7 +45,6 @@ OC.L10N.register( "View details" : "詳細表示", "Save" : "保存", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "アクティブコンテンツの混在は許可されていません。ONLYOFFICE DocsにはHTTPSアドレスが必要です", - "Restrict access to editors to following groups": "エディターの利用を以下のグループに制限する", "review" : "レビュー", "form filling" : "フォーム入力", "comment" : "コメント", diff --git a/l10n/ja.json b/l10n/ja.json index cd9ceb55..bb6d80c9 100644 --- a/l10n/ja.json +++ b/l10n/ja.json @@ -43,7 +43,6 @@ "View details" : "詳細表示", "Save" : "保存", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "アクティブコンテンツの混在は許可されていません。ONLYOFFICE DocsにはHTTPSアドレスが必要です", - "Restrict access to editors to following groups" : "エディターの利用を以下のグループに制限する", "review" : "レビュー", "form filling" : "フォーム入力", "comment" : "コメント", diff --git a/l10n/nl.js b/l10n/nl.js index c77193e9..dba08aff 100644 --- a/l10n/nl.js +++ b/l10n/nl.js @@ -45,7 +45,6 @@ OC.L10N.register( "View details": "Bekijk details", "Save": "Opslaan", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required.": "Gemende Actieve Inhoud is niet toegestaan. HTTPS-adres voor ONLYOFFICE Docs is vereist.", - "Restrict access to editors to following groups": "Beperk de toegang tot editors tot de volgende groepen", "review": "overzicht", "form filling": "formulier invullen", "comment": "opmerking", diff --git a/l10n/nl.json b/l10n/nl.json index 572f5fa7..72bdab3c 100644 --- a/l10n/nl.json +++ b/l10n/nl.json @@ -43,7 +43,6 @@ "View details" : "Bekijk details", "Save" : "Opslaan", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "Gemende Actieve Inhoud is niet toegestaan. HTTPS-adres voor ONLYOFFICE Docs is vereist.", - "Restrict access to editors to following groups" : "Beperk de toegang tot editors tot de volgende groepen", "review" : "overzicht", "form filling" : "formulier invullen", "comment" : "opmerking", diff --git a/l10n/pl.js b/l10n/pl.js index 3d97e2f5..ef921d40 100644 --- a/l10n/pl.js +++ b/l10n/pl.js @@ -45,7 +45,6 @@ OC.L10N.register( "View details" : "Szczegóły", "Save" : "Zapisz", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "Aktywna Zawartość Mieszana nie jest dozwolona. Adres HTTPS jest wymagany dla ONLYOFFICE Docs.", - "Restrict access to editors to following groups" : "Ogranicz dostęp do edytorów dla tych grup", "review" : "recenzja", "form filling" : "wypełnianie formularza", "comment" : "komentarz", diff --git a/l10n/pl.json b/l10n/pl.json index 387688bd..9f4b0565 100644 --- a/l10n/pl.json +++ b/l10n/pl.json @@ -43,7 +43,6 @@ "View details" : "Szczegóły", "Save" : "Zapisz", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "Aktywna Zawartość Mieszana nie jest dozwolona. Adres HTTPS jest wymagany dla ONLYOFFICE Docs.", - "Restrict access to editors to following groups" : "Ogranicz dostęp do edytorów dla tych grup", "review" : "recenzja", "form filling" : "wypełnianie formularza", "comment" : "komentarz", diff --git a/l10n/pt_BR.js b/l10n/pt_BR.js index 9d041625..45ecad40 100644 --- a/l10n/pt_BR.js +++ b/l10n/pt_BR.js @@ -45,7 +45,7 @@ OC.L10N.register( "View details" : "Ver detalhes", "Save" : "Salvar", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "Conteúdo Misto não é permitido. É necessário um endereço HTTPS para o ONLYOFFICE Docs.", - "Restrict access to editors to following groups" : "Acesso apenas para os seguintes grupos", + "Allow the following groups to access the editors" : "Acesso apenas para os seguintes grupos", "review" : "revisar", "form filling" : "preenchimento de formularios", "comment" : "comente", diff --git a/l10n/pt_BR.json b/l10n/pt_BR.json index 5d084772..3b5bc105 100644 --- a/l10n/pt_BR.json +++ b/l10n/pt_BR.json @@ -43,7 +43,7 @@ "View details" : "Ver detalhes", "Save" : "Salvar", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "Conteúdo Misto não é permitido. É necessário um endereço HTTPS para o ONLYOFFICE Docs.", - "Restrict access to editors to following groups" : "Acesso apenas para os seguintes grupos", + "Allow the following groups to access the editors" : "Acesso apenas para os seguintes grupos", "review" : "revisar", "form filling" : "preenchimento de formularios", "comment" : "comente", diff --git a/l10n/ru.js b/l10n/ru.js index 104bf03a..7bcf1761 100644 --- a/l10n/ru.js +++ b/l10n/ru.js @@ -45,7 +45,7 @@ OC.L10N.register( "View details" : "Подробнее", "Save" : "Сохранить", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "Смешанное активное содержимое запрещено. Для ONLYOFFICE Docs необходимо использовать HTTPS-адрес.", - "Restrict access to editors to following groups" : "Дать доступ к редакторам только следующим группам", + "Allow the following groups to access the editors" : "Дать доступ к редакторам только следующим группам", "review" : "рецензирование", "form filling" : "заполнение форм", "comment" : "комментирование", diff --git a/l10n/ru.json b/l10n/ru.json index 3dcca661..8d16535d 100644 --- a/l10n/ru.json +++ b/l10n/ru.json @@ -43,7 +43,7 @@ "View details" : "Подробнее", "Save" : "Сохранить", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "Смешанное активное содержимое запрещено. Для ONLYOFFICE Docs необходимо использовать HTTPS-адрес.", - "Restrict access to editors to following groups" : "Дать доступ к редакторам только следующим группам", + "Allow the following groups to access the editors" : "Дать доступ к редакторам только следующим группам", "review" : "рецензирование", "form filling" : "заполнение форм", "comment" : "комментирование", diff --git a/l10n/sv.js b/l10n/sv.js index 736e8142..5155e451 100644 --- a/l10n/sv.js +++ b/l10n/sv.js @@ -45,7 +45,6 @@ OC.L10N.register( "View details" : "Visa detaljer", "Save" : "Spara", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "Blandat aktivt innehåll är inte tillåtet. HTTPS-adress till ONLYOFFICE Docs krävs.", - "Restrict access to editors to following groups" : "Begränsa åtkomst till följande grupper", "review" : "granska", "form filling" : "formulärfyllning", "comment" : "kommentar", diff --git a/l10n/sv.json b/l10n/sv.json index 69956b00..feb18cb4 100644 --- a/l10n/sv.json +++ b/l10n/sv.json @@ -43,7 +43,6 @@ "View details" : "Visa detaljer", "Save" : "Spara", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "Blandat aktivt innehåll är inte tillåtet. HTTPS-adress till ONLYOFFICE Docs krävs.", - "Restrict access to editors to following groups" : "Begränsa åtkomst till följande grupper", "review" : "granska", "form filling" : "formulärfyllning", "comment" : "kommentar", diff --git a/l10n/uk.js b/l10n/uk.js index e1fdfb0a..e6dbaf54 100644 --- a/l10n/uk.js +++ b/l10n/uk.js @@ -44,7 +44,7 @@ OC.L10N.register( "View details": "Докладно", "Save": "Зберегти", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required.": "Зміщаний активний вміст заборонено. Для використання ONLYOFFICE Docs потрібно використовувати безпечне HTTPS-з'єднання.", - "Restrict access to editors to following groups": "Надати доступ до редагування лише таким групам", + "Allow the following groups to access the editors": "Надати доступ до редагування лише таким групам", "review": "рецензії", "form filling": "заповнення форм", "comment": "коментарі", diff --git a/l10n/uk.json b/l10n/uk.json index de91615b..4b98d5ce 100644 --- a/l10n/uk.json +++ b/l10n/uk.json @@ -43,7 +43,7 @@ "View details": "Докладно", "Save": "Зберегти", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required.": "Зміщаний активний вміст заборонено. Для використання ONLYOFFICE Docs потрібно використовувати безпечне HTTPS-з'єднання.", - "Restrict access to editors to following groups": "Надати доступ до редагування лише таким групам", + "Allow the following groups to access the editors": "Надати доступ до редагування лише таким групам", "review": "рецензії", "form filling": "заповнення форм", "comment": "коментарі", diff --git a/l10n/zh_CN.js b/l10n/zh_CN.js index b356622a..70fd15f7 100644 --- a/l10n/zh_CN.js +++ b/l10n/zh_CN.js @@ -45,7 +45,7 @@ OC.L10N.register( "View details" : "查看详情", "Save" : "保存", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "不允许混合活动内容,请使用HTTPS连接ONLYOFFICE Docs。", - "Restrict access to editors to following groups" : "仅授权的用户组可以使用该服务", + "Allow the following groups to access the editors" : "仅授权的用户组可以使用该服务", "review" : "审阅", "form filling" : "表单填报", "comment" : "评论", diff --git a/l10n/zh_CN.json b/l10n/zh_CN.json index 3981b395..f2d0aca2 100644 --- a/l10n/zh_CN.json +++ b/l10n/zh_CN.json @@ -43,7 +43,7 @@ "View details" : "查看详情", "Save" : "保存", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "不允许混合活动内容,请使用HTTPS连接ONLYOFFICE Docs。", - "Restrict access to editors to following groups" : "仅授权的用户组可以使用该服务", + "Allow the following groups to access the editors" : "仅授权的用户组可以使用该服务", "review" : "审阅", "form filling" : "表单填报", "comment" : "评论", diff --git a/templates/settings.php b/templates/settings.php index ebd4c575..46d46d21 100644 --- a/templates/settings.php +++ b/templates/settings.php @@ -112,7 +112,7 @@

0) { ?>checked="checked" /> - +
" style="display: block; margin-top: 6px; width: 265px;" /> From c1c2a6ff6aa0198a7abb77f68dfcc3c00d6336d4 Mon Sep 17 00:00:00 2001 From: rivexe Date: Fri, 1 Mar 2024 13:49:59 +0300 Subject: [PATCH 094/114] fix: change custom filter to global --- js/share.js | 4 ++-- l10n/bg_BG.js | 1 - l10n/bg_BG.json | 1 - l10n/ca.js | 1 - l10n/ca.json | 1 - l10n/da.js | 1 - l10n/da.json | 1 - l10n/de.js | 1 - l10n/de.json | 1 - l10n/de_DE.js | 1 - l10n/de_DE.json | 1 - l10n/es.js | 1 - l10n/es.json | 1 - l10n/fr.js | 1 - l10n/fr.json | 1 - l10n/it.js | 1 - l10n/it.json | 1 - l10n/ja.js | 1 - l10n/ja.json | 1 - l10n/nl.js | 1 - l10n/nl.json | 1 - l10n/pl.js | 1 - l10n/pl.json | 1 - l10n/pt_BR.js | 1 - l10n/pt_BR.json | 1 - l10n/ru.js | 1 - l10n/ru.json | 1 - l10n/sv.js | 1 - l10n/sv.json | 1 - l10n/uk.js | 1 - l10n/uk.json | 2 +- l10n/zh_CN.js | 1 - l10n/zh_CN.json | 1 - 33 files changed, 3 insertions(+), 34 deletions(-) diff --git a/js/share.js b/js/share.js index a1364f54..7ae75725 100644 --- a/js/share.js +++ b/js/share.js @@ -341,7 +341,7 @@ } else if (attribute.key === "comment") { label = t(OCA.Onlyoffice.AppName, "comment"); } else if (attribute.key === "modifyFilter") { - label = t(OCA.Onlyoffice.AppName, "custom filter"); + label = t(OCA.Onlyoffice.AppName, "global filter"); } else { continue; } @@ -603,7 +603,7 @@ "scope": OCA.Onlyoffice.AppName, "key": "modifyFilter", "default": true, - "label": t(OCA.Onlyoffice.AppName, "custom filter"), + "label": t(OCA.Onlyoffice.AppName, "global filter"), "requiredPermissions": [OC.PERMISSION_UPDATE], "incompatibleAttributes": [ { diff --git a/l10n/bg_BG.js b/l10n/bg_BG.js index 240a5b3c..5acba786 100644 --- a/l10n/bg_BG.js +++ b/l10n/bg_BG.js @@ -49,7 +49,6 @@ OC.L10N.register( "review" : "преглед", "form filling" : "попълване на формуляр", "comment" : "коментар", - "custom filter" : "персонализиран филтър", "download" : "изтегли", "Server settings" : "Настройки на сървъра", "Common settings" : "Общи настройки", diff --git a/l10n/bg_BG.json b/l10n/bg_BG.json index e169214b..c72951c2 100644 --- a/l10n/bg_BG.json +++ b/l10n/bg_BG.json @@ -47,7 +47,6 @@ "review" : "преглед", "form filling" : "попълване на формуляр", "comment" : "коментар", - "custom filter" : "персонализиран филтър", "download" : "изтегли", "Server settings" : "Настройки на сървъра", "Common settings" : "Общи настройки", diff --git a/l10n/ca.js b/l10n/ca.js index d8c2649e..060e9343 100644 --- a/l10n/ca.js +++ b/l10n/ca.js @@ -49,7 +49,6 @@ OC.L10N.register( "review" : "", "form filling" : "", "comment" : "", - "custom filter" : "", "download" : "", "Server settings" : "Ajustos de servidor", "Common settings" : "Ajustos comuns", diff --git a/l10n/ca.json b/l10n/ca.json index 0d037d65..3ee9d2ec 100644 --- a/l10n/ca.json +++ b/l10n/ca.json @@ -47,7 +47,6 @@ "review" : "", "form filling" : "", "comment" : "", - "custom filter" : "", "download" : "", "Server settings" : "Ajustos de servidor", "Common settings" : "Ajustos comuns", diff --git a/l10n/da.js b/l10n/da.js index f82aed55..d6b3ff7f 100644 --- a/l10n/da.js +++ b/l10n/da.js @@ -49,7 +49,6 @@ OC.L10N.register( "review": "Anmeldelse", "form filling": "Formular udfyldning", "comment": "Kommentar", - "custom filter": "Brugerdefineret filter", "download": "Hent", "Server settings": "Serverindstillinger", "Common settings": "Fælles indstillinger", diff --git a/l10n/da.json b/l10n/da.json index f651f019..e9e04510 100644 --- a/l10n/da.json +++ b/l10n/da.json @@ -47,7 +47,6 @@ "review": "Anmeldelse", "form filling": "Formular udfyldning", "comment": "Kommentar", - "custom filter": "Brugerdefineret filter", "download": "Hent", "Server settings": "Serverindstillinger", "Common settings": "Fælles indstillinger", diff --git a/l10n/de.js b/l10n/de.js index 284937b8..f0d3e182 100644 --- a/l10n/de.js +++ b/l10n/de.js @@ -49,7 +49,6 @@ OC.L10N.register( "review" : "review", "form filling" : "ausfüllen von formularen", "comment" : "kommentarе", - "custom filter" : "benutzerdefinierter filter", "download" : "herunterladen", "Server settings" : "Servereinstellungen", "Common settings" : "Allgemeine Einstellungen", diff --git a/l10n/de.json b/l10n/de.json index 17a3e527..be7f250d 100644 --- a/l10n/de.json +++ b/l10n/de.json @@ -47,7 +47,6 @@ "review" : "review", "form filling" : "ausfüllen von formularen", "comment" : "kommentarе", - "custom filter" : "benutzerdefinierter filter", "download" : "herunterladen", "Server settings" : "Servereinstellungen", "Common settings" : "Allgemeine Einstellungen", diff --git a/l10n/de_DE.js b/l10n/de_DE.js index 647b3236..689bded9 100644 --- a/l10n/de_DE.js +++ b/l10n/de_DE.js @@ -49,7 +49,6 @@ OC.L10N.register( "review" : "review", "form filling" : "ausfüllen von formularen", "comment" : "kommentarе", - "custom filter" : "benutzerdefinierter filter", "download" : "herunterladen", "Server settings" : "Servereinstellungen", "Common settings" : "Allgemeine Einstellungen", diff --git a/l10n/de_DE.json b/l10n/de_DE.json index 0d5502c8..4b570073 100644 --- a/l10n/de_DE.json +++ b/l10n/de_DE.json @@ -47,7 +47,6 @@ "review" : "review", "form filling" : "ausfüllen von formularen", "comment" : "kommentarе", - "custom filter" : "benutzerdefinierter filter", "download" : "herunterladen", "Server settings" : "Servereinstellungen", "Common settings" : "Allgemeine Einstellungen", diff --git a/l10n/es.js b/l10n/es.js index 05e233d6..16d70efd 100644 --- a/l10n/es.js +++ b/l10n/es.js @@ -49,7 +49,6 @@ OC.L10N.register( "review" : "revista", "form filling" : "relleno de formulario", "comment" : "comentarios", - "custom filter" : "filtro personalizado", "download" : "descargar", "Server settings" : "Ajustes de servidor", "Common settings" : "Ajustes comunes", diff --git a/l10n/es.json b/l10n/es.json index 3508ec87..ced261b2 100644 --- a/l10n/es.json +++ b/l10n/es.json @@ -47,7 +47,6 @@ "review" : "revista", "form filling" : "relleno de formulario", "comment" : "comentarios", - "custom filter" : "filtro personalizado", "download" : "descargar", "Server settings" : "Ajustes de servidor", "Common settings" : "Ajustes comunes", diff --git a/l10n/fr.js b/l10n/fr.js index fd532962..175b1a51 100644 --- a/l10n/fr.js +++ b/l10n/fr.js @@ -49,7 +49,6 @@ OC.L10N.register( "review" : "révision", "form filling" : "remplissage de formulaire", "comment" : "commentaire", - "custom filter" : "filtre personnalisé", "download" : "télécharger", "Server settings" : "Paramètres du serveur", "Common settings" : "Paramètres communs", diff --git a/l10n/fr.json b/l10n/fr.json index 637cc6e4..fab02059 100644 --- a/l10n/fr.json +++ b/l10n/fr.json @@ -47,7 +47,6 @@ "review" : "révision", "form filling" : "remplissage de formulaire", "comment" : "commentaire", - "custom filter" : "filtre personnalisé", "download" : "télécharger", "Server settings" : "Paramètres du serveur", "Common settings" : "Paramètres communs", diff --git a/l10n/it.js b/l10n/it.js index 0c748d66..7f0bd542 100644 --- a/l10n/it.js +++ b/l10n/it.js @@ -49,7 +49,6 @@ OC.L10N.register( "review" : "Revisione", "form filling" : "Compilare un modulo", "comment" : "Commento", - "custom filter" : "Filtro personalizzato", "download" : "Scarica", "Server settings" : "Impostazioni del server", "Common settings" : "Impostazioni comuni", diff --git a/l10n/it.json b/l10n/it.json index 7d15e8b7..5385d69a 100644 --- a/l10n/it.json +++ b/l10n/it.json @@ -47,7 +47,6 @@ "review" : "Revisione", "form filling" : "Compilare un modulo", "comment" : "Commento", - "custom filter" : "Filtro personalizzato", "download" : "Scarica", "Server settings" : "Impostazioni del server", "Common settings" : "Impostazioni comuni", diff --git a/l10n/ja.js b/l10n/ja.js index 5cd04bf3..6ca47202 100644 --- a/l10n/ja.js +++ b/l10n/ja.js @@ -49,7 +49,6 @@ OC.L10N.register( "review" : "レビュー", "form filling" : "フォーム入力", "comment" : "コメント", - "custom filter" : "ユーザー設定フィルター", "download" : "ダウンロード", "Server settings" : "サーバー設定", "Common settings" : "共通設定", diff --git a/l10n/ja.json b/l10n/ja.json index cd9ceb55..ebd5880b 100644 --- a/l10n/ja.json +++ b/l10n/ja.json @@ -47,7 +47,6 @@ "review" : "レビュー", "form filling" : "フォーム入力", "comment" : "コメント", - "custom filter" : "ユーザー設定フィルター", "download" : "ダウンロード", "Server settings" : "サーバー設定", "Common settings" : "共通設定", diff --git a/l10n/nl.js b/l10n/nl.js index c77193e9..76d363bf 100644 --- a/l10n/nl.js +++ b/l10n/nl.js @@ -49,7 +49,6 @@ OC.L10N.register( "review": "overzicht", "form filling": "formulier invullen", "comment": "opmerking", - "custom filter": "aangepast filter", "download": "downloaden", "Server settings": "Serverinstellingen", "Common settings": "Algemene instellingen", diff --git a/l10n/nl.json b/l10n/nl.json index 572f5fa7..c4cd2e61 100644 --- a/l10n/nl.json +++ b/l10n/nl.json @@ -47,7 +47,6 @@ "review" : "overzicht", "form filling" : "formulier invullen", "comment" : "opmerking", - "custom filter" : "aangepast filter", "download" : "downloaden", "Server settings" : "Serverinstellingen", "Common settings" : "Algemene instellingen", diff --git a/l10n/pl.js b/l10n/pl.js index 3d97e2f5..7962ecc8 100644 --- a/l10n/pl.js +++ b/l10n/pl.js @@ -49,7 +49,6 @@ OC.L10N.register( "review" : "recenzja", "form filling" : "wypełnianie formularza", "comment" : "komentarz", - "custom filter" : "niestandardowy filtr", "download" : "pobierz", "Server settings" : "Ustawienia serwera", "Common settings" : "Ustawienia ogólne", diff --git a/l10n/pl.json b/l10n/pl.json index 387688bd..66371c3b 100644 --- a/l10n/pl.json +++ b/l10n/pl.json @@ -47,7 +47,6 @@ "review" : "recenzja", "form filling" : "wypełnianie formularza", "comment" : "komentarz", - "custom filter" : "niestandardowy filtr", "download" : "pobierz", "Server settings" : "Ustawienia serwera", "Common settings" : "Ustawienia ogólne", diff --git a/l10n/pt_BR.js b/l10n/pt_BR.js index 9d041625..c33894e3 100644 --- a/l10n/pt_BR.js +++ b/l10n/pt_BR.js @@ -49,7 +49,6 @@ OC.L10N.register( "review" : "revisar", "form filling" : "preenchimento de formularios", "comment" : "comente", - "custom filter" : "filtro personalizado", "download" : "baixar", "Server settings" : "Configurações do servidor", "Common settings" : "Configurações comuns", diff --git a/l10n/pt_BR.json b/l10n/pt_BR.json index 5d084772..204f100c 100644 --- a/l10n/pt_BR.json +++ b/l10n/pt_BR.json @@ -47,7 +47,6 @@ "review" : "revisar", "form filling" : "preenchimento de formularios", "comment" : "comente", - "custom filter" : "filtro personalizado", "download" : "baixar", "Server settings" : "Configurações do servidor", "Common settings" : "Configurações comuns", diff --git a/l10n/ru.js b/l10n/ru.js index 104bf03a..80f1e588 100644 --- a/l10n/ru.js +++ b/l10n/ru.js @@ -49,7 +49,6 @@ OC.L10N.register( "review" : "рецензирование", "form filling" : "заполнение форм", "comment" : "комментирование", - "custom filter" : "пользовательский фильтр", "download" : "скачивание", "Server settings" : "Настройки сервера", "Common settings" : "Общие настройки", diff --git a/l10n/ru.json b/l10n/ru.json index 3dcca661..27039f65 100644 --- a/l10n/ru.json +++ b/l10n/ru.json @@ -47,7 +47,6 @@ "review" : "рецензирование", "form filling" : "заполнение форм", "comment" : "комментирование", - "custom filter" : "пользовательский фильтр", "download" : "скачивание", "Server settings" : "Настройки сервера", "Common settings" : "Общие настройки", diff --git a/l10n/sv.js b/l10n/sv.js index 736e8142..f824e8b4 100644 --- a/l10n/sv.js +++ b/l10n/sv.js @@ -49,7 +49,6 @@ OC.L10N.register( "review" : "granska", "form filling" : "formulärfyllning", "comment" : "kommentar", - "custom filter" : "anpassat filter", "download" : "ladda ner", "Server settings" : "Serverinställningar", "Common settings" : "Allmänna inställningar", diff --git a/l10n/sv.json b/l10n/sv.json index 69956b00..e5d4052f 100644 --- a/l10n/sv.json +++ b/l10n/sv.json @@ -47,7 +47,6 @@ "review" : "granska", "form filling" : "formulärfyllning", "comment" : "kommentar", - "custom filter" : "anpassat filter", "download" : "ladda ner", "Server settings" : "Serverinställningar", "Common settings" : "Allmänna inställningar", diff --git a/l10n/uk.js b/l10n/uk.js index e1fdfb0a..5c42a329 100644 --- a/l10n/uk.js +++ b/l10n/uk.js @@ -48,7 +48,6 @@ OC.L10N.register( "review": "рецензії", "form filling": "заповнення форм", "comment": "коментарі", - "custom filter": "користувацький фільтр", "download": "звантажити", "Server settings": "Налаштування сервера", "Common settings": "Загальні налаштування", diff --git a/l10n/uk.json b/l10n/uk.json index de91615b..249395dd 100644 --- a/l10n/uk.json +++ b/l10n/uk.json @@ -47,7 +47,7 @@ "review": "рецензії", "form filling": "заповнення форм", "comment": "коментарі", - "custom filter": "користувацький фільтр", + "download": "звантажити", "Server settings": "Налаштування сервера", "Common settings": "Загальні налаштування", diff --git a/l10n/zh_CN.js b/l10n/zh_CN.js index b356622a..a40f8aca 100644 --- a/l10n/zh_CN.js +++ b/l10n/zh_CN.js @@ -49,7 +49,6 @@ OC.L10N.register( "review" : "审阅", "form filling" : "表单填报", "comment" : "评论", - "custom filter" : "自定义筛选器", "download" : "下载", "Server settings" : "服务器设置", "Common settings" : "常用设置", diff --git a/l10n/zh_CN.json b/l10n/zh_CN.json index 3981b395..b8c80a87 100644 --- a/l10n/zh_CN.json +++ b/l10n/zh_CN.json @@ -47,7 +47,6 @@ "review" : "审阅", "form filling" : "表单填报", "comment" : "评论", - "custom filter" : "自定义筛选器", "download" : "下载", "Server settings" : "服务器设置", "Common settings" : "常用设置", From d6ae5c8718d9de82b851eeb877b72559ad4c2652 Mon Sep 17 00:00:00 2001 From: Sergey Linnik Date: Fri, 1 Mar 2024 19:00:02 +0300 Subject: [PATCH 095/114] ru translation --- l10n/ru.js | 1 + l10n/ru.json | 1 + l10n/uk.json | 1 - 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/l10n/ru.js b/l10n/ru.js index 80f1e588..1de595c5 100644 --- a/l10n/ru.js +++ b/l10n/ru.js @@ -49,6 +49,7 @@ OC.L10N.register( "review" : "рецензирование", "form filling" : "заполнение форм", "comment" : "комментирование", + "global filter" : "глобальный фильтр", "download" : "скачивание", "Server settings" : "Настройки сервера", "Common settings" : "Общие настройки", diff --git a/l10n/ru.json b/l10n/ru.json index 27039f65..94457b2f 100644 --- a/l10n/ru.json +++ b/l10n/ru.json @@ -47,6 +47,7 @@ "review" : "рецензирование", "form filling" : "заполнение форм", "comment" : "комментирование", + "global filter" : "глобальный фильтр", "download" : "скачивание", "Server settings" : "Настройки сервера", "Common settings" : "Общие настройки", diff --git a/l10n/uk.json b/l10n/uk.json index 249395dd..318b38f4 100644 --- a/l10n/uk.json +++ b/l10n/uk.json @@ -47,7 +47,6 @@ "review": "рецензії", "form filling": "заповнення форм", "comment": "коментарі", - "download": "звантажити", "Server settings": "Налаштування сервера", "Common settings": "Загальні налаштування", From d8d02264db23b04f6f6e3526dbdd0ffd61d39e43 Mon Sep 17 00:00:00 2001 From: rivexe Date: Mon, 4 Mar 2024 10:12:22 +0300 Subject: [PATCH 096/114] fix: don't zoom the page when the user clicks on the canvas --- js/editor.js | 6 ++++++ js/listener.js | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/js/editor.js b/js/editor.js index 512df2a0..0697cdfc 100644 --- a/js/editor.js +++ b/js/editor.js @@ -267,6 +267,8 @@ if (OCA.Onlyoffice.version > 0) { OCA.Onlyoffice.onRequestHistory(OCA.Onlyoffice.version); } + + OCA.Onlyoffice.setViewport(); }; OCA.Onlyoffice.onRequestSaveAs = function (event) { @@ -661,6 +663,10 @@ OCA.Onlyoffice.docEditor.refreshHistory(data); } + OCA.Onlyoffice.setViewport = function() { + document.querySelector('meta[name="viewport"]').setAttribute("content","width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"); + }; + $(document).ready(OCA.Onlyoffice.InitEditor); })(jQuery, OCA); diff --git a/js/listener.js b/js/listener.js index e7d41af5..12df57f6 100644 --- a/js/listener.js +++ b/js/listener.js @@ -88,12 +88,18 @@ } else { OCA.Onlyoffice.unbindVersionClick(); } + + OCA.Onlyoffice.setViewport(); }; OCA.Onlyoffice.changeFavicon = function (favicon) { $('link[rel="icon"]').attr("href", favicon); }; + OCA.Onlyoffice.setViewport = function() { + document.querySelector('meta[name="viewport"]').setAttribute("content","width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"); + }; + OCA.Onlyoffice.onShowMessage = function (messageObj) { OC.Notification.show(messageObj.message, messageObj.props); } From c12a5da25885c73436ef2eec9c06f372b2329b7e Mon Sep 17 00:00:00 2001 From: rivexe Date: Mon, 4 Mar 2024 10:18:40 +0300 Subject: [PATCH 097/114] fix: saveas file url vulnerability --- controller/editorcontroller.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/controller/editorcontroller.php b/controller/editorcontroller.php index db269095..383b4cf9 100644 --- a/controller/editorcontroller.php +++ b/controller/editorcontroller.php @@ -761,6 +761,18 @@ public function save($name, $dir, $url) { return ["error" => $this->trans->t("You don't have enough permission to create")]; } + $documentServerUrl = $this->config->getDocumentServerUrl(); + + if (empty($documentServerUrl)) { + $this->logger->error("documentServerUrl is empty", ["app" => $this->appName]); + return ["error" => $this->trans->t("ONLYOFFICE app is not configured. Please contact admin")]; + } + + if (parse_url($url, PHP_URL_HOST) !== parse_url($documentServerUrl, PHP_URL_HOST)) { + $this->logger->error("Incorrect domain in file url", ["app" => $this->appName]); + return ["error" => $this->trans->t("The domain in the file url does not match the domain of the Document server")]; + } + $url = $this->config->replaceDocumentServerUrlToInternal($url); try { From 53bbc2d14e890b88e804d2df82f4a83bdc04f7cc Mon Sep 17 00:00:00 2001 From: rivexe Date: Mon, 4 Mar 2024 10:19:17 +0300 Subject: [PATCH 098/114] feat: translations added --- l10n/ru.js | 3 ++- l10n/ru.json | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/l10n/ru.js b/l10n/ru.js index 493ec51a..9ed026a7 100644 --- a/l10n/ru.js +++ b/l10n/ru.js @@ -126,6 +126,7 @@ OC.L10N.register( "Select file to combine" : "Выбрать файл для объединения", "Select data source": "Выбрать источник данных", "The data source must not be the current document": "Источником данных не должен быть текущий документ", - "Enable background connection check to the editors": "Включить фоновую проверку подключения к редакторам" + "Enable background connection check to the editors": "Включить фоновую проверку подключения к редакторам", + "The domain in the file url does not match the domain of the Document server": "Домен в адресе файла не соответствует домену сервера документов" }, "nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);"); diff --git a/l10n/ru.json b/l10n/ru.json index 7fca1dc2..dbbbe8d2 100644 --- a/l10n/ru.json +++ b/l10n/ru.json @@ -124,6 +124,7 @@ "Select file to combine" : "Выбрать файл для объединения", "Select data source": "Выбрать источник данных", "The data source must not be the current document": "Источником данных не должен быть текущий документ", - "Enable background connection check to the editors": "Включить фоновую проверку подключения к редакторам" + "Enable background connection check to the editors": "Включить фоновую проверку подключения к редакторам", + "The domain in the file url does not match the domain of the Document server": "Домен в адресе файла не соответствует домену сервера документов" },"pluralForm" :"nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);" } \ No newline at end of file From 35311949e85ac2de835378430a131d4ccab848ed Mon Sep 17 00:00:00 2001 From: rivexe Date: Mon, 4 Mar 2024 13:13:59 +0300 Subject: [PATCH 099/114] fix: user id in avatar url --- controller/editorcontroller.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controller/editorcontroller.php b/controller/editorcontroller.php index 4fe95373..b2d97e77 100644 --- a/controller/editorcontroller.php +++ b/controller/editorcontroller.php @@ -452,7 +452,7 @@ public function userInfo($userIds) { $this->urlGenerator->linkToRoute( "core.avatar.getAvatar", [ - "userId" => $userId, + "userId" => $user->getUID(), "size" => 64, ] ) From f2b006472e4e9298bd6900f4b78094d03a295abf Mon Sep 17 00:00:00 2001 From: Sergey Linnik Date: Mon, 4 Mar 2024 14:47:51 +0300 Subject: [PATCH 100/114] reorder changelog --- CHANGELOG.md | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 02413487..a1fd3657 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,22 +1,23 @@ # Change Log -### Changed -- compatible with ownCloud Web 7.0 -- list of users to protect ranges of cells -- offline viewer for share link -- updatable list of supported formats -- filling pdf instead oform -- fixed guest redirect when limiting the app to groups -- fixed mobile editor size - +## ## Added -- reference data from coediting +- support of user avatar in editor +- list of users to protect ranges of cells +- setting for disable editors cron check - selecting a document to combine from the storage -- Arabic and Serbian empty file templates +- reference data from coediting - opening a reference data source - changing a reference data source -- setting for disable editors cron check -- support of user avatar in editor +- Arabic and Serbian empty file templates + +## Changed +- fixed guest redirect when limiting the app to groups +- fixed mobile editor size +- offline viewer for share link +- updatable list of supported formats +- filling pdf instead oform +- compatible with ownCloud Web 7.0 ## 8.2.3 ## Added From 60d0484709c2500888dd2c3c564ed62a1e330f77 Mon Sep 17 00:00:00 2001 From: Sergey Linnik Date: Mon, 4 Mar 2024 14:50:20 +0300 Subject: [PATCH 101/114] 9.1.1 --- CHANGELOG.md | 2 +- appinfo/info.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a1fd3657..46857e0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Change Log -## +## 9.1.1 ## Added - support of user avatar in editor - list of users to protect ranges of cells diff --git a/appinfo/info.xml b/appinfo/info.xml index 550ad6af..4daac1be 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -6,7 +6,7 @@ ONLYOFFICE connector allows you to view, edit and collaborate on text documents, spreadsheets and presentations within ownCloud using ONLYOFFICE Docs. This will create a new Edit in ONLYOFFICE action within the document library for Office documents. This allows multiple users to co-author documents in real time from the familiar web interface and save the changes back to your file storage. apl2 Ascensio System SIA - 8.2.3 + 9.1.1 Onlyoffice From e4c5babcd7fb11f7fcda268602d72c5bd376eb4c Mon Sep 17 00:00:00 2001 From: Maria-Sukhova Date: Tue, 5 Mar 2024 19:00:55 +0300 Subject: [PATCH 102/114] updated translations --- l10n/de.js | 15 ++++++++++++--- l10n/de.json | 13 +++++++++++-- l10n/de_DE.js | 15 ++++++++++++--- l10n/de_DE.json | 13 +++++++++++-- l10n/es.js | 16 +++++++++++++--- l10n/es.json | 12 +++++++++++- l10n/fr.js | 16 +++++++++++++--- l10n/fr.json | 12 +++++++++++- l10n/it.js | 16 +++++++++++++--- l10n/it.json | 12 +++++++++++- l10n/ja.js | 16 +++++++++++++--- l10n/ja.json | 12 +++++++++++- l10n/pt_BR.js | 15 ++++++++++++--- l10n/pt_BR.json | 13 +++++++++++-- l10n/zh_CN.js | 15 ++++++++++++--- l10n/zh_CN.json | 13 +++++++++++-- 16 files changed, 188 insertions(+), 36 deletions(-) diff --git a/l10n/de.js b/l10n/de.js index 6fb3a59b..e23c4eed 100644 --- a/l10n/de.js +++ b/l10n/de.js @@ -45,11 +45,12 @@ OC.L10N.register( "View details" : "Details anzeigen", "Save" : "Speichern", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "Mixed Active Content ist nicht möglich. HTTPS-Adresse für ONLYOFFICE Docs ist erforderlich.", - "Allow the following groups to access the editors" : "Den Zugriff auf Editoren auf folgende Gruppen gewähren", + "Allow the following groups to access the editors": "Den folgenden Gruppen den Zugriff auf die Editoren erlauben", "review" : "review", "form filling" : "ausfüllen von formularen", "comment" : "kommentarе", - "download" : "herunterladen", + "global filter": "Globaler Filter", + "download": "herunterladen", "Server settings" : "Servereinstellungen", "Common settings" : "Allgemeine Einstellungen", "Editor customization settings" : "Editor-Einstellungen", @@ -99,8 +100,11 @@ OC.L10N.register( "Notification sent successfully": "Benachrichtigung erfolgreich gesendet", "%1\$s mentioned in the %2\$s: \"%3\$s\".": "%1\$s hat dich in %2\$s erwähnt: \"%3\$s\".", "Choose a format to convert {fileName}": "Wählen Sie das Format für {fileName} aus", + "PDF form": "PDF-Formular", + "PDF form from existing text file": "PDF-Formular aus vorhandener Textdatei", "Create form": "Formular erstellen", "Fill in form in ONLYOFFICE": "Formular in ONLYOFFICE ausfüllen", + "Create new PDF form": "Neues PDF-Formular erstellen", "Security": "Sicherheit", "Run document macros": "Makros im Dokument ausführen", "Default editor theme": "Standardmäßiges Thema des Editors", @@ -118,6 +122,11 @@ OC.L10N.register( "View settings": "Einstellungen anzeigen", "ONLYOFFICE Docs Cloud": "ONLYOFFICE Docs Cloud", "Easily launch the editors in the cloud without downloading and installation": "Öffnen Sie die Editoren in der Cloud einfach ohne Herunterladen und Installation", - "Get Now": "Jetzt erhalten" + "Get Now": "Jetzt erhalten", + "Select file to combine": "Datei zum Kombinieren auswählen", + "Select data source": "Datenquelle auswählen", + "The data source must not be the current document": "Die Datenquelle darf nicht das aktuelle Dokument sein", + "Enable background connection check to the editors": "Die Hintergrund-Verbindungsprüfung zu den Editoren erlauben", + "The domain in the file url does not match the domain of the Document server": "Die Domäne in der Datei-URL stimmt nicht mit der Domäne von Document Server überein" }, "nplurals=2; plural=(n != 1);"); diff --git a/l10n/de.json b/l10n/de.json index 4299db1c..1517db62 100644 --- a/l10n/de.json +++ b/l10n/de.json @@ -43,10 +43,11 @@ "View details" : "Details anzeigen", "Save" : "Speichern", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "Mixed Active Content ist nicht möglich. HTTPS-Adresse für ONLYOFFICE Docs ist erforderlich.", - "Allow the following groups to access the editors" : "Den Zugriff auf Editoren auf folgende Gruppen gewähren", + "Allow the following groups to access the editors" : "Den folgenden Gruppen den Zugriff auf die Editoren erlauben", "review" : "review", "form filling" : "ausfüllen von formularen", "comment" : "kommentarе", + "global filter" : "Globaler Filter", "download" : "herunterladen", "Server settings" : "Servereinstellungen", "Common settings" : "Allgemeine Einstellungen", @@ -97,8 +98,11 @@ "Notification sent successfully": "Benachrichtigung erfolgreich gesendet", "%1$s mentioned in the %2$s: \"%3$s\".": "%1$s hat dich in %2$s erwähnt: \"%3$s\".", "Choose a format to convert {fileName}": "Wählen Sie das Format für {fileName} aus", + "PDF form": "PDF-Formular", + "PDF form from existing text file": "PDF-Formular aus vorhandener Textdatei", "Create form": "Formular erstellen", "Fill in form in ONLYOFFICE": "Formular in ONLYOFFICE ausfüllen", + "Create new PDF form": "Neues PDF-Formular erstellen", "Security": "Sicherheit", "Run document macros": "Makros im Dokument ausführen", "Default editor theme": "Standardmäßiges Thema des Editors", @@ -116,6 +120,11 @@ "View settings": "Einstellungen anzeigen", "ONLYOFFICE Docs Cloud": "ONLYOFFICE Docs Cloud", "Easily launch the editors in the cloud without downloading and installation": "Öffnen Sie die Editoren in der Cloud einfach ohne Herunterladen und Installation", - "Get Now": "Jetzt erhalten" + "Get Now": "Jetzt erhalten", + "Select file to combine" : "Datei zum Kombinieren auswählen", + "Select data source": "Datenquelle auswählen", + "The data source must not be the current document": "Die Datenquelle darf nicht das aktuelle Dokument sein", + "Enable background connection check to the editors": "Die Hintergrund-Verbindungsprüfung zu den Editoren erlauben", + "The domain in the file url does not match the domain of the Document server": "Die Domäne in der Datei-URL stimmt nicht mit der Domäne von Document Server überein" },"pluralForm" :"nplurals=2; plural=(n != 1);" } \ No newline at end of file diff --git a/l10n/de_DE.js b/l10n/de_DE.js index 2854ec14..be96a38f 100644 --- a/l10n/de_DE.js +++ b/l10n/de_DE.js @@ -45,11 +45,12 @@ OC.L10N.register( "View details" : "Details anzeigen", "Save" : "Speichern", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "Mixed Active Content ist nicht möglich. HTTPS-Adresse für ONLYOFFICE Docs ist erforderlich.", - "Allow the following groups to access the editors" : "Den Zugriff auf Editoren auf folgende Gruppen gewähren", + "Allow the following groups to access the editors": "Den folgenden Gruppen den Zugriff auf die Editoren erlauben", "review" : "review", "form filling" : "ausfüllen von formularen", "comment" : "kommentarе", - "download" : "herunterladen", + "global filter": "Globaler Filter", + "download": "herunterladen", "Server settings" : "Servereinstellungen", "Common settings" : "Allgemeine Einstellungen", "Editor customization settings" : "Editor-Einstellungen", @@ -99,8 +100,11 @@ OC.L10N.register( "Notification sent successfully": "Benachrichtigung erfolgreich gesendet", "%1\$s mentioned in the %2\$s: \"%3\$s\".": "%1\$s hat dich in %2\$s erwähnt: \"%3\$s\".", "Choose a format to convert {fileName}": "Wählen Sie das Format für {fileName} aus", + "PDF form": "PDF-Formular", + "PDF form from existing text file": "PDF-Formular aus vorhandener Textdatei", "Create form": "Formular erstellen", "Fill in form in ONLYOFFICE": "Formular in ONLYOFFICE ausfüllen", + "Create new PDF form": "Neues PDF-Formular erstellen", "Security": "Sicherheit", "Run document macros": "Makros im Dokument ausführen", "Default editor theme": "Standardmäßiges Thema des Editors", @@ -118,6 +122,11 @@ OC.L10N.register( "View settings": "Einstellungen anzeigen", "ONLYOFFICE Docs Cloud": "ONLYOFFICE Docs Cloud", "Easily launch the editors in the cloud without downloading and installation": "Öffnen Sie die Editoren in der Cloud einfach ohne Herunterladen und Installation", - "Get Now": "Jetzt erhalten" + "Get Now": "Jetzt erhalten", + "Select file to combine": "Datei zum Kombinieren auswählen", + "Select data source": "Datenquelle auswählen", + "The data source must not be the current document": "Die Datenquelle darf nicht das aktuelle Dokument sein", + "Enable background connection check to the editors": "Die Hintergrund-Verbindungsprüfung zu den Editoren erlauben", + "The domain in the file url does not match the domain of the Document server": "Die Domäne in der Datei-URL stimmt nicht mit der Domäne von Document Server überein" }, "nplurals=2; plural=(n != 1);"); diff --git a/l10n/de_DE.json b/l10n/de_DE.json index db670481..8a9bf9c9 100644 --- a/l10n/de_DE.json +++ b/l10n/de_DE.json @@ -43,10 +43,11 @@ "View details" : "Details anzeigen", "Save" : "Speichern", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "Mixed Active Content ist nicht möglich. HTTPS-Adresse für ONLYOFFICE Docs ist erforderlich.", - "Allow the following groups to access the editors" : "Den Zugriff auf Editoren auf folgende Gruppen gewähren", + "Allow the following groups to access the editors" : "Den folgenden Gruppen den Zugriff auf die Editoren erlauben", "review" : "review", "form filling" : "ausfüllen von formularen", "comment" : "kommentarе", + "global filter" : "Globaler Filter", "download" : "herunterladen", "Server settings" : "Servereinstellungen", "Common settings" : "Allgemeine Einstellungen", @@ -97,8 +98,11 @@ "Notification sent successfully": "Benachrichtigung erfolgreich gesendet", "%1$s mentioned in the %2$s: \"%3$s\".": "%1$s hat dich in %2$s erwähnt: \"%3$s\".", "Choose a format to convert {fileName}": "Wählen Sie das Format für {fileName} aus", + "PDF form": "PDF-Formular", + "PDF form from existing text file": "PDF-Formular aus vorhandener Textdatei", "Create form": "Formular erstellen", "Fill in form in ONLYOFFICE": "Formular in ONLYOFFICE ausfüllen", + "Create new PDF form": "Neues PDF-Formular erstellen", "Security": "Sicherheit", "Run document macros": "Makros im Dokument ausführen", "Default editor theme": "Standardmäßiges Thema des Editors", @@ -116,6 +120,11 @@ "View settings": "Einstellungen anzeigen", "ONLYOFFICE Docs Cloud": "ONLYOFFICE Docs Cloud", "Easily launch the editors in the cloud without downloading and installation": "Öffnen Sie die Editoren in der Cloud einfach ohne Herunterladen und Installation", - "Get Now": "Jetzt erhalten" + "Get Now": "Jetzt erhalten", + "Select file to combine" : "Datei zum Kombinieren auswählen", + "Select data source": "Datenquelle auswählen", + "The data source must not be the current document": "Die Datenquelle darf nicht das aktuelle Dokument sein", + "Enable background connection check to the editors": "Die Hintergrund-Verbindungsprüfung zu den Editoren erlauben", + "The domain in the file url does not match the domain of the Document server": "Die Domäne in der Datei-URL stimmt nicht mit der Domäne von Document Server überein" },"pluralForm" :"nplurals=2; plural=(n != 1);" } \ No newline at end of file diff --git a/l10n/es.js b/l10n/es.js index afd6555f..091bc6f8 100644 --- a/l10n/es.js +++ b/l10n/es.js @@ -45,10 +45,12 @@ OC.L10N.register( "View details" : "Ver detalles", "Save" : "Guardar", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "Contenido Mixto Activo no está permitido. Se requiere la dirección HTTPS para ONLYOFFICE Docs.", - "review" : "revista", + "Allow the following groups to access the editors": "Permitir a los siguientes grupos acceder a los editores", + "review": "revista", "form filling" : "relleno de formulario", "comment" : "comentarios", - "download" : "descargar", + "global filter": "filtro global", + "download": "descargar", "Server settings" : "Ajustes de servidor", "Common settings" : "Ajustes comunes", "Editor customization settings" : "Ajustes del editor", @@ -98,8 +100,11 @@ OC.L10N.register( "Notification sent successfully": "Notificación enviada correctamente", "%1\$s mentioned in the %2\$s: \"%3\$s\".": "%1\$s le ha mencionado en %2\$s: \"%3\$s\".", "Choose a format to convert {fileName}": "Elija un formato para convertir {fileName}", + "PDF form": "Formulario PDF", + "PDF form from existing text file": "Formulario PDF a partir de un archivo de texto existente", "Create form": "Crear formulario", "Fill in form in ONLYOFFICE": "Rellenar el formulario en ONLYOFFICE", + "Create new PDF form": "Crear nuevo formulario PDF", "Security": "Seguridad", "Run document macros": "Ejecutar macros de documentos", "Default editor theme": "Tema del editor predeterminado", @@ -117,6 +122,11 @@ OC.L10N.register( "View settings": "Ver configuración", "ONLYOFFICE Docs Cloud": "ONLYOFFICE Docs Cloud", "Easily launch the editors in the cloud without downloading and installation": "Inicie fácilmente los editores en la nube sin tener que descargarlos ni instalarlos", - "Get Now": "Obtener ahora" + "Get Now": "Obtener ahora", + "Select file to combine": "Seleccionar archivo para combinar", + "Select data source": "Seleccionar fuente de datos", + "The data source must not be the current document": "La fuente de datos no debe ser el documento actual", + "Enable background connection check to the editors": "Activar la comprobación de conexión en segundo plano con los editores", + "The domain in the file url does not match the domain of the Document server": "El dominio de la URL del archivo no coincide con el dominio del Servidor de documentos" }, "nplurals=2; plural=(n != 1);"); diff --git a/l10n/es.json b/l10n/es.json index 2924e886..84e00364 100644 --- a/l10n/es.json +++ b/l10n/es.json @@ -43,9 +43,11 @@ "View details" : "Ver detalles", "Save" : "Guardar", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "Contenido Mixto Activo no está permitido. Se requiere la dirección HTTPS para ONLYOFFICE Docs.", + "Allow the following groups to access the editors" : "Permitir a los siguientes grupos acceder a los editores", "review" : "revista", "form filling" : "relleno de formulario", "comment" : "comentarios", + "global filter" : "filtro global", "download" : "descargar", "Server settings" : "Ajustes de servidor", "Common settings" : "Ajustes comunes", @@ -96,8 +98,11 @@ "Notification sent successfully": "Notificación enviada correctamente", "%1$s mentioned in the %2$s: \"%3$s\".": "%1$s le ha mencionado en %2$s: \"%3$s\".", "Choose a format to convert {fileName}": "Elija un formato para convertir {fileName}", + "PDF form": "Formulario PDF", + "PDF form from existing text file": "Formulario PDF a partir de un archivo de texto existente", "Create form": "Crear formulario", "Fill in form in ONLYOFFICE": "Rellenar el formulario en ONLYOFFICE", + "Create new PDF form": "Crear nuevo formulario PDF", "Security": "Seguridad", "Run document macros": "Ejecutar macros de documentos", "Default editor theme": "Tema del editor predeterminado", @@ -115,6 +120,11 @@ "View settings": "Ver configuración", "ONLYOFFICE Docs Cloud": "ONLYOFFICE Docs Cloud", "Easily launch the editors in the cloud without downloading and installation": "Inicie fácilmente los editores en la nube sin tener que descargarlos ni instalarlos", - "Get Now": "Obtener ahora" + "Get Now": "Obtener ahora", + "Select file to combine" : "Seleccionar archivo para combinar", + "Select data source": "Seleccionar fuente de datos", + "The data source must not be the current document": "La fuente de datos no debe ser el documento actual", + "Enable background connection check to the editors": "Activar la comprobación de conexión en segundo plano con los editores", + "The domain in the file url does not match the domain of the Document server": "El dominio de la URL del archivo no coincide con el dominio del Servidor de documentos" },"pluralForm" :"nplurals=2; plural=(n != 1);" } \ No newline at end of file diff --git a/l10n/fr.js b/l10n/fr.js index 88c32fe1..7b583432 100644 --- a/l10n/fr.js +++ b/l10n/fr.js @@ -45,10 +45,12 @@ OC.L10N.register( "View details" : "Voir les détails", "Save" : "Enregistrer", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "Le contenu mixte actif n'est pas autorisé. Une adresse HTTPS pour le ONLYOFFICE Docs est requise", - "review" : "révision", + "Allow the following groups to access the editors": "Autoriser les groupes suivants à accéder aux éditeurs", + "review": "révision", "form filling" : "remplissage de formulaire", "comment" : "commentaire", - "download" : "télécharger", + "global filter": "filtre global", + "download": "télécharger", "Server settings" : "Paramètres du serveur", "Common settings" : "Paramètres communs", "Editor customization settings" : "Paramètres de personnalisation de l'éditeur", @@ -98,8 +100,11 @@ OC.L10N.register( "Notification sent successfully": "Notification a été envoyée avec succès", "%1\$s mentioned in the %2\$s: \"%3\$s\".": "%1\$s vous a mentionné dans %2\$s: \"%3\$s\".", "Choose a format to convert {fileName}": "Choisissez un format à convertir {fileName}", + "PDF form": "Formulaire PDF", + "PDF form from existing text file": "Formulaire PDF à partir d'un fichier texte existant", "Create form": "Créer un formulaire", "Fill in form in ONLYOFFICE": "Remplir le formulaire dans ONLYOFFICE", + "Create new PDF form": "Créer un nouveau formulaire PDF", "Security": "Sécurité", "Run document macros": "Exécuter des macros de documents", "Default editor theme": "Thème d'éditeur par défaut", @@ -117,6 +122,11 @@ OC.L10N.register( "View settings": "Afficher les paramètres", "ONLYOFFICE Docs Cloud": "ONLYOFFICE Docs Cloud", "Easily launch the editors in the cloud without downloading and installation": "Lancez facilement les éditeurs dans le cloud sans téléchargement ni installation", - "Get Now": "Obtenir maintenant" + "Get Now": "Obtenir maintenant", + "Select file to combine": "Sélectionner le fichier à combiner", + "Select data source": "Sélectionner la source de données", + "The data source must not be the current document": "La source de données ne doit pas être le document actuel", + "Enable background connection check to the editors": "Activer la vérification des connexions en arrière-plan avec les éditeurs", + "The domain in the file url does not match the domain of the Document server": "Le domaine dans l'URL du fichier ne correspond pas au domaine de Document Server" }, "nplurals=2; plural=(n > 1);"); diff --git a/l10n/fr.json b/l10n/fr.json index 047c47f4..4f4fd174 100644 --- a/l10n/fr.json +++ b/l10n/fr.json @@ -43,9 +43,11 @@ "View details" : "Voir les détails", "Save" : "Enregistrer", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "Le contenu mixte actif n'est pas autorisé. Une adresse HTTPS pour le ONLYOFFICE Docs est requise", + "Allow the following groups to access the editors" : "Autoriser les groupes suivants à accéder aux éditeurs", "review" : "révision", "form filling" : "remplissage de formulaire", "comment" : "commentaire", + "global filter" : "filtre global", "download" : "télécharger", "Server settings" : "Paramètres du serveur", "Common settings" : "Paramètres communs", @@ -96,8 +98,11 @@ "Notification sent successfully": "Notification a été envoyée avec succès", "%1$s mentioned in the %2$s: \"%3$s\".": "%1$s vous a mentionné dans %2$s: \"%3$s\".", "Choose a format to convert {fileName}": "Choisissez un format à convertir {fileName}", + "PDF form": "Formulaire PDF", + "PDF form from existing text file": "Formulaire PDF à partir d'un fichier texte existant", "Create form": "Créer un formulaire", "Fill in form in ONLYOFFICE": "Remplir le formulaire dans ONLYOFFICE", + "Create new PDF form": "Créer un nouveau formulaire PDF", "Security": "Sécurité", "Run document macros": "Exécuter des macros de documents", "Default editor theme": "Thème d'éditeur par défaut", @@ -115,6 +120,11 @@ "View settings": "Afficher les paramètres", "ONLYOFFICE Docs Cloud": "ONLYOFFICE Docs Cloud", "Easily launch the editors in the cloud without downloading and installation": "Lancez facilement les éditeurs dans le cloud sans téléchargement ni installation", - "Get Now": "Obtenir maintenant" + "Get Now": "Obtenir maintenant", + "Select file to combine" : "Sélectionner le fichier à combiner", + "Select data source": "Sélectionner la source de données", + "The data source must not be the current document": "La source de données ne doit pas être le document actuel", + "Enable background connection check to the editors": "Activer la vérification des connexions en arrière-plan avec les éditeurs", + "The domain in the file url does not match the domain of the Document server": "Le domaine dans l'URL du fichier ne correspond pas au domaine de Document Server" },"pluralForm" :"nplurals=2; plural=(n > 1);" } \ No newline at end of file diff --git a/l10n/it.js b/l10n/it.js index d4965b3a..18d27a34 100644 --- a/l10n/it.js +++ b/l10n/it.js @@ -45,10 +45,12 @@ OC.L10N.register( "View details" : "Vedi dettagli", "Save" : "Salva", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "Il contenuto attivo misto non è consentito. È richiesto l'indirizzo HTTPS per ONLYOFFICE Docs.", - "review" : "Revisione", + "Allow the following groups to access the editors": "Consenti ai seguenti gruppi di accedere agli editor", + "review": "Revisione", "form filling" : "Compilare un modulo", "comment" : "Commento", - "download" : "Scarica", + "global filter": "filtro globale", + "download": "Scarica", "Server settings" : "Impostazioni del server", "Common settings" : "Impostazioni comuni", "Editor customization settings" : "Impostazioni di personalizzazione dell'editor", @@ -98,8 +100,11 @@ OC.L10N.register( "Notification sent successfully": "Notifica è stata inviata con successo", "%1\$s mentioned in the %2\$s: \"%3\$s\".": "%1\$s ti ha menzionato in %2\$s: \"%3\$s\".", "Choose a format to convert {fileName}": "Scegli un formato per convertire {fileName}", + "PDF form": "Modulo PDF", + "PDF form from existing text file": "Modulo PDF da file di testo esistente", "Create form": "Creare modulo", "Fill in form in ONLYOFFICE": "Compilare il modulo in ONLYOFFICE", + "Create new PDF form": "Crea un nuovo modulo PDF", "Security": "Sicurezza", "Run document macros": "Esegui le macro del documento", "Default editor theme": "Tema dell'editor predefinito", @@ -117,6 +122,11 @@ OC.L10N.register( "View settings": "Visualizza impostazioni", "ONLYOFFICE Docs Cloud": "ONLYOFFICE Docs nel Cloud", "Easily launch the editors in the cloud without downloading and installation": "Avvia facilmente gli editor nel cloud senza scaricarli e installarli", - "Get Now": "Ottieni ora" + "Get Now": "Ottieni ora", + "Select file to combine": "Seleziona file da unire", + "Select data source": "Seleziona fonte dati", + "The data source must not be the current document": "La fonte dei dati non deve essere il documento corrente", + "Enable background connection check to the editors": "Abilita il controllo della connessione in background per gli editor", + "The domain in the file url does not match the domain of the Document server": "Il dominio nell'URL del file non corrisponde al dominio del Document server" }, "nplurals=2; plural=(n != 1);"); diff --git a/l10n/it.json b/l10n/it.json index b9c27cc3..56bc7a07 100644 --- a/l10n/it.json +++ b/l10n/it.json @@ -43,9 +43,11 @@ "View details" : "Vedi dettagli", "Save" : "Salva", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "Il contenuto attivo misto non è consentito. È richiesto l'indirizzo HTTPS per ONLYOFFICE Docs.", + "Allow the following groups to access the editors" : "Consenti ai seguenti gruppi di accedere agli editor", "review" : "Revisione", "form filling" : "Compilare un modulo", "comment" : "Commento", + "global filter" : "filtro globale", "download" : "Scarica", "Server settings" : "Impostazioni del server", "Common settings" : "Impostazioni comuni", @@ -96,8 +98,11 @@ "Notification sent successfully": "Notifica è stata inviata con successo", "%1$s mentioned in the %2$s: \"%3$s\".": "%1$s ti ha menzionato in %2$s: \"%3$s\".", "Choose a format to convert {fileName}": "Scegli un formato per convertire {fileName}", + "PDF form": "Modulo PDF", + "PDF form from existing text file": "Modulo PDF da file di testo esistente", "Create form": "Creare modulo", "Fill in form in ONLYOFFICE": "Compilare il modulo in ONLYOFFICE", + "Create new PDF form": "Crea un nuovo modulo PDF", "Security": "Sicurezza", "Run document macros": "Esegui le macro del documento", "Default editor theme": "Tema dell'editor predefinito", @@ -115,6 +120,11 @@ "View settings": "Visualizza impostazioni", "ONLYOFFICE Docs Cloud": "ONLYOFFICE Docs nel Cloud", "Easily launch the editors in the cloud without downloading and installation": "Avvia facilmente gli editor nel cloud senza scaricarli e installarli", - "Get Now": "Ottieni ora" + "Get Now": "Ottieni ora", + "Select file to combine" : "Seleziona file da unire", + "Select data source": "Seleziona fonte dati", + "The data source must not be the current document": "La fonte dei dati non deve essere il documento corrente", + "Enable background connection check to the editors": "Abilita il controllo della connessione in background per gli editor", + "The domain in the file url does not match the domain of the Document server": "Il dominio nell'URL del file non corrisponde al dominio del Document server" },"pluralForm" :"nplurals=2; plural=(n != 1);" } \ No newline at end of file diff --git a/l10n/ja.js b/l10n/ja.js index 4487242c..1991e3d3 100644 --- a/l10n/ja.js +++ b/l10n/ja.js @@ -45,10 +45,12 @@ OC.L10N.register( "View details" : "詳細表示", "Save" : "保存", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "アクティブコンテンツの混在は許可されていません。ONLYOFFICE DocsにはHTTPSアドレスが必要です", - "review" : "レビュー", + "Allow the following groups to access the editors": "以下のグループにエディタへのアクセスを許可する", + "review": "レビュー", "form filling" : "フォーム入力", "comment" : "コメント", - "download" : "ダウンロード", + "global filter": "グローバルフィルター", + "download": "ダウンロード", "Server settings" : "サーバー設定", "Common settings" : "共通設定", "Editor customization settings" : "エディターカスタム設定", @@ -98,8 +100,11 @@ OC.L10N.register( "Notification sent successfully": "通知を送信しました", "%1\$s mentioned in the %2\$s: \"%3\$s\".": "%1\$s は あなたを %2\$s: \"%3\$s\"に記載されました。", "Choose a format to convert {fileName}": "{fileName}を変換する形式を選択してください", + "PDF form": "PDFフォーム", + "PDF form from existing text file": "既存のテキストファイルからPDFフォーム", "Create form": "フォームの作成", "Fill in form in ONLYOFFICE": "ONLYOFFICEでフォームを記入する", + "Create new PDF form": "新規PDFフォームの作成", "Security": "セキュリティ", "Run document macros": "ドキュメントマクロを実行する", "Default editor theme": "エディターのデフォルトテーマ", @@ -117,6 +122,11 @@ OC.L10N.register( "View settings": "設定を見る", "ONLYOFFICE Docs Cloud": "ONLYOFFICE Docs Cloud", "Easily launch the editors in the cloud without downloading and installation": "ダウンロードやインストールをすることなく、クラウド上で簡単にエディタを起動することができます", - "Get Now": "今すぐ使ってみる" + "Get Now": "今すぐ使ってみる", + "Select file to combine": "結合するファイルの選択", + "Select data source": "データソースの選択", + "The data source must not be the current document": "データソースは現在の文書であってはなりません", + "Enable background connection check to the editors": "エディタへのバックグラウンド接続チェックを有効にする", + "The domain in the file url does not match the domain of the Document server": "ファイルURLのドメインがドキュメントサーバーのドメインと一致しません" }, "nplurals=1; plural=0;"); diff --git a/l10n/ja.json b/l10n/ja.json index ce447ca1..bc7df660 100644 --- a/l10n/ja.json +++ b/l10n/ja.json @@ -43,9 +43,11 @@ "View details" : "詳細表示", "Save" : "保存", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "アクティブコンテンツの混在は許可されていません。ONLYOFFICE DocsにはHTTPSアドレスが必要です", + "Allow the following groups to access the editors" : "以下のグループにエディタへのアクセスを許可する", "review" : "レビュー", "form filling" : "フォーム入力", "comment" : "コメント", + "global filter" : "グローバルフィルター", "download" : "ダウンロード", "Server settings" : "サーバー設定", "Common settings" : "共通設定", @@ -96,8 +98,11 @@ "Notification sent successfully": "通知を送信しました", "%1$s mentioned in the %2$s: \"%3$s\".": "%1$s は あなたを %2$s: \"%3$s\"に記載されました。", "Choose a format to convert {fileName}": "{fileName}を変換する形式を選択してください", + "PDF form": "PDFフォーム", + "PDF form from existing text file": "既存のテキストファイルからPDFフォーム", "Create form": "フォームの作成", "Fill in form in ONLYOFFICE": "ONLYOFFICEでフォームを記入する", + "Create new PDF form": "新規PDFフォームの作成", "Security": "セキュリティ", "Run document macros": "ドキュメントマクロを実行する", "Default editor theme": "エディターのデフォルトテーマ", @@ -115,6 +120,11 @@ "View settings": "設定を見る", "ONLYOFFICE Docs Cloud": "ONLYOFFICE Docs Cloud", "Easily launch the editors in the cloud without downloading and installation": "ダウンロードやインストールをすることなく、クラウド上で簡単にエディタを起動することができます", - "Get Now": "今すぐ使ってみる" + "Get Now": "今すぐ使ってみる", + "Select file to combine" : "結合するファイルの選択", + "Select data source": "データソースの選択", + "The data source must not be the current document": "データソースは現在の文書であってはなりません", + "Enable background connection check to the editors": "エディタへのバックグラウンド接続チェックを有効にする", + "The domain in the file url does not match the domain of the Document server": "ファイルURLのドメインがドキュメントサーバーのドメインと一致しません" },"pluralForm" :"nplurals=1; plural=0;" } \ No newline at end of file diff --git a/l10n/pt_BR.js b/l10n/pt_BR.js index 4166e670..27766642 100644 --- a/l10n/pt_BR.js +++ b/l10n/pt_BR.js @@ -45,11 +45,12 @@ OC.L10N.register( "View details" : "Ver detalhes", "Save" : "Salvar", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "Conteúdo Misto não é permitido. É necessário um endereço HTTPS para o ONLYOFFICE Docs.", - "Allow the following groups to access the editors" : "Acesso apenas para os seguintes grupos", + "Allow the following groups to access the editors": "Permitir que os seguintes grupos acessem os editores", "review" : "revisar", "form filling" : "preenchimento de formularios", "comment" : "comente", - "download" : "baixar", + "global filter": "filtro global", + "download": "baixar", "Server settings" : "Configurações do servidor", "Common settings" : "Configurações comuns", "Editor customization settings" : "Configurações de personalização do editor", @@ -99,8 +100,11 @@ OC.L10N.register( "Notification sent successfully": "Notificação enviada com sucesso", "%1\$s mentioned in the %2\$s: \"%3\$s\".": "%1\$s mencionado você em %2\$s: \"%3\$s\".", "Choose a format to convert {fileName}": "Escolha um formato para converter {fileName}", + "PDF form": "Formulário PDF", + "PDF form from existing text file": "Formulário PDF de arquivo de texto existente", "Create form": "Criar formulário", "Fill in form in ONLYOFFICE": "Preencher formulário no ONLYOFFICE", + "Create new PDF form": "Criar novo formulário PDF", "Security": "Segurança", "Run document macros": "Executar macros de documento", "Default editor theme": "Tema do editor padrão", @@ -118,6 +122,11 @@ OC.L10N.register( "View settings": "Configurações de exibição", "ONLYOFFICE Docs Cloud": "ONLYOFFICE Docs Cloud", "Easily launch the editors in the cloud without downloading and installation": "Inicie facilmente os editores na nuvem sem download e instalação", - "Get Now": "Obter agora" + "Get Now": "Obter agora", + "Select file to combine": "Selecione o arquivo para combinar", + "Select data source": "Selecionar fonte de dados", + "The data source must not be the current document": "A fonte de dados não deve ser o documento atual", + "Enable background connection check to the editors": "Ativar verificação de conexão em segundo plano para os editores", + "The domain in the file url does not match the domain of the Document server": "O domínio no URL do arquivo não corresponde ao domínio do servidor de documentos" }, "nplurals=2; plural=(n > 1);"); diff --git a/l10n/pt_BR.json b/l10n/pt_BR.json index f809232d..aadc2144 100644 --- a/l10n/pt_BR.json +++ b/l10n/pt_BR.json @@ -43,10 +43,11 @@ "View details" : "Ver detalhes", "Save" : "Salvar", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "Conteúdo Misto não é permitido. É necessário um endereço HTTPS para o ONLYOFFICE Docs.", - "Allow the following groups to access the editors" : "Acesso apenas para os seguintes grupos", + "Allow the following groups to access the editors" : "Permitir que os seguintes grupos acessem os editores", "review" : "revisar", "form filling" : "preenchimento de formularios", "comment" : "comente", + "global filter" : "filtro global", "download" : "baixar", "Server settings" : "Configurações do servidor", "Common settings" : "Configurações comuns", @@ -97,8 +98,11 @@ "Notification sent successfully": "Notificação enviada com sucesso", "%1$s mentioned in the %2$s: \"%3$s\".": "%1$s mencionado você em %2$s: \"%3$s\".", "Choose a format to convert {fileName}": "Escolha um formato para converter {fileName}", + "PDF form": "Formulário PDF", + "PDF form from existing text file": "Formulário PDF de arquivo de texto existente", "Create form": "Criar formulário", "Fill in form in ONLYOFFICE": "Preencher formulário no ONLYOFFICE", + "Create new PDF form": "Criar novo formulário PDF", "Security": "Segurança", "Run document macros": "Executar macros de documento", "Default editor theme": "Tema do editor padrão", @@ -116,6 +120,11 @@ "View settings": "Configurações de exibição", "ONLYOFFICE Docs Cloud": "ONLYOFFICE Docs Cloud", "Easily launch the editors in the cloud without downloading and installation": "Inicie facilmente os editores na nuvem sem download e instalação", - "Get Now": "Obter agora" + "Get Now": "Obter agora", + "Select file to combine" : "Selecione o arquivo para combinar", + "Select data source": "Selecionar fonte de dados", + "The data source must not be the current document": "A fonte de dados não deve ser o documento atual", + "Enable background connection check to the editors": "Ativar verificação de conexão em segundo plano para os editores", + "The domain in the file url does not match the domain of the Document server": "O domínio no URL do arquivo não corresponde ao domínio do servidor de documentos" },"pluralForm" :"nplurals=2; plural=(n > 1);" } \ No newline at end of file diff --git a/l10n/zh_CN.js b/l10n/zh_CN.js index e8d3ac90..a1336785 100644 --- a/l10n/zh_CN.js +++ b/l10n/zh_CN.js @@ -45,11 +45,12 @@ OC.L10N.register( "View details" : "查看详情", "Save" : "保存", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "不允许混合活动内容,请使用HTTPS连接ONLYOFFICE Docs。", - "Allow the following groups to access the editors" : "仅授权的用户组可以使用该服务", + "Allow the following groups to access the editors": "让以下用户组访问编辑器", "review" : "审阅", "form filling" : "表单填报", "comment" : "评论", - "download" : "下载", + "global filter": "全局过滤器", + "download": "下载", "Server settings" : "服务器设置", "Common settings" : "常用设置", "Editor customization settings" : "编辑器自定义设置", @@ -99,8 +100,11 @@ OC.L10N.register( "Notification sent successfully": "通知发送成功", "%1\$s mentioned in the %2\$s: \"%3\$s\".": "%1\$s 在 %2\$s: \"%3\$s\"中提到了您.", "Choose a format to convert {fileName}": "转换 {fileName} 为选中的格式", + "PDF form": "PDF 表单", + "PDF form from existing text file": "用文本文件生成 PDF 表单", "Create form": "创建表单", "Fill in form in ONLYOFFICE": "在ONLYOFFICE上填写表单", + "Create new PDF form": "创建新的 PDF 表单", "Security": "安全", "Run document macros": "运行文档宏", "Default editor theme": "编辑器默认的主题", @@ -118,6 +122,11 @@ OC.L10N.register( "View settings": "查看设置", "ONLYOFFICE Docs Cloud": "ONLYOFFICE 文档云", "Easily launch the editors in the cloud without downloading and installation": "无需下载和安装即可轻松启动云端编辑器", - "Get Now": "立即获取" + "Get Now": "立即获取", + "Select file to combine": "选择要合并的文件", + "Select data source": "选择数据源", + "The data source must not be the current document": "数据源不应该是当前文档", + "Enable background connection check to the editors": "启用编辑器后台连接检查", + "The domain in the file url does not match the domain of the Document server": "文件 URL 中的域与文档服务器的域不匹配" }, "nplurals=1; plural=0;"); diff --git a/l10n/zh_CN.json b/l10n/zh_CN.json index 4e411b7e..9d9170ca 100644 --- a/l10n/zh_CN.json +++ b/l10n/zh_CN.json @@ -43,10 +43,11 @@ "View details" : "查看详情", "Save" : "保存", "Mixed Active Content is not allowed. HTTPS address for ONLYOFFICE Docs is required." : "不允许混合活动内容,请使用HTTPS连接ONLYOFFICE Docs。", - "Allow the following groups to access the editors" : "仅授权的用户组可以使用该服务", + "Allow the following groups to access the editors" : "让以下用户组访问编辑器", "review" : "审阅", "form filling" : "表单填报", "comment" : "评论", + "global filter" : "全局过滤器", "download" : "下载", "Server settings" : "服务器设置", "Common settings" : "常用设置", @@ -97,8 +98,11 @@ "Notification sent successfully": "通知发送成功", "%1$s mentioned in the %2$s: \"%3$s\".": "%1$s 在 %2$s: \"%3$s\"中提到了您.", "Choose a format to convert {fileName}": "转换 {fileName} 为选中的格式", + "PDF form": "PDF 表单", + "PDF form from existing text file": "用文本文件生成 PDF 表单", "Create form": "创建表单", "Fill in form in ONLYOFFICE": "在ONLYOFFICE上填写表单", + "Create new PDF form": "创建新的 PDF 表单", "Security": "安全", "Run document macros": "运行文档宏", "Default editor theme": "编辑器默认的主题", @@ -116,6 +120,11 @@ "View settings": "查看设置", "ONLYOFFICE Docs Cloud": "ONLYOFFICE 文档云", "Easily launch the editors in the cloud without downloading and installation": "无需下载和安装即可轻松启动云端编辑器", - "Get Now": "立即获取" + "Get Now": "立即获取", + "Select file to combine" : "选择要合并的文件", + "Select data source": "选择数据源", + "The data source must not be the current document": "数据源不应该是当前文档", + "Enable background connection check to the editors": "启用编辑器后台连接检查", + "The domain in the file url does not match the domain of the Document server": "文件 URL 中的域与文档服务器的域不匹配" },"pluralForm" :"nplurals=1; plural=0;" } \ No newline at end of file From 38ed7c4118d9dca7e312ac29e786ef6979fd3e1d Mon Sep 17 00:00:00 2001 From: Maria-Sukhova Date: Tue, 5 Mar 2024 19:03:18 +0300 Subject: [PATCH 103/114] edited ru --- l10n/ru.js | 6 +++--- l10n/ru.json | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/l10n/ru.js b/l10n/ru.js index 9ed026a7..e989b28f 100644 --- a/l10n/ru.js +++ b/l10n/ru.js @@ -100,11 +100,11 @@ OC.L10N.register( "Notification sent successfully": "Оповещение успешно отправлено", "%1\$s mentioned in the %2\$s: \"%3\$s\".": "%1\$s упомянул вас в %2\$s: \"%3\$s\".", "Choose a format to convert {fileName}": "Выберите формат для {fileName}", - "PDF form": "PDF форма", - "PDF form from existing text file": "PDF форма из существующего текстового файла", + "PDF form": "PDF-форма", + "PDF form from existing text file": "PDF-форма из существующего текстового файла", "Create form": "Создать форму", "Fill in form in ONLYOFFICE": "Заполнить форму в ONLYOFFICE", - "Create new PDF form": "Создать новую PDF форму", + "Create new PDF form": "Создать новую PDF-форму", "Security": "Безопасность", "Run document macros": "Запускать макросы документа", "Default editor theme": "Тема редактора по умолчанию", diff --git a/l10n/ru.json b/l10n/ru.json index dbbbe8d2..873946d2 100644 --- a/l10n/ru.json +++ b/l10n/ru.json @@ -98,11 +98,11 @@ "Notification sent successfully": "Оповещение успешно отправлено", "%1$s mentioned in the %2$s: \"%3$s\".": "%1$s упомянул вас в %2$s: \"%3$s\".", "Choose a format to convert {fileName}": "Выберите формат для {fileName}", - "PDF form": "PDF форма", - "PDF form from existing text file": "PDF форма из существующего текстового файла", + "PDF form": "PDF-форма", + "PDF form from existing text file": "PDF-форма из существующего текстового файла", "Create form": "Создать форму", "Fill in form in ONLYOFFICE": "Заполнить форму в ONLYOFFICE", - "Create new PDF form": "Создать новую PDF форму", + "Create new PDF form": "Создать новую PDF-форму", "Security": "Безопасность", "Run document macros": "Запускать макросы документа", "Default editor theme": "Тема редактора по умолчанию", From a237fd9f92593aa0757275878e762bf8e6eb14fd Mon Sep 17 00:00:00 2001 From: rivexe Date: Tue, 12 Mar 2024 15:42:18 +0300 Subject: [PATCH 104/114] fix: offline viewer in share for anonymous users --- controller/editorapicontroller.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/controller/editorapicontroller.php b/controller/editorapicontroller.php index 3a13e3df..faafec5c 100644 --- a/controller/editorapicontroller.php +++ b/controller/editorapicontroller.php @@ -422,6 +422,13 @@ public function config($fileId, $filePath = null, $shareToken = null, $version = $params["editorConfig"]["callbackUrl"] = $callback; } else { $params["editorConfig"]["mode"] = "view"; + + if (isset($shareToken) && empty($userId)) { + $params["editorConfig"]["coEditing"] = [ + "mode" => "strict", + "change" => false + ]; + } } if (\OC::$server->getRequest()->isUserAgent([$this::USER_AGENT_MOBILE])) { From 881320c22816c0a9929b48bb953e77bcdc75c8b3 Mon Sep 17 00:00:00 2001 From: rivexe Date: Wed, 13 Mar 2024 12:37:34 +0300 Subject: [PATCH 105/114] fix: get first mime type from list for download --- controller/editorcontroller.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controller/editorcontroller.php b/controller/editorcontroller.php index 59dc6a81..6acb02d6 100644 --- a/controller/editorcontroller.php +++ b/controller/editorcontroller.php @@ -1276,7 +1276,7 @@ public function download($fileId, $toExtension = null, $template = false) { $formats = $this->config->formatsSetting(); - return new DataDownloadResponse($newData, $newFileName, $formats[$toExtension]["mime"]); + return new DataDownloadResponse($newData, $newFileName, $formats[$toExtension]["mime"][0]); } /** From 70cbd96b9de95321927bf213f984d8b89673e78f Mon Sep 17 00:00:00 2001 From: rivexe Date: Tue, 19 Mar 2024 11:14:19 +0300 Subject: [PATCH 106/114] fix: fixed download error for some formats. a separate method has been allocated for obtaining mime type by format name --- controller/editorcontroller.php | 4 ++-- lib/appconfig.php | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/controller/editorcontroller.php b/controller/editorcontroller.php index 6acb02d6..e3845113 100644 --- a/controller/editorcontroller.php +++ b/controller/editorcontroller.php @@ -1274,9 +1274,9 @@ public function download($fileId, $toExtension = null, $template = false) { $fileNameWithoutExt = substr($fileName, 0, \strlen($fileName) - \strlen($ext) - 1); $newFileName = $fileNameWithoutExt . "." . $toExtension; - $formats = $this->config->formatsSetting(); + $mimeType = $this->config->getMimeType($toExtension); - return new DataDownloadResponse($newData, $newFileName, $formats[$toExtension]["mime"][0]); + return new DataDownloadResponse($newData, $newFileName, $mimeType); } /** diff --git a/lib/appconfig.php b/lib/appconfig.php index f2cc4691..30306cd8 100644 --- a/lib/appconfig.php +++ b/lib/appconfig.php @@ -1391,6 +1391,27 @@ public function getFormats() { return json_decode($formats, true); } + /** + * Get the mime type by format name + * + * @param string $ext - format name + * + * @return string + */ + public function getMimeType($ext) { + $onlyofficeFormats = $this->getFormats(); + $result = "text/plain"; + + foreach ($onlyofficeFormats as $onlyOfficeFormat) { + if ($onlyOfficeFormat["name"] === $ext && !empty($onlyOfficeFormat["mime"])) { + $result = $onlyOfficeFormat["mime"][0]; + break; + } + } + + return $result; + } + /** * DEMO DATA */ From 194917bd2ec8599209fcbd29a6aa1b2f45ae7e8d Mon Sep 17 00:00:00 2001 From: rivexe Date: Tue, 19 Mar 2024 16:03:21 +0300 Subject: [PATCH 107/114] fix: if editors_check_interval is of string type then cast to integer or null --- lib/appconfig.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/appconfig.php b/lib/appconfig.php index 30306cd8..37c11e2e 100644 --- a/lib/appconfig.php +++ b/lib/appconfig.php @@ -1283,6 +1283,13 @@ public function shareAttributesVersion() { */ public function getEditorsCheckInterval() { $interval = $this->getSystemValue($this->_editors_check_interval); + if ($interval !== null && !is_int($interval)) { + if (is_string($interval) && !ctype_digit($interval)) { + $interval = null; + } else { + $interval = (integer)$interval; + } + } if (empty($interval) && $interval !== 0) { $interval = 60 * 60 * 24; From 11b17657bb42d83e63b02d063c2b4e103f23087f Mon Sep 17 00:00:00 2001 From: rivexe Date: Wed, 20 Mar 2024 10:10:21 +0300 Subject: [PATCH 108/114] fix: users from access list to user list for cells range protection --- controller/editorcontroller.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controller/editorcontroller.php b/controller/editorcontroller.php index e3845113..38d7e7fe 100644 --- a/controller/editorcontroller.php +++ b/controller/editorcontroller.php @@ -381,7 +381,7 @@ public function users($fileId, $operationType = null) { $all = false; $users = []; - if ($canShare) { + if ($canShare && $operationType !== "protect") { if ($shareMemberGroups || $autocompleteMemberGroup) { $currentUserGroups = $this->groupManager->getUserGroupIds($currentUser); foreach ($currentUserGroups as $currentUserGroup) { From 25abd45e547f712df09474cc16892c6d392ea679 Mon Sep 17 00:00:00 2001 From: Sergey Linnik Date: Wed, 20 Mar 2024 12:21:05 +0300 Subject: [PATCH 109/114] fb2 mime --- assets/document-formats | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/document-formats b/assets/document-formats index 730e13c8..e16bf990 160000 --- a/assets/document-formats +++ b/assets/document-formats @@ -1 +1 @@ -Subproject commit 730e13c89d717c03eabd845a51ad1ddc673b13ac +Subproject commit e16bf99040e73fbe803c6790d9e6145e33be037f From 9bdfdf5afdeaf71b287b8f65a500f80fcd7ab1b1 Mon Sep 17 00:00:00 2001 From: rivexe Date: Wed, 20 Mar 2024 13:33:09 +0300 Subject: [PATCH 110/114] fix: lost variable declaration and assignment --- js/editor.js | 1 + 1 file changed, 1 insertion(+) diff --git a/js/editor.js b/js/editor.js index 093c3627..12abe1c1 100644 --- a/js/editor.js +++ b/js/editor.js @@ -470,6 +470,7 @@ }; OCA.Onlyoffice.editorSetRequested = function (filePath) { + let documentSelectionType = this.documentSelectionType; $.get(OC.generateUrl("apps/" + OCA.Onlyoffice.AppName + "/ajax/url?filePath={filePath}", { filePath: filePath From 05787a8fc85b4b7e12f56ca4ea6d44ad3c4229eb Mon Sep 17 00:00:00 2001 From: rivexe Date: Tue, 26 Mar 2024 13:34:34 +0300 Subject: [PATCH 111/114] fix: set user avatar as base64 --- controller/editorapicontroller.php | 21 --------------------- controller/editorcontroller.php | 11 +---------- 2 files changed, 1 insertion(+), 31 deletions(-) diff --git a/controller/editorapicontroller.php b/controller/editorapicontroller.php index faafec5c..3e4a4fa4 100644 --- a/controller/editorapicontroller.php +++ b/controller/editorapicontroller.php @@ -113,13 +113,6 @@ class EditorApiController extends OCSController { */ private $versionManager; - /** - * Avatar manager - * - * @var IAvatarManager - */ - private $avatarManager; - /** * Tag manager * @@ -174,7 +167,6 @@ public function __construct( $this->versionManager = new VersionManager($AppName, $root); $this->fileUtility = new FileUtility($AppName, $trans, $logger, $config, $shareManager, $session); - $this->avatarManager = \OC::$server->getAvatarManager(); } /** @@ -448,19 +440,6 @@ public function config($fileId, $filePath = null, $shareToken = null, $version = "id" => $this->buildUserId($userId), "name" => $user->getDisplayName() ]; - $avatar = $this->avatarManager->getAvatar($userId); - if ($avatar->exists()) { - $userAvatarUrl = $this->urlGenerator->getAbsoluteURL( - $this->urlGenerator->linkToRoute( - "core.avatar.getAvatar", - [ - "userId" => $userId, - "size" => 64, - ] - ) - ); - $params["editorConfig"]["user"]["image"] = $userAvatarUrl; - } } $folderLink = null; diff --git a/controller/editorcontroller.php b/controller/editorcontroller.php index 38d7e7fe..7aedb397 100644 --- a/controller/editorcontroller.php +++ b/controller/editorcontroller.php @@ -448,16 +448,7 @@ public function userInfo($userIds) { ]; $avatar = $this->avatarManager->getAvatar($user->getUID()); if ($avatar->exists()) { - $userAvatarUrl = $this->urlGenerator->getAbsoluteURL( - $this->urlGenerator->linkToRoute( - "core.avatar.getAvatar", - [ - "userId" => $user->getUID(), - "size" => 64, - ] - ) - ); - $userData["image"] = $userAvatarUrl; + $userData["image"] = "data:image/png;base64," . $avatar->get()->__toString(); } array_push($result, $userData); } From b104c7c2537754729c1bbedd42b421b6b11fad12 Mon Sep 17 00:00:00 2001 From: rivexe Date: Fri, 29 Mar 2024 15:36:30 +0300 Subject: [PATCH 112/114] fix: frame height --- js/editor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/editor.js b/js/editor.js index 12abe1c1..3bcf8694 100644 --- a/js/editor.js +++ b/js/editor.js @@ -694,7 +694,7 @@ if (wrapEl.length > 0) { wrapEl[0].style.height = (screen.availHeight - headerHeight) + "px"; window.scrollTo(0, -1); - wrapEl[0].style.height = (window.innerHeight - headerHeight) + "px"; + wrapEl[0].style.height = (window.top.innerHeight - headerHeight) + "px"; } }; From 6d7766785fb0384248f5fa7f1da3224865dbd8e2 Mon Sep 17 00:00:00 2001 From: rivexe Date: Wed, 3 Apr 2024 19:49:45 +0300 Subject: [PATCH 113/114] fix: incorrect work of viewer mode --- controller/editorapicontroller.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/controller/editorapicontroller.php b/controller/editorapicontroller.php index 3e4a4fa4..1676cc5f 100644 --- a/controller/editorapicontroller.php +++ b/controller/editorapicontroller.php @@ -317,11 +317,6 @@ public function config($fileId, $filePath = null, $shareToken = null, $version = $fileStorage = $file->getStorage(); if (empty($shareToken) && $fileStorage->instanceOfStorage("\OCA\Files_Sharing\SharedStorage")) { - $params["editorConfig"]["coEditing"] = [ - "mode" => "strict", - "change" => false - ]; - $storageShare = $fileStorage->getShare(); if (method_exists($storageShare, "getAttributes")) { $attributes = $storageShare->getAttributes(); From 707af3f0d351e3146540d507d2f16b493620050a Mon Sep 17 00:00:00 2001 From: Sergey Linnik Date: Mon, 8 Apr 2024 15:00:31 +0300 Subject: [PATCH 114/114] oC Web: v1.1.0 https://github.com/ONLYOFFICE/onlyoffice-owncloud-web/commit/a0c307b9030a41857dea8cd64ad3e74deb092c66 --- js/web/onlyoffice.js | 393 +++++++++++++++++++++++-------------------- 1 file changed, 207 insertions(+), 186 deletions(-) diff --git a/js/web/onlyoffice.js b/js/web/onlyoffice.js index 98211ae2..aa358b01 100644 --- a/js/web/onlyoffice.js +++ b/js/web/onlyoffice.js @@ -2074,7 +2074,7 @@ define(['vue'], (function (vue) { 'use strict'; const isThenable = (thing) => thing && (isObject(thing) || isFunction(thing)) && isFunction(thing.then) && isFunction(thing.catch); - var utils = { + var utils$1 = { isArray: isArray$1, isArrayBuffer, isBuffer: isBuffer$1, @@ -4124,7 +4124,7 @@ define(['vue'], (function (vue) { 'use strict'; response && (this.response = response); } - utils.inherits(AxiosError, Error, { + utils$1.inherits(AxiosError, Error, { toJSON: function toJSON() { return { // Standard @@ -4139,7 +4139,7 @@ define(['vue'], (function (vue) { 'use strict'; columnNumber: this.columnNumber, stack: this.stack, // Axios - config: utils.toJSONObject(this.config), + config: utils$1.toJSONObject(this.config), code: this.code, status: this.response && this.response.status ? this.response.status : null }; @@ -4174,7 +4174,7 @@ define(['vue'], (function (vue) { 'use strict'; AxiosError.from = (error, code, config, request, response, customProps) => { const axiosError = Object.create(prototype$1); - utils.toFlatObject(error, axiosError, function filter(obj) { + utils$1.toFlatObject(error, axiosError, function filter(obj) { return obj !== Error.prototype; }, prop => { return prop !== 'isAxiosError'; @@ -4202,7 +4202,7 @@ define(['vue'], (function (vue) { 'use strict'; * @returns {boolean} */ function isVisitable(thing) { - return utils.isPlainObject(thing) || utils.isArray(thing); + return utils$1.isPlainObject(thing) || utils$1.isArray(thing); } /** @@ -4213,7 +4213,7 @@ define(['vue'], (function (vue) { 'use strict'; * @returns {string} the key without the brackets. */ function removeBrackets(key) { - return utils.endsWith(key, '[]') ? key.slice(0, -2) : key; + return utils$1.endsWith(key, '[]') ? key.slice(0, -2) : key; } /** @@ -4242,10 +4242,10 @@ define(['vue'], (function (vue) { 'use strict'; * @returns {boolean} */ function isFlatArray(arr) { - return utils.isArray(arr) && !arr.some(isVisitable); + return utils$1.isArray(arr) && !arr.some(isVisitable); } - const predicates = utils.toFlatObject(utils, {}, null, function filter(prop) { + const predicates = utils$1.toFlatObject(utils$1, {}, null, function filter(prop) { return /^is[A-Z]/.test(prop); }); @@ -4273,7 +4273,7 @@ define(['vue'], (function (vue) { 'use strict'; * @returns */ function toFormData(obj, formData, options) { - if (!utils.isObject(obj)) { + if (!utils$1.isObject(obj)) { throw new TypeError('target must be an object'); } @@ -4281,13 +4281,13 @@ define(['vue'], (function (vue) { 'use strict'; formData = formData || new (FormData)(); // eslint-disable-next-line no-param-reassign - options = utils.toFlatObject(options, { + options = utils$1.toFlatObject(options, { metaTokens: true, dots: false, indexes: false }, false, function defined(option, source) { // eslint-disable-next-line no-eq-null,eqeqeq - return !utils.isUndefined(source[option]); + return !utils$1.isUndefined(source[option]); }); const metaTokens = options.metaTokens; @@ -4296,24 +4296,24 @@ define(['vue'], (function (vue) { 'use strict'; const dots = options.dots; const indexes = options.indexes; const _Blob = options.Blob || typeof Blob !== 'undefined' && Blob; - const useBlob = _Blob && utils.isSpecCompliantForm(formData); + const useBlob = _Blob && utils$1.isSpecCompliantForm(formData); - if (!utils.isFunction(visitor)) { + if (!utils$1.isFunction(visitor)) { throw new TypeError('visitor must be a function'); } function convertValue(value) { if (value === null) return ''; - if (utils.isDate(value)) { + if (utils$1.isDate(value)) { return value.toISOString(); } - if (!useBlob && utils.isBlob(value)) { + if (!useBlob && utils$1.isBlob(value)) { throw new AxiosError('Blob is not supported. Use a Buffer instead.'); } - if (utils.isArrayBuffer(value) || utils.isTypedArray(value)) { + if (utils$1.isArrayBuffer(value) || utils$1.isTypedArray(value)) { return useBlob && typeof Blob === 'function' ? new Blob([value]) : Buffer.from(value); } @@ -4334,20 +4334,20 @@ define(['vue'], (function (vue) { 'use strict'; let arr = value; if (value && !path && typeof value === 'object') { - if (utils.endsWith(key, '{}')) { + if (utils$1.endsWith(key, '{}')) { // eslint-disable-next-line no-param-reassign key = metaTokens ? key : key.slice(0, -2); // eslint-disable-next-line no-param-reassign value = JSON.stringify(value); } else if ( - (utils.isArray(value) && isFlatArray(value)) || - ((utils.isFileList(value) || utils.endsWith(key, '[]')) && (arr = utils.toArray(value)) + (utils$1.isArray(value) && isFlatArray(value)) || + ((utils$1.isFileList(value) || utils$1.endsWith(key, '[]')) && (arr = utils$1.toArray(value)) )) { // eslint-disable-next-line no-param-reassign key = removeBrackets(key); arr.forEach(function each(el, index) { - !(utils.isUndefined(el) || el === null) && formData.append( + !(utils$1.isUndefined(el) || el === null) && formData.append( // eslint-disable-next-line no-nested-ternary indexes === true ? renderKey([key], index, dots) : (indexes === null ? key : key + '[]'), convertValue(el) @@ -4375,7 +4375,7 @@ define(['vue'], (function (vue) { 'use strict'; }); function build(value, path) { - if (utils.isUndefined(value)) return; + if (utils$1.isUndefined(value)) return; if (stack.indexOf(value) !== -1) { throw Error('Circular reference detected in ' + path.join('.')); @@ -4383,9 +4383,9 @@ define(['vue'], (function (vue) { 'use strict'; stack.push(value); - utils.forEach(value, function each(el, key) { - const result = !(utils.isUndefined(el) || el === null) && visitor.call( - formData, el, utils.isString(key) ? key.trim() : key, path, exposedHelpers + utils$1.forEach(value, function each(el, key) { + const result = !(utils$1.isUndefined(el) || el === null) && visitor.call( + formData, el, utils$1.isString(key) ? key.trim() : key, path, exposedHelpers ); if (result === true) { @@ -4396,7 +4396,7 @@ define(['vue'], (function (vue) { 'use strict'; stack.pop(); } - if (!utils.isObject(obj)) { + if (!utils$1.isObject(obj)) { throw new TypeError('data must be an object'); } @@ -4500,7 +4500,7 @@ define(['vue'], (function (vue) { 'use strict'; if (serializeFn) { serializedParams = serializeFn(params, options); } else { - serializedParams = utils.isURLSearchParams(params) ? + serializedParams = utils$1.isURLSearchParams(params) ? params.toString() : new AxiosURLSearchParams(params, options).toString(_encode); } @@ -4575,7 +4575,7 @@ define(['vue'], (function (vue) { 'use strict'; * @returns {void} */ forEach(fn) { - utils.forEach(this.handlers, function forEachHandler(h) { + utils$1.forEach(this.handlers, function forEachHandler(h) { if (h !== null) { fn(h); } @@ -4597,6 +4597,18 @@ define(['vue'], (function (vue) { 'use strict'; var Blob$1 = typeof Blob !== 'undefined' ? Blob : null; + var platform$1 = { + isBrowser: true, + classes: { + URLSearchParams: URLSearchParams$1, + FormData: FormData$1, + Blob: Blob$1 + }, + protocols: ['http', 'https', 'file', 'blob', 'url', 'data'] + }; + + const hasBrowserEnv = typeof window !== 'undefined' && typeof document !== 'undefined'; + /** * Determine if we're running in a standard browser environment * @@ -4614,18 +4626,10 @@ define(['vue'], (function (vue) { 'use strict'; * * @returns {boolean} */ - const isStandardBrowserEnv = (() => { - let product; - if (typeof navigator !== 'undefined' && ( - (product = navigator.product) === 'ReactNative' || - product === 'NativeScript' || - product === 'NS') - ) { - return false; - } - - return typeof window !== 'undefined' && typeof document !== 'undefined'; - })(); + const hasStandardBrowserEnv = ( + (product) => { + return hasBrowserEnv && ['ReactNative', 'NativeScript', 'NS'].indexOf(product) < 0 + })(typeof navigator !== 'undefined' && navigator.product); /** * Determine if we're running in a standard browser webWorker environment @@ -4636,7 +4640,7 @@ define(['vue'], (function (vue) { 'use strict'; * `typeof window !== 'undefined' && typeof document !== 'undefined'`. * This leads to a problem when axios post `FormData` in webWorker */ - const isStandardBrowserWebWorkerEnv = (() => { + const hasStandardBrowserWebWorkerEnv = (() => { return ( typeof WorkerGlobalScope !== 'undefined' && // eslint-disable-next-line no-undef @@ -4645,23 +4649,22 @@ define(['vue'], (function (vue) { 'use strict'; ); })(); + var utils = /*#__PURE__*/Object.freeze({ + __proto__: null, + hasBrowserEnv: hasBrowserEnv, + hasStandardBrowserEnv: hasStandardBrowserEnv, + hasStandardBrowserWebWorkerEnv: hasStandardBrowserWebWorkerEnv + }); var platform = { - isBrowser: true, - classes: { - URLSearchParams: URLSearchParams$1, - FormData: FormData$1, - Blob: Blob$1 - }, - isStandardBrowserEnv, - isStandardBrowserWebWorkerEnv, - protocols: ['http', 'https', 'file', 'blob', 'url', 'data'] + ...utils, + ...platform$1 }; function toURLEncodedForm(data, options) { return toFormData(data, new platform.classes.URLSearchParams(), Object.assign({ visitor: function(value, key, path, helpers) { - if (platform.isNode && utils.isBuffer(value)) { + if (platform.isNode && utils$1.isBuffer(value)) { this.append(key, value.toString('base64')); return false; } @@ -4683,7 +4686,7 @@ define(['vue'], (function (vue) { 'use strict'; // foo.x.y.z // foo-x-y-z // foo x y z - return utils.matchAll(/\w+|\[(\w*)]/g, name).map(match => { + return utils$1.matchAll(/\w+|\[(\w*)]/g, name).map(match => { return match[0] === '[]' ? '' : match[1] || match[0]; }); } @@ -4718,12 +4721,15 @@ define(['vue'], (function (vue) { 'use strict'; function formDataToJSON(formData) { function buildPath(path, value, target, index) { let name = path[index++]; + + if (name === '__proto__') return true; + const isNumericKey = Number.isFinite(+name); const isLast = index >= path.length; - name = !name && utils.isArray(target) ? target.length : name; + name = !name && utils$1.isArray(target) ? target.length : name; if (isLast) { - if (utils.hasOwnProp(target, name)) { + if (utils$1.hasOwnProp(target, name)) { target[name] = [target[name], value]; } else { target[name] = value; @@ -4732,23 +4738,23 @@ define(['vue'], (function (vue) { 'use strict'; return !isNumericKey; } - if (!target[name] || !utils.isObject(target[name])) { + if (!target[name] || !utils$1.isObject(target[name])) { target[name] = []; } const result = buildPath(path, value, target[name], index); - if (result && utils.isArray(target[name])) { + if (result && utils$1.isArray(target[name])) { target[name] = arrayToObject(target[name]); } return !isNumericKey; } - if (utils.isFormData(formData) && utils.isFunction(formData.entries)) { + if (utils$1.isFormData(formData) && utils$1.isFunction(formData.entries)) { const obj = {}; - utils.forEachEntry(formData, (name, value) => { + utils$1.forEachEntry(formData, (name, value) => { buildPath(parsePropPath(name), value, obj, 0); }); @@ -4769,10 +4775,10 @@ define(['vue'], (function (vue) { 'use strict'; * @returns {string} A stringified version of the rawValue. */ function stringifySafely(rawValue, parser, encoder) { - if (utils.isString(rawValue)) { + if (utils$1.isString(rawValue)) { try { (parser || JSON.parse)(rawValue); - return utils.trim(rawValue); + return utils$1.trim(rawValue); } catch (e) { if (e.name !== 'SyntaxError') { throw e; @@ -4792,33 +4798,30 @@ define(['vue'], (function (vue) { 'use strict'; transformRequest: [function transformRequest(data, headers) { const contentType = headers.getContentType() || ''; const hasJSONContentType = contentType.indexOf('application/json') > -1; - const isObjectPayload = utils.isObject(data); + const isObjectPayload = utils$1.isObject(data); - if (isObjectPayload && utils.isHTMLForm(data)) { + if (isObjectPayload && utils$1.isHTMLForm(data)) { data = new FormData(data); } - const isFormData = utils.isFormData(data); + const isFormData = utils$1.isFormData(data); if (isFormData) { - if (!hasJSONContentType) { - return data; - } return hasJSONContentType ? JSON.stringify(formDataToJSON(data)) : data; } - if (utils.isArrayBuffer(data) || - utils.isBuffer(data) || - utils.isStream(data) || - utils.isFile(data) || - utils.isBlob(data) + if (utils$1.isArrayBuffer(data) || + utils$1.isBuffer(data) || + utils$1.isStream(data) || + utils$1.isFile(data) || + utils$1.isBlob(data) ) { return data; } - if (utils.isArrayBufferView(data)) { + if (utils$1.isArrayBufferView(data)) { return data.buffer; } - if (utils.isURLSearchParams(data)) { + if (utils$1.isURLSearchParams(data)) { headers.setContentType('application/x-www-form-urlencoded;charset=utf-8', false); return data.toString(); } @@ -4830,7 +4833,7 @@ define(['vue'], (function (vue) { 'use strict'; return toURLEncodedForm(data, this.formSerializer).toString(); } - if ((isFileList = utils.isFileList(data)) || contentType.indexOf('multipart/form-data') > -1) { + if ((isFileList = utils$1.isFileList(data)) || contentType.indexOf('multipart/form-data') > -1) { const _FormData = this.env && this.env.FormData; return toFormData( @@ -4854,7 +4857,7 @@ define(['vue'], (function (vue) { 'use strict'; const forcedJSONParsing = transitional && transitional.forcedJSONParsing; const JSONRequested = this.responseType === 'json'; - if (data && utils.isString(data) && ((forcedJSONParsing && !this.responseType) || JSONRequested)) { + if (data && utils$1.isString(data) && ((forcedJSONParsing && !this.responseType) || JSONRequested)) { const silentJSONParsing = transitional && transitional.silentJSONParsing; const strictJSONParsing = !silentJSONParsing && JSONRequested; @@ -4902,7 +4905,7 @@ define(['vue'], (function (vue) { 'use strict'; } }; - utils.forEach(['delete', 'get', 'head', 'post', 'put', 'patch'], (method) => { + utils$1.forEach(['delete', 'get', 'head', 'post', 'put', 'patch'], (method) => { defaults.headers[method] = {}; }); @@ -4910,7 +4913,7 @@ define(['vue'], (function (vue) { 'use strict'; // RawAxiosHeaders whose duplicates are ignored by node // c.f. https://nodejs.org/api/http.html#http_message_headers - const ignoreDuplicateOf = utils.toObjectSet([ + const ignoreDuplicateOf = utils$1.toObjectSet([ 'age', 'authorization', 'content-length', 'content-type', 'etag', 'expires', 'from', 'host', 'if-modified-since', 'if-unmodified-since', 'last-modified', 'location', 'max-forwards', 'proxy-authorization', @@ -4971,7 +4974,7 @@ define(['vue'], (function (vue) { 'use strict'; return value; } - return utils.isArray(value) ? value.map(normalizeValue) : String(value); + return utils$1.isArray(value) ? value.map(normalizeValue) : String(value); } function parseTokens(str) { @@ -4989,7 +4992,7 @@ define(['vue'], (function (vue) { 'use strict'; const isValidHeaderName = (str) => /^[-_a-zA-Z0-9^`|~,!#$%&'*+.]+$/.test(str.trim()); function matchHeaderValue(context, value, header, filter, isHeaderNameFilter) { - if (utils.isFunction(filter)) { + if (utils$1.isFunction(filter)) { return filter.call(this, value, header); } @@ -4997,13 +5000,13 @@ define(['vue'], (function (vue) { 'use strict'; value = header; } - if (!utils.isString(value)) return; + if (!utils$1.isString(value)) return; - if (utils.isString(filter)) { + if (utils$1.isString(filter)) { return value.indexOf(filter) !== -1; } - if (utils.isRegExp(filter)) { + if (utils$1.isRegExp(filter)) { return filter.test(value); } } @@ -5016,7 +5019,7 @@ define(['vue'], (function (vue) { 'use strict'; } function buildAccessors(obj, header) { - const accessorName = utils.toCamelCase(' ' + header); + const accessorName = utils$1.toCamelCase(' ' + header); ['get', 'set', 'has'].forEach(methodName => { Object.defineProperty(obj, methodName + accessorName, { @@ -5043,7 +5046,7 @@ define(['vue'], (function (vue) { 'use strict'; throw new Error('header name must be a non-empty string'); } - const key = utils.findKey(self, lHeader); + const key = utils$1.findKey(self, lHeader); if(!key || self[key] === undefined || _rewrite === true || (_rewrite === undefined && self[key] !== false)) { self[key || _header] = normalizeValue(_value); @@ -5051,11 +5054,11 @@ define(['vue'], (function (vue) { 'use strict'; } const setHeaders = (headers, _rewrite) => - utils.forEach(headers, (_value, _header) => setHeader(_value, _header, _rewrite)); + utils$1.forEach(headers, (_value, _header) => setHeader(_value, _header, _rewrite)); - if (utils.isPlainObject(header) || header instanceof this.constructor) { + if (utils$1.isPlainObject(header) || header instanceof this.constructor) { setHeaders(header, valueOrRewrite); - } else if(utils.isString(header) && (header = header.trim()) && !isValidHeaderName(header)) { + } else if(utils$1.isString(header) && (header = header.trim()) && !isValidHeaderName(header)) { setHeaders(parseHeaders(header), valueOrRewrite); } else { header != null && setHeader(valueOrRewrite, header, rewrite); @@ -5068,7 +5071,7 @@ define(['vue'], (function (vue) { 'use strict'; header = normalizeHeader(header); if (header) { - const key = utils.findKey(this, header); + const key = utils$1.findKey(this, header); if (key) { const value = this[key]; @@ -5081,11 +5084,11 @@ define(['vue'], (function (vue) { 'use strict'; return parseTokens(value); } - if (utils.isFunction(parser)) { + if (utils$1.isFunction(parser)) { return parser.call(this, value, key); } - if (utils.isRegExp(parser)) { + if (utils$1.isRegExp(parser)) { return parser.exec(value); } @@ -5098,7 +5101,7 @@ define(['vue'], (function (vue) { 'use strict'; header = normalizeHeader(header); if (header) { - const key = utils.findKey(this, header); + const key = utils$1.findKey(this, header); return !!(key && this[key] !== undefined && (!matcher || matchHeaderValue(this, this[key], key, matcher))); } @@ -5114,7 +5117,7 @@ define(['vue'], (function (vue) { 'use strict'; _header = normalizeHeader(_header); if (_header) { - const key = utils.findKey(self, _header); + const key = utils$1.findKey(self, _header); if (key && (!matcher || matchHeaderValue(self, self[key], key, matcher))) { delete self[key]; @@ -5124,7 +5127,7 @@ define(['vue'], (function (vue) { 'use strict'; } } - if (utils.isArray(header)) { + if (utils$1.isArray(header)) { header.forEach(deleteHeader); } else { deleteHeader(header); @@ -5153,8 +5156,8 @@ define(['vue'], (function (vue) { 'use strict'; const self = this; const headers = {}; - utils.forEach(this, (value, header) => { - const key = utils.findKey(headers, header); + utils$1.forEach(this, (value, header) => { + const key = utils$1.findKey(headers, header); if (key) { self[key] = normalizeValue(value); @@ -5183,8 +5186,8 @@ define(['vue'], (function (vue) { 'use strict'; toJSON(asStrings) { const obj = Object.create(null); - utils.forEach(this, (value, header) => { - value != null && value !== false && (obj[header] = asStrings && utils.isArray(value) ? value.join(', ') : value); + utils$1.forEach(this, (value, header) => { + value != null && value !== false && (obj[header] = asStrings && utils$1.isArray(value) ? value.join(', ') : value); }); return obj; @@ -5231,7 +5234,7 @@ define(['vue'], (function (vue) { 'use strict'; } } - utils.isArray(header) ? header.forEach(defineAccessor) : defineAccessor(header); + utils$1.isArray(header) ? header.forEach(defineAccessor) : defineAccessor(header); return this; } @@ -5240,7 +5243,7 @@ define(['vue'], (function (vue) { 'use strict'; AxiosHeaders.accessor(['Content-Type', 'Content-Length', 'Accept', 'Accept-Encoding', 'User-Agent', 'Authorization']); // reserved names hotfix - utils.reduceDescriptors(AxiosHeaders.prototype, ({value}, key) => { + utils$1.reduceDescriptors(AxiosHeaders.prototype, ({value}, key) => { let mapped = key[0].toUpperCase() + key.slice(1); // map `set` => `Set` return { get: () => value, @@ -5250,7 +5253,7 @@ define(['vue'], (function (vue) { 'use strict'; } }); - utils.freezeMethods(AxiosHeaders); + utils$1.freezeMethods(AxiosHeaders); var AxiosHeaders$1 = AxiosHeaders; @@ -5268,7 +5271,7 @@ define(['vue'], (function (vue) { 'use strict'; const headers = AxiosHeaders$1.from(context.headers); let data = context.data; - utils.forEach(fns, function transform(fn) { + utils$1.forEach(fns, function transform(fn) { data = fn.call(config, data, headers.normalize(), response ? response.status : undefined); }); @@ -5296,7 +5299,7 @@ define(['vue'], (function (vue) { 'use strict'; this.name = 'CanceledError'; } - utils.inherits(CanceledError, AxiosError, { + utils$1.inherits(CanceledError, AxiosError, { __CANCEL__: true }); @@ -5324,53 +5327,44 @@ define(['vue'], (function (vue) { 'use strict'; } } - var cookies = platform.isStandardBrowserEnv ? + var cookies = platform.hasStandardBrowserEnv ? - // Standard browser envs support document.cookie - (function standardBrowserEnv() { - return { - write: function write(name, value, expires, path, domain, secure) { - const cookie = []; - cookie.push(name + '=' + encodeURIComponent(value)); + // Standard browser envs support document.cookie + { + write(name, value, expires, path, domain, secure) { + const cookie = [name + '=' + encodeURIComponent(value)]; - if (utils.isNumber(expires)) { - cookie.push('expires=' + new Date(expires).toGMTString()); - } + utils$1.isNumber(expires) && cookie.push('expires=' + new Date(expires).toGMTString()); - if (utils.isString(path)) { - cookie.push('path=' + path); - } + utils$1.isString(path) && cookie.push('path=' + path); - if (utils.isString(domain)) { - cookie.push('domain=' + domain); - } + utils$1.isString(domain) && cookie.push('domain=' + domain); - if (secure === true) { - cookie.push('secure'); - } + secure === true && cookie.push('secure'); - document.cookie = cookie.join('; '); - }, + document.cookie = cookie.join('; '); + }, - read: function read(name) { - const match = document.cookie.match(new RegExp('(^|;\\s*)(' + name + ')=([^;]*)')); - return (match ? decodeURIComponent(match[3]) : null); - }, + read(name) { + const match = document.cookie.match(new RegExp('(^|;\\s*)(' + name + ')=([^;]*)')); + return (match ? decodeURIComponent(match[3]) : null); + }, - remove: function remove(name) { - this.write(name, '', Date.now() - 86400000); - } - }; - })() : + remove(name) { + this.write(name, '', Date.now() - 86400000); + } + } - // Non standard browser env (web workers, react-native) lack needed support. - (function nonStandardBrowserEnv() { - return { - write: function write() {}, - read: function read() { return null; }, - remove: function remove() {} - }; - })(); + : + + // Non-standard browser env (web workers, react-native) lack needed support. + { + write() {}, + read() { + return null; + }, + remove() {} + }; /** * Determines whether the specified URL is absolute @@ -5396,7 +5390,7 @@ define(['vue'], (function (vue) { 'use strict'; */ function combineURLs(baseURL, relativeURL) { return relativeURL - ? baseURL.replace(/\/+$/, '') + '/' + relativeURL.replace(/^\/+/, '') + ? baseURL.replace(/\/?\/$/, '') + '/' + relativeURL.replace(/^\/+/, '') : baseURL; } @@ -5417,7 +5411,7 @@ define(['vue'], (function (vue) { 'use strict'; return requestedURL; } - var isURLSameOrigin = platform.isStandardBrowserEnv ? + var isURLSameOrigin = platform.hasStandardBrowserEnv ? // Standard browser envs have full support of the APIs needed to test // whether the request URL is of the same origin as current location. @@ -5427,7 +5421,7 @@ define(['vue'], (function (vue) { 'use strict'; let originURL; /** - * Parse a URL to discover it's components + * Parse a URL to discover its components * * @param {String} url The URL to be parsed * @returns {Object} @@ -5467,7 +5461,7 @@ define(['vue'], (function (vue) { 'use strict'; * @returns {boolean} True if URL shares the same origin, otherwise false */ return function isURLSameOrigin(requestURL) { - const parsed = (utils.isString(requestURL)) ? resolveURL(requestURL) : requestURL; + const parsed = (utils$1.isString(requestURL)) ? resolveURL(requestURL) : requestURL; return (parsed.protocol === originURL.protocol && parsed.host === originURL.host); }; @@ -5572,7 +5566,7 @@ define(['vue'], (function (vue) { 'use strict'; return new Promise(function dispatchXhrRequest(resolve, reject) { let requestData = config.data; const requestHeaders = AxiosHeaders$1.from(config.headers).normalize(); - const responseType = config.responseType; + let {responseType, withXSRFToken} = config; let onCanceled; function done() { if (config.cancelToken) { @@ -5586,14 +5580,13 @@ define(['vue'], (function (vue) { 'use strict'; let contentType; - if (utils.isFormData(requestData)) { - if (platform.isStandardBrowserEnv || platform.isStandardBrowserWebWorkerEnv) { + if (utils$1.isFormData(requestData)) { + if (platform.hasStandardBrowserEnv || platform.hasStandardBrowserWebWorkerEnv) { requestHeaders.setContentType(false); // Let the browser set it - } else if(!requestHeaders.getContentType(/^\s*multipart\/form-data/)){ - requestHeaders.setContentType('multipart/form-data'); // mobile/desktop app frameworks - } else if(utils.isString(contentType = requestHeaders.getContentType())){ + } else if ((contentType = requestHeaders.getContentType()) !== false) { // fix semicolon duplication issue for ReactNative FormData implementation - requestHeaders.setContentType(contentType.replace(/^\s*(multipart\/form-data);+/, '$1')); + const [type, ...tokens] = contentType ? contentType.split(';').map(token => token.trim()).filter(Boolean) : []; + requestHeaders.setContentType([type || 'multipart/form-data', ...tokens].join('; ')); } } @@ -5709,13 +5702,16 @@ define(['vue'], (function (vue) { 'use strict'; // Add xsrf header // This is only done if running in a standard browser environment. // Specifically not if we're in a web worker, or react-native. - if (platform.isStandardBrowserEnv) { - // Add xsrf header - const xsrfValue = (config.withCredentials || isURLSameOrigin(fullPath)) - && config.xsrfCookieName && cookies.read(config.xsrfCookieName); + if(platform.hasStandardBrowserEnv) { + withXSRFToken && utils$1.isFunction(withXSRFToken) && (withXSRFToken = withXSRFToken(config)); + + if (withXSRFToken || (withXSRFToken !== false && isURLSameOrigin(fullPath))) { + // Add xsrf header + const xsrfValue = config.xsrfHeaderName && config.xsrfCookieName && cookies.read(config.xsrfCookieName); - if (xsrfValue) { - requestHeaders.set(config.xsrfHeaderName, xsrfValue); + if (xsrfValue) { + requestHeaders.set(config.xsrfHeaderName, xsrfValue); + } } } @@ -5724,13 +5720,13 @@ define(['vue'], (function (vue) { 'use strict'; // Add headers to the request if ('setRequestHeader' in request) { - utils.forEach(requestHeaders.toJSON(), function setRequestHeader(val, key) { + utils$1.forEach(requestHeaders.toJSON(), function setRequestHeader(val, key) { request.setRequestHeader(key, val); }); } // Add withCredentials to request if needed - if (!utils.isUndefined(config.withCredentials)) { + if (!utils$1.isUndefined(config.withCredentials)) { request.withCredentials = !!config.withCredentials; } @@ -5785,7 +5781,7 @@ define(['vue'], (function (vue) { 'use strict'; xhr: xhrAdapter }; - utils.forEach(knownAdapters, (fn, value) => { + utils$1.forEach(knownAdapters, (fn, value) => { if (fn) { try { Object.defineProperty(fn, 'name', {value}); @@ -5798,11 +5794,11 @@ define(['vue'], (function (vue) { 'use strict'; const renderReason = (reason) => `- ${reason}`; - const isResolvedHandle = (adapter) => utils.isFunction(adapter) || adapter === null || adapter === false; + const isResolvedHandle = (adapter) => utils$1.isFunction(adapter) || adapter === null || adapter === false; var adapters = { getAdapter: (adapters) => { - adapters = utils.isArray(adapters) ? adapters : [adapters]; + adapters = utils$1.isArray(adapters) ? adapters : [adapters]; const {length} = adapters; let nameOrAdapter; @@ -5926,7 +5922,7 @@ define(['vue'], (function (vue) { 'use strict'; }); } - const headersToObject = (thing) => thing instanceof AxiosHeaders$1 ? thing.toJSON() : thing; + const headersToObject = (thing) => thing instanceof AxiosHeaders$1 ? { ...thing } : thing; /** * Config-specific merge-function which creates a new config-object @@ -5943,11 +5939,11 @@ define(['vue'], (function (vue) { 'use strict'; const config = {}; function getMergedValue(target, source, caseless) { - if (utils.isPlainObject(target) && utils.isPlainObject(source)) { - return utils.merge.call({caseless}, target, source); - } else if (utils.isPlainObject(source)) { - return utils.merge({}, source); - } else if (utils.isArray(source)) { + if (utils$1.isPlainObject(target) && utils$1.isPlainObject(source)) { + return utils$1.merge.call({caseless}, target, source); + } else if (utils$1.isPlainObject(source)) { + return utils$1.merge({}, source); + } else if (utils$1.isArray(source)) { return source.slice(); } return source; @@ -5955,25 +5951,25 @@ define(['vue'], (function (vue) { 'use strict'; // eslint-disable-next-line consistent-return function mergeDeepProperties(a, b, caseless) { - if (!utils.isUndefined(b)) { + if (!utils$1.isUndefined(b)) { return getMergedValue(a, b, caseless); - } else if (!utils.isUndefined(a)) { + } else if (!utils$1.isUndefined(a)) { return getMergedValue(undefined, a, caseless); } } // eslint-disable-next-line consistent-return function valueFromConfig2(a, b) { - if (!utils.isUndefined(b)) { + if (!utils$1.isUndefined(b)) { return getMergedValue(undefined, b); } } // eslint-disable-next-line consistent-return function defaultToConfig2(a, b) { - if (!utils.isUndefined(b)) { + if (!utils$1.isUndefined(b)) { return getMergedValue(undefined, b); - } else if (!utils.isUndefined(a)) { + } else if (!utils$1.isUndefined(a)) { return getMergedValue(undefined, a); } } @@ -5998,6 +5994,7 @@ define(['vue'], (function (vue) { 'use strict'; timeout: defaultToConfig2, timeoutMessage: defaultToConfig2, withCredentials: defaultToConfig2, + withXSRFToken: defaultToConfig2, adapter: defaultToConfig2, responseType: defaultToConfig2, xsrfCookieName: defaultToConfig2, @@ -6018,16 +6015,16 @@ define(['vue'], (function (vue) { 'use strict'; headers: (a, b) => mergeDeepProperties(headersToObject(a), headersToObject(b), true) }; - utils.forEach(Object.keys(Object.assign({}, config1, config2)), function computeConfigValue(prop) { + utils$1.forEach(Object.keys(Object.assign({}, config1, config2)), function computeConfigValue(prop) { const merge = mergeMap[prop] || mergeDeepProperties; const configValue = merge(config1[prop], config2[prop], prop); - (utils.isUndefined(configValue) && merge !== mergeDirectKeys) || (config[prop] = configValue); + (utils$1.isUndefined(configValue) && merge !== mergeDirectKeys) || (config[prop] = configValue); }); return config; } - const VERSION = "1.5.1"; + const VERSION = "1.6.8"; const validators$1 = {}; @@ -6142,7 +6139,31 @@ define(['vue'], (function (vue) { 'use strict'; * * @returns {Promise} The Promise to be fulfilled */ - request(configOrUrl, config) { + async request(configOrUrl, config) { + try { + return await this._request(configOrUrl, config); + } catch (err) { + if (err instanceof Error) { + let dummy; + + Error.captureStackTrace ? Error.captureStackTrace(dummy = {}) : (dummy = new Error()); + + // slice off the Error: ... line + const stack = dummy.stack ? dummy.stack.replace(/^.+\n/, '') : ''; + + if (!err.stack) { + err.stack = stack; + // match without the 2 top stack lines + } else if (stack && !String(err.stack).endsWith(stack.replace(/^.+\n.+\n/, ''))) { + err.stack += '\n' + stack; + } + } + + throw err; + } + } + + _request(configOrUrl, config) { /*eslint no-param-reassign:0*/ // Allow for axios('example/url'[, config]) a la fetch API if (typeof configOrUrl === 'string') { @@ -6165,7 +6186,7 @@ define(['vue'], (function (vue) { 'use strict'; } if (paramsSerializer != null) { - if (utils.isFunction(paramsSerializer)) { + if (utils$1.isFunction(paramsSerializer)) { config.paramsSerializer = { serialize: paramsSerializer }; @@ -6181,12 +6202,12 @@ define(['vue'], (function (vue) { 'use strict'; config.method = (config.method || this.defaults.method || 'get').toLowerCase(); // Flatten headers - let contextHeaders = headers && utils.merge( + let contextHeaders = headers && utils$1.merge( headers.common, headers[config.method] ); - headers && utils.forEach( + headers && utils$1.forEach( ['delete', 'get', 'head', 'post', 'put', 'patch', 'common'], (method) => { delete headers[method]; @@ -6273,7 +6294,7 @@ define(['vue'], (function (vue) { 'use strict'; } // Provide aliases for supported request methods - utils.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData(method) { + utils$1.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData(method) { /*eslint func-names:0*/ Axios.prototype[method] = function(url, config) { return this.request(mergeConfig(config || {}, { @@ -6284,7 +6305,7 @@ define(['vue'], (function (vue) { 'use strict'; }; }); - utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) { + utils$1.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) { /*eslint func-names:0*/ function generateHTTPMethod(isForm) { @@ -6460,7 +6481,7 @@ define(['vue'], (function (vue) { 'use strict'; * @returns {boolean} True if the payload is an error thrown by Axios, otherwise false */ function isAxiosError(payload) { - return utils.isObject(payload) && (payload.isAxiosError === true); + return utils$1.isObject(payload) && (payload.isAxiosError === true); } const HttpStatusCode = { @@ -6547,10 +6568,10 @@ define(['vue'], (function (vue) { 'use strict'; const instance = bind(Axios$1.prototype.request, context); // Copy axios.prototype to instance - utils.extend(instance, Axios$1.prototype, context, {allOwnKeys: true}); + utils$1.extend(instance, Axios$1.prototype, context, {allOwnKeys: true}); // Copy context to instance - utils.extend(instance, context, null, {allOwnKeys: true}); + utils$1.extend(instance, context, null, {allOwnKeys: true}); // Factory for creating new instances instance.create = function create(instanceConfig) { @@ -6594,7 +6615,7 @@ define(['vue'], (function (vue) { 'use strict'; axios.AxiosHeaders = AxiosHeaders$1; - axios.formToJSON = thing => formDataToJSON(utils.isHTMLForm(thing) ? new FormData(thing) : thing); + axios.formToJSON = thing => formDataToJSON(utils$1.isHTMLForm(thing) ? new FormData(thing) : thing); axios.getAdapter = adapters.getAdapter; @@ -6762,7 +6783,7 @@ define(['vue'], (function (vue) { 'use strict'; /** * - * (c) Copyright Ascensio System SIA 2024 + * (c) Copyright Ascensio System SIA 2023 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License.