Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b3d95d60af | |||
| 828cd544ac | |||
| eabf571982 | |||
| 7a5379cd13 | |||
| 4987175abb |
@@ -165,3 +165,46 @@ updates:
|
||||
# no major updates on stable branches
|
||||
- dependency-name: "*"
|
||||
update-types: ["version-update:semver-major"]
|
||||
|
||||
# Composer dependencies for linting and testing
|
||||
- package-ecosystem: composer
|
||||
target-branch: stable31
|
||||
directories:
|
||||
- "/"
|
||||
- "/build/integration"
|
||||
- "/vendor-bin/cs-fixer"
|
||||
- "/vendor-bin/openapi-extractor"
|
||||
- "/vendor-bin/phpunit"
|
||||
- "/vendor-bin/psalm"
|
||||
schedule:
|
||||
interval: weekly
|
||||
day: saturday
|
||||
time: "04:00"
|
||||
timezone: Europe/Paris
|
||||
labels:
|
||||
- "3. to review"
|
||||
- "feature: dependencies"
|
||||
ignore:
|
||||
# only patch updates on stable branches
|
||||
- dependency-name: "*"
|
||||
update-types: ["version-update:semver-major", "version-update:semver-minor"]
|
||||
|
||||
# frontend dependencies
|
||||
- package-ecosystem: npm
|
||||
target-branch: stable31
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: weekly
|
||||
day: saturday
|
||||
time: "04:00"
|
||||
timezone: Europe/Paris
|
||||
open-pull-requests-limit: 20
|
||||
labels:
|
||||
- "3. to review"
|
||||
- "feature: dependencies"
|
||||
# Disable automatic rebasing because without a build CI will likely fail anyway
|
||||
rebase-strategy: "disabled"
|
||||
ignore:
|
||||
# no major updates on stable branches
|
||||
- dependency-name: "*"
|
||||
update-types: ["version-update:semver-major"]
|
||||
|
||||
@@ -37,13 +37,13 @@ jobs:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@45cbd0c69e560cd9e7cd7f8c32362050c9b7ded2 # v4.32.2
|
||||
uses: github/codeql-action/init@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v4.32.0
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
build-mode: ${{ matrix.build-mode }}
|
||||
config-file: ./.github/codeql-config.yml
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@45cbd0c69e560cd9e7cd7f8c32362050c9b7ded2 # v4.32.2
|
||||
uses: github/codeql-action/analyze@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v4.32.0
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
|
||||
@@ -171,7 +171,7 @@ jobs:
|
||||
run: ./node_modules/cypress/bin/cypress install
|
||||
|
||||
- name: Run ${{ matrix.containers == 'component' && 'component' || 'E2E' }} cypress tests
|
||||
uses: cypress-io/github-action@84d178e4bbce871e23f2ffa3085898cde0e4f0ec # v7.1.2
|
||||
uses: cypress-io/github-action@0f330ebf0d60f87608ed72f1d6232e5644aa3171 # v7.1.1
|
||||
with:
|
||||
# We already installed the dependencies in the init job
|
||||
install: false
|
||||
|
||||
@@ -71,7 +71,7 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Set up Python
|
||||
uses: LizardByte/actions/actions/setup_python@9bf3ef783775e17fe6b8dde3585d94ec570b93c2 # v2026.212.22356
|
||||
uses: LizardByte/actions/actions/setup_python@09a6e10dc8175f2933c20bdf35fde0a193a9c00e # v2026.129.194351
|
||||
with:
|
||||
python-version: '2.7'
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ jobs:
|
||||
|
||||
- name: Upload Security Analysis results to GitHub
|
||||
if: always()
|
||||
uses: github/codeql-action/upload-sarif@45cbd0c69e560cd9e7cd7f8c32362050c9b7ded2 # v3
|
||||
uses: github/codeql-action/upload-sarif@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v3
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ OC.L10N.register(
|
||||
"Delete comment" : "Zmazať komentár",
|
||||
"Cancel edit" : "Zrušiť upravovanie",
|
||||
"New comment" : "Nový komentár",
|
||||
"Write a comment …" : "Napísať komentár ...",
|
||||
"Post comment" : "Odoslať komentár",
|
||||
"@ for mentions, : for emoji, / for smart picker" : "@ pre spomienky, : pre emotikony, / pre inteligentný výber",
|
||||
"Could not reload comments" : "Nepodarilo sa obnoviť komentáre",
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
"Delete comment" : "Zmazať komentár",
|
||||
"Cancel edit" : "Zrušiť upravovanie",
|
||||
"New comment" : "Nový komentár",
|
||||
"Write a comment …" : "Napísať komentár ...",
|
||||
"Post comment" : "Odoslať komentár",
|
||||
"@ for mentions, : for emoji, / for smart picker" : "@ pre spomienky, : pre emotikony, / pre inteligentný výber",
|
||||
"Could not reload comments" : "Nepodarilo sa obnoviť komentáre",
|
||||
|
||||
@@ -9,7 +9,6 @@ import CommentProcessingSvg from '@mdi/svg/svg/comment-processing.svg?raw'
|
||||
import { getSidebar } from '@nextcloud/files'
|
||||
import { n, t } from '@nextcloud/l10n'
|
||||
import logger from '../logger.js'
|
||||
import { isUsingActivityIntegration } from '../utils/activity.js'
|
||||
|
||||
export const action: IFileAction = {
|
||||
id: 'comments-unread',
|
||||
@@ -39,13 +38,7 @@ export const action: IFileAction = {
|
||||
|
||||
try {
|
||||
const sidebar = getSidebar()
|
||||
const sidebarTabId = isUsingActivityIntegration() ? 'activity' : 'comments'
|
||||
if (sidebar.isOpen && sidebar.node?.source === nodes[0].source) {
|
||||
logger.debug('Sidebar already open for this node, just activating comments tab')
|
||||
sidebar.setActiveTab(sidebarTabId)
|
||||
return null
|
||||
}
|
||||
sidebar.open(nodes[0], sidebarTabId)
|
||||
sidebar.open(nodes[0], 'comments')
|
||||
return null
|
||||
} catch (error) {
|
||||
logger.error('Error while opening sidebar', { error })
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*!
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
@@ -6,18 +6,18 @@
|
||||
import MessageReplyText from '@mdi/svg/svg/message-reply-text.svg?raw'
|
||||
import { getCSPNonce } from '@nextcloud/auth'
|
||||
import { registerSidebarTab } from '@nextcloud/files'
|
||||
import { loadState } from '@nextcloud/initial-state'
|
||||
import { t } from '@nextcloud/l10n'
|
||||
import wrap from '@vue/web-component-wrapper'
|
||||
import { createPinia, PiniaVuePlugin } from 'pinia'
|
||||
import Vue from 'vue'
|
||||
import { registerCommentsPlugins } from './comments-activity-tab.ts'
|
||||
import { isUsingActivityIntegration } from './utils/activity.ts'
|
||||
|
||||
__webpack_nonce__ = getCSPNonce()
|
||||
|
||||
const tagName = 'comments_files-sidebar-tab'
|
||||
|
||||
if (isUsingActivityIntegration()) {
|
||||
if (loadState('comments', 'activityEnabled', false) && OCA?.Activity?.registerSidebarAction !== undefined) {
|
||||
// Do not mount own tab but mount into activity
|
||||
window.addEventListener('DOMContentLoaded', function() {
|
||||
registerCommentsPlugins()
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
/*!
|
||||
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { loadState } from '@nextcloud/initial-state'
|
||||
|
||||
/**
|
||||
* Check if the comments app is using the Activity app integration for the sidebar.
|
||||
*/
|
||||
export function isUsingActivityIntegration() {
|
||||
return loadState('comments', 'activityEnabled', false) && window.OCA?.Activity?.registerSidebarAction !== undefined
|
||||
}
|
||||
@@ -20,7 +20,6 @@ OC.L10N.register(
|
||||
"Edit widgets" : "Upraviť miniaplikácie",
|
||||
"Get more widgets from the App Store" : "Získať viac miniaplikácií v Obchode s aplikáciami",
|
||||
"Weather service" : "Služba počasie",
|
||||
"For your privacy, the weather data is requested by your {productName} server on your behalf so the weather service receives no personal information." : "Pre vaše súkromie sú údaje o počasí požadované vaším {productName} serverom vo vašom mene, takže služba počasia neobdrží žiadne osobné informácie.",
|
||||
"Weather data from Met.no" : "Dáta počasia z Met.no",
|
||||
"geocoding with Nominatim" : "geokódovanie pomocou Nominatim",
|
||||
"elevation data from OpenTopoData" : "dáta o nadmorskej výške z OpenTopoData",
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
"Edit widgets" : "Upraviť miniaplikácie",
|
||||
"Get more widgets from the App Store" : "Získať viac miniaplikácií v Obchode s aplikáciami",
|
||||
"Weather service" : "Služba počasie",
|
||||
"For your privacy, the weather data is requested by your {productName} server on your behalf so the weather service receives no personal information." : "Pre vaše súkromie sú údaje o počasí požadované vaším {productName} serverom vo vašom mene, takže služba počasia neobdrží žiadne osobné informácie.",
|
||||
"Weather data from Met.no" : "Dáta počasia z Met.no",
|
||||
"geocoding with Nominatim" : "geokódovanie pomocou Nominatim",
|
||||
"elevation data from OpenTopoData" : "dáta o nadmorskej výške z OpenTopoData",
|
||||
|
||||
@@ -12,8 +12,8 @@ OC.L10N.register(
|
||||
"Good afternoon, {name}" : "Добрий день, {name}",
|
||||
"Good evening" : "Добрий вечір",
|
||||
"Good evening, {name}" : "Добрий вечір, {name}",
|
||||
"Hello" : "Вітання",
|
||||
"Hello, {name}" : "Вітання, {name}",
|
||||
"Hello" : "Привіт",
|
||||
"Hello, {name}" : "Привіт, {name}",
|
||||
"Happy birthday 🥳🤩🎂🎉" : "З Днем народження 🥳🤩🎂🎉",
|
||||
"Happy birthday, {name} 🥳🤩🎂🎉" : "З Днем народження, {name} 🥳🤩🎂🎉",
|
||||
"Customize" : "Редагувати",
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
"Good afternoon, {name}" : "Добрий день, {name}",
|
||||
"Good evening" : "Добрий вечір",
|
||||
"Good evening, {name}" : "Добрий вечір, {name}",
|
||||
"Hello" : "Вітання",
|
||||
"Hello, {name}" : "Вітання, {name}",
|
||||
"Hello" : "Привіт",
|
||||
"Hello, {name}" : "Привіт, {name}",
|
||||
"Happy birthday 🥳🤩🎂🎉" : "З Днем народження 🥳🤩🎂🎉",
|
||||
"Happy birthday, {name} 🥳🤩🎂🎉" : "З Днем народження, {name} 🥳🤩🎂🎉",
|
||||
"Customize" : "Редагувати",
|
||||
|
||||
+2
-2
@@ -159,9 +159,9 @@ OC.L10N.register(
|
||||
"Attendees:" : "Asistentes:",
|
||||
"Title:" : "Título:",
|
||||
"When:" : "Cando:",
|
||||
"Location:" : "Onde:",
|
||||
"Location:" : "Lugar:",
|
||||
"Link:" : "Ligazón:",
|
||||
"Occurring:" : "Acaecerá:",
|
||||
"Occurring:" : "Acaecendo:",
|
||||
"Accept" : "Aceptar",
|
||||
"Decline" : "Declinar",
|
||||
"More options …" : "Máis opcións…",
|
||||
|
||||
@@ -157,9 +157,9 @@
|
||||
"Attendees:" : "Asistentes:",
|
||||
"Title:" : "Título:",
|
||||
"When:" : "Cando:",
|
||||
"Location:" : "Onde:",
|
||||
"Location:" : "Lugar:",
|
||||
"Link:" : "Ligazón:",
|
||||
"Occurring:" : "Acaecerá:",
|
||||
"Occurring:" : "Acaecendo:",
|
||||
"Accept" : "Aceptar",
|
||||
"Decline" : "Declinar",
|
||||
"More options …" : "Máis opcións…",
|
||||
|
||||
@@ -75,17 +75,7 @@ OC.L10N.register(
|
||||
"In the past on %1$s for the entire day" : "W przeszłości w %1$s na cały dzień",
|
||||
"_In %n minute on %1$s for the entire day_::_In %n minutes on %1$s for the entire day_" : ["Za minutę o %1$s przez cały dzień","Za %n minut o %1$s przez cały dzień","Za %n minut o %1$s przez cały dzień","Za %n minut o %1$s przez cały dzień"],
|
||||
"_In %n hour on %1$s for the entire day_::_In %n hours on %1$s for the entire day_" : ["Za %n godzinę o %1$s przez cały dzień","Za %n godzin o %1$s przez cały dzień","Za %n godzin o %1$s przez cały dzień","Za %n godziny o %1$s przez cały dzień"],
|
||||
"_In %n day on %1$s for the entire day_::_In %n days on %1$s for the entire day_" : ["W ciągu %n dnia o %1$s przez cały dzień","W ciągu %n dni o %1$s przez cały dzień","W ciągu %n dni o %1$s przez cały dzień","W ciągu %n dni o %1$s przez cały dzień"],
|
||||
"_In %n week on %1$s for the entire day_::_In %n weeks on %1$s for the entire day_" : ["Za %n tydzień o %1$s przez cały dzień","W ciągu %n tygodni o %1$s przez cały dzień","W ciągu %n tygodni o %1$s przez cały dzień","W ciągu %n tygodni o %1$s przez cały dzień"],
|
||||
"_In %n month on %1$s for the entire day_::_In %n months on %1$s for the entire day_" : ["Za %n miesiąc, o %1$s przez cały dzień","W ciągu %n miesięcy, o %1$s przez cały dzień","W ciągu %n miesięcy, o %1$s przez cały dzień","W ciągu %n miesięcy, o %1$s przez cały dzień"],
|
||||
"_In %n year on %1$s for the entire day_::_In %n years on %1$s for the entire day_" : ["Za %n rok o %1$s przez cały dzień","Za %n lat o %1$s przez cały dzień","Za %n lat o %1$s przez cały dzień","Za %n lat o %1$s przez cały dzień"],
|
||||
"In the past on %1$s between %2$s - %3$s" : "W przeszłości dnia %1$s między %2$s - %3$s",
|
||||
"_In %n minute on %1$s between %2$s - %3$s_::_In %n minutes on %1$s between %2$s - %3$s_" : ["Za %n minutę o %1$s pomiędzy %2$s - %3$s","Za %n minut o %1$s pomiędzy %2$s - %3$s","Za %n minut o %1$s pomiędzy %2$s - %3$s","Za %n minut o %1$s pomiędzy %2$s - %3$s"],
|
||||
"_In %n hour on %1$s between %2$s - %3$s_::_In %n hours on %1$s between %2$s - %3$s_" : ["Za %n godzinę o %1$s między %2$s - %3$s","Za %n godzin o %1$s między %2$s - %3$s","Za %n godzin o %1$s między %2$s - %3$s","Za %n godzin o %1$s między %2$s - %3$s"],
|
||||
"_In %n day on %1$s between %2$s - %3$s_::_In %n days on %1$s between %2$s - %3$s_" : ["Za %n dzień o %1$s między %2$s - %3$s","Za %n dni o %1$s między %2$s - %3$s","Za %n dni o %1$s między %2$s - %3$s","Za %n dni o %1$s między %2$s - %3$s"],
|
||||
"_In %n week on %1$s between %2$s - %3$s_::_In %n weeks on %1$s between %2$s - %3$s_" : ["Za %n tydzień o %1$s między %2$s - %3$s","Za %n tygodni o %1$s między %2$s - %3$s","Za %n tygodni o %1$s między %2$s - %3$s","Za %n tygodnie o %1$s między %2$s - %3$s"],
|
||||
"_In %n month on %1$s between %2$s - %3$s_::_In %n months on %1$s between %2$s - %3$s_" : ["Za %n miesiąc o %1$s między %2$s - %3$s","Za %n miesięcy o %1$s między %2$s - %3$s","Za %n miesięcy o %1$s między %2$s - %3$s","Za %n miesiące o %1$s między %2$s - %3$s"],
|
||||
"_In %n year on %1$s between %2$s - %3$s_::_In %n years on %1$s between %2$s - %3$s_" : ["Za %n rok o %1$s między %2$s - %3$s","Za %n lat o %1$s między %2$s - %3$s","Za %n lat o %1$s między %2$s - %3$s","Za %n lata o %1$s między %2$s - %3$s"],
|
||||
"Could not generate when statement" : "Nie można wygenerować instrukcji when",
|
||||
"Every Day for the entire day" : "Codziennie przez cały dzień",
|
||||
"Every Day for the entire day until %1$s" : "Codziennie przez cały dzień do %1$s",
|
||||
@@ -123,12 +113,6 @@ OC.L10N.register(
|
||||
"On specific dates for the entire day until %1$s" : "W określonych datach przez cały dzień do %1$s",
|
||||
"On specific dates between %1$s - %2$s until %3$s" : "W określonych datach między %1$s - %2$s do %3$s",
|
||||
"In the past on %1$s" : "W przeszłości dnia %1$s",
|
||||
"_In %n minute on %1$s_::_In %n minutes on %1$s_" : ["Za %n minutę o %1$s","Za %n minuty o %1$s","Za %n minuty o %1$s","Za %n minuty o %1$s"],
|
||||
"_In %n hour on %1$s_::_In %n hours on %1$s_" : ["Za %n godzinę o %1$s","Za %n godzin o %1$s","Za %n godzin o %1$s","Za %n godzin o %1$s"],
|
||||
"_In %n day on %1$s_::_In %n days on %1$s_" : ["Za %n dzień o %1$s","Za %n dni o %1$s","Za %n dni o %1$s","Za %n dni o %1$s"],
|
||||
"_In %n week on %1$s_::_In %n weeks on %1$s_" : ["Za %n tydzień o %1$s","Za %n tygodnie o %1$s","Za %n tygodnie o %1$s","Za %n tygodnie o %1$s"],
|
||||
"_In %n month on %1$s_::_In %n months on %1$s_" : ["Za %n miesiąc o %1$s","W ciągu %n miesięcy o %1$s","W ciągu %n miesięcy o %1$s","W ciągu %n miesięcy o %1$s"],
|
||||
"_In %n year on %1$s_::_In %n years on %1$s_" : ["Za %n rok o %1$s","Za %n lat o %1$s","Za %n lat o %1$s","Za %n lat o %1$s"],
|
||||
"In the past on %1$s then on %2$s" : "W przeszłości dnia %1$s, a następnie %2$s",
|
||||
"In the past on %1$s then on %2$s and %3$s" : "W przeszłości dnia %1$s, następnie dnia %2$s i %3$s",
|
||||
"Could not generate next recurrence statement" : "Nie można wygenerować następnej instrukcji powtarzania",
|
||||
@@ -222,8 +206,6 @@ OC.L10N.register(
|
||||
"Could not rename part file to final file, canceled by hook" : "Nie można zmienić nazwy pliku podzielonego na plik końcowy, anulowane przez hook",
|
||||
"Could not rename part file to final file" : "Nie można zmienić nazwy pliku podzielonego na plik końcowy",
|
||||
"Failed to check file size: %1$s" : "Nie udało się sprawdzić rozmiaru pliku: %1$s",
|
||||
"Could not open file: %1$s (%2$d), file does seem to exist" : "Nie można otworzyć: %1$s (%2$d), zdaje się, że plik istnieje",
|
||||
"Could not open file: %1$s (%2$d), file doesn't seem to exist" : "Nie można otworzyć: %1$s (%2$d), zdaje się, że plik nie istnieje",
|
||||
"Encryption not ready: %1$s" : "Szyfrowanie nie jest gotowe: %1$s",
|
||||
"Failed to open file: %1$s" : "Nie udało się otworzyć pliku: %1$s",
|
||||
"Failed to unlink: %1$s" : "Nie udało się odłączyć: %1$s",
|
||||
|
||||
@@ -73,17 +73,7 @@
|
||||
"In the past on %1$s for the entire day" : "W przeszłości w %1$s na cały dzień",
|
||||
"_In %n minute on %1$s for the entire day_::_In %n minutes on %1$s for the entire day_" : ["Za minutę o %1$s przez cały dzień","Za %n minut o %1$s przez cały dzień","Za %n minut o %1$s przez cały dzień","Za %n minut o %1$s przez cały dzień"],
|
||||
"_In %n hour on %1$s for the entire day_::_In %n hours on %1$s for the entire day_" : ["Za %n godzinę o %1$s przez cały dzień","Za %n godzin o %1$s przez cały dzień","Za %n godzin o %1$s przez cały dzień","Za %n godziny o %1$s przez cały dzień"],
|
||||
"_In %n day on %1$s for the entire day_::_In %n days on %1$s for the entire day_" : ["W ciągu %n dnia o %1$s przez cały dzień","W ciągu %n dni o %1$s przez cały dzień","W ciągu %n dni o %1$s przez cały dzień","W ciągu %n dni o %1$s przez cały dzień"],
|
||||
"_In %n week on %1$s for the entire day_::_In %n weeks on %1$s for the entire day_" : ["Za %n tydzień o %1$s przez cały dzień","W ciągu %n tygodni o %1$s przez cały dzień","W ciągu %n tygodni o %1$s przez cały dzień","W ciągu %n tygodni o %1$s przez cały dzień"],
|
||||
"_In %n month on %1$s for the entire day_::_In %n months on %1$s for the entire day_" : ["Za %n miesiąc, o %1$s przez cały dzień","W ciągu %n miesięcy, o %1$s przez cały dzień","W ciągu %n miesięcy, o %1$s przez cały dzień","W ciągu %n miesięcy, o %1$s przez cały dzień"],
|
||||
"_In %n year on %1$s for the entire day_::_In %n years on %1$s for the entire day_" : ["Za %n rok o %1$s przez cały dzień","Za %n lat o %1$s przez cały dzień","Za %n lat o %1$s przez cały dzień","Za %n lat o %1$s przez cały dzień"],
|
||||
"In the past on %1$s between %2$s - %3$s" : "W przeszłości dnia %1$s między %2$s - %3$s",
|
||||
"_In %n minute on %1$s between %2$s - %3$s_::_In %n minutes on %1$s between %2$s - %3$s_" : ["Za %n minutę o %1$s pomiędzy %2$s - %3$s","Za %n minut o %1$s pomiędzy %2$s - %3$s","Za %n minut o %1$s pomiędzy %2$s - %3$s","Za %n minut o %1$s pomiędzy %2$s - %3$s"],
|
||||
"_In %n hour on %1$s between %2$s - %3$s_::_In %n hours on %1$s between %2$s - %3$s_" : ["Za %n godzinę o %1$s między %2$s - %3$s","Za %n godzin o %1$s między %2$s - %3$s","Za %n godzin o %1$s między %2$s - %3$s","Za %n godzin o %1$s między %2$s - %3$s"],
|
||||
"_In %n day on %1$s between %2$s - %3$s_::_In %n days on %1$s between %2$s - %3$s_" : ["Za %n dzień o %1$s między %2$s - %3$s","Za %n dni o %1$s między %2$s - %3$s","Za %n dni o %1$s między %2$s - %3$s","Za %n dni o %1$s między %2$s - %3$s"],
|
||||
"_In %n week on %1$s between %2$s - %3$s_::_In %n weeks on %1$s between %2$s - %3$s_" : ["Za %n tydzień o %1$s między %2$s - %3$s","Za %n tygodni o %1$s między %2$s - %3$s","Za %n tygodni o %1$s między %2$s - %3$s","Za %n tygodnie o %1$s między %2$s - %3$s"],
|
||||
"_In %n month on %1$s between %2$s - %3$s_::_In %n months on %1$s between %2$s - %3$s_" : ["Za %n miesiąc o %1$s między %2$s - %3$s","Za %n miesięcy o %1$s między %2$s - %3$s","Za %n miesięcy o %1$s między %2$s - %3$s","Za %n miesiące o %1$s między %2$s - %3$s"],
|
||||
"_In %n year on %1$s between %2$s - %3$s_::_In %n years on %1$s between %2$s - %3$s_" : ["Za %n rok o %1$s między %2$s - %3$s","Za %n lat o %1$s między %2$s - %3$s","Za %n lat o %1$s między %2$s - %3$s","Za %n lata o %1$s między %2$s - %3$s"],
|
||||
"Could not generate when statement" : "Nie można wygenerować instrukcji when",
|
||||
"Every Day for the entire day" : "Codziennie przez cały dzień",
|
||||
"Every Day for the entire day until %1$s" : "Codziennie przez cały dzień do %1$s",
|
||||
@@ -121,12 +111,6 @@
|
||||
"On specific dates for the entire day until %1$s" : "W określonych datach przez cały dzień do %1$s",
|
||||
"On specific dates between %1$s - %2$s until %3$s" : "W określonych datach między %1$s - %2$s do %3$s",
|
||||
"In the past on %1$s" : "W przeszłości dnia %1$s",
|
||||
"_In %n minute on %1$s_::_In %n minutes on %1$s_" : ["Za %n minutę o %1$s","Za %n minuty o %1$s","Za %n minuty o %1$s","Za %n minuty o %1$s"],
|
||||
"_In %n hour on %1$s_::_In %n hours on %1$s_" : ["Za %n godzinę o %1$s","Za %n godzin o %1$s","Za %n godzin o %1$s","Za %n godzin o %1$s"],
|
||||
"_In %n day on %1$s_::_In %n days on %1$s_" : ["Za %n dzień o %1$s","Za %n dni o %1$s","Za %n dni o %1$s","Za %n dni o %1$s"],
|
||||
"_In %n week on %1$s_::_In %n weeks on %1$s_" : ["Za %n tydzień o %1$s","Za %n tygodnie o %1$s","Za %n tygodnie o %1$s","Za %n tygodnie o %1$s"],
|
||||
"_In %n month on %1$s_::_In %n months on %1$s_" : ["Za %n miesiąc o %1$s","W ciągu %n miesięcy o %1$s","W ciągu %n miesięcy o %1$s","W ciągu %n miesięcy o %1$s"],
|
||||
"_In %n year on %1$s_::_In %n years on %1$s_" : ["Za %n rok o %1$s","Za %n lat o %1$s","Za %n lat o %1$s","Za %n lat o %1$s"],
|
||||
"In the past on %1$s then on %2$s" : "W przeszłości dnia %1$s, a następnie %2$s",
|
||||
"In the past on %1$s then on %2$s and %3$s" : "W przeszłości dnia %1$s, następnie dnia %2$s i %3$s",
|
||||
"Could not generate next recurrence statement" : "Nie można wygenerować następnej instrukcji powtarzania",
|
||||
@@ -220,8 +204,6 @@
|
||||
"Could not rename part file to final file, canceled by hook" : "Nie można zmienić nazwy pliku podzielonego na plik końcowy, anulowane przez hook",
|
||||
"Could not rename part file to final file" : "Nie można zmienić nazwy pliku podzielonego na plik końcowy",
|
||||
"Failed to check file size: %1$s" : "Nie udało się sprawdzić rozmiaru pliku: %1$s",
|
||||
"Could not open file: %1$s (%2$d), file does seem to exist" : "Nie można otworzyć: %1$s (%2$d), zdaje się, że plik istnieje",
|
||||
"Could not open file: %1$s (%2$d), file doesn't seem to exist" : "Nie można otworzyć: %1$s (%2$d), zdaje się, że plik nie istnieje",
|
||||
"Encryption not ready: %1$s" : "Szyfrowanie nie jest gotowe: %1$s",
|
||||
"Failed to open file: %1$s" : "Nie udało się otworzyć pliku: %1$s",
|
||||
"Failed to unlink: %1$s" : "Nie udało się odłączyć: %1$s",
|
||||
|
||||
@@ -73,19 +73,7 @@ OC.L10N.register(
|
||||
"Where: %s" : "Kde: %s",
|
||||
"%1$s via %2$s" : "%1$s cez %2$s",
|
||||
"In the past on %1$s for the entire day" : "V minulosti %1$s na celý deň",
|
||||
"_In %n minute on %1$s for the entire day_::_In %n minutes on %1$s for the entire day_" : ["Za %n minútu %1$s na celý deň","Za %n minúty %1$s na celý deň","Za %n minút %1$s na celý deň","Za %n minút %1$s na celý deň"],
|
||||
"_In %n hour on %1$s for the entire day_::_In %n hours on %1$s for the entire day_" : ["Za %n hodinu %1$s na celý deň","Za %n hodiny %1$s na celý deň","Za %n hodín %1$s na celý deň","Za %n hodín %1$s na celý deň"],
|
||||
"_In %n day on %1$s for the entire day_::_In %n days on %1$s for the entire day_" : ["Za %n deň %1$s na celý deň","Za %n dni %1$s na celý deň","Za %n dní %1$s na celý deň","Za %n dní %1$s na celý deň"],
|
||||
"_In %n week on %1$s for the entire day_::_In %n weeks on %1$s for the entire day_" : ["Za %n týždeň %1$s na celý deň","Za %n týždne %1$s na celý deň","Za %n týždňov %1$s na celý deň","Za %n týždňov %1$s na celý deň"],
|
||||
"_In %n month on %1$s for the entire day_::_In %n months on %1$s for the entire day_" : ["Za %n mesiac %1$s na celý deň","Za %n mesiace %1$s na celý deň","Za %n mesiacov %1$s na celý deň","Za %n mesiacov %1$s na celý deň"],
|
||||
"_In %n year on %1$s for the entire day_::_In %n years on %1$s for the entire day_" : ["Za %n rok %1$s na celý deň","Za %n roky %1$s na celý deň","Za %n rokov %1$s na celý deň","Za %n rokov %1$s na celý deň"],
|
||||
"In the past on %1$s between %2$s - %3$s" : "V minulosti %1$s medzi %2$s - %3$s",
|
||||
"_In %n minute on %1$s between %2$s - %3$s_::_In %n minutes on %1$s between %2$s - %3$s_" : ["Za %n minútu %1$s %2$s medzi %2$s - %3$s","Za %n minúty %1$s %2$s medzi %2$s - %3$s","Za %n minút %1$s %2$s medzi %2$s - %3$s","Za %n minút %1$s %2$s medzi %2$s - %3$s"],
|
||||
"_In %n hour on %1$s between %2$s - %3$s_::_In %n hours on %1$s between %2$s - %3$s_" : ["Za %n hodinu %1$s %2$s medzi %2$s - %3$s","Za %n hodiny %1$s %2$s medzi %2$s - %3$s","Za %n hodín %1$s %2$s medzi %2$s - %3$s","Za %n hodín %1$s %2$s medzi %2$s - %3$s"],
|
||||
"_In %n day on %1$s between %2$s - %3$s_::_In %n days on %1$s between %2$s - %3$s_" : ["Za %n deň %1$s %2$s medzi %2$s - %3$s","Za %n dni %1$s %2$s medzi %2$s - %3$s","Za %n dní %1$s %2$s medzi %2$s - %3$s","Za %n dní %1$s %2$s medzi %2$s - %3$s"],
|
||||
"_In %n week on %1$s between %2$s - %3$s_::_In %n weeks on %1$s between %2$s - %3$s_" : ["Za %n týždeň %1$s %2$s medzi %2$s - %3$s","Za %n týždne %1$s %2$s medzi %2$s - %3$s","Za %n týždňov %1$s %2$s medzi %2$s - %3$s","Za %n týždňov %1$s %2$s medzi %2$s - %3$s"],
|
||||
"_In %n month on %1$s between %2$s - %3$s_::_In %n months on %1$s between %2$s - %3$s_" : ["Za %n mesiac %1$s %2$s medzi %2$s - %3$s","Za %n mesiace %1$s %2$s medzi %2$s - %3$s","Za %n mesiacov %1$s %2$s medzi %2$s - %3$s","Za %n mesiacov %1$s %2$s medzi %2$s - %3$s"],
|
||||
"_In %n year on %1$s between %2$s - %3$s_::_In %n years on %1$s between %2$s - %3$s_" : ["Za %n rok %1$s %2$s medzi %2$s - %3$s","Za %n roky %1$s %2$s medzi %2$s - %3$s","Za %n rokov %1$s %2$s medzi %2$s - %3$s","Za %n rokov %1$s %2$s medzi %2$s - %3$s"],
|
||||
"Could not generate when statement" : "Nepodarilo sa vygenerovať vyhlásenie kedy",
|
||||
"Every Day for the entire day" : "Každý deň, na celý deň",
|
||||
"Every Day for the entire day until %1$s" : "Každý deň, na celý deň, do %1$s",
|
||||
@@ -123,26 +111,8 @@ OC.L10N.register(
|
||||
"On specific dates for the entire day until %1$s" : "V konkrétnych dátumoch na celý deň %1$s",
|
||||
"On specific dates between %1$s - %2$s until %3$s" : "V konkrétnych dátumoch medzi %1$s - %2$s do %3$s",
|
||||
"In the past on %1$s" : "V minulosti %1$s",
|
||||
"_In %n minute on %1$s_::_In %n minutes on %1$s_" : ["Za %n minútu na %1$s","Za %n minúty na %1$s","Za %n minút na %1$s","Za %n minút na %1$s"],
|
||||
"_In %n hour on %1$s_::_In %n hours on %1$s_" : ["Za %n hodinu na %1$s","Za %n hodiny na %1$s","Za %n hodín na %1$s","Za %n hodín na%1$s"],
|
||||
"_In %n day on %1$s_::_In %n days on %1$s_" : ["Za %n deň na %1$s","Za %n dni na %1$s","Za %n dní na %1$s","Za %n dní na %1$s"],
|
||||
"_In %n week on %1$s_::_In %n weeks on %1$s_" : ["Za %n týždeň %1$s","Za %n týždne na %1$s","Za %n týždňov na %1$s","Za %n týždňov na %1$s"],
|
||||
"_In %n month on %1$s_::_In %n months on %1$s_" : ["Za %n mesiac na%1$s","Za %n mesiace na%1$s","Za %n mesiacov na%1$s","Za %n mesiacov na %1$s"],
|
||||
"_In %n year on %1$s_::_In %n years on %1$s_" : ["Za %n rok na %1$s","Za %n roky na %1$s","Za %n rokov na %1$s","Za %n rokov na %1$s"],
|
||||
"In the past on %1$s then on %2$s" : "V minulosti %1$s a potom %2$s",
|
||||
"_In %n minute on %1$s then on %2$s_::_In %n minutes on %1$s then on %2$s_" : ["Za %n minútu %1$s a potom %2$s","Za %n minúty %1$s a potom %2$s","Za %n minút %1$s a potom %2$s","Za %n minút %1$s a potom %2$s"],
|
||||
"_In %n hour on %1$s then on %2$s_::_In %n hours on %1$s then on %2$s_" : ["Za %n hodinu %1$s a potom %2$s","Za %n hodiny %1$s a potom %2$s","Za %n hodín %1$s a potom %2$s","Za %n hodín %1$s a potom %2$s"],
|
||||
"_In %n day on %1$s then on %2$s_::_In %n days on %1$s then on %2$s_" : ["Za %n deň %1$s a potom %2$s","Za %n dni %1$s a potom %2$s","Za %n dní %1$s a potom %2$s","Za %n dní %1$s a potom %2$s"],
|
||||
"_In %n week on %1$s then on %2$s_::_In %n weeks on %1$s then on %2$s_" : ["Za %n týždeň %1$s a potom %2$s","Za %n týždne %1$s a potom %2$s","Za %n týždňov %1$s a potom %2$s","Za %n týždňov %1$s a potom %2$s"],
|
||||
"_In %n month on %1$s then on %2$s_::_In %n months on %1$s then on %2$s_" : ["Za %n mesiac %1$s a potom %2$s","Za %n mesiace %1$s a potom %2$s","Za %n mesiacov %1$s a potom %2$s","Za %n mesiacov %1$s a potom %2$s"],
|
||||
"_In %n year on %1$s then on %2$s_::_In %n years on %1$s then on %2$s_" : ["Za %n rok %1$s a potom %2$s","Za %n roky %1$s a potom %2$s","Za %n rokov %1$s a potom %2$s","Za %n rokov %1$s a potom %2$s"],
|
||||
"In the past on %1$s then on %2$s and %3$s" : "V minulosti %1$s potom %2$s a %3$s",
|
||||
"_In %n minute on %1$s then on %2$s and %3$s_::_In %n minutes on %1$s then on %2$s and %3$s_" : ["Za %n minútu %1$s potom %2$s a %3$s","Za %n minúty %1$s potom %2$s a %3$s","Za %n minút %1$s potom %2$s a %3$s","Za %n minút %1$s potom %2$s a %3$s"],
|
||||
"_In %n hour on %1$s then on %2$s and %3$s_::_In %n hours on %1$s then on %2$s and %3$s_" : ["Za %n hodinu %1$s potom %2$s a %3$s","Za %n hodiny %1$s potom %2$s a %3$s","Za %n hodín %1$s potom %2$s a %3$s","Za %nhodín %1$s potom %2$s a %3$s"],
|
||||
"_In %n day on %1$s then on %2$s and %3$s_::_In %n days on %1$s then on %2$s and %3$s_" : ["Za %n deň %1$s potom %2$s a %3$s","Za %n dni %1$s potom %2$s a %3$s","Za %n dní %1$s potom %2$s a %3$s","Za %n dní %1$s potom %2$s a %3$s"],
|
||||
"_In %n week on %1$s then on %2$s and %3$s_::_In %n weeks on %1$s then on %2$s and %3$s_" : ["Za %n týždeň %1$s potom %2$s a %3$s","Za %n týždne %1$s potom %2$s a %3$s","Za %n týždňov %1$s potom %2$s a %3$s","Za %n týždňov %1$s potom %2$s a %3$s"],
|
||||
"_In %n month on %1$s then on %2$s and %3$s_::_In %n months on %1$s then on %2$s and %3$s_" : ["Za %n mesiac %1$s potom %2$s a %3$s","Za %n mesiace %1$s potom %2$s a %3$s","Za %n mesiacov %1$s potom %2$s a %3$s","Za %n mesiacov %1$s potom %2$s a %3$s"],
|
||||
"_In %n year on %1$s then on %2$s and %3$s_::_In %n years on %1$s then on %2$s and %3$s_" : ["Za %n rok %1$s potom %2$s a %3$s","Za %n roky %1$s potom %2$s a %3$s","Za %n rokov %1$s potom %2$s a %3$s","Za %n rokov %1$s potom %2$s a %3$s"],
|
||||
"Could not generate next recurrence statement" : "Nepodarilo sa vygenerovať ďalšie opakovanie",
|
||||
"Cancelled: %1$s" : "Zrušené: %1$s",
|
||||
"\"%1$s\" has been canceled" : "\"%1$s\" bolo zrušené",
|
||||
@@ -220,8 +190,6 @@ OC.L10N.register(
|
||||
"{actor} updated contact {card} in address book {addressbook}" : "{actor} upravil kontakt {card} v adresári {addressbook}",
|
||||
"You updated contact {card} in address book {addressbook}" : "Upravili ste kontakt {card} v adresári {addressbook}",
|
||||
"A <strong>contact</strong> or <strong>address book</strong> was modified" : "<strong>kontakt</strong> alebo <strong>adresár</strong> bol upravený",
|
||||
"System address book disabled" : "Systémový adresár je vypnutý",
|
||||
"The system contacts address book has been automatically disabled during upgrade. This means that the address book will no longer be available to users in the contacts app or other clients. The system contacts address book was disabled because the amount of contacts in the address book exceeded the maximum recommended number of contacts. This limit is set to prevent performance issues. You can re-enable the system address book with the following command {command}" : "Systémový adresár kontaktov bol automaticky vypnutý počas aktualizácie. To znamená, že adresár kontaktov už nebude dostupný pre používateľov v aplikácii Kontakty ani v iných klientoch. Systémový adresár kontaktov bol vypnutý, pretože počet kontaktov v adresári prekročil maximálny odporúčaný počet kontaktov. Tento limit je nastavený na prevenciu problémov s výkonom. Systémový adresár kontaktov môžete znovu povoliť pomocou nasledujúcej príkazu {command}.",
|
||||
"Accounts" : "Účty",
|
||||
"System address book which holds all accounts" : "Systémový adresár, ktorý obsahuje všetky účty.",
|
||||
"File is not updatable: %1$s" : "Súbor nie je možné aktualizovať: %1$s",
|
||||
@@ -234,8 +202,6 @@ OC.L10N.register(
|
||||
"Could not rename part file to final file, canceled by hook" : "Nepodarilo sa premenovať dočasný súbor na finálny, zrušené háčikom (hook)",
|
||||
"Could not rename part file to final file" : "Nepodarilo sa premenovať dočasný súbor na finálny.",
|
||||
"Failed to check file size: %1$s" : "Kontrola veľkosti súboru zlyhala: %1$s",
|
||||
"Could not open file: %1$s (%2$d), file does seem to exist" : "Nie je možné otvoriť súbor: %1$s (%2$d), zdá sa že súbor existuje",
|
||||
"Could not open file: %1$s (%2$d), file doesn't seem to exist" : "Nie je možné otvoriť súbor: %1$s (%2$d), nezdá sa že súbor existuje",
|
||||
"Encryption not ready: %1$s" : "Šifrovanie nie je dostupné: %1$s",
|
||||
"Failed to open file: %1$s" : "Otvorenie súboru zlyhalo: %1$s",
|
||||
"Failed to unlink: %1$s" : "Odpojenie zlyhalo: %1$s",
|
||||
@@ -252,18 +218,12 @@ OC.L10N.register(
|
||||
"Completed on %s" : "Dokončené %s",
|
||||
"Due on %s by %s" : "Termín od %s do %s",
|
||||
"Due on %s" : "Termín do %s",
|
||||
"Welcome to Nextcloud Calendar!\n\nThis is a sample event - explore the flexibility of planning with Nextcloud Calendar by making any edits you want!\n\nWith Nextcloud Calendar, you can:\n- Create, edit, and manage events effortlessly.\n- Create multiple calendars and share them with teammates, friends, or family.\n- Check availability and display your busy times to others.\n- Seamlessly integrate with apps and devices via CalDAV.\n- Customize your experience: schedule recurring events, adjust notifications and other settings." : "Vitajte v Nextcloud Calendar!\n\nToto je ukážková udalosť – preskúmajte flexibilitu plánovania s Nextcloud Calendar tým, že vykonáte akékoľvek úpravy, ktoré chcete!\n\nS Nextcloud Calendar môžete:\n- Jednoducho vytvárať, upravovať a spravovať udalosti.\n- Vytvárať viacero kalendárov a zdieľať ich s tímom, priateľmi alebo rodinou.\n- Skontrolovať dostupnosť a zobraziť svoje zaneprázdnené časy pre ostatných.\n- Bezproblémovo integrovať s aplikáciami a zariadeniami cez CalDAV.\n- Prispôsobiť si skúsenosti: naplánovať opakujúce sa udalosti, nastaviť notifikácie a iné nastavenia.",
|
||||
"Example event - open me!" : "Príklad udalosti - otvorte ma!",
|
||||
"System Address Book" : "Systémový Adresár",
|
||||
"The system address book contains contact information for all users in your instance." : "Systémový adresár obsahuje kontaktné informácie o všetkých užívateľov vo vašej inštancii.",
|
||||
"Enable System Address Book" : "Povoliť systémový Adresár",
|
||||
"DAV system address book" : "Systémový DAV adresár",
|
||||
"No outstanding DAV system address book sync." : "Žiadna zostávajúca synchronizácia adresára systému DAV.",
|
||||
"The DAV system address book sync has not run yet as your instance has more than 1000 users or because an error occurred. Please run it manually by calling \"occ dav:sync-system-addressbook\"." : "DAV synchronizácia systémového adresára ešte nebola spustená, pretože vaša inštancia má viac ako 1000 užívateľov alebo sa vyskytla chyba. Prosím, spustite ju manuálne volaním \"occ dav:sync-system-addressbook\".",
|
||||
"DAV system address book size" : "Veľkosť adresára systému DAV",
|
||||
"The system address book is disabled" : "Systémový adresár je zakázaný",
|
||||
"The system address book is enabled, but contains more than the configured limit of %d contacts" : "Adresár systému je povolený, ale obsahuje viac kontaktov, než je nastavený limit %dkontaktov.",
|
||||
"The system address book is enabled and contains less than the configured limit of %d contacts" : "Adresár systému je povolený a obsahuje menej kontaktov, než je nastavený limit %dkontaktov.",
|
||||
"WebDAV endpoint" : "Koncový bod WebDAV",
|
||||
"Could not check that your web server is properly set up to allow file synchronization over WebDAV. Please check manually." : "Nepodarilo sa skontrolovať, či je váš webový server správne nastavený tak, aby umožňoval synchronizáciu súborov cez WebDAV. Skontrolujte prosím manuálne.",
|
||||
"Your web server is not yet properly set up to allow file synchronization, because the WebDAV interface seems to be broken." : "Váš webový server nie je zatiaľ správne nastavený, aby umožnil synchronizáciu súborov, pretože rozhranie WebDAV sa zdá byť nefunkčné.",
|
||||
@@ -306,14 +266,6 @@ OC.L10N.register(
|
||||
"Reset to default" : "Nastaviť predvolené",
|
||||
"Import contacts" : "Importovať kontakty",
|
||||
"Importing a new .vcf file will delete the existing default contact and replace it with the new one. Do you want to continue?" : "Importovaním nového súboru .vcf sa vymaže existujúci predvolený kontakt a nahradí sa novým. Chcete pokračovať?",
|
||||
"Failed to save example event creation setting" : "Nepodarilo sa uložiť nastavenie vytvorenia príkladu udalosti",
|
||||
"Failed to upload the example event" : "Nezvládlo sa nahrať príklad udalosti",
|
||||
"Custom example event was saved successfully" : "Vlastný príklad udalosti bol úspešne uložený",
|
||||
"Failed to delete the custom example event" : "Nepodarilo sa odstrániť vlastnú ukážkovú udalosť",
|
||||
"Custom example event was deleted successfully" : "Vlastný príklad udalosti bol úspešne odstránený",
|
||||
"Import calendar event" : "Importovať udalosť kalendára",
|
||||
"Uploading a new event will overwrite the existing one." : "Nahrávanie novej udalosti prepíše existujúcu.",
|
||||
"Upload event" : "Nahratie udalosti",
|
||||
"Also install the {calendarappstoreopen}Calendar app{linkclose}, or {calendardocopen}connect your desktop & mobile for syncing ↗{linkclose}." : "Tiež nainštalujte {calendarappstoreopen}apku Kalendár{linkclose} alebo {calendardocopen}pripojte svoj počítač a smartfón pre synchronizáciu ↗{linkclose}.",
|
||||
"Please make sure to properly set up {emailopen}the email server{linkclose}." : "Uistite sa, že ste správne nastavili {emailopen}e-mailový server{linkclose}.",
|
||||
"Calendar server" : "Kalendárový server",
|
||||
@@ -326,8 +278,6 @@ OC.L10N.register(
|
||||
"Send reminder notifications to calendar sharees as well" : "Posielať upozornenia na pripomienky aj zdieľaným osobám v kalendári",
|
||||
"Reminders are always sent to organizers and attendees." : "Upozornenia sa vždy posielajú organizátorom a účastníkom.",
|
||||
"Enable notifications for events via push" : "Zapnúť oznámenia o udalostiach prostredníctvom technológie push.",
|
||||
"Example content" : "Príklad obsahu",
|
||||
"Example content serves to showcase the features of Nextcloud. Default content is shipped with Nextcloud, and can be replaced by custom content." : "Príklad obsahu slúži na predvedenie funkcií Nextcloud. Predvolený obsah je dodávaný s Nextcloudom a môže byť nahradený vlastným obsahom.",
|
||||
"Availability" : "Dostupnosť",
|
||||
"If you configure your working hours, other people will see when you are out of office when they book a meeting." : "Ak nakonfigurujete svoj pracovný čas, ostatní užívatelia vás uvidia ako neprítomného, keď si rezervujete schôdzku",
|
||||
"Absence" : "Neprítomnosť",
|
||||
|
||||
@@ -71,19 +71,7 @@
|
||||
"Where: %s" : "Kde: %s",
|
||||
"%1$s via %2$s" : "%1$s cez %2$s",
|
||||
"In the past on %1$s for the entire day" : "V minulosti %1$s na celý deň",
|
||||
"_In %n minute on %1$s for the entire day_::_In %n minutes on %1$s for the entire day_" : ["Za %n minútu %1$s na celý deň","Za %n minúty %1$s na celý deň","Za %n minút %1$s na celý deň","Za %n minút %1$s na celý deň"],
|
||||
"_In %n hour on %1$s for the entire day_::_In %n hours on %1$s for the entire day_" : ["Za %n hodinu %1$s na celý deň","Za %n hodiny %1$s na celý deň","Za %n hodín %1$s na celý deň","Za %n hodín %1$s na celý deň"],
|
||||
"_In %n day on %1$s for the entire day_::_In %n days on %1$s for the entire day_" : ["Za %n deň %1$s na celý deň","Za %n dni %1$s na celý deň","Za %n dní %1$s na celý deň","Za %n dní %1$s na celý deň"],
|
||||
"_In %n week on %1$s for the entire day_::_In %n weeks on %1$s for the entire day_" : ["Za %n týždeň %1$s na celý deň","Za %n týždne %1$s na celý deň","Za %n týždňov %1$s na celý deň","Za %n týždňov %1$s na celý deň"],
|
||||
"_In %n month on %1$s for the entire day_::_In %n months on %1$s for the entire day_" : ["Za %n mesiac %1$s na celý deň","Za %n mesiace %1$s na celý deň","Za %n mesiacov %1$s na celý deň","Za %n mesiacov %1$s na celý deň"],
|
||||
"_In %n year on %1$s for the entire day_::_In %n years on %1$s for the entire day_" : ["Za %n rok %1$s na celý deň","Za %n roky %1$s na celý deň","Za %n rokov %1$s na celý deň","Za %n rokov %1$s na celý deň"],
|
||||
"In the past on %1$s between %2$s - %3$s" : "V minulosti %1$s medzi %2$s - %3$s",
|
||||
"_In %n minute on %1$s between %2$s - %3$s_::_In %n minutes on %1$s between %2$s - %3$s_" : ["Za %n minútu %1$s %2$s medzi %2$s - %3$s","Za %n minúty %1$s %2$s medzi %2$s - %3$s","Za %n minút %1$s %2$s medzi %2$s - %3$s","Za %n minút %1$s %2$s medzi %2$s - %3$s"],
|
||||
"_In %n hour on %1$s between %2$s - %3$s_::_In %n hours on %1$s between %2$s - %3$s_" : ["Za %n hodinu %1$s %2$s medzi %2$s - %3$s","Za %n hodiny %1$s %2$s medzi %2$s - %3$s","Za %n hodín %1$s %2$s medzi %2$s - %3$s","Za %n hodín %1$s %2$s medzi %2$s - %3$s"],
|
||||
"_In %n day on %1$s between %2$s - %3$s_::_In %n days on %1$s between %2$s - %3$s_" : ["Za %n deň %1$s %2$s medzi %2$s - %3$s","Za %n dni %1$s %2$s medzi %2$s - %3$s","Za %n dní %1$s %2$s medzi %2$s - %3$s","Za %n dní %1$s %2$s medzi %2$s - %3$s"],
|
||||
"_In %n week on %1$s between %2$s - %3$s_::_In %n weeks on %1$s between %2$s - %3$s_" : ["Za %n týždeň %1$s %2$s medzi %2$s - %3$s","Za %n týždne %1$s %2$s medzi %2$s - %3$s","Za %n týždňov %1$s %2$s medzi %2$s - %3$s","Za %n týždňov %1$s %2$s medzi %2$s - %3$s"],
|
||||
"_In %n month on %1$s between %2$s - %3$s_::_In %n months on %1$s between %2$s - %3$s_" : ["Za %n mesiac %1$s %2$s medzi %2$s - %3$s","Za %n mesiace %1$s %2$s medzi %2$s - %3$s","Za %n mesiacov %1$s %2$s medzi %2$s - %3$s","Za %n mesiacov %1$s %2$s medzi %2$s - %3$s"],
|
||||
"_In %n year on %1$s between %2$s - %3$s_::_In %n years on %1$s between %2$s - %3$s_" : ["Za %n rok %1$s %2$s medzi %2$s - %3$s","Za %n roky %1$s %2$s medzi %2$s - %3$s","Za %n rokov %1$s %2$s medzi %2$s - %3$s","Za %n rokov %1$s %2$s medzi %2$s - %3$s"],
|
||||
"Could not generate when statement" : "Nepodarilo sa vygenerovať vyhlásenie kedy",
|
||||
"Every Day for the entire day" : "Každý deň, na celý deň",
|
||||
"Every Day for the entire day until %1$s" : "Každý deň, na celý deň, do %1$s",
|
||||
@@ -121,26 +109,8 @@
|
||||
"On specific dates for the entire day until %1$s" : "V konkrétnych dátumoch na celý deň %1$s",
|
||||
"On specific dates between %1$s - %2$s until %3$s" : "V konkrétnych dátumoch medzi %1$s - %2$s do %3$s",
|
||||
"In the past on %1$s" : "V minulosti %1$s",
|
||||
"_In %n minute on %1$s_::_In %n minutes on %1$s_" : ["Za %n minútu na %1$s","Za %n minúty na %1$s","Za %n minút na %1$s","Za %n minút na %1$s"],
|
||||
"_In %n hour on %1$s_::_In %n hours on %1$s_" : ["Za %n hodinu na %1$s","Za %n hodiny na %1$s","Za %n hodín na %1$s","Za %n hodín na%1$s"],
|
||||
"_In %n day on %1$s_::_In %n days on %1$s_" : ["Za %n deň na %1$s","Za %n dni na %1$s","Za %n dní na %1$s","Za %n dní na %1$s"],
|
||||
"_In %n week on %1$s_::_In %n weeks on %1$s_" : ["Za %n týždeň %1$s","Za %n týždne na %1$s","Za %n týždňov na %1$s","Za %n týždňov na %1$s"],
|
||||
"_In %n month on %1$s_::_In %n months on %1$s_" : ["Za %n mesiac na%1$s","Za %n mesiace na%1$s","Za %n mesiacov na%1$s","Za %n mesiacov na %1$s"],
|
||||
"_In %n year on %1$s_::_In %n years on %1$s_" : ["Za %n rok na %1$s","Za %n roky na %1$s","Za %n rokov na %1$s","Za %n rokov na %1$s"],
|
||||
"In the past on %1$s then on %2$s" : "V minulosti %1$s a potom %2$s",
|
||||
"_In %n minute on %1$s then on %2$s_::_In %n minutes on %1$s then on %2$s_" : ["Za %n minútu %1$s a potom %2$s","Za %n minúty %1$s a potom %2$s","Za %n minút %1$s a potom %2$s","Za %n minút %1$s a potom %2$s"],
|
||||
"_In %n hour on %1$s then on %2$s_::_In %n hours on %1$s then on %2$s_" : ["Za %n hodinu %1$s a potom %2$s","Za %n hodiny %1$s a potom %2$s","Za %n hodín %1$s a potom %2$s","Za %n hodín %1$s a potom %2$s"],
|
||||
"_In %n day on %1$s then on %2$s_::_In %n days on %1$s then on %2$s_" : ["Za %n deň %1$s a potom %2$s","Za %n dni %1$s a potom %2$s","Za %n dní %1$s a potom %2$s","Za %n dní %1$s a potom %2$s"],
|
||||
"_In %n week on %1$s then on %2$s_::_In %n weeks on %1$s then on %2$s_" : ["Za %n týždeň %1$s a potom %2$s","Za %n týždne %1$s a potom %2$s","Za %n týždňov %1$s a potom %2$s","Za %n týždňov %1$s a potom %2$s"],
|
||||
"_In %n month on %1$s then on %2$s_::_In %n months on %1$s then on %2$s_" : ["Za %n mesiac %1$s a potom %2$s","Za %n mesiace %1$s a potom %2$s","Za %n mesiacov %1$s a potom %2$s","Za %n mesiacov %1$s a potom %2$s"],
|
||||
"_In %n year on %1$s then on %2$s_::_In %n years on %1$s then on %2$s_" : ["Za %n rok %1$s a potom %2$s","Za %n roky %1$s a potom %2$s","Za %n rokov %1$s a potom %2$s","Za %n rokov %1$s a potom %2$s"],
|
||||
"In the past on %1$s then on %2$s and %3$s" : "V minulosti %1$s potom %2$s a %3$s",
|
||||
"_In %n minute on %1$s then on %2$s and %3$s_::_In %n minutes on %1$s then on %2$s and %3$s_" : ["Za %n minútu %1$s potom %2$s a %3$s","Za %n minúty %1$s potom %2$s a %3$s","Za %n minút %1$s potom %2$s a %3$s","Za %n minút %1$s potom %2$s a %3$s"],
|
||||
"_In %n hour on %1$s then on %2$s and %3$s_::_In %n hours on %1$s then on %2$s and %3$s_" : ["Za %n hodinu %1$s potom %2$s a %3$s","Za %n hodiny %1$s potom %2$s a %3$s","Za %n hodín %1$s potom %2$s a %3$s","Za %nhodín %1$s potom %2$s a %3$s"],
|
||||
"_In %n day on %1$s then on %2$s and %3$s_::_In %n days on %1$s then on %2$s and %3$s_" : ["Za %n deň %1$s potom %2$s a %3$s","Za %n dni %1$s potom %2$s a %3$s","Za %n dní %1$s potom %2$s a %3$s","Za %n dní %1$s potom %2$s a %3$s"],
|
||||
"_In %n week on %1$s then on %2$s and %3$s_::_In %n weeks on %1$s then on %2$s and %3$s_" : ["Za %n týždeň %1$s potom %2$s a %3$s","Za %n týždne %1$s potom %2$s a %3$s","Za %n týždňov %1$s potom %2$s a %3$s","Za %n týždňov %1$s potom %2$s a %3$s"],
|
||||
"_In %n month on %1$s then on %2$s and %3$s_::_In %n months on %1$s then on %2$s and %3$s_" : ["Za %n mesiac %1$s potom %2$s a %3$s","Za %n mesiace %1$s potom %2$s a %3$s","Za %n mesiacov %1$s potom %2$s a %3$s","Za %n mesiacov %1$s potom %2$s a %3$s"],
|
||||
"_In %n year on %1$s then on %2$s and %3$s_::_In %n years on %1$s then on %2$s and %3$s_" : ["Za %n rok %1$s potom %2$s a %3$s","Za %n roky %1$s potom %2$s a %3$s","Za %n rokov %1$s potom %2$s a %3$s","Za %n rokov %1$s potom %2$s a %3$s"],
|
||||
"Could not generate next recurrence statement" : "Nepodarilo sa vygenerovať ďalšie opakovanie",
|
||||
"Cancelled: %1$s" : "Zrušené: %1$s",
|
||||
"\"%1$s\" has been canceled" : "\"%1$s\" bolo zrušené",
|
||||
@@ -218,8 +188,6 @@
|
||||
"{actor} updated contact {card} in address book {addressbook}" : "{actor} upravil kontakt {card} v adresári {addressbook}",
|
||||
"You updated contact {card} in address book {addressbook}" : "Upravili ste kontakt {card} v adresári {addressbook}",
|
||||
"A <strong>contact</strong> or <strong>address book</strong> was modified" : "<strong>kontakt</strong> alebo <strong>adresár</strong> bol upravený",
|
||||
"System address book disabled" : "Systémový adresár je vypnutý",
|
||||
"The system contacts address book has been automatically disabled during upgrade. This means that the address book will no longer be available to users in the contacts app or other clients. The system contacts address book was disabled because the amount of contacts in the address book exceeded the maximum recommended number of contacts. This limit is set to prevent performance issues. You can re-enable the system address book with the following command {command}" : "Systémový adresár kontaktov bol automaticky vypnutý počas aktualizácie. To znamená, že adresár kontaktov už nebude dostupný pre používateľov v aplikácii Kontakty ani v iných klientoch. Systémový adresár kontaktov bol vypnutý, pretože počet kontaktov v adresári prekročil maximálny odporúčaný počet kontaktov. Tento limit je nastavený na prevenciu problémov s výkonom. Systémový adresár kontaktov môžete znovu povoliť pomocou nasledujúcej príkazu {command}.",
|
||||
"Accounts" : "Účty",
|
||||
"System address book which holds all accounts" : "Systémový adresár, ktorý obsahuje všetky účty.",
|
||||
"File is not updatable: %1$s" : "Súbor nie je možné aktualizovať: %1$s",
|
||||
@@ -232,8 +200,6 @@
|
||||
"Could not rename part file to final file, canceled by hook" : "Nepodarilo sa premenovať dočasný súbor na finálny, zrušené háčikom (hook)",
|
||||
"Could not rename part file to final file" : "Nepodarilo sa premenovať dočasný súbor na finálny.",
|
||||
"Failed to check file size: %1$s" : "Kontrola veľkosti súboru zlyhala: %1$s",
|
||||
"Could not open file: %1$s (%2$d), file does seem to exist" : "Nie je možné otvoriť súbor: %1$s (%2$d), zdá sa že súbor existuje",
|
||||
"Could not open file: %1$s (%2$d), file doesn't seem to exist" : "Nie je možné otvoriť súbor: %1$s (%2$d), nezdá sa že súbor existuje",
|
||||
"Encryption not ready: %1$s" : "Šifrovanie nie je dostupné: %1$s",
|
||||
"Failed to open file: %1$s" : "Otvorenie súboru zlyhalo: %1$s",
|
||||
"Failed to unlink: %1$s" : "Odpojenie zlyhalo: %1$s",
|
||||
@@ -250,18 +216,12 @@
|
||||
"Completed on %s" : "Dokončené %s",
|
||||
"Due on %s by %s" : "Termín od %s do %s",
|
||||
"Due on %s" : "Termín do %s",
|
||||
"Welcome to Nextcloud Calendar!\n\nThis is a sample event - explore the flexibility of planning with Nextcloud Calendar by making any edits you want!\n\nWith Nextcloud Calendar, you can:\n- Create, edit, and manage events effortlessly.\n- Create multiple calendars and share them with teammates, friends, or family.\n- Check availability and display your busy times to others.\n- Seamlessly integrate with apps and devices via CalDAV.\n- Customize your experience: schedule recurring events, adjust notifications and other settings." : "Vitajte v Nextcloud Calendar!\n\nToto je ukážková udalosť – preskúmajte flexibilitu plánovania s Nextcloud Calendar tým, že vykonáte akékoľvek úpravy, ktoré chcete!\n\nS Nextcloud Calendar môžete:\n- Jednoducho vytvárať, upravovať a spravovať udalosti.\n- Vytvárať viacero kalendárov a zdieľať ich s tímom, priateľmi alebo rodinou.\n- Skontrolovať dostupnosť a zobraziť svoje zaneprázdnené časy pre ostatných.\n- Bezproblémovo integrovať s aplikáciami a zariadeniami cez CalDAV.\n- Prispôsobiť si skúsenosti: naplánovať opakujúce sa udalosti, nastaviť notifikácie a iné nastavenia.",
|
||||
"Example event - open me!" : "Príklad udalosti - otvorte ma!",
|
||||
"System Address Book" : "Systémový Adresár",
|
||||
"The system address book contains contact information for all users in your instance." : "Systémový adresár obsahuje kontaktné informácie o všetkých užívateľov vo vašej inštancii.",
|
||||
"Enable System Address Book" : "Povoliť systémový Adresár",
|
||||
"DAV system address book" : "Systémový DAV adresár",
|
||||
"No outstanding DAV system address book sync." : "Žiadna zostávajúca synchronizácia adresára systému DAV.",
|
||||
"The DAV system address book sync has not run yet as your instance has more than 1000 users or because an error occurred. Please run it manually by calling \"occ dav:sync-system-addressbook\"." : "DAV synchronizácia systémového adresára ešte nebola spustená, pretože vaša inštancia má viac ako 1000 užívateľov alebo sa vyskytla chyba. Prosím, spustite ju manuálne volaním \"occ dav:sync-system-addressbook\".",
|
||||
"DAV system address book size" : "Veľkosť adresára systému DAV",
|
||||
"The system address book is disabled" : "Systémový adresár je zakázaný",
|
||||
"The system address book is enabled, but contains more than the configured limit of %d contacts" : "Adresár systému je povolený, ale obsahuje viac kontaktov, než je nastavený limit %dkontaktov.",
|
||||
"The system address book is enabled and contains less than the configured limit of %d contacts" : "Adresár systému je povolený a obsahuje menej kontaktov, než je nastavený limit %dkontaktov.",
|
||||
"WebDAV endpoint" : "Koncový bod WebDAV",
|
||||
"Could not check that your web server is properly set up to allow file synchronization over WebDAV. Please check manually." : "Nepodarilo sa skontrolovať, či je váš webový server správne nastavený tak, aby umožňoval synchronizáciu súborov cez WebDAV. Skontrolujte prosím manuálne.",
|
||||
"Your web server is not yet properly set up to allow file synchronization, because the WebDAV interface seems to be broken." : "Váš webový server nie je zatiaľ správne nastavený, aby umožnil synchronizáciu súborov, pretože rozhranie WebDAV sa zdá byť nefunkčné.",
|
||||
@@ -304,14 +264,6 @@
|
||||
"Reset to default" : "Nastaviť predvolené",
|
||||
"Import contacts" : "Importovať kontakty",
|
||||
"Importing a new .vcf file will delete the existing default contact and replace it with the new one. Do you want to continue?" : "Importovaním nového súboru .vcf sa vymaže existujúci predvolený kontakt a nahradí sa novým. Chcete pokračovať?",
|
||||
"Failed to save example event creation setting" : "Nepodarilo sa uložiť nastavenie vytvorenia príkladu udalosti",
|
||||
"Failed to upload the example event" : "Nezvládlo sa nahrať príklad udalosti",
|
||||
"Custom example event was saved successfully" : "Vlastný príklad udalosti bol úspešne uložený",
|
||||
"Failed to delete the custom example event" : "Nepodarilo sa odstrániť vlastnú ukážkovú udalosť",
|
||||
"Custom example event was deleted successfully" : "Vlastný príklad udalosti bol úspešne odstránený",
|
||||
"Import calendar event" : "Importovať udalosť kalendára",
|
||||
"Uploading a new event will overwrite the existing one." : "Nahrávanie novej udalosti prepíše existujúcu.",
|
||||
"Upload event" : "Nahratie udalosti",
|
||||
"Also install the {calendarappstoreopen}Calendar app{linkclose}, or {calendardocopen}connect your desktop & mobile for syncing ↗{linkclose}." : "Tiež nainštalujte {calendarappstoreopen}apku Kalendár{linkclose} alebo {calendardocopen}pripojte svoj počítač a smartfón pre synchronizáciu ↗{linkclose}.",
|
||||
"Please make sure to properly set up {emailopen}the email server{linkclose}." : "Uistite sa, že ste správne nastavili {emailopen}e-mailový server{linkclose}.",
|
||||
"Calendar server" : "Kalendárový server",
|
||||
@@ -324,8 +276,6 @@
|
||||
"Send reminder notifications to calendar sharees as well" : "Posielať upozornenia na pripomienky aj zdieľaným osobám v kalendári",
|
||||
"Reminders are always sent to organizers and attendees." : "Upozornenia sa vždy posielajú organizátorom a účastníkom.",
|
||||
"Enable notifications for events via push" : "Zapnúť oznámenia o udalostiach prostredníctvom technológie push.",
|
||||
"Example content" : "Príklad obsahu",
|
||||
"Example content serves to showcase the features of Nextcloud. Default content is shipped with Nextcloud, and can be replaced by custom content." : "Príklad obsahu slúži na predvedenie funkcií Nextcloud. Predvolený obsah je dodávaný s Nextcloudom a môže byť nahradený vlastným obsahom.",
|
||||
"Availability" : "Dostupnosť",
|
||||
"If you configure your working hours, other people will see when you are out of office when they book a meeting." : "Ak nakonfigurujete svoj pracovný čas, ostatní užívatelia vás uvidia ako neprítomného, keď si rezervujete schôdzku",
|
||||
"Absence" : "Neprítomnosť",
|
||||
|
||||
@@ -165,7 +165,6 @@ class Plugin extends \Sabre\CalDAV\Schedule\Plugin {
|
||||
|
||||
// Do not generate iTip and iMip messages if scheduling is disabled for this message
|
||||
if ($request->getHeader('x-nc-scheduling') === 'false') {
|
||||
$this->logger->debug('Skipping scheduling messages for calendar object change because x-nc-scheduling header is set to false');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -213,13 +212,6 @@ class Plugin extends \Sabre\CalDAV\Schedule\Plugin {
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function beforeUnbind($path): void {
|
||||
|
||||
// Do not generate iTip and iMip messages if scheduling is disabled for this message
|
||||
if ($this->server->httpRequest->getHeader('x-nc-scheduling') === 'false') {
|
||||
$this->logger->debug('Skipping scheduling messages for calendar object delete because x-nc-scheduling header is set to false');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
parent::beforeUnbind($path);
|
||||
} catch (SameOrganizerForAllComponentsException $e) {
|
||||
|
||||
+129
-242
@@ -9,7 +9,6 @@ declare(strict_types=1);
|
||||
|
||||
namespace OCA\DAV\CalDAV;
|
||||
|
||||
use Sabre\VObject\Component;
|
||||
use Sabre\VObject\Component\VCalendar;
|
||||
use Sabre\VObject\ITip\Broker;
|
||||
use Sabre\VObject\ITip\Message;
|
||||
@@ -28,56 +27,9 @@ class TipBroker extends Broker {
|
||||
'SUMMARY',
|
||||
'DESCRIPTION',
|
||||
'LOCATION',
|
||||
|
||||
];
|
||||
|
||||
/**
|
||||
* Processes incoming CANCEL messages.
|
||||
*
|
||||
* This is a message from an organizer, and means that either an
|
||||
* attendee got removed from an event, or an event got cancelled
|
||||
* altogether.
|
||||
*
|
||||
* @param VCalendar $existingObject
|
||||
*
|
||||
* @return VCalendar|null
|
||||
*/
|
||||
protected function processMessageCancel(Message $itipMessage, ?VCalendar $existingObject = null) {
|
||||
if ($existingObject === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$componentType = $itipMessage->component;
|
||||
$instances = [];
|
||||
|
||||
foreach ($itipMessage->message->$componentType as $component) {
|
||||
$instanceId = isset($component->{'RECURRENCE-ID'}) ? $component->{'RECURRENCE-ID'}->getValue() : 'base';
|
||||
$instances[$instanceId] = $component;
|
||||
}
|
||||
// any existing instances should be marked as cancelled
|
||||
foreach ($existingObject->$componentType as $component) {
|
||||
$instanceId = isset($component->{'RECURRENCE-ID'}) ? $component->{'RECURRENCE-ID'}->getValue() : 'base';
|
||||
if (isset($instances[$instanceId])) {
|
||||
if (isset($component->STATUS)) {
|
||||
$component->STATUS->setValue('CANCELLED');
|
||||
} else {
|
||||
$component->add('STATUS', 'CANCELLED');
|
||||
}
|
||||
if (isset($component->SEQUENCE)) {
|
||||
$component->SEQUENCE->setValue($itipMessage->sequence);
|
||||
} else {
|
||||
$component->add('SEQUENCE', $itipMessage->sequence);
|
||||
}
|
||||
unset($instances[$instanceId]);
|
||||
}
|
||||
}
|
||||
// any remaining instances are new and should be added
|
||||
foreach ($instances as $instance) {
|
||||
$existingObject->add($instance);
|
||||
}
|
||||
|
||||
return $existingObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used in cases where an event got updated, and we
|
||||
* potentially need to send emails to attendees to let them know of updates
|
||||
@@ -86,219 +38,154 @@ class TipBroker extends Broker {
|
||||
* We will detect which attendees got added, which got removed and create
|
||||
* specific messages for these situations.
|
||||
*
|
||||
* @return array<int,Message>
|
||||
* @return array
|
||||
*/
|
||||
protected function parseEventForOrganizer(VCalendar $calendar, array $eventInfo, array $oldEventInfo) {
|
||||
// Merging attendee lists.
|
||||
$attendees = [];
|
||||
foreach ($oldEventInfo['attendees'] as $attendee) {
|
||||
$attendees[$attendee['href']] = [
|
||||
'href' => $attendee['href'],
|
||||
'oldInstances' => $attendee['instances'],
|
||||
'newInstances' => [],
|
||||
'name' => $attendee['name'],
|
||||
'forceSend' => null,
|
||||
];
|
||||
}
|
||||
foreach ($eventInfo['attendees'] as $attendee) {
|
||||
if (isset($attendees[$attendee['href']])) {
|
||||
$attendees[$attendee['href']]['name'] = $attendee['name'];
|
||||
$attendees[$attendee['href']]['newInstances'] = $attendee['instances'];
|
||||
$attendees[$attendee['href']]['forceSend'] = $attendee['forceSend'];
|
||||
} else {
|
||||
$attendees[$attendee['href']] = [
|
||||
'href' => $attendee['href'],
|
||||
'oldInstances' => [],
|
||||
'newInstances' => $attendee['instances'],
|
||||
'name' => $attendee['name'],
|
||||
'forceSend' => $attendee['forceSend'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$messages = [];
|
||||
|
||||
// construct template calendar from original calendar without components
|
||||
$template = new VCalendar();
|
||||
foreach ($template->children() as $property) {
|
||||
$template->remove($property);
|
||||
}
|
||||
foreach ($calendar->children() as $property) {
|
||||
if (in_array($property->name, ['METHOD', 'VEVENT', 'VTODO', 'VJOURNAL', 'VFREEBUSY'], true) === false) {
|
||||
$template->add(clone $property);
|
||||
}
|
||||
}
|
||||
// extract event information
|
||||
$objectId = $eventInfo['uid'];
|
||||
if ($calendar->getBaseComponent() === null) {
|
||||
$objectType = $calendar->getComponents()[0]->name;
|
||||
} else {
|
||||
$objectType = $calendar->getBaseComponent()->name;
|
||||
}
|
||||
$objectSequence = $eventInfo['sequence'] ?? 1;
|
||||
$organizerHref = $eventInfo['organizer'] ?? $oldEventInfo['organizer'];
|
||||
if ($eventInfo['organizerName'] instanceof \Sabre\VObject\Parameter) {
|
||||
$organizerName = $eventInfo['organizerName']->getValue();
|
||||
} else {
|
||||
$organizerName = $eventInfo['organizerName'];
|
||||
}
|
||||
// detect if the singleton or recurring base instance was converted to non-scheduling
|
||||
if (count($eventInfo['instances']) === 0 && count($oldEventInfo['instances']) > 0) {
|
||||
foreach ($oldEventInfo['attendees'] as $attendee) {
|
||||
$messages[] = $this->generateMessage(
|
||||
$oldEventInfo['instances'], $organizerHref, $organizerName, $attendee, $objectId, $objectType, $objectSequence, 'CANCEL', $template
|
||||
);
|
||||
}
|
||||
return $messages;
|
||||
}
|
||||
// detect if the singleton or recurring base instance was cancelled
|
||||
if ($eventInfo['instances']['master']?->STATUS?->getValue() === 'CANCELLED' && $oldEventInfo['instances']['master']?->STATUS?->getValue() !== 'CANCELLED') {
|
||||
foreach ($eventInfo['attendees'] as $attendee) {
|
||||
$messages[] = $this->generateMessage(
|
||||
$eventInfo['instances'], $organizerHref, $organizerName, $attendee, $objectId, $objectType, $objectSequence, 'CANCEL', $template
|
||||
);
|
||||
}
|
||||
return $messages;
|
||||
}
|
||||
// detect if a new cancelled instance was created
|
||||
$cancelledNewInstances = [];
|
||||
if (isset($oldEventInfo['instances'])) {
|
||||
$instancesDelta = array_diff_key($eventInfo['instances'], $oldEventInfo['instances']);
|
||||
foreach ($instancesDelta as $id => $instance) {
|
||||
if ($instance->STATUS?->getValue() === 'CANCELLED') {
|
||||
$cancelledNewInstances[] = $id;
|
||||
foreach ($eventInfo['attendees'] as $attendee) {
|
||||
$messages[] = $this->generateMessage(
|
||||
[$id => $instance], $organizerHref, $organizerName, $attendee, $objectId, $objectType, $objectSequence, 'CANCEL', $template
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// detect attendee mutations
|
||||
$attendees = array_unique(
|
||||
array_merge(
|
||||
array_keys($eventInfo['attendees']),
|
||||
array_keys($oldEventInfo['attendees'])
|
||||
)
|
||||
);
|
||||
foreach ($attendees as $attendee) {
|
||||
// Skip organizer
|
||||
if ($attendee === $organizerHref) {
|
||||
// An organizer can also be an attendee. We should not generate any
|
||||
// messages for those.
|
||||
if ($attendee['href'] === $eventInfo['organizer']) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip if SCHEDULE-AGENT=CLIENT (respect RFC 6638)
|
||||
if ($this->scheduleAgentServerRules
|
||||
&& isset($eventInfo['attendees'][$attendee]['scheduleAgent'])
|
||||
&& strtoupper($eventInfo['attendees'][$attendee]['scheduleAgent']) === 'CLIENT') {
|
||||
continue;
|
||||
$message = new Message();
|
||||
$message->uid = $eventInfo['uid'];
|
||||
$message->component = 'VEVENT';
|
||||
$message->sequence = $eventInfo['sequence'];
|
||||
$message->sender = $eventInfo['organizer'];
|
||||
$message->senderName = $eventInfo['organizerName'];
|
||||
$message->recipient = $attendee['href'];
|
||||
$message->recipientName = $attendee['name'];
|
||||
|
||||
// Creating the new iCalendar body.
|
||||
$icalMsg = new VCalendar();
|
||||
|
||||
foreach ($calendar->select('VTIMEZONE') as $timezone) {
|
||||
$icalMsg->add(clone $timezone);
|
||||
}
|
||||
// If there are no instances the attendee is a part of, it means
|
||||
// the attendee was removed and we need to send them a CANCEL message.
|
||||
// Also If the meeting STATUS property was changed to CANCELLED
|
||||
// we need to send the attendee a CANCEL message.
|
||||
if (!$attendee['newInstances'] || $eventInfo['status'] === 'CANCELLED') {
|
||||
|
||||
// detect if attendee was removed and send cancel message
|
||||
if (!isset($eventInfo['attendees'][$attendee]) && isset($oldEventInfo['attendees'][$attendee])) {
|
||||
//get all instances of the attendee was removed from.
|
||||
$instances = array_intersect_key($oldEventInfo['instances'], array_flip(array_keys($oldEventInfo['attendees'][$attendee]['instances'])));
|
||||
$messages[] = $this->generateMessage(
|
||||
$instances, $organizerHref, $organizerName, $oldEventInfo['attendees'][$attendee], $objectId, $objectType, $objectSequence, 'CANCEL', $template
|
||||
);
|
||||
continue;
|
||||
}
|
||||
// otherwise any created or modified instances will be sent as REQUEST
|
||||
$instances = array_intersect_key($eventInfo['instances'], array_flip(array_keys($eventInfo['attendees'][$attendee]['instances'])));
|
||||
|
||||
// Remove already-cancelled new instances from REQUEST
|
||||
if (!empty($cancelledNewInstances)) {
|
||||
$instances = array_diff_key($instances, array_flip($cancelledNewInstances));
|
||||
}
|
||||
|
||||
// Skip if no instances left to send
|
||||
if (empty($instances)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add EXDATE for instances the attendee is NOT part of (only for recurring events with master)
|
||||
if (isset($instances['master']) && count($eventInfo['instances']) > 1) {
|
||||
$masterInstance = clone $instances['master'];
|
||||
$excludedDates = [];
|
||||
|
||||
foreach ($eventInfo['instances'] as $instanceId => $instance) {
|
||||
if ($instanceId !== 'master' && !isset($eventInfo['attendees'][$attendee]['instances'][$instanceId])) {
|
||||
$excludedDates[] = $instance->{'RECURRENCE-ID'}->getValue();
|
||||
}
|
||||
$message->method = $icalMsg->METHOD = 'CANCEL';
|
||||
$message->significantChange = true;
|
||||
// clone base event
|
||||
if (isset($eventInfo['instances']['master'])) {
|
||||
$event = clone $eventInfo['instances']['master'];
|
||||
} else {
|
||||
$event = clone $oldEventInfo['instances']['master'];
|
||||
}
|
||||
// alter some properties
|
||||
unset($event->ATTENDEE);
|
||||
$event->add('ATTENDEE', $attendee['href'], ['CN' => $attendee['name'],]);
|
||||
$event->DTSTAMP = gmdate('Ymd\\THis\\Z');
|
||||
$event->SEQUENCE = $message->sequence;
|
||||
$icalMsg->add($event);
|
||||
|
||||
if (!empty($excludedDates)) {
|
||||
if (isset($masterInstance->EXDATE)) {
|
||||
$currentExdates = $masterInstance->EXDATE->getParts();
|
||||
$masterInstance->EXDATE->setParts(array_merge($currentExdates, $excludedDates));
|
||||
} else {
|
||||
$masterInstance->EXDATE = $excludedDates;
|
||||
} else {
|
||||
// The attendee gets the updated event body
|
||||
$message->method = $icalMsg->METHOD = 'REQUEST';
|
||||
|
||||
// We need to find out that this change is significant. If it's
|
||||
// not, systems may opt to not send messages.
|
||||
//
|
||||
// We do this based on the 'significantChangeHash' which is
|
||||
// some value that changes if there's a certain set of
|
||||
// properties changed in the event, or simply if there's a
|
||||
// difference in instances that the attendee is invited to.
|
||||
|
||||
$oldAttendeeInstances = array_keys($attendee['oldInstances']);
|
||||
$newAttendeeInstances = array_keys($attendee['newInstances']);
|
||||
|
||||
$message->significantChange
|
||||
= $attendee['forceSend'] === 'REQUEST'
|
||||
|| count($oldAttendeeInstances) !== count($newAttendeeInstances)
|
||||
|| count(array_diff($oldAttendeeInstances, $newAttendeeInstances)) > 0
|
||||
|| $oldEventInfo['significantChangeHash'] !== $eventInfo['significantChangeHash'];
|
||||
|
||||
foreach ($attendee['newInstances'] as $instanceId => $instanceInfo) {
|
||||
$currentEvent = clone $eventInfo['instances'][$instanceId];
|
||||
if ($instanceId === 'master') {
|
||||
// We need to find a list of events that the attendee
|
||||
// is not a part of to add to the list of exceptions.
|
||||
$exceptions = [];
|
||||
foreach ($eventInfo['instances'] as $instanceId => $vevent) {
|
||||
if (!isset($attendee['newInstances'][$instanceId])) {
|
||||
$exceptions[] = $instanceId;
|
||||
}
|
||||
}
|
||||
|
||||
// If there were exceptions, we need to add it to an
|
||||
// existing EXDATE property, if it exists.
|
||||
if ($exceptions) {
|
||||
if (isset($currentEvent->EXDATE)) {
|
||||
$currentEvent->EXDATE->setParts(array_merge(
|
||||
$currentEvent->EXDATE->getParts(),
|
||||
$exceptions
|
||||
));
|
||||
} else {
|
||||
$currentEvent->EXDATE = $exceptions;
|
||||
}
|
||||
}
|
||||
|
||||
// Cleaning up any scheduling information that
|
||||
// shouldn't be sent along.
|
||||
unset($currentEvent->ORGANIZER['SCHEDULE-FORCE-SEND']);
|
||||
unset($currentEvent->ORGANIZER['SCHEDULE-STATUS']);
|
||||
|
||||
foreach ($currentEvent->ATTENDEE as $attendee) {
|
||||
unset($attendee['SCHEDULE-FORCE-SEND']);
|
||||
unset($attendee['SCHEDULE-STATUS']);
|
||||
|
||||
// We're adding PARTSTAT=NEEDS-ACTION to ensure that
|
||||
// iOS shows an "Inbox Item"
|
||||
if (!isset($attendee['PARTSTAT'])) {
|
||||
$attendee['PARTSTAT'] = 'NEEDS-ACTION';
|
||||
}
|
||||
}
|
||||
}
|
||||
$instances['master'] = $masterInstance;
|
||||
|
||||
$currentEvent->DTSTAMP = gmdate('Ymd\\THis\\Z');
|
||||
$icalMsg->add($currentEvent);
|
||||
}
|
||||
}
|
||||
|
||||
$messages[] = $this->generateMessage(
|
||||
$instances, $organizerHref, $organizerName, $eventInfo['attendees'][$attendee], $objectId, $objectType, $objectSequence, 'REQUEST', $template
|
||||
);
|
||||
$message->message = $icalMsg;
|
||||
$messages[] = $message;
|
||||
}
|
||||
|
||||
return $messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an iTip message for a specific attendee
|
||||
*
|
||||
* @param array<string, Component> $instances Array of event instances to include, keyed by instance ID:
|
||||
* - 'master' => Component: The master/base event
|
||||
* - '{RECURRENCE-ID}' => Component: Exception instances
|
||||
* @param string $organizerHref The organizer's calendar-user address (e.g., 'mailto:user@example.com')
|
||||
* @param string|null $organizerName The organizer's display name
|
||||
* @param array $attendee The attendee information containing:
|
||||
* - 'href' (string): The attendee's calendar-user address
|
||||
* - 'name' (string): The attendee's display name
|
||||
* - 'scheduleAgent' (string|null): SCHEDULE-AGENT parameter
|
||||
* - 'instances' (array): Instances this attendee is part of
|
||||
* @param string $objectId The UID of the event
|
||||
* @param string $objectType The component type ('VEVENT', 'VTODO', etc.)
|
||||
* @param int $objectSequence The sequence number of the event
|
||||
* @param string $method The iTip method ('REQUEST', 'CANCEL', 'REPLY', etc.)
|
||||
* @param VCalendar $template The template calendar object (without event components)
|
||||
* @return Message The generated iTip message ready to be sent
|
||||
*/
|
||||
protected function generateMessage(
|
||||
array $instances,
|
||||
string $organizerHref,
|
||||
?string $organizerName,
|
||||
array $attendee,
|
||||
string $objectId,
|
||||
string $objectType,
|
||||
int $objectSequence,
|
||||
string $method,
|
||||
VCalendar $template,
|
||||
): Message {
|
||||
|
||||
$recipientAddress = $attendee['href'] ?? '';
|
||||
$recipientName = $attendee['name'] ?? '';
|
||||
|
||||
$vObject = clone $template;
|
||||
if ($vObject->METHOD && $vObject->METHOD->getValue() !== $method) {
|
||||
$vObject->METHOD->setValue($method);
|
||||
} else {
|
||||
$vObject->add('METHOD', $method);
|
||||
}
|
||||
foreach ($instances as $instance) {
|
||||
$vObject->add($this->componentSanitizeScheduling(clone $instance));
|
||||
}
|
||||
|
||||
$message = new Message();
|
||||
$message->method = $method;
|
||||
$message->uid = $objectId;
|
||||
$message->component = $objectType;
|
||||
$message->sequence = $objectSequence;
|
||||
$message->sender = $organizerHref;
|
||||
$message->senderName = $organizerName;
|
||||
$message->recipient = $recipientAddress;
|
||||
$message->recipientName = $recipientName;
|
||||
$message->significantChange = true;
|
||||
$message->message = $vObject;
|
||||
|
||||
return $message;
|
||||
|
||||
}
|
||||
|
||||
protected function componentSanitizeScheduling(Component $component): Component {
|
||||
// Cleaning up any scheduling information that should not be sent or is missing
|
||||
unset($component->ORGANIZER['SCHEDULE-FORCE-SEND'], $component->ORGANIZER['SCHEDULE-STATUS']);
|
||||
foreach ($component->ATTENDEE as $attendee) {
|
||||
unset($attendee['SCHEDULE-FORCE-SEND'], $attendee['SCHEDULE-STATUS']);
|
||||
|
||||
if (!isset($attendee['PARTSTAT'])) {
|
||||
$attendee['PARTSTAT'] = 'NEEDS-ACTION';
|
||||
}
|
||||
}
|
||||
// Sequence is a required property, default is 0
|
||||
// https://datatracker.ietf.org/doc/html/rfc5545#section-3.8.7.4
|
||||
if ($component->SEQUENCE === null) {
|
||||
$component->add('SEQUENCE', 0);
|
||||
}
|
||||
|
||||
return $component;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -236,13 +236,7 @@ class File extends Node implements IFile {
|
||||
// because we have no clue about the cause we can only throw back a 500/Internal Server Error
|
||||
throw new Exception($this->l10n->t('Could not write file contents'));
|
||||
}
|
||||
$count = stream_copy_to_stream($data, $target);
|
||||
if ($count === false) {
|
||||
$result = false;
|
||||
$count = 0;
|
||||
} else {
|
||||
$result = true;
|
||||
}
|
||||
[$count, $result] = Files::streamCopy($data, $target, true);
|
||||
fclose($target);
|
||||
}
|
||||
if ($result === false && $expected !== null) {
|
||||
|
||||
@@ -166,6 +166,11 @@ class FilesPlugin extends ServerPlugin {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure source exists
|
||||
$sourceNodeFileInfo = $sourceNode->getFileInfo();
|
||||
if ($sourceNodeFileInfo === null) {
|
||||
throw new NotFound($source . ' does not exist');
|
||||
}
|
||||
// Ensure the target name is valid
|
||||
try {
|
||||
[$targetPath, $targetName] = \Sabre\Uri\split($target);
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-FileCopyrightText: 2016 ownCloud, Inc.
|
||||
@@ -22,48 +20,42 @@ use OCP\Files\IRootFolder;
|
||||
use OCP\Files\NotFoundException;
|
||||
use OCP\Files\Storage\ISharedStorage;
|
||||
use OCP\Files\StorageNotAvailableException;
|
||||
use OCP\IUser;
|
||||
use OCP\Lock\ILockingProvider;
|
||||
use OCP\Lock\LockedException;
|
||||
use OCP\PreConditionNotMetException;
|
||||
use OCP\Server;
|
||||
use OCP\Share\Exceptions\ShareNotFound;
|
||||
use OCP\Share\IManager;
|
||||
use RuntimeException;
|
||||
use Sabre\DAV\Exception;
|
||||
use Sabre\DAV\Exception\Forbidden;
|
||||
use Sabre\DAV\INode;
|
||||
|
||||
abstract class Node implements INode {
|
||||
abstract class Node implements \Sabre\DAV\INode {
|
||||
/**
|
||||
* The path to the current node
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected string $path;
|
||||
protected $path;
|
||||
|
||||
protected FileInfo $info;
|
||||
|
||||
protected IManager $shareManager;
|
||||
/**
|
||||
* @var IManager
|
||||
*/
|
||||
protected $shareManager;
|
||||
|
||||
protected \OCP\Files\Node $node;
|
||||
|
||||
/**
|
||||
* Sets up the node, expects a full path name
|
||||
* @throws PreConditionNotMetException
|
||||
*/
|
||||
public function __construct(
|
||||
protected View $fileView,
|
||||
FileInfo $info,
|
||||
?IManager $shareManager = null,
|
||||
) {
|
||||
$relativePath = $this->fileView->getRelativePath($info->getPath());
|
||||
if ($relativePath === null) {
|
||||
throw new RuntimeException('Failed to get relative path for ' . $info->getPath());
|
||||
}
|
||||
|
||||
$this->path = $relativePath;
|
||||
$this->path = $this->fileView->getRelativePath($info->getPath());
|
||||
$this->info = $info;
|
||||
$this->shareManager = $shareManager instanceof IManager ? $shareManager : Server::get(IManager::class);
|
||||
|
||||
if ($shareManager) {
|
||||
$this->shareManager = $shareManager;
|
||||
} else {
|
||||
$this->shareManager = Server::get(\OCP\Share\IManager::class);
|
||||
}
|
||||
if ($info instanceof Folder || $info instanceof File) {
|
||||
$this->node = $info;
|
||||
} else {
|
||||
@@ -78,16 +70,11 @@ abstract class Node implements INode {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
* @throws PreConditionNotMetException
|
||||
*/
|
||||
protected function refreshInfo(): void {
|
||||
$info = $this->fileView->getFileInfo($this->path);
|
||||
if ($info === false) {
|
||||
throw new Exception('Failed to get fileinfo for ' . $this->path);
|
||||
throw new \Sabre\DAV\Exception('Failed to get fileinfo for ' . $this->path);
|
||||
}
|
||||
|
||||
$this->info = $info;
|
||||
$root = Server::get(IRootFolder::class);
|
||||
$rootView = Server::get(View::class);
|
||||
@@ -100,15 +87,19 @@ abstract class Node implements INode {
|
||||
|
||||
/**
|
||||
* Returns the name of the node
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string {
|
||||
public function getName() {
|
||||
return $this->info->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full path
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPath(): string {
|
||||
public function getPath() {
|
||||
return $this->path;
|
||||
}
|
||||
|
||||
@@ -116,30 +107,25 @@ abstract class Node implements INode {
|
||||
* Renames the node
|
||||
*
|
||||
* @param string $name The new name
|
||||
* @throws Exception
|
||||
* @throws Forbidden
|
||||
* @throws InvalidPath
|
||||
* @throws PreConditionNotMetException
|
||||
* @throws LockedException
|
||||
* @throws \Sabre\DAV\Exception\BadRequest
|
||||
* @throws \Sabre\DAV\Exception\Forbidden
|
||||
*/
|
||||
public function setName($name): void {
|
||||
public function setName($name) {
|
||||
// rename is only allowed if the delete privilege is granted
|
||||
// (basically rename is a copy with delete of the original node)
|
||||
if (!$this->info->isDeletable() && !($this->info->getMountPoint() instanceof MoveableMount && $this->info->getInternalPath() === '')) {
|
||||
throw new Forbidden();
|
||||
if (!($this->info->isDeletable() || ($this->info->getMountPoint() instanceof MoveableMount && $this->info->getInternalPath() === ''))) {
|
||||
throw new \Sabre\DAV\Exception\Forbidden();
|
||||
}
|
||||
|
||||
/** @var string $parentPath */
|
||||
[$parentPath,] = \Sabre\Uri\split($this->path);
|
||||
/** @var string $newName */
|
||||
[, $newName] = \Sabre\Uri\split($name);
|
||||
$newPath = $parentPath . '/' . $newName;
|
||||
|
||||
// verify path of the target
|
||||
$this->verifyPath($newPath);
|
||||
|
||||
if ($this->fileView->rename($this->path, $newPath) === false) {
|
||||
throw new Exception('Failed to rename ' . $this->path . ' to ' . $newPath);
|
||||
if (!$this->fileView->rename($this->path, $newPath)) {
|
||||
throw new \Sabre\DAV\Exception('Failed to rename ' . $this->path . ' to ' . $newPath);
|
||||
}
|
||||
|
||||
$this->path = $newPath;
|
||||
@@ -152,8 +138,12 @@ abstract class Node implements INode {
|
||||
*
|
||||
* @return int timestamp as integer
|
||||
*/
|
||||
public function getLastModified(): int {
|
||||
return $this->info->getMtime();
|
||||
public function getLastModified() {
|
||||
$timestamp = $this->info->getMtime();
|
||||
if (!empty($timestamp)) {
|
||||
return (int)$timestamp;
|
||||
}
|
||||
return $timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -161,7 +151,7 @@ abstract class Node implements INode {
|
||||
* in the second parameter or to now if the second param is empty.
|
||||
* Even if the modification time is set to a custom value the access time is set to now.
|
||||
*/
|
||||
public function touch(string $mtime): void {
|
||||
public function touch($mtime) {
|
||||
$mtime = $this->sanitizeMtime($mtime);
|
||||
$this->fileView->touch($this->path, $mtime);
|
||||
$this->refreshInfo();
|
||||
@@ -175,29 +165,37 @@ abstract class Node implements INode {
|
||||
* arbitrary string, but MUST be surrounded by double-quotes.
|
||||
*
|
||||
* Return null if the ETag can not effectively be determined
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getETag(): string {
|
||||
public function getETag() {
|
||||
return '"' . $this->info->getEtag() . '"';
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ETag
|
||||
*
|
||||
* @param string $etag
|
||||
*
|
||||
* @return int file id of updated file or -1 on failure
|
||||
*/
|
||||
public function setETag(string $etag): int {
|
||||
public function setETag($etag) {
|
||||
return $this->fileView->putFileInfo($this->path, ['etag' => $etag]);
|
||||
}
|
||||
|
||||
public function setCreationTime(int $time): int {
|
||||
public function setCreationTime(int $time) {
|
||||
return $this->fileView->putFileInfo($this->path, ['creation_time' => $time]);
|
||||
}
|
||||
|
||||
public function setUploadTime(int $time) {
|
||||
return $this->fileView->putFileInfo($this->path, ['upload_time' => $time]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the node, in bytes
|
||||
*
|
||||
* @psalm-suppress UnusedPsalmSuppress psalm:strict actually thinks there is no mismatch, idk lol
|
||||
* @psalm-suppress ImplementedReturnTypeMismatch \Sabre\DAV\IFile::getSize signature does not support 32bit
|
||||
* @return int|float
|
||||
*/
|
||||
public function getSize(): int|float {
|
||||
return $this->info->getSize();
|
||||
@@ -205,21 +203,28 @@ abstract class Node implements INode {
|
||||
|
||||
/**
|
||||
* Returns the cache's file id
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getId(): ?int {
|
||||
public function getId() {
|
||||
return $this->info->getId();
|
||||
}
|
||||
|
||||
public function getFileId(): ?string {
|
||||
$id = $this->info->getId();
|
||||
if ($id !== null) {
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getFileId() {
|
||||
if ($id = $this->info->getId()) {
|
||||
return DavUtil::getDavFileId($id);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getInternalFileId(): ?int {
|
||||
/**
|
||||
* @return integer
|
||||
*/
|
||||
public function getInternalFileId() {
|
||||
return $this->info->getId();
|
||||
}
|
||||
|
||||
@@ -227,24 +232,30 @@ abstract class Node implements INode {
|
||||
return $this->info->getInternalPath();
|
||||
}
|
||||
|
||||
public function getSharePermissions(?string $user): int {
|
||||
/**
|
||||
* @param string $user
|
||||
* @return int
|
||||
*/
|
||||
public function getSharePermissions($user) {
|
||||
// check of we access a federated share
|
||||
if ($user !== null) {
|
||||
try {
|
||||
return $this->shareManager->getShareByToken($user)->getPermissions();
|
||||
} catch (ShareNotFound) {
|
||||
$share = $this->shareManager->getShareByToken($user);
|
||||
return $share->getPermissions();
|
||||
} catch (ShareNotFound $e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$storage = $this->info->getStorage();
|
||||
} catch (StorageNotAvailableException) {
|
||||
} catch (StorageNotAvailableException $e) {
|
||||
$storage = null;
|
||||
}
|
||||
|
||||
if ($storage && $storage->instanceOfStorage(ISharedStorage::class)) {
|
||||
$permissions = $storage->getShare()->getPermissions();
|
||||
/** @var ISharedStorage $storage */
|
||||
$permissions = (int)$storage->getShare()->getPermissions();
|
||||
} else {
|
||||
$permissions = $this->info->getPermissions();
|
||||
}
|
||||
@@ -255,10 +266,6 @@ abstract class Node implements INode {
|
||||
*/
|
||||
$mountpoint = $this->info->getMountPoint();
|
||||
if (!($mountpoint instanceof MoveableMount)) {
|
||||
/**
|
||||
* @psalm-suppress UnnecessaryVarAnnotation Rector doesn't trust the return type annotation
|
||||
* @var string $mountpointpath
|
||||
*/
|
||||
$mountpointpath = $mountpoint->getMountPoint();
|
||||
if (str_ends_with($mountpointpath, '/')) {
|
||||
$mountpointpath = substr($mountpointpath, 0, -1);
|
||||
@@ -279,21 +286,25 @@ abstract class Node implements INode {
|
||||
return $permissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getShareAttributes(): array {
|
||||
try {
|
||||
$storage = $this->node->getStorage();
|
||||
} catch (NotFoundException) {
|
||||
} catch (NotFoundException $e) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$attributes = [];
|
||||
if ($storage->instanceOfStorage(ISharedStorage::class)) {
|
||||
/** @var ISharedStorage $storage */
|
||||
$attributes = $storage->getShare()->getAttributes();
|
||||
if ($attributes === null) {
|
||||
return [];
|
||||
} else {
|
||||
return $attributes->toArray();
|
||||
}
|
||||
|
||||
return $attributes->toArray();
|
||||
}
|
||||
|
||||
return $attributes;
|
||||
@@ -307,66 +318,63 @@ abstract class Node implements INode {
|
||||
}
|
||||
|
||||
if ($storage->instanceOfStorage(ISharedStorage::class)) {
|
||||
/** @var ISharedStorage $storage */
|
||||
$share = $storage->getShare();
|
||||
if ($user === $share->getShareOwner()) {
|
||||
// Note is only for recipient not the owner
|
||||
return null;
|
||||
}
|
||||
|
||||
return $share->getNote();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getDavPermissions(): string {
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getDavPermissions() {
|
||||
return DavUtil::getDavPermissions($this->info);
|
||||
}
|
||||
|
||||
public function getOwner(): ?IUser {
|
||||
public function getOwner() {
|
||||
return $this->info->getOwner();
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidPath
|
||||
*/
|
||||
protected function verifyPath(?string $path = null): void {
|
||||
try {
|
||||
$path ??= $this->info->getPath();
|
||||
$path = $path ?? $this->info->getPath();
|
||||
$this->fileView->verifyPath(
|
||||
dirname($path),
|
||||
basename($path),
|
||||
);
|
||||
} catch (InvalidPathException $invalidPathException) {
|
||||
throw new InvalidPath($invalidPathException->getMessage(), false, $invalidPathException);
|
||||
} catch (InvalidPathException $ex) {
|
||||
throw new InvalidPath($ex->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ILockingProvider::LOCK_* $type
|
||||
* @throws LockedException
|
||||
* @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
|
||||
*/
|
||||
public function acquireLock($type): void {
|
||||
public function acquireLock($type) {
|
||||
$this->fileView->lockFile($this->path, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ILockingProvider::LOCK_* $type
|
||||
* @throws LockedException
|
||||
* @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
|
||||
*/
|
||||
public function releaseLock($type): void {
|
||||
public function releaseLock($type) {
|
||||
$this->fileView->unlockFile($this->path, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ILockingProvider::LOCK_* $type
|
||||
* @throws LockedException
|
||||
* @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
|
||||
*/
|
||||
public function changeLock($type): void {
|
||||
public function changeLock($type) {
|
||||
$this->fileView->changeLock($this->path, $type);
|
||||
}
|
||||
|
||||
public function getFileInfo(): FileInfo {
|
||||
public function getFileInfo() {
|
||||
return $this->info;
|
||||
}
|
||||
|
||||
|
||||
@@ -86,7 +86,6 @@ class FileSearchBackend implements ISearchBackend {
|
||||
new SearchPropertyDefinition('{DAV:}displayname', true, true, true),
|
||||
new SearchPropertyDefinition('{DAV:}getcontenttype', true, true, true),
|
||||
new SearchPropertyDefinition('{DAV:}getlastmodified', true, true, true, SearchPropertyDefinition::DATATYPE_DATETIME),
|
||||
new SearchPropertyDefinition('{http://nextcloud.org/ns}upload_time', true, true, true, SearchPropertyDefinition::DATATYPE_DATETIME),
|
||||
new SearchPropertyDefinition(FilesPlugin::SIZE_PROPERTYNAME, true, true, true, SearchPropertyDefinition::DATATYPE_NONNEGATIVE_INTEGER),
|
||||
new SearchPropertyDefinition(TagsPlugin::FAVORITE_PROPERTYNAME, true, true, true, SearchPropertyDefinition::DATATYPE_BOOLEAN),
|
||||
new SearchPropertyDefinition(FilesPlugin::INTERNAL_FILEID_PROPERTYNAME, true, true, false, SearchPropertyDefinition::DATATYPE_NONNEGATIVE_INTEGER),
|
||||
@@ -299,8 +298,6 @@ class FileSearchBackend implements ISearchBackend {
|
||||
return $node->getName();
|
||||
case '{DAV:}getlastmodified':
|
||||
return $node->getLastModified();
|
||||
case '{http://nextcloud.org/ns}upload_time':
|
||||
return $node->getNode()->getUploadTime();
|
||||
case FilesPlugin::SIZE_PROPERTYNAME:
|
||||
return $node->getSize();
|
||||
case FilesPlugin::INTERNAL_FILEID_PROPERTYNAME:
|
||||
@@ -461,8 +458,6 @@ class FileSearchBackend implements ISearchBackend {
|
||||
return 'mimetype';
|
||||
case '{DAV:}getlastmodified':
|
||||
return 'mtime';
|
||||
case '{http://nextcloud.org/ns}upload_time':
|
||||
return 'upload_time';
|
||||
case FilesPlugin::SIZE_PROPERTYNAME:
|
||||
return 'size';
|
||||
case TagsPlugin::FAVORITE_PROPERTYNAME:
|
||||
|
||||
@@ -32,12 +32,12 @@ class FilesHome extends Directory {
|
||||
throw new Forbidden('Permission denied to delete home folder');
|
||||
}
|
||||
|
||||
public function getName(): string {
|
||||
public function getName() {
|
||||
[,$name] = \Sabre\Uri\split($this->principalInfo['uri']);
|
||||
return $name;
|
||||
}
|
||||
|
||||
public function setName($name): void {
|
||||
public function setName($name) {
|
||||
throw new Forbidden('Permission denied to rename this folder');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,17 +17,21 @@ use OCP\DB\Types;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\Migration\IOutput;
|
||||
use OCP\Migration\SimpleMigrationStep;
|
||||
use Override;
|
||||
|
||||
class Version1025Date20240308063933 extends SimpleMigrationStep {
|
||||
|
||||
public function __construct(
|
||||
private readonly IAppConfig $appConfig,
|
||||
private readonly IDBConnection $db,
|
||||
private IAppConfig $appConfig,
|
||||
private IDBConnection $db,
|
||||
) {
|
||||
}
|
||||
|
||||
#[Override]
|
||||
/**
|
||||
* @param IOutput $output
|
||||
* @param Closure(): ISchemaWrapper $schemaClosure
|
||||
* @param array $options
|
||||
* @return null|ISchemaWrapper
|
||||
*/
|
||||
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
|
||||
/** @var ISchemaWrapper $schema */
|
||||
$schema = $schemaClosure();
|
||||
@@ -46,7 +50,6 @@ class Version1025Date20240308063933 extends SimpleMigrationStep {
|
||||
return $schema;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function postSchemaChange(IOutput $output, \Closure $schemaClosure, array $options): void {
|
||||
// The threshold is higher than the default of \OCA\DAV\BackgroundJob\PruneOutdatedSyncTokensJob
|
||||
// but small enough to fit into a cluster transaction size.
|
||||
|
||||
@@ -11,11 +11,11 @@ namespace OCA\DAV\Migration;
|
||||
|
||||
use Closure;
|
||||
use OCA\DAV\CardDAV\SyncService;
|
||||
use OCP\DB\ISchemaWrapper;
|
||||
use OCP\IConfig;
|
||||
use OCP\IUserManager;
|
||||
use OCP\Migration\IOutput;
|
||||
use OCP\Migration\SimpleMigrationStep;
|
||||
use Override;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Throwable;
|
||||
|
||||
@@ -27,8 +27,11 @@ class Version1027Date20230504122946 extends SimpleMigrationStep {
|
||||
private IConfig $config,
|
||||
) {
|
||||
}
|
||||
|
||||
#[Override]
|
||||
/**
|
||||
* @param IOutput $output
|
||||
* @param Closure(): ISchemaWrapper $schemaClosure
|
||||
* @param array $options
|
||||
*/
|
||||
public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options): void {
|
||||
if ($this->userManager->countSeenUsers() > 100 || $this->userManager->countUsersTotal(100) >= 100) {
|
||||
$this->config->setAppValue('dav', 'needs_system_address_book_sync', 'yes');
|
||||
|
||||
@@ -12,14 +12,16 @@ namespace OCA\DAV\Migration;
|
||||
use Closure;
|
||||
use OCP\DB\ISchemaWrapper;
|
||||
use OCP\DB\Types;
|
||||
use OCP\Migration\Attributes\CreateTable;
|
||||
use OCP\Migration\IOutput;
|
||||
use OCP\Migration\SimpleMigrationStep;
|
||||
use Override;
|
||||
|
||||
#[CreateTable(table: 'dav_absence')]
|
||||
class Version1029Date20231004091403 extends SimpleMigrationStep {
|
||||
#[Override]
|
||||
/**
|
||||
* @param IOutput $output
|
||||
* @param Closure(): ISchemaWrapper $schemaClosure
|
||||
* @param array $options
|
||||
* @return null|ISchemaWrapper
|
||||
*/
|
||||
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
|
||||
/** @var ISchemaWrapper $schema */
|
||||
$schema = $schemaClosure();
|
||||
|
||||
@@ -11,14 +11,17 @@ namespace OCA\DAV\Migration;
|
||||
|
||||
use Closure;
|
||||
use OCP\DB\ISchemaWrapper;
|
||||
use OCP\Migration\Attributes\DropIndex;
|
||||
use OCP\Migration\IOutput;
|
||||
use OCP\Migration\SimpleMigrationStep;
|
||||
use Override;
|
||||
|
||||
#[DropIndex(table: 'cards')]
|
||||
class Version1030Date20240205103243 extends SimpleMigrationStep {
|
||||
#[Override]
|
||||
|
||||
/**
|
||||
* @param IOutput $output
|
||||
* @param Closure(): ISchemaWrapper $schemaClosure
|
||||
* @param array $options
|
||||
* @return null|ISchemaWrapper
|
||||
*/
|
||||
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
|
||||
/** @var ISchemaWrapper $schema */
|
||||
$schema = $schemaClosure();
|
||||
|
||||
@@ -17,12 +17,16 @@ use OCP\Migration\Attributes\ColumnType;
|
||||
use OCP\Migration\Attributes\CreateTable;
|
||||
use OCP\Migration\IOutput;
|
||||
use OCP\Migration\SimpleMigrationStep;
|
||||
use Override;
|
||||
|
||||
#[AddColumn(table: 'dav_shares', name: 'token', type: ColumnType::STRING)]
|
||||
#[CreateTable(table: 'calendars_federated', columns: ['id', 'display_name', 'color', 'uri', 'principaluri', 'remote_Url', 'token', 'sync_token', 'last_sync', 'shared_by', 'shared_by_display_name', 'components', 'permissions'], description: 'Supporting Federated Calender')]
|
||||
class Version1034Date20250605132605 extends SimpleMigrationStep {
|
||||
#[Override]
|
||||
/**
|
||||
* @param IOutput $output
|
||||
* @param Closure(): ISchemaWrapper $schemaClosure
|
||||
* @param array $options
|
||||
* @return null|ISchemaWrapper
|
||||
*/
|
||||
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
|
||||
/** @var ISchemaWrapper $schema */
|
||||
$schema = $schemaClosure();
|
||||
|
||||
@@ -10,6 +10,7 @@ declare(strict_types=1);
|
||||
namespace OCA\DAV\Migration;
|
||||
|
||||
use Closure;
|
||||
use OCP\DB\ISchemaWrapper;
|
||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\Migration\Attributes\DataCleansing;
|
||||
@@ -24,6 +25,11 @@ class Version1034Date20250813093701 extends SimpleMigrationStep {
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param IOutput $output
|
||||
* @param Closure(): ISchemaWrapper $schemaClosure
|
||||
* @param array $options
|
||||
*/
|
||||
#[Override]
|
||||
public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options): void {
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
|
||||
@@ -21,6 +21,9 @@ use Override;
|
||||
#[ModifyColumn(table: 'calendar_reminders', name: 'uid', type: ColumnType::STRING, description: 'Increase uid length to 512 characters')]
|
||||
#[ModifyColumn(table: 'calendar_invitations', name: 'uid', type: ColumnType::STRING, description: 'Increase uid length to 512 characters')]
|
||||
class Version1036Date20251202000000 extends SimpleMigrationStep {
|
||||
/**
|
||||
* @param Closure(): ISchemaWrapper $schemaClosure
|
||||
*/
|
||||
#[Override]
|
||||
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
|
||||
/** @var ISchemaWrapper $schema */
|
||||
|
||||
@@ -15,19 +15,11 @@ class TipBrokerTest extends TestCase {
|
||||
|
||||
private TipBroker $broker;
|
||||
private VCalendar $vCalendar1a;
|
||||
private VCalendar $vCalendar2a;
|
||||
private array $templateEventInfo;
|
||||
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->broker = new TipBroker();
|
||||
|
||||
$this->templateEventInfo = [
|
||||
'organizer' => null,
|
||||
'attendees' => [],
|
||||
'significantChangeHash' => '',
|
||||
];
|
||||
// construct calendar with a 1 hour event and same start/end time zones
|
||||
$this->vCalendar1a = new VCalendar();
|
||||
/** @var VEvent $vEvent */
|
||||
@@ -36,7 +28,7 @@ class TipBrokerTest extends TestCase {
|
||||
$vEvent->add('DTSTAMP', '20240701T000000Z');
|
||||
$vEvent->add('CREATED', '20240701T000000Z');
|
||||
$vEvent->add('LAST-MODIFIED', '20240701T000000Z');
|
||||
$vEvent->add('SEQUENCE', 1);
|
||||
$vEvent->add('SEQUENCE', '1');
|
||||
$vEvent->add('STATUS', 'CONFIRMED');
|
||||
$vEvent->add('DTSTART', '20240701T080000', ['TZID' => 'America/Toronto']);
|
||||
$vEvent->add('DTEND', '20240701T090000', ['TZID' => 'America/Toronto']);
|
||||
@@ -49,534 +41,140 @@ class TipBrokerTest extends TestCase {
|
||||
'ROLE' => 'REQ-PARTICIPANT',
|
||||
'RSVP' => 'TRUE'
|
||||
]);
|
||||
|
||||
// construct calendar with a 1 hour event and same start/end time zones
|
||||
// recurring every week on Monday for 12 weeks
|
||||
$this->vCalendar2a = new VCalendar();
|
||||
/** @var VEvent $vEvent */
|
||||
$vEvent = $this->vCalendar2a->add('VEVENT', []);
|
||||
$vEvent->add('UID', '96a0e6b1-d886-4a55-a60d-152b31401dcc');
|
||||
$vEvent->add('DTSTAMP', '20240701T000000Z');
|
||||
$vEvent->add('CREATED', '20240701T000000Z');
|
||||
$vEvent->add('LAST-MODIFIED', '20240701T000000Z');
|
||||
$vEvent->add('SEQUENCE', 1);
|
||||
$vEvent->add('STATUS', 'CONFIRMED');
|
||||
$vEvent->add('DTSTART', '20240701T080000', ['TZID' => 'America/Toronto']);
|
||||
$vEvent->add('DTEND', '20240701T090000', ['TZID' => 'America/Toronto']);
|
||||
$vEvent->add('RRULE', 'FREQ=WEEKLY;COUNT=12;BYDAY=MO');
|
||||
$vEvent->add('SUMMARY', 'Test Event');
|
||||
$vEvent->add('ORGANIZER', 'mailto:organizer@testing.com', ['CN' => 'Organizer']);
|
||||
$vEvent->add('ATTENDEE', 'mailto:attendee1@testing.com', [
|
||||
'CN' => 'Attendee One',
|
||||
'CUTYPE' => 'INDIVIDUAL',
|
||||
'PARTSTAT' => 'NEEDS-ACTION',
|
||||
'ROLE' => 'REQ-PARTICIPANT',
|
||||
'RSVP' => 'TRUE'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests user creating a new singleton or recurring event
|
||||
*/
|
||||
public function testParseEventForOrganizerCreated(): void {
|
||||
public function testParseEventForOrganizerOnCreate(): void {
|
||||
|
||||
// construct calendar and generate event info for newly created event with one attendee
|
||||
$mutatedCalendar = clone $this->vCalendar1a;
|
||||
$originalEventInfo = $this->templateEventInfo;
|
||||
$mutatedEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$mutatedCalendar]);
|
||||
$calendar = clone $this->vCalendar1a;
|
||||
$previousEventInfo = [
|
||||
'organizer' => null,
|
||||
'significantChangeHash' => '',
|
||||
'attendees' => [],
|
||||
];
|
||||
$currentEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$calendar]);
|
||||
// test iTip generation
|
||||
$messages = $this->invokePrivate($this->broker, 'parseEventForOrganizer', [$mutatedCalendar, $mutatedEventInfo, $originalEventInfo]);
|
||||
$messages = $this->invokePrivate($this->broker, 'parseEventForOrganizer', [$calendar, $currentEventInfo, $previousEventInfo]);
|
||||
$this->assertCount(1, $messages);
|
||||
$this->assertEquals('REQUEST', $messages[0]->method);
|
||||
$this->assertEquals($mutatedCalendar->VEVENT->ORGANIZER->getValue(), $messages[0]->sender);
|
||||
$this->assertEquals($mutatedCalendar->VEVENT->ATTENDEE[0]->getValue(), $messages[0]->recipient);
|
||||
$this->assertEquals($calendar->VEVENT->ORGANIZER->getValue(), $messages[0]->sender);
|
||||
$this->assertEquals($calendar->VEVENT->ATTENDEE[0]->getValue(), $messages[0]->recipient);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests user modifying an existing singleton or recurring (base) event
|
||||
*/
|
||||
public function testParseEventForOrganizerModified(): void {
|
||||
public function testParseEventForOrganizerOnModify(): void {
|
||||
|
||||
// construct calendar and generate event info for modified event with one attendee
|
||||
$originalCalendar = clone $this->vCalendar1a;
|
||||
$originalEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$originalCalendar]);
|
||||
$mutatedCalendar = clone $this->vCalendar1a;
|
||||
$mutatedCalendar->VEVENT->{'LAST-MODIFIED'}->setValue('20240701T020000Z');
|
||||
$mutatedCalendar->VEVENT->SEQUENCE->setValue(2);
|
||||
$mutatedCalendar->VEVENT->SUMMARY->setValue('Test Event Modified');
|
||||
$mutatedEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$mutatedCalendar]);
|
||||
$calendar = clone $this->vCalendar1a;
|
||||
$previousEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$calendar]);
|
||||
$calendar->VEVENT->{'LAST-MODIFIED'}->setValue('20240701T020000Z');
|
||||
$calendar->VEVENT->SEQUENCE->setValue(2);
|
||||
$calendar->VEVENT->SUMMARY->setValue('Test Event Modified');
|
||||
$currentEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$calendar]);
|
||||
// test iTip generation
|
||||
$messages = $this->invokePrivate($this->broker, 'parseEventForOrganizer', [$mutatedCalendar, $mutatedEventInfo, $originalEventInfo]);
|
||||
$messages = $this->invokePrivate($this->broker, 'parseEventForOrganizer', [$calendar, $currentEventInfo, $previousEventInfo]);
|
||||
$this->assertCount(1, $messages);
|
||||
$this->assertEquals('REQUEST', $messages[0]->method);
|
||||
$this->assertEquals($mutatedCalendar->VEVENT->ORGANIZER->getValue(), $messages[0]->sender);
|
||||
$this->assertEquals($mutatedCalendar->VEVENT->ATTENDEE[0]->getValue(), $messages[0]->recipient);
|
||||
$this->assertEquals($calendar->VEVENT->ORGANIZER->getValue(), $messages[0]->sender);
|
||||
$this->assertEquals($calendar->VEVENT->ATTENDEE[0]->getValue(), $messages[0]->recipient);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests user deleting an existing singleton or recurring (base) event
|
||||
*/
|
||||
public function testParseEventForOrganizerDeleted(): void {
|
||||
public function testParseEventForOrganizerOnDelete(): void {
|
||||
|
||||
// construct calendar and generate event info for modified event with one attendee
|
||||
$originalCalendar = clone $this->vCalendar1a;
|
||||
$originalEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$originalCalendar]);
|
||||
$mutatedEventInfo = $originalEventInfo;
|
||||
$mutatedEventInfo['attendees'] = [];
|
||||
++$mutatedEventInfo['sequence'];
|
||||
$calendar = clone $this->vCalendar1a;
|
||||
$previousEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$calendar]);
|
||||
$currentEventInfo = $previousEventInfo;
|
||||
$currentEventInfo['attendees'] = [];
|
||||
++$currentEventInfo['sequence'];
|
||||
// test iTip generation
|
||||
$messages = $this->invokePrivate($this->broker, 'parseEventForOrganizer', [$originalCalendar, $mutatedEventInfo, $originalEventInfo]);
|
||||
$messages = $this->invokePrivate($this->broker, 'parseEventForOrganizer', [$calendar, $currentEventInfo, $previousEventInfo]);
|
||||
$this->assertCount(1, $messages);
|
||||
$this->assertEquals('CANCEL', $messages[0]->method);
|
||||
$this->assertEquals($originalCalendar->VEVENT->ORGANIZER->getValue(), $messages[0]->sender);
|
||||
$this->assertEquals($originalCalendar->VEVENT->ATTENDEE[0]->getValue(), $messages[0]->recipient);
|
||||
$this->assertEquals($calendar->VEVENT->ORGANIZER->getValue(), $messages[0]->sender);
|
||||
$this->assertEquals($calendar->VEVENT->ATTENDEE[0]->getValue(), $messages[0]->recipient);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests user cancelling an existing singleton or recurring (base) event
|
||||
*/
|
||||
public function testParseEventForOrganizerStatusCancelled(): void {
|
||||
public function testParseEventForOrganizerOnStatusCancelled(): void {
|
||||
|
||||
// construct calendar and generate event info for modified event with one attendee
|
||||
$originalCalendar = clone $this->vCalendar1a;
|
||||
$originalEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$originalCalendar]);
|
||||
$mutatedCalendar = clone $this->vCalendar1a;
|
||||
$mutatedCalendar->VEVENT->{'LAST-MODIFIED'}->setValue('20240701T020000Z');
|
||||
$mutatedCalendar->VEVENT->SEQUENCE->setValue(2);
|
||||
$mutatedCalendar->VEVENT->STATUS->setValue('CANCELLED');
|
||||
$mutatedEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$mutatedCalendar]);
|
||||
$calendar = clone $this->vCalendar1a;
|
||||
$previousEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$calendar]);
|
||||
$calendar->VEVENT->{'LAST-MODIFIED'}->setValue('20240701T020000Z');
|
||||
$calendar->VEVENT->SEQUENCE->setValue(2);
|
||||
$calendar->VEVENT->STATUS->setValue('CANCELLED');
|
||||
$currentEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$calendar]);
|
||||
// test iTip generation
|
||||
$messages = $this->invokePrivate($this->broker, 'parseEventForOrganizer', [$mutatedCalendar, $mutatedEventInfo, $originalEventInfo]);
|
||||
$messages = $this->invokePrivate($this->broker, 'parseEventForOrganizer', [$calendar, $currentEventInfo, $previousEventInfo]);
|
||||
$this->assertCount(1, $messages);
|
||||
$this->assertEquals('CANCEL', $messages[0]->method);
|
||||
$this->assertEquals($mutatedCalendar->VEVENT->ORGANIZER->getValue(), $messages[0]->sender);
|
||||
$this->assertEquals($mutatedCalendar->VEVENT->ATTENDEE[0]->getValue(), $messages[0]->recipient);
|
||||
$this->assertEquals($calendar->VEVENT->ORGANIZER->getValue(), $messages[0]->sender);
|
||||
$this->assertEquals($calendar->VEVENT->ATTENDEE[0]->getValue(), $messages[0]->recipient);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests user adding an attendee to an existing singleton or recurring (base) event
|
||||
*/
|
||||
public function testParseEventForOrganizerAddAttendee(): void {
|
||||
public function testParseEventForOrganizerOnAddAttendee(): void {
|
||||
|
||||
// construct calendar and generate event info for modified event with two attendees
|
||||
$originalCalendar = clone $this->vCalendar1a;
|
||||
$originalEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$originalCalendar]);
|
||||
$mutatedCalendar = clone $this->vCalendar1a;
|
||||
$mutatedCalendar->VEVENT->{'LAST-MODIFIED'}->setValue('20240701T020000Z');
|
||||
$mutatedCalendar->VEVENT->SEQUENCE->setValue(2);
|
||||
$mutatedCalendar->VEVENT->add('ATTENDEE', 'mailto:attendee2@testing.com', [
|
||||
$calendar = clone $this->vCalendar1a;
|
||||
$previousEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$calendar]);
|
||||
$calendar->VEVENT->{'LAST-MODIFIED'}->setValue('20240701T020000Z');
|
||||
$calendar->VEVENT->SEQUENCE->setValue(2);
|
||||
$calendar->VEVENT->add('ATTENDEE', 'mailto:attendee2@testing.com', [
|
||||
'CN' => 'Attendee Two',
|
||||
'CUTYPE' => 'INDIVIDUAL',
|
||||
'PARTSTAT' => 'NEEDS-ACTION',
|
||||
'ROLE' => 'REQ-PARTICIPANT',
|
||||
'RSVP' => 'TRUE'
|
||||
]);
|
||||
$mutatedEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$mutatedCalendar]);
|
||||
$currentEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$calendar]);
|
||||
// test iTip generation
|
||||
$messages = $this->invokePrivate($this->broker, 'parseEventForOrganizer', [$mutatedCalendar, $mutatedEventInfo, $originalEventInfo]);
|
||||
// attendee modifications get generated in order of Added, Removed, Existing
|
||||
$messages = $this->invokePrivate($this->broker, 'parseEventForOrganizer', [$calendar, $currentEventInfo, $previousEventInfo]);
|
||||
$this->assertCount(2, $messages);
|
||||
$this->assertEquals('REQUEST', $messages[0]->method);
|
||||
$this->assertEquals($mutatedCalendar->VEVENT->ORGANIZER->getValue(), $messages[0]->sender);
|
||||
$this->assertEquals($mutatedCalendar->VEVENT->ATTENDEE[0]->getValue(), $messages[0]->recipient);
|
||||
$this->assertEquals($calendar->VEVENT->ORGANIZER->getValue(), $messages[0]->sender);
|
||||
$this->assertEquals($calendar->VEVENT->ATTENDEE[0]->getValue(), $messages[0]->recipient);
|
||||
$this->assertEquals('REQUEST', $messages[1]->method);
|
||||
$this->assertEquals($mutatedCalendar->VEVENT->ORGANIZER->getValue(), $messages[1]->sender);
|
||||
$this->assertEquals($mutatedCalendar->VEVENT->ATTENDEE[1]->getValue(), $messages[1]->recipient);
|
||||
$this->assertEquals($calendar->VEVENT->ORGANIZER->getValue(), $messages[1]->sender);
|
||||
$this->assertEquals($calendar->VEVENT->ATTENDEE[1]->getValue(), $messages[1]->recipient);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests user removing an attendee from an existing singleton or recurring (base) event
|
||||
*/
|
||||
public function testParseEventForOrganizerRemoveAttendee(): void {
|
||||
public function testParseEventForOrganizerOnRemoveAttendee(): void {
|
||||
|
||||
// construct calendar and generate event info for modified event with two attendees
|
||||
$originalCalendar = clone $this->vCalendar1a;
|
||||
$originalCalendar->VEVENT->add('ATTENDEE', 'mailto:attendee2@testing.com', [
|
||||
$calendar = clone $this->vCalendar1a;
|
||||
$calendar->VEVENT->add('ATTENDEE', 'mailto:attendee2@testing.com', [
|
||||
'CN' => 'Attendee Two',
|
||||
'CUTYPE' => 'INDIVIDUAL',
|
||||
'PARTSTAT' => 'NEEDS-ACTION',
|
||||
'ROLE' => 'REQ-PARTICIPANT',
|
||||
'RSVP' => 'TRUE'
|
||||
]);
|
||||
$originalEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$originalCalendar]);
|
||||
$mutatedCalendar = clone $this->vCalendar1a;
|
||||
$mutatedCalendar->VEVENT->{'LAST-MODIFIED'}->setValue('20240701T020000Z');
|
||||
$mutatedCalendar->VEVENT->SEQUENCE->setValue(2);
|
||||
$mutatedCalendar->VEVENT->remove('ATTENDEE');
|
||||
$mutatedCalendar->VEVENT->add('ATTENDEE', 'mailto:attendee1@testing.com', [
|
||||
$previousEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$calendar]);
|
||||
$calendar->VEVENT->{'LAST-MODIFIED'}->setValue('20240701T020000Z');
|
||||
$calendar->VEVENT->SEQUENCE->setValue(2);
|
||||
$calendar->VEVENT->remove('ATTENDEE');
|
||||
$calendar->VEVENT->add('ATTENDEE', 'mailto:attendee1@testing.com', [
|
||||
'CN' => 'Attendee One',
|
||||
'CUTYPE' => 'INDIVIDUAL',
|
||||
'PARTSTAT' => 'NEEDS-ACTION',
|
||||
'ROLE' => 'REQ-PARTICIPANT',
|
||||
'RSVP' => 'TRUE'
|
||||
]);
|
||||
$mutatedEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$mutatedCalendar]);
|
||||
$currentEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$calendar]);
|
||||
// test iTip generation
|
||||
$messages = $this->invokePrivate($this->broker, 'parseEventForOrganizer', [$mutatedCalendar, $mutatedEventInfo, $originalEventInfo]);
|
||||
// attendee modifications get generated in order of Added, Removed, Existing
|
||||
$messages = $this->invokePrivate($this->broker, 'parseEventForOrganizer', [$calendar, $currentEventInfo, $previousEventInfo]);
|
||||
$this->assertCount(2, $messages);
|
||||
$this->assertEquals('REQUEST', $messages[0]->method);
|
||||
$this->assertEquals($mutatedCalendar->VEVENT->ORGANIZER->getValue(), $messages[0]->sender);
|
||||
$this->assertEquals($mutatedCalendar->VEVENT->ATTENDEE[0]->getValue(), $messages[0]->recipient);
|
||||
$this->assertEquals($calendar->VEVENT->ORGANIZER->getValue(), $messages[0]->sender);
|
||||
$this->assertEquals($calendar->VEVENT->ATTENDEE[0]->getValue(), $messages[0]->recipient);
|
||||
$this->assertEquals('CANCEL', $messages[1]->method);
|
||||
$this->assertEquals($mutatedCalendar->VEVENT->ORGANIZER->getValue(), $messages[1]->sender);
|
||||
$this->assertEquals($calendar->VEVENT->ORGANIZER->getValue(), $messages[1]->sender);
|
||||
$this->assertEquals('mailto:attendee2@testing.com', $messages[1]->recipient);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tests user converts existing singleton or recurring (base) event from attended to attendeless
|
||||
*/
|
||||
public function testParseEventForOrganizerRemoveOrganizerAndAttendees(): void {
|
||||
// construct calendar and generate event info for modified event with two attendees
|
||||
$originalCalendar = clone $this->vCalendar1a;
|
||||
$originalEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$originalCalendar]);
|
||||
$mutatedCalendar = clone $this->vCalendar1a;
|
||||
$mutatedCalendar->VEVENT->{'LAST-MODIFIED'}->setValue('20240701T020000Z');
|
||||
$mutatedCalendar->VEVENT->SEQUENCE->setValue(2);
|
||||
$mutatedCalendar->VEVENT->remove('ORGANIZER');
|
||||
$mutatedCalendar->VEVENT->remove('ATTENDEE');
|
||||
$mutatedEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$mutatedCalendar]);
|
||||
// test iTip generation
|
||||
$messages = $this->invokePrivate($this->broker, 'parseEventForOrganizer', [$mutatedCalendar, $mutatedEventInfo, $originalEventInfo]);
|
||||
// attendee modifications get generated in order of Added, Removed, Existing
|
||||
$this->assertCount(1, $messages);
|
||||
$this->assertEquals('CANCEL', $messages[0]->method);
|
||||
$this->assertEquals(2, $messages[0]->sequence);
|
||||
$this->assertEquals($originalCalendar->VEVENT->ORGANIZER->getValue(), $messages[0]->sender);
|
||||
$this->assertEquals($originalCalendar->VEVENT->ATTENDEE[0]->getValue(), $messages[0]->recipient);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests user modifying recurring (base) event by moving instance to a new date
|
||||
*/
|
||||
public function testParseEventForOrganizerCreatedInstance(): void {
|
||||
// construct calendar and generate event info for modified event with two attendees
|
||||
$originalCalendar = clone $this->vCalendar2a;
|
||||
$originalEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$originalCalendar]);
|
||||
$mutatedInstance = clone $originalCalendar->VEVENT;
|
||||
$mutatedInstance->add('RECURRENCE-ID', '20240715T080000', ['TZID' => 'America/Toronto']);
|
||||
$mutatedInstance->SEQUENCE->setValue(0);
|
||||
$mutatedInstance->DTSTART->setValue('20240717T080000');
|
||||
$mutatedInstance->DTEND->setValue('20240717T090000');
|
||||
$mutatedCalendar = clone $this->vCalendar2a;
|
||||
$mutatedCalendar->add($mutatedInstance);
|
||||
$mutatedEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$mutatedCalendar]);
|
||||
// test iTip generation
|
||||
$messages = $this->invokePrivate($this->broker, 'parseEventForOrganizer', [$mutatedCalendar, $mutatedEventInfo, $originalEventInfo]);
|
||||
// attendee modifications get generated in order of Added, Removed, Existing
|
||||
$this->assertCount(1, $messages);
|
||||
$this->assertEquals('REQUEST', $messages[0]->method);
|
||||
$this->assertEquals(1, $messages[0]->sequence);
|
||||
$this->assertEquals($mutatedCalendar->VEVENT->ORGANIZER->getValue(), $messages[0]->sender);
|
||||
$this->assertEquals($mutatedCalendar->VEVENT->ATTENDEE[0]->getValue(), $messages[0]->recipient);
|
||||
$this->assertCount(2, $messages[0]->message->VEVENT);
|
||||
$this->assertEquals('20240715T080000', $messages[0]->message->VEVENT[1]->{'RECURRENCE-ID'}->getValue());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests user modifying recurring (base) event by cancelling a single instance
|
||||
*/
|
||||
public function testParseEventForOrganizerCreatedInstanceCancelled(): void {
|
||||
// construct calendar and generate event info for modified event with two attendees
|
||||
$originalCalendar = clone $this->vCalendar2a;
|
||||
$originalEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$originalCalendar]);
|
||||
$mutatedInstance = clone $originalCalendar->VEVENT;
|
||||
$mutatedInstance->add('RECURRENCE-ID', '20240715T080000', ['TZID' => 'America/Toronto']);
|
||||
$mutatedInstance->SEQUENCE->setValue(0);
|
||||
$mutatedInstance->STATUS->setValue('CANCELLED');
|
||||
$mutatedCalendar = clone $this->vCalendar2a;
|
||||
$mutatedCalendar->add($mutatedInstance);
|
||||
$mutatedEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$mutatedCalendar]);
|
||||
// test iTip generation
|
||||
$messages = $this->invokePrivate($this->broker, 'parseEventForOrganizer', [$mutatedCalendar, $mutatedEventInfo, $originalEventInfo]);
|
||||
// attendee modifications get generated in order of Added, Removed, Existing
|
||||
$this->assertCount(2, $messages);
|
||||
$this->assertEquals('CANCEL', $messages[0]->method);
|
||||
$this->assertEquals(1, $messages[0]->sequence);
|
||||
$this->assertEquals($mutatedCalendar->VEVENT[1]->ORGANIZER->getValue(), $messages[0]->sender);
|
||||
$this->assertEquals($mutatedCalendar->VEVENT[1]->ATTENDEE[0]->getValue(), $messages[0]->recipient);
|
||||
$this->assertCount(1, $messages[0]->message->VEVENT);
|
||||
$this->assertEquals('20240715T080000', $messages[0]->message->VEVENT->{'RECURRENCE-ID'}->getValue());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests user modifying recurring (instance) event with non status or attendee changes
|
||||
*/
|
||||
public function testParseEventForOrganizerModifyInstance(): void {
|
||||
// construct calendar and generate event info for modified event with two attendees
|
||||
$originalCalendar = clone $this->vCalendar2a;
|
||||
$originalInstance = clone $originalCalendar->VEVENT;
|
||||
$originalInstance->add('RECURRENCE-ID', '20240715T080000', ['TZID' => 'America/Toronto']);
|
||||
$originalInstance->SEQUENCE->setValue(1);
|
||||
$originalInstance->DTSTART->setValue('20240717T080000');
|
||||
$originalInstance->DTEND->setValue('20240717T090000');
|
||||
$originalCalendar->add($originalInstance);
|
||||
$originalEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$originalCalendar]);
|
||||
|
||||
$mutatedInstance = clone $originalInstance;
|
||||
$mutatedInstance->SEQUENCE->setValue(2);
|
||||
$mutatedInstance->DTSTART->setValue('20240718T080000');
|
||||
$mutatedInstance->DTEND->setValue('20240718T090000');
|
||||
$mutatedCalendar = clone $this->vCalendar2a;
|
||||
$mutatedCalendar->add($mutatedInstance);
|
||||
$mutatedEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$mutatedCalendar]);
|
||||
// test iTip generation
|
||||
$messages = $this->invokePrivate($this->broker, 'parseEventForOrganizer', [$mutatedCalendar, $mutatedEventInfo, $originalEventInfo]);
|
||||
// attendee modifications get generated in order of Added, Removed, Existing
|
||||
$this->assertCount(1, $messages);
|
||||
$this->assertEquals('REQUEST', $messages[0]->method);
|
||||
$this->assertEquals(1, $messages[0]->sequence);
|
||||
$this->assertEquals($mutatedCalendar->VEVENT[1]->ORGANIZER->getValue(), $messages[0]->sender);
|
||||
$this->assertEquals($mutatedCalendar->VEVENT[1]->ATTENDEE[0]->getValue(), $messages[0]->recipient);
|
||||
$this->assertCount(2, $messages[0]->message->VEVENT);
|
||||
$this->assertEquals('20240715T080000', $messages[0]->message->VEVENT[1]->{'RECURRENCE-ID'}->getValue());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests user modifying recurring (instance) event by setting status to cancelled
|
||||
*/
|
||||
public function testParseEventForOrganizerModifyInstanceStatus(): void {
|
||||
// construct calendar and generate event info for modified event with two attendees
|
||||
$originalCalendar = clone $this->vCalendar2a;
|
||||
$originalInstance = clone $originalCalendar->VEVENT;
|
||||
$originalInstance->add('RECURRENCE-ID', '20240715T080000', ['TZID' => 'America/Toronto']);
|
||||
$originalInstance->SEQUENCE->setValue(1);
|
||||
$originalInstance->DTSTART->setValue('20240717T080000');
|
||||
$originalInstance->DTEND->setValue('20240717T090000');
|
||||
$originalCalendar->add($originalInstance);
|
||||
$originalEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$originalCalendar]);
|
||||
$mutatedInstance = clone $originalInstance;
|
||||
$mutatedInstance->SEQUENCE->setValue(2);
|
||||
$mutatedInstance->STATUS->setValue('CANCELLED');
|
||||
$mutatedCalendar = clone $this->vCalendar2a;
|
||||
$mutatedCalendar->add($mutatedInstance);
|
||||
$mutatedEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$mutatedCalendar]);
|
||||
// test iTip generation
|
||||
$messages = $this->invokePrivate($this->broker, 'parseEventForOrganizer', [$mutatedCalendar, $mutatedEventInfo, $originalEventInfo]);
|
||||
// attendee modifications get generated in order of Added, Removed, Existing
|
||||
$this->assertCount(1, $messages);
|
||||
$this->assertEquals('REQUEST', $messages[0]->method);
|
||||
$this->assertEquals(1, $messages[0]->sequence);
|
||||
$this->assertEquals($mutatedCalendar->VEVENT[1]->ORGANIZER->getValue(), $messages[0]->sender);
|
||||
$this->assertEquals($mutatedCalendar->VEVENT[1]->ATTENDEE[0]->getValue(), $messages[0]->recipient);
|
||||
$this->assertCount(2, $messages[0]->message->VEVENT);
|
||||
$this->assertEquals('20240715T080000', $messages[0]->message->VEVENT[1]->{'RECURRENCE-ID'}->getValue());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests user modifying recurring (instance) event by adding attendee
|
||||
*/
|
||||
public function testParseEventForOrganizerModifyInstanceAddAttendee(): void {
|
||||
// construct calendar and generate event info for modified event with two attendees
|
||||
$originalCalendar = clone $this->vCalendar2a;
|
||||
$originalInstance = clone $originalCalendar->VEVENT;
|
||||
$originalInstance->add('RECURRENCE-ID', '20240715T080000', ['TZID' => 'America/Toronto']);
|
||||
$originalInstance->SEQUENCE->setValue(1);
|
||||
$originalInstance->DTSTART->setValue('20240717T080000');
|
||||
$originalInstance->DTEND->setValue('20240717T090000');
|
||||
$originalCalendar->add($originalInstance);
|
||||
$originalEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$originalCalendar]);
|
||||
$mutatedInstance = clone $originalInstance;
|
||||
$mutatedInstance->SEQUENCE->setValue(2);
|
||||
$mutatedInstance->add('ATTENDEE', 'mailto:attendee2@testing.com', [
|
||||
'CN' => 'Attendee Two',
|
||||
'CUTYPE' => 'INDIVIDUAL',
|
||||
'PARTSTAT' => 'NEEDS-ACTION',
|
||||
'ROLE' => 'REQ-PARTICIPANT',
|
||||
'RSVP' => 'TRUE'
|
||||
]);
|
||||
$mutatedCalendar = clone $this->vCalendar2a;
|
||||
$mutatedCalendar->add($mutatedInstance);
|
||||
$mutatedEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$mutatedCalendar]);
|
||||
// test iTip generation
|
||||
$messages = $this->invokePrivate($this->broker, 'parseEventForOrganizer', [$mutatedCalendar, $mutatedEventInfo, $originalEventInfo]);
|
||||
// attendee modifications get generated in order of Added, Removed, Existing
|
||||
$this->assertCount(2, $messages);
|
||||
$this->assertEquals('REQUEST', $messages[0]->method);
|
||||
$this->assertEquals(1, $messages[0]->sequence);
|
||||
$this->assertEquals($mutatedCalendar->VEVENT[1]->ORGANIZER->getValue(), $messages[0]->sender);
|
||||
$this->assertEquals($mutatedCalendar->VEVENT[1]->ATTENDEE[0]->getValue(), $messages[0]->recipient);
|
||||
$this->assertCount(2, $messages[0]->message->VEVENT);
|
||||
$this->assertEquals('20240715T080000', $messages[0]->message->VEVENT[1]->{'RECURRENCE-ID'}->getValue());
|
||||
$this->assertEquals('REQUEST', $messages[1]->method);
|
||||
$this->assertEquals(1, $messages[1]->sequence);
|
||||
$this->assertEquals($mutatedCalendar->VEVENT[1]->ORGANIZER->getValue(), $messages[1]->sender);
|
||||
$this->assertEquals($mutatedCalendar->VEVENT[1]->ATTENDEE[1]->getValue(), $messages[1]->recipient);
|
||||
$this->assertCount(1, $messages[1]->message->VEVENT);
|
||||
$this->assertEquals('20240715T080000', $messages[1]->message->VEVENT->{'RECURRENCE-ID'}->getValue());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests user modifying recurring (instance) event by removing attendee
|
||||
*/
|
||||
public function testParseEventForOrganizerModifyInstanceRemoveAttendee(): void {
|
||||
// construct calendar and generate event info for modified event with two attendees
|
||||
$originalCalendar = clone $this->vCalendar2a;
|
||||
$originalInstance = clone $originalCalendar->VEVENT;
|
||||
$originalInstance->add('RECURRENCE-ID', '20240715T080000', ['TZID' => 'America/Toronto']);
|
||||
$originalInstance->SEQUENCE->setValue(1);
|
||||
$originalInstance->DTSTART->setValue('20240717T080000');
|
||||
$originalInstance->DTEND->setValue('20240717T090000');
|
||||
$originalInstance->add('ATTENDEE', 'mailto:attendee2@testing.com', [
|
||||
'CN' => 'Attendee Two',
|
||||
'CUTYPE' => 'INDIVIDUAL',
|
||||
'PARTSTAT' => 'NEEDS-ACTION',
|
||||
'ROLE' => 'REQ-PARTICIPANT',
|
||||
'RSVP' => 'TRUE'
|
||||
]);
|
||||
$originalCalendar->add($originalInstance);
|
||||
$originalEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$originalCalendar]);
|
||||
$mutatedInstance = clone $originalInstance;
|
||||
$mutatedInstance->SEQUENCE->setValue(2);
|
||||
$mutatedInstance->remove('ATTENDEE');
|
||||
$mutatedInstance->add('ATTENDEE', 'mailto:attendee1@testing.com', [
|
||||
'CN' => 'Attendee One',
|
||||
'CUTYPE' => 'INDIVIDUAL',
|
||||
'PARTSTAT' => 'NEEDS-ACTION',
|
||||
'ROLE' => 'REQ-PARTICIPANT',
|
||||
'RSVP' => 'TRUE'
|
||||
]);
|
||||
$mutatedCalendar = clone $this->vCalendar2a;
|
||||
$mutatedCalendar->add($mutatedInstance);
|
||||
$mutatedEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$mutatedCalendar]);
|
||||
// test iTip generation
|
||||
$messages = $this->invokePrivate($this->broker, 'parseEventForOrganizer', [$mutatedCalendar, $mutatedEventInfo, $originalEventInfo]);
|
||||
// attendee modifications get generated in order of Added, Removed, Existing
|
||||
$this->assertCount(2, $messages);
|
||||
$this->assertEquals('REQUEST', $messages[0]->method);
|
||||
$this->assertEquals(1, $messages[0]->sequence);
|
||||
$this->assertEquals($originalCalendar->VEVENT[1]->ORGANIZER->getValue(), $messages[0]->sender);
|
||||
$this->assertEquals($originalCalendar->VEVENT[1]->ATTENDEE[0]->getValue(), $messages[0]->recipient);
|
||||
$this->assertCount(2, $messages[0]->message->VEVENT);
|
||||
$this->assertEquals('20240715T080000', $messages[0]->message->VEVENT[1]->{'RECURRENCE-ID'}->getValue());
|
||||
$this->assertEquals('CANCEL', $messages[1]->method);
|
||||
$this->assertEquals(1, $messages[1]->sequence);
|
||||
$this->assertEquals($originalCalendar->VEVENT[1]->ORGANIZER->getValue(), $messages[1]->sender);
|
||||
$this->assertEquals($originalCalendar->VEVENT[1]->ATTENDEE[1]->getValue(), $messages[1]->recipient);
|
||||
$this->assertCount(1, $messages[1]->message->VEVENT);
|
||||
$this->assertEquals('20240715T080000', $messages[1]->message->VEVENT->{'RECURRENCE-ID'}->getValue());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests user deleting master instance of recurring event
|
||||
*/
|
||||
public function testParseEventForOrganizerDeleteMasterInstance(): void {
|
||||
// construct calendar with recurring event
|
||||
$originalCalendar = clone $this->vCalendar2a;
|
||||
$originalEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$originalCalendar]);
|
||||
// delete the master instance (convert to non-scheduling)
|
||||
$mutatedCalendar = clone $this->vCalendar2a;
|
||||
$mutatedCalendar->VEVENT->{'LAST-MODIFIED'}->setValue('20240701T020000Z');
|
||||
$mutatedCalendar->VEVENT->SEQUENCE->setValue(2);
|
||||
$mutatedCalendar->VEVENT->remove('ORGANIZER');
|
||||
$mutatedCalendar->VEVENT->remove('ATTENDEE');
|
||||
$mutatedEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$mutatedCalendar]);
|
||||
// test iTip generation
|
||||
$messages = $this->invokePrivate($this->broker, 'parseEventForOrganizer', [$mutatedCalendar, $mutatedEventInfo, $originalEventInfo]);
|
||||
$this->assertCount(1, $messages);
|
||||
$this->assertEquals('CANCEL', $messages[0]->method);
|
||||
$this->assertEquals(2, $messages[0]->sequence);
|
||||
$this->assertEquals($originalCalendar->VEVENT->ORGANIZER->getValue(), $messages[0]->sender);
|
||||
$this->assertEquals($originalCalendar->VEVENT->ATTENDEE[0]->getValue(), $messages[0]->recipient);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests user adding EXDATE to master instance
|
||||
*/
|
||||
public function testParseEventForOrganizerAddExdate(): void {
|
||||
// construct calendar with recurring event
|
||||
$originalCalendar = clone $this->vCalendar2a;
|
||||
$originalEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$originalCalendar]);
|
||||
// add EXDATE to exclude specific occurrences
|
||||
$mutatedCalendar = clone $this->vCalendar2a;
|
||||
$mutatedCalendar->VEVENT->{'LAST-MODIFIED'}->setValue('20240701T020000Z');
|
||||
$mutatedCalendar->VEVENT->SEQUENCE->setValue(2);
|
||||
$mutatedCalendar->VEVENT->add('EXDATE', ['20240715T080000', '20240722T080000'], ['TZID' => 'America/Toronto']);
|
||||
$mutatedEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$mutatedCalendar]);
|
||||
// test iTip generation
|
||||
$messages = $this->invokePrivate($this->broker, 'parseEventForOrganizer', [$mutatedCalendar, $mutatedEventInfo, $originalEventInfo]);
|
||||
$this->assertCount(1, $messages);
|
||||
$this->assertEquals('REQUEST', $messages[0]->method);
|
||||
$this->assertEquals(2, $messages[0]->sequence);
|
||||
$this->assertEquals($mutatedCalendar->VEVENT->ORGANIZER->getValue(), $messages[0]->sender);
|
||||
$this->assertEquals($mutatedCalendar->VEVENT->ATTENDEE[0]->getValue(), $messages[0]->recipient);
|
||||
// verify EXDATE is present in the message
|
||||
$this->assertTrue(isset($messages[0]->message->VEVENT->EXDATE));
|
||||
$exdates = $messages[0]->message->VEVENT->EXDATE->getParts();
|
||||
$this->assertContains('20240715T080000', $exdates);
|
||||
$this->assertContains('20240722T080000', $exdates);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests user removing EXDATE from master instance
|
||||
*/
|
||||
public function testParseEventForOrganizerRemoveExdate(): void {
|
||||
// construct calendar with recurring event that has EXDATE
|
||||
$originalCalendar = clone $this->vCalendar2a;
|
||||
$originalCalendar->VEVENT->add('EXDATE', ['20240715T080000', '20240722T080000'], ['TZID' => 'America/Toronto']);
|
||||
$originalEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$originalCalendar]);
|
||||
// remove EXDATE to restore excluded occurrences
|
||||
$mutatedCalendar = clone $this->vCalendar2a;
|
||||
$mutatedCalendar->VEVENT->{'LAST-MODIFIED'}->setValue('20240701T020000Z');
|
||||
$mutatedCalendar->VEVENT->SEQUENCE->setValue(2);
|
||||
$mutatedEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$mutatedCalendar]);
|
||||
// test iTip generation
|
||||
$messages = $this->invokePrivate($this->broker, 'parseEventForOrganizer', [$mutatedCalendar, $mutatedEventInfo, $originalEventInfo]);
|
||||
$this->assertCount(1, $messages);
|
||||
$this->assertEquals('REQUEST', $messages[0]->method);
|
||||
$this->assertEquals(2, $messages[0]->sequence);
|
||||
$this->assertEquals($mutatedCalendar->VEVENT->ORGANIZER->getValue(), $messages[0]->sender);
|
||||
$this->assertEquals($mutatedCalendar->VEVENT->ATTENDEE[0]->getValue(), $messages[0]->recipient);
|
||||
// verify EXDATE is not present in the message
|
||||
$this->assertFalse(isset($messages[0]->message->VEVENT->EXDATE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests user converting recurring event to non-scheduling
|
||||
*/
|
||||
public function testParseEventForOrganizerConvertRecurringToNonScheduling(): void {
|
||||
// construct calendar with recurring event
|
||||
$originalCalendar = clone $this->vCalendar2a;
|
||||
$originalEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$originalCalendar]);
|
||||
// remove ORGANIZER and ATTENDEE properties to convert to non-scheduling
|
||||
$mutatedCalendar = clone $this->vCalendar2a;
|
||||
$mutatedCalendar->VEVENT->{'LAST-MODIFIED'}->setValue('20240701T020000Z');
|
||||
$mutatedCalendar->VEVENT->SEQUENCE->setValue(2);
|
||||
$mutatedCalendar->VEVENT->remove('ORGANIZER');
|
||||
$mutatedCalendar->VEVENT->remove('ATTENDEE');
|
||||
$mutatedEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$mutatedCalendar]);
|
||||
// test iTip generation
|
||||
$messages = $this->invokePrivate($this->broker, 'parseEventForOrganizer', [$mutatedCalendar, $mutatedEventInfo, $originalEventInfo]);
|
||||
$this->assertCount(1, $messages);
|
||||
$this->assertEquals('CANCEL', $messages[0]->method);
|
||||
$this->assertEquals(2, $messages[0]->sequence);
|
||||
$this->assertEquals($originalCalendar->VEVENT->ORGANIZER->getValue(), $messages[0]->sender);
|
||||
$this->assertEquals($originalCalendar->VEVENT->ATTENDEE[0]->getValue(), $messages[0]->recipient);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests SCHEDULE-FORCE-SEND parameter handling
|
||||
*/
|
||||
public function testParseEventForOrganizerScheduleForceSend(): void {
|
||||
// construct calendar with event
|
||||
$originalCalendar = clone $this->vCalendar1a;
|
||||
$originalEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$originalCalendar]);
|
||||
// add SCHEDULE-FORCE-SEND parameter to ATTENDEE
|
||||
$mutatedCalendar = clone $this->vCalendar1a;
|
||||
$mutatedCalendar->VEVENT->{'LAST-MODIFIED'}->setValue('20240701T020000Z');
|
||||
$mutatedCalendar->VEVENT->SEQUENCE->setValue(2);
|
||||
$mutatedCalendar->VEVENT->ATTENDEE->add('SCHEDULE-FORCE-SEND', 'REQUEST');
|
||||
$mutatedEventInfo = $this->invokePrivate($this->broker, 'parseEventInfo', [$mutatedCalendar]);
|
||||
// test iTip generation
|
||||
$messages = $this->invokePrivate($this->broker, 'parseEventForOrganizer', [$mutatedCalendar, $mutatedEventInfo, $originalEventInfo]);
|
||||
$this->assertCount(1, $messages);
|
||||
$this->assertEquals('REQUEST', $messages[0]->method);
|
||||
$this->assertEquals(2, $messages[0]->sequence);
|
||||
$this->assertEquals($mutatedCalendar->VEVENT->ORGANIZER->getValue(), $messages[0]->sender);
|
||||
$this->assertEquals($mutatedCalendar->VEVENT->ATTENDEE->getValue(), $messages[0]->recipient);
|
||||
// verify SCHEDULE-FORCE-SEND is removed from the message (sanitized)
|
||||
$this->assertFalse(isset($messages[0]->message->VEVENT->ATTENDEE['SCHEDULE-FORCE-SEND']));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -61,14 +61,14 @@ class CommentsPropertiesPluginTest extends \Test\TestCase {
|
||||
|
||||
public static function baseUriProvider(): array {
|
||||
return [
|
||||
['owncloud/remote.php/webdav/', 4567, 'owncloud/remote.php/dav/comments/files/4567'],
|
||||
['owncloud/remote.php/files/', 4567, 'owncloud/remote.php/dav/comments/files/4567'],
|
||||
['owncloud/wicked.php/files/', 4567, null]
|
||||
['owncloud/remote.php/webdav/', '4567', 'owncloud/remote.php/dav/comments/files/4567'],
|
||||
['owncloud/remote.php/files/', '4567', 'owncloud/remote.php/dav/comments/files/4567'],
|
||||
['owncloud/wicked.php/files/', '4567', null]
|
||||
];
|
||||
}
|
||||
|
||||
#[\PHPUnit\Framework\Attributes\DataProvider(methodName: 'baseUriProvider')]
|
||||
public function testGetCommentsLink(string $baseUri, int $fid, ?string $expectedHref): void {
|
||||
public function testGetCommentsLink(string $baseUri, string $fid, ?string $expectedHref): void {
|
||||
$node = $this->createMock(File::class);
|
||||
$node->expects($this->any())
|
||||
->method('getId')
|
||||
@@ -94,7 +94,7 @@ class CommentsPropertiesPluginTest extends \Test\TestCase {
|
||||
$node = $this->createMock(File::class);
|
||||
$node->expects($this->any())
|
||||
->method('getId')
|
||||
->willReturn(4567);
|
||||
->willReturn('4567');
|
||||
|
||||
if ($user !== null) {
|
||||
$user = $this->createMock($user);
|
||||
|
||||
@@ -230,10 +230,6 @@ class DirectoryTest extends \Test\TestCase {
|
||||
$info->expects($this->any())
|
||||
->method('isReadable')
|
||||
->willReturn(false);
|
||||
$this->view
|
||||
->method('getRelativePath')
|
||||
->with(null)
|
||||
->willReturn('');
|
||||
|
||||
$dir = new Directory($this->view, $info);
|
||||
$dir->getChildren();
|
||||
@@ -246,10 +242,6 @@ class DirectoryTest extends \Test\TestCase {
|
||||
$this->info->expects($this->any())
|
||||
->method('isReadable')
|
||||
->willReturn(false);
|
||||
$this->view
|
||||
->method('getRelativePath')
|
||||
->with('/admin/files/folder')
|
||||
->willReturn('');
|
||||
|
||||
$dir = new Directory($this->view, $this->info);
|
||||
$dir->getChild('test');
|
||||
@@ -262,10 +254,6 @@ class DirectoryTest extends \Test\TestCase {
|
||||
$this->view->expects($this->once())
|
||||
->method('getFileInfo')
|
||||
->willThrowException(new StorageNotAvailableException());
|
||||
$this->view
|
||||
->method('getRelativePath')
|
||||
->with('/admin/files/folder')
|
||||
->willReturn('');
|
||||
|
||||
$dir = new Directory($this->view, $this->info);
|
||||
$dir->getChild('.');
|
||||
@@ -280,10 +268,6 @@ class DirectoryTest extends \Test\TestCase {
|
||||
->willThrowException(new InvalidPathException());
|
||||
$this->view->expects($this->never())
|
||||
->method('getFileInfo');
|
||||
$this->view
|
||||
->method('getRelativePath')
|
||||
->with('/admin/files/folder')
|
||||
->willReturn('');
|
||||
|
||||
$dir = new Directory($this->view, $this->info);
|
||||
$dir->getChild('.');
|
||||
@@ -392,11 +376,6 @@ class DirectoryTest extends \Test\TestCase {
|
||||
}
|
||||
|
||||
public function testGetNodeForPathFailsWithNoReadPermissionsForPath(): void {
|
||||
$this->view
|
||||
->method('getRelativePath')
|
||||
->with('/admin/files/')
|
||||
->willReturn('');
|
||||
|
||||
$directoryNode = $this->createMock(Folder::class);
|
||||
$pathNode = $this->createMock(Folder::class);
|
||||
$storage = $this->createMock(IStorage::class);
|
||||
@@ -417,7 +396,7 @@ class DirectoryTest extends \Test\TestCase {
|
||||
2 => false,
|
||||
};
|
||||
});
|
||||
$directoryNode
|
||||
$directoryNode->expects($this->once())
|
||||
->method('getPath')
|
||||
->willReturn('/admin/files/');
|
||||
$directoryNode->expects($this->once())
|
||||
|
||||
@@ -673,10 +673,6 @@ class FileTest extends TestCase {
|
||||
/** @var View&MockObject */
|
||||
$view = $this->getMockBuilder(View::class)
|
||||
->getMock();
|
||||
$view
|
||||
->method('getRelativePath')
|
||||
->with('/test.txt')
|
||||
->willReturn('');
|
||||
|
||||
$view->expects($this->once())
|
||||
->method('unlink')
|
||||
@@ -701,10 +697,6 @@ class FileTest extends TestCase {
|
||||
/** @var View&MockObject */
|
||||
$view = $this->getMockBuilder(View::class)
|
||||
->getMock();
|
||||
$view
|
||||
->method('getRelativePath')
|
||||
->with('/test.txt')
|
||||
->willReturn('');
|
||||
|
||||
$info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, [
|
||||
'permissions' => 0,
|
||||
@@ -725,10 +717,6 @@ class FileTest extends TestCase {
|
||||
/** @var View&MockObject */
|
||||
$view = $this->getMockBuilder(View::class)
|
||||
->getMock();
|
||||
$view
|
||||
->method('getRelativePath')
|
||||
->with('/test.txt')
|
||||
->willReturn('');
|
||||
|
||||
// but fails
|
||||
$view->expects($this->once())
|
||||
@@ -754,10 +742,6 @@ class FileTest extends TestCase {
|
||||
/** @var View&MockObject */
|
||||
$view = $this->getMockBuilder(View::class)
|
||||
->getMock();
|
||||
$view
|
||||
->method('getRelativePath')
|
||||
->with('/test.txt')
|
||||
->willReturn('');
|
||||
|
||||
// but fails
|
||||
$view->expects($this->once())
|
||||
|
||||
@@ -101,7 +101,7 @@ class FilesPluginTest extends TestCase {
|
||||
->willReturn('00000123instanceid');
|
||||
$node->expects($this->any())
|
||||
->method('getInternalFileId')
|
||||
->willReturn(123);
|
||||
->willReturn('123');
|
||||
$node->expects($this->any())
|
||||
->method('getEtag')
|
||||
->willReturn('"abc"');
|
||||
@@ -455,7 +455,7 @@ class FilesPluginTest extends TestCase {
|
||||
$node->expects($this->once())
|
||||
->method('setEtag')
|
||||
->with('newetag')
|
||||
->willReturn(123);
|
||||
->willReturn(true);
|
||||
|
||||
$node->expects($this->once())
|
||||
->method('setCreationTime')
|
||||
@@ -562,11 +562,35 @@ class FilesPluginTest extends TestCase {
|
||||
$this->plugin->checkMove('FolderA/test.txt', 'test.txt');
|
||||
}
|
||||
|
||||
public function testMoveSrcNotExist(): void {
|
||||
$this->expectException(\Sabre\DAV\Exception\NotFound::class);
|
||||
$this->expectExceptionMessage('FolderA/test.txt does not exist');
|
||||
|
||||
$node = $this->createMock(Node::class);
|
||||
$node->expects($this->atLeastOnce())
|
||||
->method('getFileInfo')
|
||||
->willReturn(null);
|
||||
|
||||
$this->tree->expects($this->atLeastOnce())
|
||||
->method('getNodeForPath')
|
||||
->willReturn($node);
|
||||
|
||||
$this->plugin->checkMove('FolderA/test.txt', 'test.txt');
|
||||
}
|
||||
|
||||
public function testMoveDestinationInvalid(): void {
|
||||
$this->expectException(InvalidPath::class);
|
||||
$this->expectExceptionMessage('Mocked exception');
|
||||
|
||||
$fileInfoFolderATestTXT = $this->createMock(FileInfo::class);
|
||||
$fileInfoFolderATestTXT->expects(self::any())
|
||||
->method('isDeletable')
|
||||
->willReturn(true);
|
||||
|
||||
$node = $this->createMock(Node::class);
|
||||
$node->expects($this->atLeastOnce())
|
||||
->method('getFileInfo')
|
||||
->willReturn($fileInfoFolderATestTXT);
|
||||
|
||||
$this->tree->expects($this->atLeastOnce())
|
||||
->method('getNodeForPath')
|
||||
@@ -580,11 +604,31 @@ class FilesPluginTest extends TestCase {
|
||||
$this->plugin->checkMove('FolderA/test.txt', 'invalid\\path.txt');
|
||||
}
|
||||
|
||||
public function testCopySrcNotExist(): void {
|
||||
$this->expectException(\Sabre\DAV\Exception\NotFound::class);
|
||||
$this->expectExceptionMessage('FolderA/test.txt does not exist');
|
||||
|
||||
$node = $this->createMock(Node::class);
|
||||
$node->expects($this->atLeastOnce())
|
||||
->method('getFileInfo')
|
||||
->willReturn(null);
|
||||
|
||||
$this->tree->expects($this->atLeastOnce())
|
||||
->method('getNodeForPath')
|
||||
->willReturn($node);
|
||||
|
||||
$this->plugin->checkCopy('FolderA/test.txt', 'test.txt');
|
||||
}
|
||||
|
||||
public function testCopyDestinationInvalid(): void {
|
||||
$this->expectException(InvalidPath::class);
|
||||
$this->expectExceptionMessage('Mocked exception');
|
||||
|
||||
$fileInfoFolderATestTXT = $this->createMock(FileInfo::class);
|
||||
$node = $this->createMock(Node::class);
|
||||
$node->expects($this->atLeastOnce())
|
||||
->method('getFileInfo')
|
||||
->willReturn($fileInfoFolderATestTXT);
|
||||
|
||||
$this->tree->expects($this->atLeastOnce())
|
||||
->method('getNodeForPath')
|
||||
|
||||
@@ -57,10 +57,6 @@ class FilesReportPluginTest extends \Test\TestCase {
|
||||
|
||||
$this->tree = $this->createMock(Tree::class);
|
||||
$this->view = $this->createMock(View::class);
|
||||
$this->view
|
||||
->method('getRelativePath')
|
||||
->with(null)
|
||||
->willReturn('');
|
||||
|
||||
$this->server = $this->getMockBuilder(Server::class)
|
||||
->setConstructorArgs([$this->tree])
|
||||
@@ -319,14 +315,14 @@ class FilesReportPluginTest extends \Test\TestCase {
|
||||
|
||||
$node1->expects($this->once())
|
||||
->method('getInternalFileId')
|
||||
->willReturn(111);
|
||||
->willReturn('111');
|
||||
$node1->expects($this->any())
|
||||
->method('getPath')
|
||||
->willReturn('/node1');
|
||||
$node1->method('getFileInfo')->willReturn($fileInfo);
|
||||
$node2->expects($this->once())
|
||||
->method('getInternalFileId')
|
||||
->willReturn(222);
|
||||
->willReturn('222');
|
||||
$node2->expects($this->once())
|
||||
->method('getSize')
|
||||
->willReturn(1024);
|
||||
|
||||
@@ -94,10 +94,6 @@ class NodeTest extends \Test\TestCase {
|
||||
$info->method('getStorage')
|
||||
->willReturn($storage);
|
||||
$view = $this->createMock(View::class);
|
||||
$view
|
||||
->method('getRelativePath')
|
||||
->with(null)
|
||||
->willReturn('');
|
||||
|
||||
$node = new File($view, $info);
|
||||
$this->assertEquals($expected, $node->getDavPermissions());
|
||||
@@ -173,10 +169,6 @@ class NodeTest extends \Test\TestCase {
|
||||
$info->method('getPermissions')->willReturn($permissions);
|
||||
|
||||
$view = $this->createMock(View::class);
|
||||
$view
|
||||
->method('getRelativePath')
|
||||
->with(null)
|
||||
->willReturn('');
|
||||
|
||||
$node = new File($view, $info);
|
||||
$this->invokePrivate($node, 'shareManager', [$shareManager]);
|
||||
@@ -212,10 +204,6 @@ class NodeTest extends \Test\TestCase {
|
||||
|
||||
/** @var View&MockObject $view */
|
||||
$view = $this->createMock(View::class);
|
||||
$view
|
||||
->method('getRelativePath')
|
||||
->with(null)
|
||||
->willReturn('');
|
||||
|
||||
$node = new File($view, $info);
|
||||
$this->invokePrivate($node, 'shareManager', [$shareManager]);
|
||||
@@ -237,10 +225,6 @@ class NodeTest extends \Test\TestCase {
|
||||
|
||||
/** @var View&MockObject */
|
||||
$view = $this->createMock(View::class);
|
||||
$view
|
||||
->method('getRelativePath')
|
||||
->with(null)
|
||||
->willReturn('');
|
||||
|
||||
$node = new File($view, $info);
|
||||
$this->invokePrivate($node, 'shareManager', [$shareManager]);
|
||||
@@ -259,10 +243,6 @@ class NodeTest extends \Test\TestCase {
|
||||
$view = $this->getMockBuilder(View::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$view
|
||||
->method('getRelativePath')
|
||||
->with(null)
|
||||
->willReturn('');
|
||||
$info = $this->getMockBuilder(FileInfo::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
@@ -283,11 +263,6 @@ class NodeTest extends \Test\TestCase {
|
||||
$this->expectException(\InvalidArgumentException::class);
|
||||
|
||||
$view = $this->createMock(View::class);
|
||||
$view
|
||||
->method('getRelativePath')
|
||||
->with(null)
|
||||
->willReturn('');
|
||||
|
||||
$info = $this->createMock(FileInfo::class);
|
||||
|
||||
$node = new File($view, $info);
|
||||
|
||||
@@ -63,10 +63,6 @@ class ObjectTreeTest extends \Test\TestCase {
|
||||
->method('getFileInfo')
|
||||
->with($targetParent === '' ? '.' : $targetParent)
|
||||
->willReturn($info);
|
||||
$view
|
||||
->method('getRelativePath')
|
||||
->with(null)
|
||||
->willReturn('');
|
||||
|
||||
$rootDir = new Directory($view, $info);
|
||||
$objectTree = $this->getMockBuilder(ObjectTree::class)
|
||||
@@ -108,10 +104,6 @@ class ObjectTreeTest extends \Test\TestCase {
|
||||
->method('getFileInfo')
|
||||
->with($targetParent === '' ? '.' : $targetParent)
|
||||
->willReturn($info);
|
||||
$view
|
||||
->method('getRelativePath')
|
||||
->with(null)
|
||||
->willReturn('');
|
||||
|
||||
$rootDir = new Directory($view, $info);
|
||||
$objectTree = $this->getMockBuilder(ObjectTree::class)
|
||||
@@ -149,10 +141,6 @@ class ObjectTreeTest extends \Test\TestCase {
|
||||
$view->method('getFileInfo')
|
||||
->with($fileInfoQueryPath)
|
||||
->willReturn($fileInfo);
|
||||
$view
|
||||
->method('getRelativePath')
|
||||
->with(null)
|
||||
->willReturn('');
|
||||
|
||||
$tree = new ObjectTree();
|
||||
$tree->init($rootNode, $view, $mountManager);
|
||||
|
||||
@@ -331,7 +331,7 @@ class EncryptAllTest extends TestCase {
|
||||
->willReturnMap([
|
||||
[
|
||||
'/user1/files',
|
||||
null,
|
||||
'',
|
||||
null,
|
||||
[
|
||||
$this->createFileInfoMock(FileInfo::TYPE_FOLDER, 'foo'),
|
||||
@@ -340,7 +340,7 @@ class EncryptAllTest extends TestCase {
|
||||
],
|
||||
[
|
||||
'/user1/files/foo',
|
||||
null,
|
||||
'',
|
||||
null,
|
||||
[
|
||||
$this->createFileInfoMock(FileInfo::TYPE_FILE, 'subfile'),
|
||||
|
||||
@@ -29,7 +29,7 @@ OC.L10N.register(
|
||||
"Disable upload" : "Вимкнути завантаження",
|
||||
"Confirm querying lookup server" : "Підтвердити запит до сервера пошуку",
|
||||
"When enabled, the search input when creating shares will be sent to an external system that provides a public and global address book." : "When enabled, the search input when creating shares will be sent to an external system that provides a public and global address book.",
|
||||
"This is used to retrieve the federated cloud ID to make federated sharing easier." : "Це використовується для отримання ідентифікатора об'єднаної хмари, щоб спростити спільне використання ресурсів.",
|
||||
"This is used to retrieve the federated cloud ID to make federated sharing easier." : "Це використовується для отримання ідентифікатора федеративної хмари, щоб спростити федеративне спільне використання.",
|
||||
"Moreover, email addresses of users might be sent to that system in order to verify them." : "Крім того, адреси електронної пошти користувачів можуть бути надіслані до цієї системи з метою їх перевірки.",
|
||||
"Enable querying" : "Увімкнути запити",
|
||||
"Disable querying" : "Вимкнути запити",
|
||||
@@ -43,21 +43,21 @@ OC.L10N.register(
|
||||
"Search global and public address book for people" : "Шукати користувачів у глобальній та публічній адресних книгах",
|
||||
"Allow people to publish their data to a global and public address book" : "Дозволити користувачам розміщувати власні дані у глобальній публічній адресній книзі",
|
||||
"Trusted federation" : "Довірена федерація",
|
||||
"Automatically accept shares from trusted federated accounts and groups by default" : "Типово автоматично приймати пропозиції спільного доступу від надійних облікових записів та груп об'єднаних хмар",
|
||||
"Automatically accept shares from trusted federated accounts and groups by default" : "Автоматично приймати акції від надійних федеративних облікових записів та груп за замовчуванням",
|
||||
"Share with me through my #Nextcloud Federated Cloud ID, see {url}" : "Поділітися зі мною через мій #Nextcloud Federated Cloud ID, див. {url}",
|
||||
"Share with me through my #Nextcloud Federated Cloud ID" : "Поділітися зі мною через мій #Nextcloud Federated Cloud ID",
|
||||
"Share with me via Nextcloud" : "Поділіться зі мною у Nextcloud",
|
||||
"Share with me via Nextcloud" : "Поділися зі мною через Nextcloud",
|
||||
"Cloud ID copied" : "Хмарний ідентифікатор скопійовано",
|
||||
"Copy" : "Копіювати",
|
||||
"Clipboard not available. Please copy the cloud ID manually." : "Буфер обміну недоступний. Будь ласка, скопіюйте ідентифікатор хмари вручну.",
|
||||
"Copied!" : "Скопійовано!",
|
||||
"Federated Cloud" : "Об'єднана хмара",
|
||||
"Your Federated Cloud ID" : "Ваш ідентифікатор Federated Cloud",
|
||||
"Share it so your friends can share files with you:" : "Поділіться цим кодом з вашими друзями або колеги, щоби вони могли поділитися своїми файлами з вами:",
|
||||
"Share it so your friends can share files with you:" : "Поділітися ним, щоб ваші друзі могли ділитися з вами файлами:",
|
||||
"Bluesky" : "Bluesky",
|
||||
"Facebook" : "Facebook",
|
||||
"Mastodon" : "Мастодонт",
|
||||
"Add to your website" : "Додати код на ваш вебсайт",
|
||||
"Add to your website" : "Додати на ваш вебсайт",
|
||||
"HTML Code:" : "Код HTML:",
|
||||
"Cancel" : "Скасувати",
|
||||
"Add remote share" : "Додати віддалений каталог",
|
||||
@@ -65,9 +65,9 @@ OC.L10N.register(
|
||||
"Do you want to add the remote share {name} from {owner}@{remote}?" : "Додати віддалений каталог {name} з {owner}@{remote}?",
|
||||
"Remote share password" : "Пароль для віддаленого каталогу",
|
||||
"Incoming share could not be processed" : "Неможливо обробити вхідну частку",
|
||||
"Cloud ID copied to the clipboard" : "Cloud ID скопійовано до буфера обміну",
|
||||
"Cloud ID copied to the clipboard" : "Cloud ID скопійовано в буфер обміну",
|
||||
"Copy to clipboard" : "Копіювати до буфера обміну",
|
||||
"You can share with anyone who uses a Nextcloud server or other Open Cloud Mesh (OCM) compatible servers and services! Just put their Federated Cloud ID in the share dialog. It looks like person@cloud.example.com" : "Ви можете надати у спільним доступ ваші файли будь-кому, хто використовує сервер Nextcloud або інші сервери та служби, що є сумісні з Open Cloud Mesh (OCM). Для цього зазначте ідентифікатор об'єднаної хмари у діалоговому вікні спільного доступу у форматі person@cloud.example.com",
|
||||
"You can share with anyone who uses a Nextcloud server or other Open Cloud Mesh (OCM) compatible servers and services! Just put their Federated Cloud ID in the share dialog. It looks like person@cloud.example.com" : "Ви можете поділитися з будь-ким, хто використовує сервер Nextcloud або інші сервери та служби, сумісні з Open Cloud Mesh (OCM). Просто введіть їхній Federated Cloud ID у діалоговому вікні спільного доступу. Це виглядає як person@cloud.example.com",
|
||||
"X (formerly Twitter)" : "X (раніше відома як Twitter)",
|
||||
"formerly Twitter" : "раніше відома як Twitter"
|
||||
},
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
"Disable upload" : "Вимкнути завантаження",
|
||||
"Confirm querying lookup server" : "Підтвердити запит до сервера пошуку",
|
||||
"When enabled, the search input when creating shares will be sent to an external system that provides a public and global address book." : "When enabled, the search input when creating shares will be sent to an external system that provides a public and global address book.",
|
||||
"This is used to retrieve the federated cloud ID to make federated sharing easier." : "Це використовується для отримання ідентифікатора об'єднаної хмари, щоб спростити спільне використання ресурсів.",
|
||||
"This is used to retrieve the federated cloud ID to make federated sharing easier." : "Це використовується для отримання ідентифікатора федеративної хмари, щоб спростити федеративне спільне використання.",
|
||||
"Moreover, email addresses of users might be sent to that system in order to verify them." : "Крім того, адреси електронної пошти користувачів можуть бути надіслані до цієї системи з метою їх перевірки.",
|
||||
"Enable querying" : "Увімкнути запити",
|
||||
"Disable querying" : "Вимкнути запити",
|
||||
@@ -41,21 +41,21 @@
|
||||
"Search global and public address book for people" : "Шукати користувачів у глобальній та публічній адресних книгах",
|
||||
"Allow people to publish their data to a global and public address book" : "Дозволити користувачам розміщувати власні дані у глобальній публічній адресній книзі",
|
||||
"Trusted federation" : "Довірена федерація",
|
||||
"Automatically accept shares from trusted federated accounts and groups by default" : "Типово автоматично приймати пропозиції спільного доступу від надійних облікових записів та груп об'єднаних хмар",
|
||||
"Automatically accept shares from trusted federated accounts and groups by default" : "Автоматично приймати акції від надійних федеративних облікових записів та груп за замовчуванням",
|
||||
"Share with me through my #Nextcloud Federated Cloud ID, see {url}" : "Поділітися зі мною через мій #Nextcloud Federated Cloud ID, див. {url}",
|
||||
"Share with me through my #Nextcloud Federated Cloud ID" : "Поділітися зі мною через мій #Nextcloud Federated Cloud ID",
|
||||
"Share with me via Nextcloud" : "Поділіться зі мною у Nextcloud",
|
||||
"Share with me via Nextcloud" : "Поділися зі мною через Nextcloud",
|
||||
"Cloud ID copied" : "Хмарний ідентифікатор скопійовано",
|
||||
"Copy" : "Копіювати",
|
||||
"Clipboard not available. Please copy the cloud ID manually." : "Буфер обміну недоступний. Будь ласка, скопіюйте ідентифікатор хмари вручну.",
|
||||
"Copied!" : "Скопійовано!",
|
||||
"Federated Cloud" : "Об'єднана хмара",
|
||||
"Your Federated Cloud ID" : "Ваш ідентифікатор Federated Cloud",
|
||||
"Share it so your friends can share files with you:" : "Поділіться цим кодом з вашими друзями або колеги, щоби вони могли поділитися своїми файлами з вами:",
|
||||
"Share it so your friends can share files with you:" : "Поділітися ним, щоб ваші друзі могли ділитися з вами файлами:",
|
||||
"Bluesky" : "Bluesky",
|
||||
"Facebook" : "Facebook",
|
||||
"Mastodon" : "Мастодонт",
|
||||
"Add to your website" : "Додати код на ваш вебсайт",
|
||||
"Add to your website" : "Додати на ваш вебсайт",
|
||||
"HTML Code:" : "Код HTML:",
|
||||
"Cancel" : "Скасувати",
|
||||
"Add remote share" : "Додати віддалений каталог",
|
||||
@@ -63,9 +63,9 @@
|
||||
"Do you want to add the remote share {name} from {owner}@{remote}?" : "Додати віддалений каталог {name} з {owner}@{remote}?",
|
||||
"Remote share password" : "Пароль для віддаленого каталогу",
|
||||
"Incoming share could not be processed" : "Неможливо обробити вхідну частку",
|
||||
"Cloud ID copied to the clipboard" : "Cloud ID скопійовано до буфера обміну",
|
||||
"Cloud ID copied to the clipboard" : "Cloud ID скопійовано в буфер обміну",
|
||||
"Copy to clipboard" : "Копіювати до буфера обміну",
|
||||
"You can share with anyone who uses a Nextcloud server or other Open Cloud Mesh (OCM) compatible servers and services! Just put their Federated Cloud ID in the share dialog. It looks like person@cloud.example.com" : "Ви можете надати у спільним доступ ваші файли будь-кому, хто використовує сервер Nextcloud або інші сервери та служби, що є сумісні з Open Cloud Mesh (OCM). Для цього зазначте ідентифікатор об'єднаної хмари у діалоговому вікні спільного доступу у форматі person@cloud.example.com",
|
||||
"You can share with anyone who uses a Nextcloud server or other Open Cloud Mesh (OCM) compatible servers and services! Just put their Federated Cloud ID in the share dialog. It looks like person@cloud.example.com" : "Ви можете поділитися з будь-ким, хто використовує сервер Nextcloud або інші сервери та служби, сумісні з Open Cloud Mesh (OCM). Просто введіть їхній Federated Cloud ID у діалоговому вікні спільного доступу. Це виглядає як person@cloud.example.com",
|
||||
"X (formerly Twitter)" : "X (раніше відома як Twitter)",
|
||||
"formerly Twitter" : "раніше відома як Twitter"
|
||||
},"pluralForm" :"nplurals=4; plural=(n % 1 == 0 && n % 10 == 1 && n % 100 != 11 ? 0 : n % 1 == 0 && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14) ? 1 : n % 1 == 0 && (n % 10 ==0 || (n % 10 >=5 && n % 10 <=9) || (n % 100 >=11 && n % 100 <=14 )) ? 2: 3);"
|
||||
|
||||
@@ -11,9 +11,6 @@ OC.L10N.register(
|
||||
"Federation" : "Fédération",
|
||||
"Federation allows you to connect with other trusted servers to exchange the account directory." : "Une fédération vous permet de vous connecter avec d'autres serveurs de confiance pour échanger la liste des comptes.",
|
||||
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing." : "Une fédération vous permet de vous connecter avec d'autres serveurs de confiance pour échanger la liste des comptes. Par exemple, ce sera utilisé pour auto-compléter les comptes externes lors du partage fédéré.",
|
||||
"Could not add trusted server. Please try again later." : "Impossible d'ajouter un serveur de confiance. Veuillez réessayer plus tard.",
|
||||
"Add trusted server" : "Ajouter un serveur de confiance",
|
||||
"Server url" : "URL du serveur",
|
||||
"Add" : "Ajouter",
|
||||
"Delete" : "Supprimer",
|
||||
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing. It is not necessary to add a server as trusted server in order to create a federated share." : "Une fédération vous permet de vous connecter avec d'autres serveurs de confiance pour échanger la liste des comptes. Par exemple, ce sera utilisé pour auto-compléter les comptes externes lors du partage fédéré. Il n'est pas nécessaire d'ajouter un serveur comme serveur de confiance afin de créer un partage fédéré.",
|
||||
|
||||
@@ -9,9 +9,6 @@
|
||||
"Federation" : "Fédération",
|
||||
"Federation allows you to connect with other trusted servers to exchange the account directory." : "Une fédération vous permet de vous connecter avec d'autres serveurs de confiance pour échanger la liste des comptes.",
|
||||
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing." : "Une fédération vous permet de vous connecter avec d'autres serveurs de confiance pour échanger la liste des comptes. Par exemple, ce sera utilisé pour auto-compléter les comptes externes lors du partage fédéré.",
|
||||
"Could not add trusted server. Please try again later." : "Impossible d'ajouter un serveur de confiance. Veuillez réessayer plus tard.",
|
||||
"Add trusted server" : "Ajouter un serveur de confiance",
|
||||
"Server url" : "URL du serveur",
|
||||
"Add" : "Ajouter",
|
||||
"Delete" : "Supprimer",
|
||||
"Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing. It is not necessary to add a server as trusted server in order to create a federated share." : "Une fédération vous permet de vous connecter avec d'autres serveurs de confiance pour échanger la liste des comptes. Par exemple, ce sera utilisé pour auto-compléter les comptes externes lors du partage fédéré. Il n'est pas nécessaire d'ajouter un serveur comme serveur de confiance afin de créer un partage fédéré.",
|
||||
|
||||
@@ -146,7 +146,6 @@ OC.L10N.register(
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "لم يتم عرض هذه القائمة بالكامل لأسباب تتعلق بالأداء. سيتم عرض الملفات تباعاً أثناء التنقل عبر القائمة.",
|
||||
"File not found" : "تعذر العثور على الملف",
|
||||
"_{count} selected_::_{count} selected_" : ["{count} تمّ تحديده","{count} تمّ تحديده","{count} تمّ تحديده","{count} تمّ تحديده","{count} تمّ تحديده","{count} تمّ تحديده"],
|
||||
"Views" : "مشاهدات",
|
||||
"Owner" : "المالك",
|
||||
"{usedQuotaByte} used" : "{usedQuotaByte} مستخدمة",
|
||||
"{used} of {quota} used" : "{used} من {quota} مستخدم",
|
||||
@@ -202,6 +201,7 @@ OC.L10N.register(
|
||||
"No files in here" : "لا توجد ملفات هنا ",
|
||||
"Upload some content or sync with your devices!" : "ارفع بعض المحتوى أو قم بالمزامنة مع أجهزتك!",
|
||||
"Go back" : "العودة",
|
||||
"Views" : "مشاهدات",
|
||||
"Your files" : "ملفاتك",
|
||||
"Open in files" : "فتح في تطبيق الملفات",
|
||||
"File cannot be accessed" : "الملف لم يمكن الوصول إليه",
|
||||
|
||||
@@ -144,7 +144,6 @@
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "لم يتم عرض هذه القائمة بالكامل لأسباب تتعلق بالأداء. سيتم عرض الملفات تباعاً أثناء التنقل عبر القائمة.",
|
||||
"File not found" : "تعذر العثور على الملف",
|
||||
"_{count} selected_::_{count} selected_" : ["{count} تمّ تحديده","{count} تمّ تحديده","{count} تمّ تحديده","{count} تمّ تحديده","{count} تمّ تحديده","{count} تمّ تحديده"],
|
||||
"Views" : "مشاهدات",
|
||||
"Owner" : "المالك",
|
||||
"{usedQuotaByte} used" : "{usedQuotaByte} مستخدمة",
|
||||
"{used} of {quota} used" : "{used} من {quota} مستخدم",
|
||||
@@ -200,6 +199,7 @@
|
||||
"No files in here" : "لا توجد ملفات هنا ",
|
||||
"Upload some content or sync with your devices!" : "ارفع بعض المحتوى أو قم بالمزامنة مع أجهزتك!",
|
||||
"Go back" : "العودة",
|
||||
"Views" : "مشاهدات",
|
||||
"Your files" : "ملفاتك",
|
||||
"Open in files" : "فتح في تطبيق الملفات",
|
||||
"File cannot be accessed" : "الملف لم يمكن الوصول إليه",
|
||||
|
||||
@@ -111,7 +111,6 @@ OC.L10N.register(
|
||||
"Column headers with buttons are sortable." : "Les testeres de les columnes con botones puen ordenase.",
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Esta llista nun ta completa por motivos de rindimientu. Los ficheros van apaecer a midida que navegues pela llista.",
|
||||
"File not found" : "Nun s'atopó'l ficheru",
|
||||
"Views" : "Vistes",
|
||||
"Owner" : "Propietariu",
|
||||
"{usedQuotaByte} used" : "{usedQuotaByte} n'usu",
|
||||
"{used} of {quota} used" : "{used} de {quota} n'usu",
|
||||
@@ -153,6 +152,7 @@ OC.L10N.register(
|
||||
"No files in here" : "Nun hai ficheros",
|
||||
"Upload some content or sync with your devices!" : "¡Xubi conteníu o sincroniza daqué colos tos preseos!",
|
||||
"Go back" : "Dir p'atrás",
|
||||
"Views" : "Vistes",
|
||||
"Your files" : "Los tos ficheros",
|
||||
"Open in files" : "Abrir en Ficheros",
|
||||
"File cannot be accessed" : "Nun se pue acceder al ficheru",
|
||||
|
||||
@@ -109,7 +109,6 @@
|
||||
"Column headers with buttons are sortable." : "Les testeres de les columnes con botones puen ordenase.",
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Esta llista nun ta completa por motivos de rindimientu. Los ficheros van apaecer a midida que navegues pela llista.",
|
||||
"File not found" : "Nun s'atopó'l ficheru",
|
||||
"Views" : "Vistes",
|
||||
"Owner" : "Propietariu",
|
||||
"{usedQuotaByte} used" : "{usedQuotaByte} n'usu",
|
||||
"{used} of {quota} used" : "{used} de {quota} n'usu",
|
||||
@@ -151,6 +150,7 @@
|
||||
"No files in here" : "Nun hai ficheros",
|
||||
"Upload some content or sync with your devices!" : "¡Xubi conteníu o sincroniza daqué colos tos preseos!",
|
||||
"Go back" : "Dir p'atrás",
|
||||
"Views" : "Vistes",
|
||||
"Your files" : "Los tos ficheros",
|
||||
"Open in files" : "Abrir en Ficheros",
|
||||
"File cannot be accessed" : "Nun se pue acceder al ficheru",
|
||||
|
||||
@@ -171,7 +171,6 @@ OC.L10N.register(
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Този списък не е изобразен изцяло от съображения за производителност. Файловете ще се изобразяват, докато навигирате в списъка.",
|
||||
"File not found" : "Файлът не е намерен",
|
||||
"_{count} selected_::_{count} selected_" : ["{count} избрани","{count} избрани"],
|
||||
"Views" : "Изгледи",
|
||||
"Search everywhere …" : "Търсете навсякъде...",
|
||||
"Search here …" : "Търсете тук...",
|
||||
"Search scope options" : "Опции за обхват на търсене",
|
||||
@@ -249,6 +248,7 @@ OC.L10N.register(
|
||||
"No files in here" : "Няма файлове",
|
||||
"Upload some content or sync with your devices!" : "Качете съдържание или синхронизирайте с вашите устройства!",
|
||||
"Go back" : "Назад",
|
||||
"Views" : "Изгледи",
|
||||
"Your files" : "Вашите файлове",
|
||||
"Open in files" : "Отваряне във файлове",
|
||||
"File cannot be accessed" : "Файлът не е достъпен",
|
||||
|
||||
@@ -169,7 +169,6 @@
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Този списък не е изобразен изцяло от съображения за производителност. Файловете ще се изобразяват, докато навигирате в списъка.",
|
||||
"File not found" : "Файлът не е намерен",
|
||||
"_{count} selected_::_{count} selected_" : ["{count} избрани","{count} избрани"],
|
||||
"Views" : "Изгледи",
|
||||
"Search everywhere …" : "Търсете навсякъде...",
|
||||
"Search here …" : "Търсете тук...",
|
||||
"Search scope options" : "Опции за обхват на търсене",
|
||||
@@ -247,6 +246,7 @@
|
||||
"No files in here" : "Няма файлове",
|
||||
"Upload some content or sync with your devices!" : "Качете съдържание или синхронизирайте с вашите устройства!",
|
||||
"Go back" : "Назад",
|
||||
"Views" : "Изгледи",
|
||||
"Your files" : "Вашите файлове",
|
||||
"Open in files" : "Отваряне във файлове",
|
||||
"File cannot be accessed" : "Файлът не е достъпен",
|
||||
|
||||
@@ -146,7 +146,6 @@ OC.L10N.register(
|
||||
"Column headers with buttons are sortable." : "Les capçaleres de columna amb botons es poder ordenar.",
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Aquesta llista no es mostra completament per raons de rendiment. Es mostraran els fitxers a mesura que navegueu per la llista.",
|
||||
"File not found" : "No s'ha trobat el fitxer",
|
||||
"Views" : "Vistes",
|
||||
"Owner" : "Propietat",
|
||||
"{usedQuotaByte} used" : "{usedQuotaByte} en ús",
|
||||
"{used} of {quota} used" : "{used} de {quota} en ús",
|
||||
@@ -202,6 +201,7 @@ OC.L10N.register(
|
||||
"No files in here" : "No hi ha cap fitxer aquí",
|
||||
"Upload some content or sync with your devices!" : "Pugeu contingut o sincronitzeu els vostres dispositius!",
|
||||
"Go back" : "Torna",
|
||||
"Views" : "Vistes",
|
||||
"Your files" : "Els vostres fitxers",
|
||||
"Open in files" : "Obre a Fitxers",
|
||||
"File cannot be accessed" : "No es pot accedir al fitxer",
|
||||
|
||||
@@ -144,7 +144,6 @@
|
||||
"Column headers with buttons are sortable." : "Les capçaleres de columna amb botons es poder ordenar.",
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Aquesta llista no es mostra completament per raons de rendiment. Es mostraran els fitxers a mesura que navegueu per la llista.",
|
||||
"File not found" : "No s'ha trobat el fitxer",
|
||||
"Views" : "Vistes",
|
||||
"Owner" : "Propietat",
|
||||
"{usedQuotaByte} used" : "{usedQuotaByte} en ús",
|
||||
"{used} of {quota} used" : "{used} de {quota} en ús",
|
||||
@@ -200,6 +199,7 @@
|
||||
"No files in here" : "No hi ha cap fitxer aquí",
|
||||
"Upload some content or sync with your devices!" : "Pugeu contingut o sincronitzeu els vostres dispositius!",
|
||||
"Go back" : "Torna",
|
||||
"Views" : "Vistes",
|
||||
"Your files" : "Els vostres fitxers",
|
||||
"Open in files" : "Obre a Fitxers",
|
||||
"File cannot be accessed" : "No es pot accedir al fitxer",
|
||||
|
||||
@@ -175,7 +175,6 @@ OC.L10N.register(
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Seznam není vykreslen celý z důvodu nároků na výkon. Soubory budou dokreslovány, jak se budete posouvat seznamem.",
|
||||
"File not found" : "Soubor nenalezen",
|
||||
"_{count} selected_::_{count} selected_" : ["vybráno {count}","vybráno {count}","vybráno {count}","vybráno {count}"],
|
||||
"Views" : "Zobrazení",
|
||||
"Search everywhere …" : "Hledat všude …",
|
||||
"Search here …" : "Hledat zde …",
|
||||
"Search scope options" : "Předvolby rozsahu prohledávaného",
|
||||
@@ -257,6 +256,7 @@ OC.L10N.register(
|
||||
"No files in here" : "Žádné soubory",
|
||||
"Upload some content or sync with your devices!" : "Nahrajte nějaký obsah nebo proveďte synchronizaci se svými zařízeními!",
|
||||
"Go back" : "Jít zpět",
|
||||
"Views" : "Zobrazení",
|
||||
"Loading …" : "Načítání …",
|
||||
"Your files" : "Vaše soubory",
|
||||
"Open in files" : "Otevřít v aplikaci Soubory",
|
||||
|
||||
@@ -173,7 +173,6 @@
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Seznam není vykreslen celý z důvodu nároků na výkon. Soubory budou dokreslovány, jak se budete posouvat seznamem.",
|
||||
"File not found" : "Soubor nenalezen",
|
||||
"_{count} selected_::_{count} selected_" : ["vybráno {count}","vybráno {count}","vybráno {count}","vybráno {count}"],
|
||||
"Views" : "Zobrazení",
|
||||
"Search everywhere …" : "Hledat všude …",
|
||||
"Search here …" : "Hledat zde …",
|
||||
"Search scope options" : "Předvolby rozsahu prohledávaného",
|
||||
@@ -255,6 +254,7 @@
|
||||
"No files in here" : "Žádné soubory",
|
||||
"Upload some content or sync with your devices!" : "Nahrajte nějaký obsah nebo proveďte synchronizaci se svými zařízeními!",
|
||||
"Go back" : "Jít zpět",
|
||||
"Views" : "Zobrazení",
|
||||
"Loading …" : "Načítání …",
|
||||
"Your files" : "Vaše soubory",
|
||||
"Open in files" : "Otevřít v aplikaci Soubory",
|
||||
|
||||
@@ -168,7 +168,6 @@ OC.L10N.register(
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Hele listen er ikke hentet, af hensyn til størrelsen. Listen vil blive hentet løbende som du kører igennem listen.",
|
||||
"File not found" : "Filen blev ikke fundet",
|
||||
"_{count} selected_::_{count} selected_" : ["{count} valgt","{count} valgt"],
|
||||
"Views" : "Visninger",
|
||||
"Search everywhere …" : "Søg over alt ...",
|
||||
"Search here …" : "Søg her ...",
|
||||
"Search scope options" : "Indstillinger for søgeområde",
|
||||
@@ -246,6 +245,7 @@ OC.L10N.register(
|
||||
"No files in here" : "Her er ingen filer",
|
||||
"Upload some content or sync with your devices!" : "Upload indhold eller synkroniser med dine enheder!",
|
||||
"Go back" : "Gå tilbage",
|
||||
"Views" : "Visninger",
|
||||
"Loading …" : "Indlæser …",
|
||||
"Your files" : "Dine filer",
|
||||
"Open in files" : "Åben i Filer",
|
||||
|
||||
@@ -166,7 +166,6 @@
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Hele listen er ikke hentet, af hensyn til størrelsen. Listen vil blive hentet løbende som du kører igennem listen.",
|
||||
"File not found" : "Filen blev ikke fundet",
|
||||
"_{count} selected_::_{count} selected_" : ["{count} valgt","{count} valgt"],
|
||||
"Views" : "Visninger",
|
||||
"Search everywhere …" : "Søg over alt ...",
|
||||
"Search here …" : "Søg her ...",
|
||||
"Search scope options" : "Indstillinger for søgeområde",
|
||||
@@ -244,6 +243,7 @@
|
||||
"No files in here" : "Her er ingen filer",
|
||||
"Upload some content or sync with your devices!" : "Upload indhold eller synkroniser med dine enheder!",
|
||||
"Go back" : "Gå tilbage",
|
||||
"Views" : "Visninger",
|
||||
"Loading …" : "Indlæser …",
|
||||
"Your files" : "Dine filer",
|
||||
"Open in files" : "Åben i Filer",
|
||||
|
||||
@@ -175,7 +175,6 @@ OC.L10N.register(
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Diese Liste wird aus Performance-Gründen nicht vollständig angezeigt. Die Dateien werden angezeigt, wenn du durch die Liste navigierst.",
|
||||
"File not found" : "Datei nicht gefunden",
|
||||
"_{count} selected_::_{count} selected_" : ["{count} ausgewählt","{count} ausgewählt"],
|
||||
"Views" : "Ansichten",
|
||||
"Search everywhere …" : "Überall suchen …",
|
||||
"Search here …" : "Hier suchen …",
|
||||
"Search scope options" : "Suchbereichsoptionen",
|
||||
@@ -257,6 +256,7 @@ OC.L10N.register(
|
||||
"No files in here" : "Keine Dateien vorhanden",
|
||||
"Upload some content or sync with your devices!" : "Lade Inhalte hoch oder synchronisiere sie mit deinen Geräten!",
|
||||
"Go back" : "Zurückgehen",
|
||||
"Views" : "Ansichten",
|
||||
"Loading …" : "Lade …",
|
||||
"Your files" : "Deine Dateien",
|
||||
"Open in files" : "In Dateien öffnen",
|
||||
|
||||
@@ -173,7 +173,6 @@
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Diese Liste wird aus Performance-Gründen nicht vollständig angezeigt. Die Dateien werden angezeigt, wenn du durch die Liste navigierst.",
|
||||
"File not found" : "Datei nicht gefunden",
|
||||
"_{count} selected_::_{count} selected_" : ["{count} ausgewählt","{count} ausgewählt"],
|
||||
"Views" : "Ansichten",
|
||||
"Search everywhere …" : "Überall suchen …",
|
||||
"Search here …" : "Hier suchen …",
|
||||
"Search scope options" : "Suchbereichsoptionen",
|
||||
@@ -255,6 +254,7 @@
|
||||
"No files in here" : "Keine Dateien vorhanden",
|
||||
"Upload some content or sync with your devices!" : "Lade Inhalte hoch oder synchronisiere sie mit deinen Geräten!",
|
||||
"Go back" : "Zurückgehen",
|
||||
"Views" : "Ansichten",
|
||||
"Loading …" : "Lade …",
|
||||
"Your files" : "Deine Dateien",
|
||||
"Open in files" : "In Dateien öffnen",
|
||||
|
||||
@@ -175,7 +175,6 @@ OC.L10N.register(
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Diese Liste ist aus Performance-Gründen nicht vollständig gerendert. Die Dateien werden gerendert, wenn Sie durch die Liste navigieren.",
|
||||
"File not found" : "Datei nicht gefunden",
|
||||
"_{count} selected_::_{count} selected_" : ["{count} ausgewählt","{count} ausgewählt"],
|
||||
"Views" : "Ansichten",
|
||||
"Search everywhere …" : "Überall suchen …",
|
||||
"Search here …" : "Hier suchen …",
|
||||
"Search scope options" : "Suchbereichsoptionen",
|
||||
@@ -257,6 +256,7 @@ OC.L10N.register(
|
||||
"No files in here" : "Keine Dateien vorhanden",
|
||||
"Upload some content or sync with your devices!" : "Laden Sie Inhalte hoch oder synchronisieren Sie Ihre Geräte!",
|
||||
"Go back" : "Zurückgehen",
|
||||
"Views" : "Ansichten",
|
||||
"Loading …" : "Lade …",
|
||||
"Your files" : "Ihre Dateien",
|
||||
"Open in files" : "In Dateien öffnen",
|
||||
|
||||
@@ -173,7 +173,6 @@
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Diese Liste ist aus Performance-Gründen nicht vollständig gerendert. Die Dateien werden gerendert, wenn Sie durch die Liste navigieren.",
|
||||
"File not found" : "Datei nicht gefunden",
|
||||
"_{count} selected_::_{count} selected_" : ["{count} ausgewählt","{count} ausgewählt"],
|
||||
"Views" : "Ansichten",
|
||||
"Search everywhere …" : "Überall suchen …",
|
||||
"Search here …" : "Hier suchen …",
|
||||
"Search scope options" : "Suchbereichsoptionen",
|
||||
@@ -255,6 +254,7 @@
|
||||
"No files in here" : "Keine Dateien vorhanden",
|
||||
"Upload some content or sync with your devices!" : "Laden Sie Inhalte hoch oder synchronisieren Sie Ihre Geräte!",
|
||||
"Go back" : "Zurückgehen",
|
||||
"Views" : "Ansichten",
|
||||
"Loading …" : "Lade …",
|
||||
"Your files" : "Ihre Dateien",
|
||||
"Open in files" : "In Dateien öffnen",
|
||||
|
||||
@@ -168,7 +168,6 @@ OC.L10N.register(
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Η λίστα αυτή δεν εμφανίζεται πλήρως για λόγους απόδοσης. Τα αρχεία θα εμφανίζονται καθώς πλοηγείστε στη λίστα.",
|
||||
"File not found" : "Δε βρέθηκε το αρχείο",
|
||||
"_{count} selected_::_{count} selected_" : ["{count} επιλεγμένο","{count} επιλεγμένα"],
|
||||
"Views" : "Προβολές",
|
||||
"Search everywhere …" : "Αναζήτηση παντού …",
|
||||
"Search here …" : "Αναζήτηση εδώ …",
|
||||
"Search scope options" : "Επιλογές εμβέλειας αναζήτησης",
|
||||
@@ -246,6 +245,7 @@ OC.L10N.register(
|
||||
"No files in here" : "Δεν υπάρχουν αρχεία εδώ",
|
||||
"Upload some content or sync with your devices!" : "Μεταφόρτωση περιεχομένου ή συγχρονισμός με τις συσκευές σας!",
|
||||
"Go back" : "Επιστροφή",
|
||||
"Views" : "Προβολές",
|
||||
"Loading …" : "Φόρτωση …",
|
||||
"Your files" : "Τα αρχεία σας",
|
||||
"Open in files" : "Άνοιγμα στα αρχεία",
|
||||
|
||||
@@ -166,7 +166,6 @@
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Η λίστα αυτή δεν εμφανίζεται πλήρως για λόγους απόδοσης. Τα αρχεία θα εμφανίζονται καθώς πλοηγείστε στη λίστα.",
|
||||
"File not found" : "Δε βρέθηκε το αρχείο",
|
||||
"_{count} selected_::_{count} selected_" : ["{count} επιλεγμένο","{count} επιλεγμένα"],
|
||||
"Views" : "Προβολές",
|
||||
"Search everywhere …" : "Αναζήτηση παντού …",
|
||||
"Search here …" : "Αναζήτηση εδώ …",
|
||||
"Search scope options" : "Επιλογές εμβέλειας αναζήτησης",
|
||||
@@ -244,6 +243,7 @@
|
||||
"No files in here" : "Δεν υπάρχουν αρχεία εδώ",
|
||||
"Upload some content or sync with your devices!" : "Μεταφόρτωση περιεχομένου ή συγχρονισμός με τις συσκευές σας!",
|
||||
"Go back" : "Επιστροφή",
|
||||
"Views" : "Προβολές",
|
||||
"Loading …" : "Φόρτωση …",
|
||||
"Your files" : "Τα αρχεία σας",
|
||||
"Open in files" : "Άνοιγμα στα αρχεία",
|
||||
|
||||
@@ -175,7 +175,6 @@ OC.L10N.register(
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list.",
|
||||
"File not found" : "File not found",
|
||||
"_{count} selected_::_{count} selected_" : ["{count} selected","{count} selected"],
|
||||
"Views" : "Views",
|
||||
"Search everywhere …" : "Search everywhere …",
|
||||
"Search here …" : "Search here …",
|
||||
"Search scope options" : "Search scope options",
|
||||
@@ -257,6 +256,7 @@ OC.L10N.register(
|
||||
"No files in here" : "No files in here",
|
||||
"Upload some content or sync with your devices!" : "Upload some content or sync with your devices!",
|
||||
"Go back" : "Go back",
|
||||
"Views" : "Views",
|
||||
"Loading …" : "Loading …",
|
||||
"Your files" : "Your files",
|
||||
"Open in files" : "Open in files",
|
||||
|
||||
@@ -173,7 +173,6 @@
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list.",
|
||||
"File not found" : "File not found",
|
||||
"_{count} selected_::_{count} selected_" : ["{count} selected","{count} selected"],
|
||||
"Views" : "Views",
|
||||
"Search everywhere …" : "Search everywhere …",
|
||||
"Search here …" : "Search here …",
|
||||
"Search scope options" : "Search scope options",
|
||||
@@ -255,6 +254,7 @@
|
||||
"No files in here" : "No files in here",
|
||||
"Upload some content or sync with your devices!" : "Upload some content or sync with your devices!",
|
||||
"Go back" : "Go back",
|
||||
"Views" : "Views",
|
||||
"Loading …" : "Loading …",
|
||||
"Your files" : "Your files",
|
||||
"Open in files" : "Open in files",
|
||||
|
||||
@@ -175,7 +175,6 @@ OC.L10N.register(
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Esta lista no se muestra completamente por motivos de rendimiento. Los archivos se mostrarán a medida que navega por la lista.",
|
||||
"File not found" : "No se ha encontrado el archivo",
|
||||
"_{count} selected_::_{count} selected_" : ["{count} seleccionado","{count} seleccionados","{count} seleccionados"],
|
||||
"Views" : "Vistas",
|
||||
"Search everywhere …" : "Buscar en todas partes …",
|
||||
"Search here …" : "Buscar aquí …",
|
||||
"Search scope options" : "Opciones de alcance de la búsqueda",
|
||||
@@ -257,6 +256,7 @@ OC.L10N.register(
|
||||
"No files in here" : "Aquí no hay archivos",
|
||||
"Upload some content or sync with your devices!" : "¡Sube contenido o sincroniza tus dispositivos!",
|
||||
"Go back" : "Ir atrás",
|
||||
"Views" : "Vistas",
|
||||
"Loading …" : "Cargando …",
|
||||
"Your files" : "Sus archivos",
|
||||
"Open in files" : "Abrir en Archivos",
|
||||
|
||||
@@ -173,7 +173,6 @@
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Esta lista no se muestra completamente por motivos de rendimiento. Los archivos se mostrarán a medida que navega por la lista.",
|
||||
"File not found" : "No se ha encontrado el archivo",
|
||||
"_{count} selected_::_{count} selected_" : ["{count} seleccionado","{count} seleccionados","{count} seleccionados"],
|
||||
"Views" : "Vistas",
|
||||
"Search everywhere …" : "Buscar en todas partes …",
|
||||
"Search here …" : "Buscar aquí …",
|
||||
"Search scope options" : "Opciones de alcance de la búsqueda",
|
||||
@@ -255,6 +254,7 @@
|
||||
"No files in here" : "Aquí no hay archivos",
|
||||
"Upload some content or sync with your devices!" : "¡Sube contenido o sincroniza tus dispositivos!",
|
||||
"Go back" : "Ir atrás",
|
||||
"Views" : "Vistas",
|
||||
"Loading …" : "Cargando …",
|
||||
"Your files" : "Sus archivos",
|
||||
"Open in files" : "Abrir en Archivos",
|
||||
|
||||
@@ -129,7 +129,6 @@ OC.L10N.register(
|
||||
"Column headers with buttons are sortable." : "Las columnas con botones en la cabecera son ordenables.",
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Esta lista no se muestra completamente por motivos de rendimiento. Los archivos se mostrarán a medida que navega por la lista.",
|
||||
"File not found" : "Archivo no encontrado",
|
||||
"Views" : "Vistas",
|
||||
"Owner" : "Propietario",
|
||||
"{usedQuotaByte} used" : "{usedQuotaByte} utilizados",
|
||||
"{used} of {quota} used" : "{used} de {quota} usados",
|
||||
@@ -180,6 +179,7 @@ OC.L10N.register(
|
||||
"No files in here" : "No hay archivos aquí",
|
||||
"Upload some content or sync with your devices!" : "¡Carga algún contenido o sincroniza con tus dispositivos!",
|
||||
"Go back" : "Regresar",
|
||||
"Views" : "Vistas",
|
||||
"Your files" : "Sus archivos",
|
||||
"Open in files" : "Abrir en archivos",
|
||||
"File cannot be accessed" : "No se puede acceder al archivo",
|
||||
|
||||
@@ -127,7 +127,6 @@
|
||||
"Column headers with buttons are sortable." : "Las columnas con botones en la cabecera son ordenables.",
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Esta lista no se muestra completamente por motivos de rendimiento. Los archivos se mostrarán a medida que navega por la lista.",
|
||||
"File not found" : "Archivo no encontrado",
|
||||
"Views" : "Vistas",
|
||||
"Owner" : "Propietario",
|
||||
"{usedQuotaByte} used" : "{usedQuotaByte} utilizados",
|
||||
"{used} of {quota} used" : "{used} de {quota} usados",
|
||||
@@ -178,6 +177,7 @@
|
||||
"No files in here" : "No hay archivos aquí",
|
||||
"Upload some content or sync with your devices!" : "¡Carga algún contenido o sincroniza con tus dispositivos!",
|
||||
"Go back" : "Regresar",
|
||||
"Views" : "Vistas",
|
||||
"Your files" : "Sus archivos",
|
||||
"Open in files" : "Abrir en archivos",
|
||||
"File cannot be accessed" : "No se puede acceder al archivo",
|
||||
|
||||
@@ -175,7 +175,6 @@ OC.L10N.register(
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Jõudluse mõttes ei ole kogu loend esimesel hetkel tervikuna nähtav. Uued failid lisanduvad sedamööda, kuid sa loendis edasi liigud.",
|
||||
"File not found" : "Faili ei leitud",
|
||||
"_{count} selected_::_{count} selected_" : ["{count} valitud","{count} valitud"],
|
||||
"Views" : "Vaated",
|
||||
"Search everywhere …" : "Otsi kõikjalt…",
|
||||
"Search here …" : "Otsi siin…",
|
||||
"Search scope options" : "Otsinguulatuse valikud",
|
||||
@@ -257,6 +256,7 @@ OC.L10N.register(
|
||||
"No files in here" : "Siin ei ole faile",
|
||||
"Upload some content or sync with your devices!" : "Laadi sisu üles või süngi oma seadmetega!",
|
||||
"Go back" : "Mine tagasi",
|
||||
"Views" : "Vaated",
|
||||
"Loading …" : "Andmed on laadimisel…",
|
||||
"Your files" : "Sinu failid",
|
||||
"Open in files" : "Ava failirakenduses",
|
||||
|
||||
@@ -173,7 +173,6 @@
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Jõudluse mõttes ei ole kogu loend esimesel hetkel tervikuna nähtav. Uued failid lisanduvad sedamööda, kuid sa loendis edasi liigud.",
|
||||
"File not found" : "Faili ei leitud",
|
||||
"_{count} selected_::_{count} selected_" : ["{count} valitud","{count} valitud"],
|
||||
"Views" : "Vaated",
|
||||
"Search everywhere …" : "Otsi kõikjalt…",
|
||||
"Search here …" : "Otsi siin…",
|
||||
"Search scope options" : "Otsinguulatuse valikud",
|
||||
@@ -255,6 +254,7 @@
|
||||
"No files in here" : "Siin ei ole faile",
|
||||
"Upload some content or sync with your devices!" : "Laadi sisu üles või süngi oma seadmetega!",
|
||||
"Go back" : "Mine tagasi",
|
||||
"Views" : "Vaated",
|
||||
"Loading …" : "Andmed on laadimisel…",
|
||||
"Your files" : "Sinu failid",
|
||||
"Open in files" : "Ava failirakenduses",
|
||||
|
||||
@@ -172,7 +172,6 @@ OC.L10N.register(
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Zerrenda hau ez da guztiz ikusten errendimendu arrazoiengatik. Fitxategiak zerrendan zehar nabigatzen duten heinean bistaratuko dira.",
|
||||
"File not found" : "Ez da fitxategia aurkitu",
|
||||
"_{count} selected_::_{count} selected_" : ["{count} hautatuta","{count} hautatuta"],
|
||||
"Views" : "Ikuspegiak",
|
||||
"Search everywhere …" : "Bilatu nonahi …",
|
||||
"Search here …" : "Bilatu hemen …",
|
||||
"Search scope options" : "Bilaketa-eremuaren aukerak",
|
||||
@@ -250,6 +249,7 @@ OC.L10N.register(
|
||||
"No files in here" : "Ez dago fitxategirik hemen",
|
||||
"Upload some content or sync with your devices!" : "Igo edukiren bat edo sinkronizatu zure gailuekin!",
|
||||
"Go back" : "Atzera",
|
||||
"Views" : "Ikuspegiak",
|
||||
"Loading …" : "Kargatzen …",
|
||||
"Your files" : "Zure fitxategiak",
|
||||
"Open in files" : "Ireki Fitxategiak aplikazioan",
|
||||
|
||||
@@ -170,7 +170,6 @@
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Zerrenda hau ez da guztiz ikusten errendimendu arrazoiengatik. Fitxategiak zerrendan zehar nabigatzen duten heinean bistaratuko dira.",
|
||||
"File not found" : "Ez da fitxategia aurkitu",
|
||||
"_{count} selected_::_{count} selected_" : ["{count} hautatuta","{count} hautatuta"],
|
||||
"Views" : "Ikuspegiak",
|
||||
"Search everywhere …" : "Bilatu nonahi …",
|
||||
"Search here …" : "Bilatu hemen …",
|
||||
"Search scope options" : "Bilaketa-eremuaren aukerak",
|
||||
@@ -248,6 +247,7 @@
|
||||
"No files in here" : "Ez dago fitxategirik hemen",
|
||||
"Upload some content or sync with your devices!" : "Igo edukiren bat edo sinkronizatu zure gailuekin!",
|
||||
"Go back" : "Atzera",
|
||||
"Views" : "Ikuspegiak",
|
||||
"Loading …" : "Kargatzen …",
|
||||
"Your files" : "Zure fitxategiak",
|
||||
"Open in files" : "Ireki Fitxategiak aplikazioan",
|
||||
|
||||
@@ -172,7 +172,6 @@ OC.L10N.register(
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "این لیست به دلایل عملکرد به طور کامل ارائه نشده است. در حین حرکت در لیست، فایل ها ارائه می شوند.",
|
||||
"File not found" : "فایل یافت نشد",
|
||||
"_{count} selected_::_{count} selected_" : ["{count} انتخاب شده","{count} انتخاب شده"],
|
||||
"Views" : "بازدیدها",
|
||||
"Search everywhere …" : "جستجو در همهجا ...",
|
||||
"Search here …" : "جستجو ...",
|
||||
"Search scope options" : "گزینههای محدوده جستجو",
|
||||
@@ -250,6 +249,7 @@ OC.L10N.register(
|
||||
"No files in here" : "هیچ فایلی اینجا وجود ندارد",
|
||||
"Upload some content or sync with your devices!" : "محتوایی را آپلود کنید یا با دستگاه خود همگامسازی کنید!",
|
||||
"Go back" : "برگرد",
|
||||
"Views" : "بازدیدها",
|
||||
"Loading …" : "بارگیری",
|
||||
"Your files" : "فایلهای شما",
|
||||
"Open in files" : "باز کردن در فایلها",
|
||||
|
||||
@@ -170,7 +170,6 @@
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "این لیست به دلایل عملکرد به طور کامل ارائه نشده است. در حین حرکت در لیست، فایل ها ارائه می شوند.",
|
||||
"File not found" : "فایل یافت نشد",
|
||||
"_{count} selected_::_{count} selected_" : ["{count} انتخاب شده","{count} انتخاب شده"],
|
||||
"Views" : "بازدیدها",
|
||||
"Search everywhere …" : "جستجو در همهجا ...",
|
||||
"Search here …" : "جستجو ...",
|
||||
"Search scope options" : "گزینههای محدوده جستجو",
|
||||
@@ -248,6 +247,7 @@
|
||||
"No files in here" : "هیچ فایلی اینجا وجود ندارد",
|
||||
"Upload some content or sync with your devices!" : "محتوایی را آپلود کنید یا با دستگاه خود همگامسازی کنید!",
|
||||
"Go back" : "برگرد",
|
||||
"Views" : "بازدیدها",
|
||||
"Loading …" : "بارگیری",
|
||||
"Your files" : "فایلهای شما",
|
||||
"Open in files" : "باز کردن در فایلها",
|
||||
|
||||
@@ -157,7 +157,6 @@ OC.L10N.register(
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Tätä luetteloa ei ole esitetty täysin suorituskykyyn liittyvistä syistä. Tiedostot esitetään sitä mukaa, kun selaat luetteloa.",
|
||||
"File not found" : "Tiedostoa ei löytynyt",
|
||||
"_{count} selected_::_{count} selected_" : ["{count} valittu","{count} valittu"],
|
||||
"Views" : "Näkymät",
|
||||
"Search everywhere …" : "Etsi kaikkialta …",
|
||||
"Search here …" : "Etsi täältä …",
|
||||
"Search here" : "Etsi tästä",
|
||||
@@ -222,6 +221,7 @@ OC.L10N.register(
|
||||
"No files in here" : "Täällä ei ole tiedostoja",
|
||||
"Upload some content or sync with your devices!" : "Lähetä tiedostoja tai synkronoi sisältö laitteidesi kanssa!",
|
||||
"Go back" : "Mene takaisin",
|
||||
"Views" : "Näkymät",
|
||||
"Loading …" : "Ladataan …",
|
||||
"Your files" : "Tiedostot",
|
||||
"Open in files" : "Avaa tiedostosovelluksessa",
|
||||
|
||||
@@ -155,7 +155,6 @@
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Tätä luetteloa ei ole esitetty täysin suorituskykyyn liittyvistä syistä. Tiedostot esitetään sitä mukaa, kun selaat luetteloa.",
|
||||
"File not found" : "Tiedostoa ei löytynyt",
|
||||
"_{count} selected_::_{count} selected_" : ["{count} valittu","{count} valittu"],
|
||||
"Views" : "Näkymät",
|
||||
"Search everywhere …" : "Etsi kaikkialta …",
|
||||
"Search here …" : "Etsi täältä …",
|
||||
"Search here" : "Etsi tästä",
|
||||
@@ -220,6 +219,7 @@
|
||||
"No files in here" : "Täällä ei ole tiedostoja",
|
||||
"Upload some content or sync with your devices!" : "Lähetä tiedostoja tai synkronoi sisältö laitteidesi kanssa!",
|
||||
"Go back" : "Mene takaisin",
|
||||
"Views" : "Näkymät",
|
||||
"Loading …" : "Ladataan …",
|
||||
"Your files" : "Tiedostot",
|
||||
"Open in files" : "Avaa tiedostosovelluksessa",
|
||||
|
||||
@@ -175,7 +175,6 @@ OC.L10N.register(
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Cette liste n'est pas entièrement affichée pour des raisons de performances. Les fichiers seront affichés au fur et à mesure que vous naviguerez dans la liste.",
|
||||
"File not found" : "Fichier non trouvé",
|
||||
"_{count} selected_::_{count} selected_" : ["{count} sélectionné","{count} sélectionné(s)","{count} sélectionné(s)"],
|
||||
"Views" : "Vues",
|
||||
"Search everywhere …" : "Rechercher partout …",
|
||||
"Search here …" : "Rechercher ici …",
|
||||
"Search scope options" : "Options de portée de recherche",
|
||||
@@ -257,6 +256,7 @@ OC.L10N.register(
|
||||
"No files in here" : "Aucun fichier",
|
||||
"Upload some content or sync with your devices!" : "Déposez du contenu ou synchronisez vos appareils !",
|
||||
"Go back" : "Revenir en arrière",
|
||||
"Views" : "Vues",
|
||||
"Loading …" : "Chargement...",
|
||||
"Your files" : "Vos fichiers",
|
||||
"Open in files" : "Ouvrir dans Fichiers",
|
||||
|
||||
@@ -173,7 +173,6 @@
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Cette liste n'est pas entièrement affichée pour des raisons de performances. Les fichiers seront affichés au fur et à mesure que vous naviguerez dans la liste.",
|
||||
"File not found" : "Fichier non trouvé",
|
||||
"_{count} selected_::_{count} selected_" : ["{count} sélectionné","{count} sélectionné(s)","{count} sélectionné(s)"],
|
||||
"Views" : "Vues",
|
||||
"Search everywhere …" : "Rechercher partout …",
|
||||
"Search here …" : "Rechercher ici …",
|
||||
"Search scope options" : "Options de portée de recherche",
|
||||
@@ -255,6 +254,7 @@
|
||||
"No files in here" : "Aucun fichier",
|
||||
"Upload some content or sync with your devices!" : "Déposez du contenu ou synchronisez vos appareils !",
|
||||
"Go back" : "Revenir en arrière",
|
||||
"Views" : "Vues",
|
||||
"Loading …" : "Chargement...",
|
||||
"Your files" : "Vos fichiers",
|
||||
"Open in files" : "Ouvrir dans Fichiers",
|
||||
|
||||
@@ -175,7 +175,6 @@ OC.L10N.register(
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Níl an liosta seo le fáil go hiomlán ar chúiseanna feidhmíochta. Déanfar na comhaid a rindreáil agus tú ag dul tríd an liosta.",
|
||||
"File not found" : "Comhad gan aimsiú",
|
||||
"_{count} selected_::_{count} selected_" : ["{count} roghnaithe","{count} roghnaithe","{count} roghnaithe","{count} roghnaithe","{count} roghnaithe"],
|
||||
"Views" : "Radhairc",
|
||||
"Search everywhere …" : "Cuardaigh i ngach áit …",
|
||||
"Search here …" : "Cuardaigh anseo …",
|
||||
"Search scope options" : "Roghanna raon feidhme cuardaigh",
|
||||
@@ -257,6 +256,7 @@ OC.L10N.register(
|
||||
"No files in here" : "Níl aon chomhaid istigh anseo",
|
||||
"Upload some content or sync with your devices!" : "Uaslódáil roinnt inneachair nó sioncronaigh le do ghléasanna!",
|
||||
"Go back" : "Dul ar ais",
|
||||
"Views" : "Radhairc",
|
||||
"Loading …" : "Ag luchtú …",
|
||||
"Your files" : "Do chuid comhad",
|
||||
"Open in files" : "Oscail i gcomhaid",
|
||||
|
||||
@@ -173,7 +173,6 @@
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Níl an liosta seo le fáil go hiomlán ar chúiseanna feidhmíochta. Déanfar na comhaid a rindreáil agus tú ag dul tríd an liosta.",
|
||||
"File not found" : "Comhad gan aimsiú",
|
||||
"_{count} selected_::_{count} selected_" : ["{count} roghnaithe","{count} roghnaithe","{count} roghnaithe","{count} roghnaithe","{count} roghnaithe"],
|
||||
"Views" : "Radhairc",
|
||||
"Search everywhere …" : "Cuardaigh i ngach áit …",
|
||||
"Search here …" : "Cuardaigh anseo …",
|
||||
"Search scope options" : "Roghanna raon feidhme cuardaigh",
|
||||
@@ -255,6 +254,7 @@
|
||||
"No files in here" : "Níl aon chomhaid istigh anseo",
|
||||
"Upload some content or sync with your devices!" : "Uaslódáil roinnt inneachair nó sioncronaigh le do ghléasanna!",
|
||||
"Go back" : "Dul ar ais",
|
||||
"Views" : "Radhairc",
|
||||
"Loading …" : "Ag luchtú …",
|
||||
"Your files" : "Do chuid comhad",
|
||||
"Open in files" : "Oscail i gcomhaid",
|
||||
|
||||
@@ -175,7 +175,6 @@ OC.L10N.register(
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Esta lista non se representa de xeito completo por mor do rendemento. Os ficheiros represéntanse mentres se despraza pola lista.",
|
||||
"File not found" : "Non se atopou o ficheiro",
|
||||
"_{count} selected_::_{count} selected_" : ["{count} seleccionado","{count} seleccionados"],
|
||||
"Views" : "Vistas",
|
||||
"Search everywhere …" : "Buscar en todos os sitios…",
|
||||
"Search here …" : "Buscar aquí…",
|
||||
"Search scope options" : "Opcións do alcance da busca",
|
||||
@@ -257,6 +256,7 @@ OC.L10N.register(
|
||||
"No files in here" : "Aquí non hai ficheiros",
|
||||
"Upload some content or sync with your devices!" : "Envíe algún contido ou sincronice cos seus dispositivos!",
|
||||
"Go back" : "Volver",
|
||||
"Views" : "Vistas",
|
||||
"Loading …" : "Cargando…",
|
||||
"Your files" : "Os seus ficheiros",
|
||||
"Open in files" : "Abrir en ficheiros",
|
||||
|
||||
@@ -173,7 +173,6 @@
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Esta lista non se representa de xeito completo por mor do rendemento. Os ficheiros represéntanse mentres se despraza pola lista.",
|
||||
"File not found" : "Non se atopou o ficheiro",
|
||||
"_{count} selected_::_{count} selected_" : ["{count} seleccionado","{count} seleccionados"],
|
||||
"Views" : "Vistas",
|
||||
"Search everywhere …" : "Buscar en todos os sitios…",
|
||||
"Search here …" : "Buscar aquí…",
|
||||
"Search scope options" : "Opcións do alcance da busca",
|
||||
@@ -255,6 +254,7 @@
|
||||
"No files in here" : "Aquí non hai ficheiros",
|
||||
"Upload some content or sync with your devices!" : "Envíe algún contido ou sincronice cos seus dispositivos!",
|
||||
"Go back" : "Volver",
|
||||
"Views" : "Vistas",
|
||||
"Loading …" : "Cargando…",
|
||||
"Your files" : "Os seus ficheiros",
|
||||
"Open in files" : "Abrir en ficheiros",
|
||||
|
||||
@@ -175,7 +175,6 @@ OC.L10N.register(
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Ovaj popis nije u potpunosti prikazan zbog performansnih razloga. Datoteke će se prikazivati kako se krećete kroz popis.",
|
||||
"File not found" : "Datoteka nije pronađena",
|
||||
"_{count} selected_::_{count} selected_" : ["Odabrano je {count}","Odabrano je {count}","Odabrano je {count}"],
|
||||
"Views" : "Prikazi",
|
||||
"Search everywhere …" : "Traži svugdje …",
|
||||
"Search here …" : "Traži ovdje …",
|
||||
"Search scope options" : "Opcije opsega pretraživanja",
|
||||
@@ -257,6 +256,7 @@ OC.L10N.register(
|
||||
"No files in here" : "Nema datoteka",
|
||||
"Upload some content or sync with your devices!" : "Otpremite neki sadržaj ili sinkronizirajte sa svojim uređajima!",
|
||||
"Go back" : "Natrag",
|
||||
"Views" : "Prikazi",
|
||||
"Loading …" : "Učitavanje …",
|
||||
"Your files" : "Vaše datoteke",
|
||||
"Open in files" : "Otvori u datotekama",
|
||||
|
||||
@@ -173,7 +173,6 @@
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Ovaj popis nije u potpunosti prikazan zbog performansnih razloga. Datoteke će se prikazivati kako se krećete kroz popis.",
|
||||
"File not found" : "Datoteka nije pronađena",
|
||||
"_{count} selected_::_{count} selected_" : ["Odabrano je {count}","Odabrano je {count}","Odabrano je {count}"],
|
||||
"Views" : "Prikazi",
|
||||
"Search everywhere …" : "Traži svugdje …",
|
||||
"Search here …" : "Traži ovdje …",
|
||||
"Search scope options" : "Opcije opsega pretraživanja",
|
||||
@@ -255,6 +254,7 @@
|
||||
"No files in here" : "Nema datoteka",
|
||||
"Upload some content or sync with your devices!" : "Otpremite neki sadržaj ili sinkronizirajte sa svojim uređajima!",
|
||||
"Go back" : "Natrag",
|
||||
"Views" : "Prikazi",
|
||||
"Loading …" : "Učitavanje …",
|
||||
"Your files" : "Vaše datoteke",
|
||||
"Open in files" : "Otvori u datotekama",
|
||||
|
||||
@@ -172,7 +172,6 @@ OC.L10N.register(
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Ez a lista teljesítménybeli okokból nincs teljes egészében megjelenítve. A fájlok a listában navigálás során jelennek meg.",
|
||||
"File not found" : "A fájl nem található",
|
||||
"_{count} selected_::_{count} selected_" : ["{count} kijelölve","{count} kijelölve"],
|
||||
"Views" : "Nézetek",
|
||||
"Search everywhere …" : "Keresés mindenhol…",
|
||||
"Search here …" : "Keresés itt…",
|
||||
"Search scope options" : "Keresési hatókör beállításai",
|
||||
@@ -250,6 +249,7 @@ OC.L10N.register(
|
||||
"No files in here" : "Itt nincsenek fájlok",
|
||||
"Upload some content or sync with your devices!" : "Töltsön fel néhány tartalmat, vagy szinkronizáljon az eszközeivel.",
|
||||
"Go back" : "Visszalépés",
|
||||
"Views" : "Nézetek",
|
||||
"Loading …" : "Betöltés…",
|
||||
"Your files" : "Saját fájlok",
|
||||
"Open in files" : "Megnyitás a fájlokban",
|
||||
|
||||
@@ -170,7 +170,6 @@
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Ez a lista teljesítménybeli okokból nincs teljes egészében megjelenítve. A fájlok a listában navigálás során jelennek meg.",
|
||||
"File not found" : "A fájl nem található",
|
||||
"_{count} selected_::_{count} selected_" : ["{count} kijelölve","{count} kijelölve"],
|
||||
"Views" : "Nézetek",
|
||||
"Search everywhere …" : "Keresés mindenhol…",
|
||||
"Search here …" : "Keresés itt…",
|
||||
"Search scope options" : "Keresési hatókör beállításai",
|
||||
@@ -248,6 +247,7 @@
|
||||
"No files in here" : "Itt nincsenek fájlok",
|
||||
"Upload some content or sync with your devices!" : "Töltsön fel néhány tartalmat, vagy szinkronizáljon az eszközeivel.",
|
||||
"Go back" : "Visszalépés",
|
||||
"Views" : "Nézetek",
|
||||
"Loading …" : "Betöltés…",
|
||||
"Your files" : "Saját fájlok",
|
||||
"Open in files" : "Megnyitás a fájlokban",
|
||||
|
||||
@@ -172,7 +172,6 @@ OC.L10N.register(
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Daftar ini tidak dirender sepenuhnya demi alasan performa. File akan dirender saat Anda menavigasi melalui daftar.",
|
||||
"File not found" : "Berkas tidak ditemukan",
|
||||
"_{count} selected_::_{count} selected_" : ["{count} dipilih"],
|
||||
"Views" : "Tampilan",
|
||||
"Search everywhere …" : "Cari di mana saja …",
|
||||
"Search here …" : "Cari di sini …",
|
||||
"Search scope options" : "Opsi cakupan pencarian",
|
||||
@@ -250,6 +249,7 @@ OC.L10N.register(
|
||||
"No files in here" : "Tidak ada berkas di sini",
|
||||
"Upload some content or sync with your devices!" : "Unggah beberapa konten dan sinkronisasikan dengan perangkat Anda!",
|
||||
"Go back" : "Kembali",
|
||||
"Views" : "Tampilan",
|
||||
"Loading …" : "Memuat …",
|
||||
"Your files" : "File Anda",
|
||||
"Open in files" : "Buka di File",
|
||||
|
||||
@@ -170,7 +170,6 @@
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Daftar ini tidak dirender sepenuhnya demi alasan performa. File akan dirender saat Anda menavigasi melalui daftar.",
|
||||
"File not found" : "Berkas tidak ditemukan",
|
||||
"_{count} selected_::_{count} selected_" : ["{count} dipilih"],
|
||||
"Views" : "Tampilan",
|
||||
"Search everywhere …" : "Cari di mana saja …",
|
||||
"Search here …" : "Cari di sini …",
|
||||
"Search scope options" : "Opsi cakupan pencarian",
|
||||
@@ -248,6 +247,7 @@
|
||||
"No files in here" : "Tidak ada berkas di sini",
|
||||
"Upload some content or sync with your devices!" : "Unggah beberapa konten dan sinkronisasikan dengan perangkat Anda!",
|
||||
"Go back" : "Kembali",
|
||||
"Views" : "Tampilan",
|
||||
"Loading …" : "Memuat …",
|
||||
"Your files" : "File Anda",
|
||||
"Open in files" : "Buka di File",
|
||||
|
||||
@@ -168,7 +168,6 @@ OC.L10N.register(
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Til að halda sem bestum afköstum er þessi listi ekki myndgerður að fullu. Skrárnar munu birtast eftir því sem farið er í gegnum listann.",
|
||||
"File not found" : "Skrá finnst ekki",
|
||||
"_{count} selected_::_{count} selected_" : ["{count} valið","{count} valið"],
|
||||
"Views" : "Skoðun",
|
||||
"Search everywhere …" : "Leita allsstaðar …",
|
||||
"Search here …" : "Leita hér …",
|
||||
"Search scope options" : "Valkostir leitarsviðs",
|
||||
@@ -246,6 +245,7 @@ OC.L10N.register(
|
||||
"No files in here" : "Engar skrár hér",
|
||||
"Upload some content or sync with your devices!" : "Sendu inn eitthvað efni eða samstilltu við tækin þín!",
|
||||
"Go back" : "Fara til baka",
|
||||
"Views" : "Skoðun",
|
||||
"Your files" : "Skrárnar þínar",
|
||||
"Open in files" : "Opna í skráaforritinu",
|
||||
"File cannot be accessed" : "Skráin er ekki aðgengileg",
|
||||
|
||||
@@ -166,7 +166,6 @@
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Til að halda sem bestum afköstum er þessi listi ekki myndgerður að fullu. Skrárnar munu birtast eftir því sem farið er í gegnum listann.",
|
||||
"File not found" : "Skrá finnst ekki",
|
||||
"_{count} selected_::_{count} selected_" : ["{count} valið","{count} valið"],
|
||||
"Views" : "Skoðun",
|
||||
"Search everywhere …" : "Leita allsstaðar …",
|
||||
"Search here …" : "Leita hér …",
|
||||
"Search scope options" : "Valkostir leitarsviðs",
|
||||
@@ -244,6 +243,7 @@
|
||||
"No files in here" : "Engar skrár hér",
|
||||
"Upload some content or sync with your devices!" : "Sendu inn eitthvað efni eða samstilltu við tækin þín!",
|
||||
"Go back" : "Fara til baka",
|
||||
"Views" : "Skoðun",
|
||||
"Your files" : "Skrárnar þínar",
|
||||
"Open in files" : "Opna í skráaforritinu",
|
||||
"File cannot be accessed" : "Skráin er ekki aðgengileg",
|
||||
|
||||
@@ -175,7 +175,6 @@ OC.L10N.register(
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Questa lista non è stata mostrata completamente per ragioni di prestazioni. I file verranno mostrati durante la navigazione della lista.",
|
||||
"File not found" : "File non trovato",
|
||||
"_{count} selected_::_{count} selected_" : ["{count} selezionato","{count} selezionati","{count} selezionati"],
|
||||
"Views" : "Viste",
|
||||
"Search everywhere …" : "Cerca ovunque …",
|
||||
"Search here …" : "Cerca qui …",
|
||||
"Search scope options" : "Opzioni nell'ambito di ricerca",
|
||||
@@ -253,6 +252,7 @@ OC.L10N.register(
|
||||
"No files in here" : "Qui non c'è alcun file",
|
||||
"Upload some content or sync with your devices!" : "Carica dei contenuti o sincronizza con i tuoi dispositivi!",
|
||||
"Go back" : "Indietro",
|
||||
"Views" : "Viste",
|
||||
"Loading …" : "Caricamento in corso...",
|
||||
"Your files" : "I tuoi files",
|
||||
"Open in files" : "Apri in file",
|
||||
|
||||
@@ -173,7 +173,6 @@
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "Questa lista non è stata mostrata completamente per ragioni di prestazioni. I file verranno mostrati durante la navigazione della lista.",
|
||||
"File not found" : "File non trovato",
|
||||
"_{count} selected_::_{count} selected_" : ["{count} selezionato","{count} selezionati","{count} selezionati"],
|
||||
"Views" : "Viste",
|
||||
"Search everywhere …" : "Cerca ovunque …",
|
||||
"Search here …" : "Cerca qui …",
|
||||
"Search scope options" : "Opzioni nell'ambito di ricerca",
|
||||
@@ -251,6 +250,7 @@
|
||||
"No files in here" : "Qui non c'è alcun file",
|
||||
"Upload some content or sync with your devices!" : "Carica dei contenuti o sincronizza con i tuoi dispositivi!",
|
||||
"Go back" : "Indietro",
|
||||
"Views" : "Viste",
|
||||
"Loading …" : "Caricamento in corso...",
|
||||
"Your files" : "I tuoi files",
|
||||
"Open in files" : "Apri in file",
|
||||
|
||||
@@ -175,7 +175,6 @@ OC.L10N.register(
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "このリストはパフォーマンスの都合上、すべてレンダリングされているわけではありません。リスト内を移動すると、ファイルが次々と表示されていきます。",
|
||||
"File not found" : "ファイルが見つかりません",
|
||||
"_{count} selected_::_{count} selected_" : ["{count}選択済み"],
|
||||
"Views" : "表示",
|
||||
"Search everywhere …" : "あらゆる場所を検索 …",
|
||||
"Search here …" : "ここを検索 …",
|
||||
"Search scope options" : "検索範囲オプション",
|
||||
@@ -257,6 +256,7 @@ OC.L10N.register(
|
||||
"No files in here" : "ファイルがありません",
|
||||
"Upload some content or sync with your devices!" : "何かコンテンツをアップロードするか、デバイスからファイルを同期してください。",
|
||||
"Go back" : "戻る",
|
||||
"Views" : "表示",
|
||||
"Loading …" : "読み込み中…",
|
||||
"Your files" : "あなたのファイル",
|
||||
"Open in files" : "ファイルで開く",
|
||||
|
||||
@@ -173,7 +173,6 @@
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "このリストはパフォーマンスの都合上、すべてレンダリングされているわけではありません。リスト内を移動すると、ファイルが次々と表示されていきます。",
|
||||
"File not found" : "ファイルが見つかりません",
|
||||
"_{count} selected_::_{count} selected_" : ["{count}選択済み"],
|
||||
"Views" : "表示",
|
||||
"Search everywhere …" : "あらゆる場所を検索 …",
|
||||
"Search here …" : "ここを検索 …",
|
||||
"Search scope options" : "検索範囲オプション",
|
||||
@@ -255,6 +254,7 @@
|
||||
"No files in here" : "ファイルがありません",
|
||||
"Upload some content or sync with your devices!" : "何かコンテンツをアップロードするか、デバイスからファイルを同期してください。",
|
||||
"Go back" : "戻る",
|
||||
"Views" : "表示",
|
||||
"Loading …" : "読み込み中…",
|
||||
"Your files" : "あなたのファイル",
|
||||
"Open in files" : "ファイルで開く",
|
||||
|
||||
@@ -154,7 +154,6 @@ OC.L10N.register(
|
||||
"Column headers with buttons are sortable." : "버튼이 있는 열 머리글은 정렬할 수 있습니다.",
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "성능 상의 이유로 목록을 전부 표시하지 않았습니다. 목록을 탐색하면 파일들이 표시됩니다.",
|
||||
"File not found" : "파일을 찾을 수 없음",
|
||||
"Views" : "보기",
|
||||
"Search everywhere …" : "모든 곳에서 검색 ...",
|
||||
"Search here …" : "여기서 검색 ...",
|
||||
"Search here" : "여기서 검색",
|
||||
@@ -212,6 +211,7 @@ OC.L10N.register(
|
||||
"No files in here" : "여기에 파일 없음",
|
||||
"Upload some content or sync with your devices!" : "파일을 업로드하거나 장치와 동기화하십시오!",
|
||||
"Go back" : "뒤로 가기",
|
||||
"Views" : "보기",
|
||||
"Loading …" : "로딩 중 …",
|
||||
"Your files" : "내 파일",
|
||||
"Open in files" : "파일에서 열기",
|
||||
|
||||
@@ -152,7 +152,6 @@
|
||||
"Column headers with buttons are sortable." : "버튼이 있는 열 머리글은 정렬할 수 있습니다.",
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "성능 상의 이유로 목록을 전부 표시하지 않았습니다. 목록을 탐색하면 파일들이 표시됩니다.",
|
||||
"File not found" : "파일을 찾을 수 없음",
|
||||
"Views" : "보기",
|
||||
"Search everywhere …" : "모든 곳에서 검색 ...",
|
||||
"Search here …" : "여기서 검색 ...",
|
||||
"Search here" : "여기서 검색",
|
||||
@@ -210,6 +209,7 @@
|
||||
"No files in here" : "여기에 파일 없음",
|
||||
"Upload some content or sync with your devices!" : "파일을 업로드하거나 장치와 동기화하십시오!",
|
||||
"Go back" : "뒤로 가기",
|
||||
"Views" : "보기",
|
||||
"Loading …" : "로딩 중 …",
|
||||
"Your files" : "내 파일",
|
||||
"Open in files" : "파일에서 열기",
|
||||
|
||||
@@ -172,7 +172,6 @@ OC.L10N.register(
|
||||
"This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list." : "This list is not fully rendered for performance reasons. The files will be rendered as you navigate through the list.",
|
||||
"File not found" : "File not found",
|
||||
"_{count} selected_::_{count} selected_" : ["ເລືອກ{count}"],
|
||||
"Views" : "Views",
|
||||
"Search everywhere …" : "Search everywhere …",
|
||||
"Search here …" : "Search here …",
|
||||
"Search scope options" : "Search scope options",
|
||||
@@ -250,6 +249,7 @@ OC.L10N.register(
|
||||
"No files in here" : "ບໍ່ມີຟາຍໃນທີ່ນີ້",
|
||||
"Upload some content or sync with your devices!" : "Upload some content or sync with your devices!",
|
||||
"Go back" : "Go back",
|
||||
"Views" : "Views",
|
||||
"Loading …" : "Loading …",
|
||||
"Your files" : "Your files",
|
||||
"Open in files" : "Open in files",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user